@point3/node-rdkafka 3.6.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (707) hide show
  1. package/LICENSE.txt +20 -0
  2. package/README.md +636 -0
  3. package/binding.gyp +154 -0
  4. package/deps/librdkafka/.clang-format +136 -0
  5. package/deps/librdkafka/.clang-format-cpp +103 -0
  6. package/deps/librdkafka/.dir-locals.el +10 -0
  7. package/deps/librdkafka/.formatignore +33 -0
  8. package/deps/librdkafka/.gdbmacros +19 -0
  9. package/deps/librdkafka/.github/CODEOWNERS +1 -0
  10. package/deps/librdkafka/.github/ISSUE_TEMPLATE +34 -0
  11. package/deps/librdkafka/.semaphore/run-all-tests.yml +77 -0
  12. package/deps/librdkafka/.semaphore/semaphore-integration.yml +250 -0
  13. package/deps/librdkafka/.semaphore/semaphore.yml +378 -0
  14. package/deps/librdkafka/.semaphore/verify-linux-packages.yml +41 -0
  15. package/deps/librdkafka/CHANGELOG.md +2208 -0
  16. package/deps/librdkafka/CMakeLists.txt +291 -0
  17. package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
  18. package/deps/librdkafka/CONFIGURATION.md +209 -0
  19. package/deps/librdkafka/CONTRIBUTING.md +431 -0
  20. package/deps/librdkafka/Doxyfile +2375 -0
  21. package/deps/librdkafka/INTRODUCTION.md +2481 -0
  22. package/deps/librdkafka/LICENSE +26 -0
  23. package/deps/librdkafka/LICENSE.cjson +22 -0
  24. package/deps/librdkafka/LICENSE.crc32c +28 -0
  25. package/deps/librdkafka/LICENSE.fnv1a +18 -0
  26. package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
  27. package/deps/librdkafka/LICENSE.lz4 +26 -0
  28. package/deps/librdkafka/LICENSE.murmur2 +25 -0
  29. package/deps/librdkafka/LICENSE.nanopb +22 -0
  30. package/deps/librdkafka/LICENSE.opentelemetry +203 -0
  31. package/deps/librdkafka/LICENSE.pycrc +23 -0
  32. package/deps/librdkafka/LICENSE.queue +31 -0
  33. package/deps/librdkafka/LICENSE.regexp +5 -0
  34. package/deps/librdkafka/LICENSE.snappy +36 -0
  35. package/deps/librdkafka/LICENSE.tinycthread +26 -0
  36. package/deps/librdkafka/LICENSE.wingetopt +49 -0
  37. package/deps/librdkafka/LICENSES.txt +625 -0
  38. package/deps/librdkafka/Makefile +125 -0
  39. package/deps/librdkafka/README.md +199 -0
  40. package/deps/librdkafka/README.win32 +26 -0
  41. package/deps/librdkafka/STATISTICS.md +624 -0
  42. package/deps/librdkafka/configure +214 -0
  43. package/deps/librdkafka/configure.self +331 -0
  44. package/deps/librdkafka/debian/changelog +111 -0
  45. package/deps/librdkafka/debian/compat +1 -0
  46. package/deps/librdkafka/debian/control +71 -0
  47. package/deps/librdkafka/debian/copyright +99 -0
  48. package/deps/librdkafka/debian/gbp.conf +9 -0
  49. package/deps/librdkafka/debian/librdkafka++1.install +1 -0
  50. package/deps/librdkafka/debian/librdkafka-dev.examples +2 -0
  51. package/deps/librdkafka/debian/librdkafka-dev.install +9 -0
  52. package/deps/librdkafka/debian/librdkafka1.docs +5 -0
  53. package/deps/librdkafka/debian/librdkafka1.install +1 -0
  54. package/deps/librdkafka/debian/librdkafka1.symbols +135 -0
  55. package/deps/librdkafka/debian/rules +19 -0
  56. package/deps/librdkafka/debian/source/format +1 -0
  57. package/deps/librdkafka/debian/watch +2 -0
  58. package/deps/librdkafka/dev-conf.sh +123 -0
  59. package/deps/librdkafka/examples/CMakeLists.txt +79 -0
  60. package/deps/librdkafka/examples/Makefile +167 -0
  61. package/deps/librdkafka/examples/README.md +42 -0
  62. package/deps/librdkafka/examples/alter_consumer_group_offsets.c +338 -0
  63. package/deps/librdkafka/examples/consumer.c +271 -0
  64. package/deps/librdkafka/examples/delete_records.c +233 -0
  65. package/deps/librdkafka/examples/describe_cluster.c +322 -0
  66. package/deps/librdkafka/examples/describe_consumer_groups.c +455 -0
  67. package/deps/librdkafka/examples/describe_topics.c +427 -0
  68. package/deps/librdkafka/examples/elect_leaders.c +317 -0
  69. package/deps/librdkafka/examples/globals.json +11 -0
  70. package/deps/librdkafka/examples/idempotent_producer.c +344 -0
  71. package/deps/librdkafka/examples/incremental_alter_configs.c +347 -0
  72. package/deps/librdkafka/examples/kafkatest_verifiable_client.cpp +945 -0
  73. package/deps/librdkafka/examples/list_consumer_group_offsets.c +359 -0
  74. package/deps/librdkafka/examples/list_consumer_groups.c +365 -0
  75. package/deps/librdkafka/examples/list_offsets.c +327 -0
  76. package/deps/librdkafka/examples/misc.c +287 -0
  77. package/deps/librdkafka/examples/openssl_engine_example.cpp +248 -0
  78. package/deps/librdkafka/examples/producer.c +251 -0
  79. package/deps/librdkafka/examples/producer.cpp +228 -0
  80. package/deps/librdkafka/examples/rdkafka_complex_consumer_example.c +617 -0
  81. package/deps/librdkafka/examples/rdkafka_complex_consumer_example.cpp +467 -0
  82. package/deps/librdkafka/examples/rdkafka_consume_batch.cpp +264 -0
  83. package/deps/librdkafka/examples/rdkafka_example.c +853 -0
  84. package/deps/librdkafka/examples/rdkafka_example.cpp +679 -0
  85. package/deps/librdkafka/examples/rdkafka_performance.c +1781 -0
  86. package/deps/librdkafka/examples/transactions-older-broker.c +668 -0
  87. package/deps/librdkafka/examples/transactions.c +665 -0
  88. package/deps/librdkafka/examples/user_scram.c +491 -0
  89. package/deps/librdkafka/examples/win_ssl_cert_store.cpp +396 -0
  90. package/deps/librdkafka/lds-gen.py +73 -0
  91. package/deps/librdkafka/mainpage.doxy +40 -0
  92. package/deps/librdkafka/mklove/Makefile.base +329 -0
  93. package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
  94. package/deps/librdkafka/mklove/modules/configure.base +2484 -0
  95. package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
  96. package/deps/librdkafka/mklove/modules/configure.cc +186 -0
  97. package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
  98. package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
  99. package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
  100. package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
  101. package/deps/librdkafka/mklove/modules/configure.host +132 -0
  102. package/deps/librdkafka/mklove/modules/configure.lib +49 -0
  103. package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
  104. package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
  105. package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
  106. package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
  107. package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
  108. package/deps/librdkafka/mklove/modules/configure.pic +16 -0
  109. package/deps/librdkafka/mklove/modules/configure.socket +20 -0
  110. package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
  111. package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
  112. package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
  113. package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
  114. package/deps/librdkafka/packaging/RELEASE.md +319 -0
  115. package/deps/librdkafka/packaging/alpine/build-alpine.sh +38 -0
  116. package/deps/librdkafka/packaging/archlinux/PKGBUILD +30 -0
  117. package/deps/librdkafka/packaging/cmake/Config.cmake.in +37 -0
  118. package/deps/librdkafka/packaging/cmake/Modules/FindLZ4.cmake +38 -0
  119. package/deps/librdkafka/packaging/cmake/Modules/FindZSTD.cmake +27 -0
  120. package/deps/librdkafka/packaging/cmake/Modules/LICENSE.FindZstd +178 -0
  121. package/deps/librdkafka/packaging/cmake/README.md +38 -0
  122. package/deps/librdkafka/packaging/cmake/config.h.in +52 -0
  123. package/deps/librdkafka/packaging/cmake/parseversion.cmake +60 -0
  124. package/deps/librdkafka/packaging/cmake/rdkafka.pc.in +12 -0
  125. package/deps/librdkafka/packaging/cmake/try_compile/atomic_32_test.c +8 -0
  126. package/deps/librdkafka/packaging/cmake/try_compile/atomic_64_test.c +8 -0
  127. package/deps/librdkafka/packaging/cmake/try_compile/c11threads_test.c +14 -0
  128. package/deps/librdkafka/packaging/cmake/try_compile/crc32c_hw_test.c +27 -0
  129. package/deps/librdkafka/packaging/cmake/try_compile/dlopen_test.c +11 -0
  130. package/deps/librdkafka/packaging/cmake/try_compile/libsasl2_test.c +7 -0
  131. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_darwin_test.c +6 -0
  132. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_freebsd_test.c +7 -0
  133. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_gnu_test.c +5 -0
  134. package/deps/librdkafka/packaging/cmake/try_compile/rand_r_test.c +7 -0
  135. package/deps/librdkafka/packaging/cmake/try_compile/rdkafka_setup.cmake +122 -0
  136. package/deps/librdkafka/packaging/cmake/try_compile/regex_test.c +10 -0
  137. package/deps/librdkafka/packaging/cmake/try_compile/strndup_test.c +5 -0
  138. package/deps/librdkafka/packaging/cmake/try_compile/sync_32_test.c +8 -0
  139. package/deps/librdkafka/packaging/cmake/try_compile/sync_64_test.c +8 -0
  140. package/deps/librdkafka/packaging/cp/README.md +16 -0
  141. package/deps/librdkafka/packaging/cp/check_features.c +72 -0
  142. package/deps/librdkafka/packaging/cp/verify-deb.sh +33 -0
  143. package/deps/librdkafka/packaging/cp/verify-packages.sh +69 -0
  144. package/deps/librdkafka/packaging/cp/verify-rpm.sh +32 -0
  145. package/deps/librdkafka/packaging/debian/changelog +66 -0
  146. package/deps/librdkafka/packaging/debian/compat +1 -0
  147. package/deps/librdkafka/packaging/debian/control +49 -0
  148. package/deps/librdkafka/packaging/debian/copyright +84 -0
  149. package/deps/librdkafka/packaging/debian/docs +5 -0
  150. package/deps/librdkafka/packaging/debian/gbp.conf +9 -0
  151. package/deps/librdkafka/packaging/debian/librdkafka-dev.dirs +2 -0
  152. package/deps/librdkafka/packaging/debian/librdkafka-dev.examples +2 -0
  153. package/deps/librdkafka/packaging/debian/librdkafka-dev.install +6 -0
  154. package/deps/librdkafka/packaging/debian/librdkafka-dev.substvars +1 -0
  155. package/deps/librdkafka/packaging/debian/librdkafka.dsc +16 -0
  156. package/deps/librdkafka/packaging/debian/librdkafka1-dbg.substvars +1 -0
  157. package/deps/librdkafka/packaging/debian/librdkafka1.dirs +1 -0
  158. package/deps/librdkafka/packaging/debian/librdkafka1.install +2 -0
  159. package/deps/librdkafka/packaging/debian/librdkafka1.postinst.debhelper +5 -0
  160. package/deps/librdkafka/packaging/debian/librdkafka1.postrm.debhelper +5 -0
  161. package/deps/librdkafka/packaging/debian/librdkafka1.symbols +64 -0
  162. package/deps/librdkafka/packaging/debian/rules +19 -0
  163. package/deps/librdkafka/packaging/debian/source/format +1 -0
  164. package/deps/librdkafka/packaging/debian/watch +2 -0
  165. package/deps/librdkafka/packaging/get_version.py +21 -0
  166. package/deps/librdkafka/packaging/homebrew/README.md +15 -0
  167. package/deps/librdkafka/packaging/homebrew/brew-update-pr.sh +31 -0
  168. package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw-static.sh +52 -0
  169. package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw.sh +21 -0
  170. package/deps/librdkafka/packaging/mingw-w64/export-variables.sh +13 -0
  171. package/deps/librdkafka/packaging/mingw-w64/run-tests.sh +6 -0
  172. package/deps/librdkafka/packaging/mingw-w64/semaphoreci-build.sh +38 -0
  173. package/deps/librdkafka/packaging/nuget/README.md +84 -0
  174. package/deps/librdkafka/packaging/nuget/artifact.py +177 -0
  175. package/deps/librdkafka/packaging/nuget/cleanup-s3.py +143 -0
  176. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr120.zip +0 -0
  177. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr140.zip +0 -0
  178. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr120.zip +0 -0
  179. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr140.zip +0 -0
  180. package/deps/librdkafka/packaging/nuget/nuget.sh +21 -0
  181. package/deps/librdkafka/packaging/nuget/nugetpackage.py +278 -0
  182. package/deps/librdkafka/packaging/nuget/packaging.py +448 -0
  183. package/deps/librdkafka/packaging/nuget/push-to-nuget.sh +21 -0
  184. package/deps/librdkafka/packaging/nuget/release.py +167 -0
  185. package/deps/librdkafka/packaging/nuget/requirements.txt +3 -0
  186. package/deps/librdkafka/packaging/nuget/staticpackage.py +178 -0
  187. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.nuspec +21 -0
  188. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.props +18 -0
  189. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.targets +19 -0
  190. package/deps/librdkafka/packaging/nuget/zfile/__init__.py +0 -0
  191. package/deps/librdkafka/packaging/nuget/zfile/zfile.py +98 -0
  192. package/deps/librdkafka/packaging/rpm/Makefile +92 -0
  193. package/deps/librdkafka/packaging/rpm/README.md +23 -0
  194. package/deps/librdkafka/packaging/rpm/el7-x86_64.cfg +40 -0
  195. package/deps/librdkafka/packaging/rpm/librdkafka.spec +118 -0
  196. package/deps/librdkafka/packaging/rpm/mock-on-docker.sh +96 -0
  197. package/deps/librdkafka/packaging/rpm/tests/Makefile +25 -0
  198. package/deps/librdkafka/packaging/rpm/tests/README.md +8 -0
  199. package/deps/librdkafka/packaging/rpm/tests/run-test.sh +42 -0
  200. package/deps/librdkafka/packaging/rpm/tests/test-on-docker.sh +56 -0
  201. package/deps/librdkafka/packaging/rpm/tests/test.c +77 -0
  202. package/deps/librdkafka/packaging/rpm/tests/test.cpp +34 -0
  203. package/deps/librdkafka/packaging/tools/Dockerfile +31 -0
  204. package/deps/librdkafka/packaging/tools/build-configurations-checks.sh +12 -0
  205. package/deps/librdkafka/packaging/tools/build-deb-package.sh +64 -0
  206. package/deps/librdkafka/packaging/tools/build-debian.sh +65 -0
  207. package/deps/librdkafka/packaging/tools/build-manylinux.sh +68 -0
  208. package/deps/librdkafka/packaging/tools/build-release-artifacts.sh +139 -0
  209. package/deps/librdkafka/packaging/tools/distro-build.sh +38 -0
  210. package/deps/librdkafka/packaging/tools/gh-release-checksums.py +39 -0
  211. package/deps/librdkafka/packaging/tools/rdutcoverage.sh +25 -0
  212. package/deps/librdkafka/packaging/tools/requirements.txt +2 -0
  213. package/deps/librdkafka/packaging/tools/run-in-docker.sh +28 -0
  214. package/deps/librdkafka/packaging/tools/run-integration-tests.sh +31 -0
  215. package/deps/librdkafka/packaging/tools/run-style-check.sh +4 -0
  216. package/deps/librdkafka/packaging/tools/style-format.sh +149 -0
  217. package/deps/librdkafka/packaging/tools/update_rpcs_max_versions.py +100 -0
  218. package/deps/librdkafka/service.yml +172 -0
  219. package/deps/librdkafka/src/CMakeLists.txt +374 -0
  220. package/deps/librdkafka/src/Makefile +103 -0
  221. package/deps/librdkafka/src/README.lz4.md +30 -0
  222. package/deps/librdkafka/src/cJSON.c +2834 -0
  223. package/deps/librdkafka/src/cJSON.h +398 -0
  224. package/deps/librdkafka/src/crc32c.c +430 -0
  225. package/deps/librdkafka/src/crc32c.h +38 -0
  226. package/deps/librdkafka/src/generate_proto.sh +66 -0
  227. package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
  228. package/deps/librdkafka/src/lz4.c +2727 -0
  229. package/deps/librdkafka/src/lz4.h +842 -0
  230. package/deps/librdkafka/src/lz4frame.c +2078 -0
  231. package/deps/librdkafka/src/lz4frame.h +692 -0
  232. package/deps/librdkafka/src/lz4frame_static.h +47 -0
  233. package/deps/librdkafka/src/lz4hc.c +1631 -0
  234. package/deps/librdkafka/src/lz4hc.h +413 -0
  235. package/deps/librdkafka/src/nanopb/pb.h +917 -0
  236. package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
  237. package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
  238. package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
  239. package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
  240. package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
  241. package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
  242. package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
  243. package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
  244. package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
  245. package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
  246. package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
  247. package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
  248. package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
  249. package/deps/librdkafka/src/queue.h +850 -0
  250. package/deps/librdkafka/src/rd.h +584 -0
  251. package/deps/librdkafka/src/rdaddr.c +255 -0
  252. package/deps/librdkafka/src/rdaddr.h +202 -0
  253. package/deps/librdkafka/src/rdatomic.h +230 -0
  254. package/deps/librdkafka/src/rdavg.h +260 -0
  255. package/deps/librdkafka/src/rdavl.c +210 -0
  256. package/deps/librdkafka/src/rdavl.h +250 -0
  257. package/deps/librdkafka/src/rdbase64.c +200 -0
  258. package/deps/librdkafka/src/rdbase64.h +43 -0
  259. package/deps/librdkafka/src/rdbuf.c +1884 -0
  260. package/deps/librdkafka/src/rdbuf.h +375 -0
  261. package/deps/librdkafka/src/rdcrc32.c +114 -0
  262. package/deps/librdkafka/src/rdcrc32.h +170 -0
  263. package/deps/librdkafka/src/rddl.c +179 -0
  264. package/deps/librdkafka/src/rddl.h +43 -0
  265. package/deps/librdkafka/src/rdendian.h +175 -0
  266. package/deps/librdkafka/src/rdfloat.h +67 -0
  267. package/deps/librdkafka/src/rdfnv1a.c +113 -0
  268. package/deps/librdkafka/src/rdfnv1a.h +35 -0
  269. package/deps/librdkafka/src/rdgz.c +120 -0
  270. package/deps/librdkafka/src/rdgz.h +46 -0
  271. package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
  272. package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
  273. package/deps/librdkafka/src/rdhttp.c +830 -0
  274. package/deps/librdkafka/src/rdhttp.h +101 -0
  275. package/deps/librdkafka/src/rdinterval.h +177 -0
  276. package/deps/librdkafka/src/rdkafka.c +5505 -0
  277. package/deps/librdkafka/src/rdkafka.h +10686 -0
  278. package/deps/librdkafka/src/rdkafka_admin.c +9794 -0
  279. package/deps/librdkafka/src/rdkafka_admin.h +661 -0
  280. package/deps/librdkafka/src/rdkafka_assignment.c +1010 -0
  281. package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
  282. package/deps/librdkafka/src/rdkafka_assignor.c +1786 -0
  283. package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
  284. package/deps/librdkafka/src/rdkafka_aux.c +409 -0
  285. package/deps/librdkafka/src/rdkafka_aux.h +174 -0
  286. package/deps/librdkafka/src/rdkafka_background.c +221 -0
  287. package/deps/librdkafka/src/rdkafka_broker.c +6337 -0
  288. package/deps/librdkafka/src/rdkafka_broker.h +744 -0
  289. package/deps/librdkafka/src/rdkafka_buf.c +543 -0
  290. package/deps/librdkafka/src/rdkafka_buf.h +1525 -0
  291. package/deps/librdkafka/src/rdkafka_cert.c +576 -0
  292. package/deps/librdkafka/src/rdkafka_cert.h +62 -0
  293. package/deps/librdkafka/src/rdkafka_cgrp.c +7587 -0
  294. package/deps/librdkafka/src/rdkafka_cgrp.h +477 -0
  295. package/deps/librdkafka/src/rdkafka_conf.c +4880 -0
  296. package/deps/librdkafka/src/rdkafka_conf.h +732 -0
  297. package/deps/librdkafka/src/rdkafka_confval.h +97 -0
  298. package/deps/librdkafka/src/rdkafka_coord.c +623 -0
  299. package/deps/librdkafka/src/rdkafka_coord.h +132 -0
  300. package/deps/librdkafka/src/rdkafka_error.c +228 -0
  301. package/deps/librdkafka/src/rdkafka_error.h +80 -0
  302. package/deps/librdkafka/src/rdkafka_event.c +502 -0
  303. package/deps/librdkafka/src/rdkafka_event.h +126 -0
  304. package/deps/librdkafka/src/rdkafka_feature.c +898 -0
  305. package/deps/librdkafka/src/rdkafka_feature.h +104 -0
  306. package/deps/librdkafka/src/rdkafka_fetcher.c +1422 -0
  307. package/deps/librdkafka/src/rdkafka_fetcher.h +44 -0
  308. package/deps/librdkafka/src/rdkafka_header.c +220 -0
  309. package/deps/librdkafka/src/rdkafka_header.h +76 -0
  310. package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
  311. package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
  312. package/deps/librdkafka/src/rdkafka_int.h +1260 -0
  313. package/deps/librdkafka/src/rdkafka_interceptor.c +819 -0
  314. package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
  315. package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
  316. package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
  317. package/deps/librdkafka/src/rdkafka_metadata.c +2209 -0
  318. package/deps/librdkafka/src/rdkafka_metadata.h +345 -0
  319. package/deps/librdkafka/src/rdkafka_metadata_cache.c +1183 -0
  320. package/deps/librdkafka/src/rdkafka_mock.c +3661 -0
  321. package/deps/librdkafka/src/rdkafka_mock.h +610 -0
  322. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +1876 -0
  323. package/deps/librdkafka/src/rdkafka_mock_handlers.c +3113 -0
  324. package/deps/librdkafka/src/rdkafka_mock_int.h +710 -0
  325. package/deps/librdkafka/src/rdkafka_msg.c +2589 -0
  326. package/deps/librdkafka/src/rdkafka_msg.h +614 -0
  327. package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
  328. package/deps/librdkafka/src/rdkafka_msgset.h +98 -0
  329. package/deps/librdkafka/src/rdkafka_msgset_reader.c +1806 -0
  330. package/deps/librdkafka/src/rdkafka_msgset_writer.c +1474 -0
  331. package/deps/librdkafka/src/rdkafka_offset.c +1565 -0
  332. package/deps/librdkafka/src/rdkafka_offset.h +150 -0
  333. package/deps/librdkafka/src/rdkafka_op.c +997 -0
  334. package/deps/librdkafka/src/rdkafka_op.h +858 -0
  335. package/deps/librdkafka/src/rdkafka_partition.c +4896 -0
  336. package/deps/librdkafka/src/rdkafka_partition.h +1182 -0
  337. package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
  338. package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
  339. package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
  340. package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
  341. package/deps/librdkafka/src/rdkafka_proto.h +736 -0
  342. package/deps/librdkafka/src/rdkafka_protocol.h +128 -0
  343. package/deps/librdkafka/src/rdkafka_queue.c +1230 -0
  344. package/deps/librdkafka/src/rdkafka_queue.h +1220 -0
  345. package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
  346. package/deps/librdkafka/src/rdkafka_request.c +7089 -0
  347. package/deps/librdkafka/src/rdkafka_request.h +732 -0
  348. package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
  349. package/deps/librdkafka/src/rdkafka_sasl.c +530 -0
  350. package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
  351. package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
  352. package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
  353. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1833 -0
  354. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
  355. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +1666 -0
  356. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +47 -0
  357. package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
  358. package/deps/librdkafka/src/rdkafka_sasl_scram.c +858 -0
  359. package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
  360. package/deps/librdkafka/src/rdkafka_ssl.c +2129 -0
  361. package/deps/librdkafka/src/rdkafka_ssl.h +86 -0
  362. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4785 -0
  363. package/deps/librdkafka/src/rdkafka_subscription.c +278 -0
  364. package/deps/librdkafka/src/rdkafka_telemetry.c +760 -0
  365. package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
  366. package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1053 -0
  367. package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
  368. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +997 -0
  369. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +301 -0
  370. package/deps/librdkafka/src/rdkafka_timer.c +402 -0
  371. package/deps/librdkafka/src/rdkafka_timer.h +117 -0
  372. package/deps/librdkafka/src/rdkafka_topic.c +2161 -0
  373. package/deps/librdkafka/src/rdkafka_topic.h +334 -0
  374. package/deps/librdkafka/src/rdkafka_transport.c +1309 -0
  375. package/deps/librdkafka/src/rdkafka_transport.h +99 -0
  376. package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
  377. package/deps/librdkafka/src/rdkafka_txnmgr.c +3256 -0
  378. package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
  379. package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
  380. package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
  381. package/deps/librdkafka/src/rdlist.c +576 -0
  382. package/deps/librdkafka/src/rdlist.h +434 -0
  383. package/deps/librdkafka/src/rdlog.c +89 -0
  384. package/deps/librdkafka/src/rdlog.h +41 -0
  385. package/deps/librdkafka/src/rdmap.c +508 -0
  386. package/deps/librdkafka/src/rdmap.h +492 -0
  387. package/deps/librdkafka/src/rdmurmur2.c +167 -0
  388. package/deps/librdkafka/src/rdmurmur2.h +35 -0
  389. package/deps/librdkafka/src/rdports.c +61 -0
  390. package/deps/librdkafka/src/rdports.h +38 -0
  391. package/deps/librdkafka/src/rdposix.h +250 -0
  392. package/deps/librdkafka/src/rdrand.c +80 -0
  393. package/deps/librdkafka/src/rdrand.h +43 -0
  394. package/deps/librdkafka/src/rdregex.c +156 -0
  395. package/deps/librdkafka/src/rdregex.h +43 -0
  396. package/deps/librdkafka/src/rdsignal.h +57 -0
  397. package/deps/librdkafka/src/rdstring.c +645 -0
  398. package/deps/librdkafka/src/rdstring.h +98 -0
  399. package/deps/librdkafka/src/rdsysqueue.h +404 -0
  400. package/deps/librdkafka/src/rdtime.h +356 -0
  401. package/deps/librdkafka/src/rdtypes.h +86 -0
  402. package/deps/librdkafka/src/rdunittest.c +549 -0
  403. package/deps/librdkafka/src/rdunittest.h +232 -0
  404. package/deps/librdkafka/src/rdvarint.c +134 -0
  405. package/deps/librdkafka/src/rdvarint.h +165 -0
  406. package/deps/librdkafka/src/rdwin32.h +382 -0
  407. package/deps/librdkafka/src/rdxxhash.c +1030 -0
  408. package/deps/librdkafka/src/rdxxhash.h +328 -0
  409. package/deps/librdkafka/src/regexp.c +1352 -0
  410. package/deps/librdkafka/src/regexp.h +41 -0
  411. package/deps/librdkafka/src/snappy.c +1866 -0
  412. package/deps/librdkafka/src/snappy.h +62 -0
  413. package/deps/librdkafka/src/snappy_compat.h +138 -0
  414. package/deps/librdkafka/src/statistics_schema.json +444 -0
  415. package/deps/librdkafka/src/tinycthread.c +932 -0
  416. package/deps/librdkafka/src/tinycthread.h +503 -0
  417. package/deps/librdkafka/src/tinycthread_extra.c +199 -0
  418. package/deps/librdkafka/src/tinycthread_extra.h +212 -0
  419. package/deps/librdkafka/src/win32_config.h +58 -0
  420. package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
  421. package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
  422. package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
  423. package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
  424. package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
  425. package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
  426. package/deps/librdkafka/src-cpp/Makefile +55 -0
  427. package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
  428. package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
  429. package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
  430. package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
  431. package/deps/librdkafka/src-cpp/README.md +16 -0
  432. package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
  433. package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
  434. package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
  435. package/deps/librdkafka/src-cpp/rdkafkacpp.h +3797 -0
  436. package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
  437. package/deps/librdkafka/tests/0000-unittests.c +72 -0
  438. package/deps/librdkafka/tests/0001-multiobj.c +102 -0
  439. package/deps/librdkafka/tests/0002-unkpart.c +244 -0
  440. package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
  441. package/deps/librdkafka/tests/0004-conf.c +934 -0
  442. package/deps/librdkafka/tests/0005-order.c +133 -0
  443. package/deps/librdkafka/tests/0006-symbols.c +163 -0
  444. package/deps/librdkafka/tests/0007-autotopic.c +136 -0
  445. package/deps/librdkafka/tests/0008-reqacks.c +179 -0
  446. package/deps/librdkafka/tests/0009-mock_cluster.c +97 -0
  447. package/deps/librdkafka/tests/0011-produce_batch.c +753 -0
  448. package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
  449. package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
  450. package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
  451. package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
  452. package/deps/librdkafka/tests/0016-client_swname.c +181 -0
  453. package/deps/librdkafka/tests/0017-compression.c +140 -0
  454. package/deps/librdkafka/tests/0018-cgrp_term.c +338 -0
  455. package/deps/librdkafka/tests/0019-list_groups.c +289 -0
  456. package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
  457. package/deps/librdkafka/tests/0021-rkt_destroy.c +72 -0
  458. package/deps/librdkafka/tests/0022-consume_batch.c +279 -0
  459. package/deps/librdkafka/tests/0025-timers.c +147 -0
  460. package/deps/librdkafka/tests/0026-consume_pause.c +547 -0
  461. package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
  462. package/deps/librdkafka/tests/0029-assign_offset.c +202 -0
  463. package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
  464. package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
  465. package/deps/librdkafka/tests/0033-regex_subscribe.c +536 -0
  466. package/deps/librdkafka/tests/0034-offset_reset.c +398 -0
  467. package/deps/librdkafka/tests/0035-api_version.c +73 -0
  468. package/deps/librdkafka/tests/0036-partial_fetch.c +87 -0
  469. package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
  470. package/deps/librdkafka/tests/0038-performance.c +121 -0
  471. package/deps/librdkafka/tests/0039-event.c +284 -0
  472. package/deps/librdkafka/tests/0040-io_event.c +257 -0
  473. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +97 -0
  474. package/deps/librdkafka/tests/0042-many_topics.c +252 -0
  475. package/deps/librdkafka/tests/0043-no_connection.c +77 -0
  476. package/deps/librdkafka/tests/0044-partition_cnt.c +94 -0
  477. package/deps/librdkafka/tests/0045-subscribe_update.c +1010 -0
  478. package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
  479. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +98 -0
  480. package/deps/librdkafka/tests/0048-partitioner.c +283 -0
  481. package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
  482. package/deps/librdkafka/tests/0050-subscribe_adds.c +145 -0
  483. package/deps/librdkafka/tests/0051-assign_adds.c +126 -0
  484. package/deps/librdkafka/tests/0052-msg_timestamps.c +238 -0
  485. package/deps/librdkafka/tests/0053-stats_cb.cpp +527 -0
  486. package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
  487. package/deps/librdkafka/tests/0055-producer_latency.c +539 -0
  488. package/deps/librdkafka/tests/0056-balanced_group_mt.c +315 -0
  489. package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
  490. package/deps/librdkafka/tests/0058-log.cpp +123 -0
  491. package/deps/librdkafka/tests/0059-bsearch.cpp +241 -0
  492. package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
  493. package/deps/librdkafka/tests/0061-consumer_lag.cpp +295 -0
  494. package/deps/librdkafka/tests/0062-stats_event.c +126 -0
  495. package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
  496. package/deps/librdkafka/tests/0064-interceptors.c +481 -0
  497. package/deps/librdkafka/tests/0065-yield.cpp +140 -0
  498. package/deps/librdkafka/tests/0066-plugins.cpp +129 -0
  499. package/deps/librdkafka/tests/0067-empty_topic.cpp +151 -0
  500. package/deps/librdkafka/tests/0068-produce_timeout.c +136 -0
  501. package/deps/librdkafka/tests/0069-consumer_add_parts.c +119 -0
  502. package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
  503. package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
  504. package/deps/librdkafka/tests/0073-headers.c +381 -0
  505. package/deps/librdkafka/tests/0074-producev.c +87 -0
  506. package/deps/librdkafka/tests/0075-retry.c +290 -0
  507. package/deps/librdkafka/tests/0076-produce_retry.c +452 -0
  508. package/deps/librdkafka/tests/0077-compaction.c +363 -0
  509. package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
  510. package/deps/librdkafka/tests/0079-fork.c +93 -0
  511. package/deps/librdkafka/tests/0080-admin_ut.c +3095 -0
  512. package/deps/librdkafka/tests/0081-admin.c +5633 -0
  513. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +137 -0
  514. package/deps/librdkafka/tests/0083-cb_event.c +233 -0
  515. package/deps/librdkafka/tests/0084-destroy_flags.c +208 -0
  516. package/deps/librdkafka/tests/0085-headers.cpp +392 -0
  517. package/deps/librdkafka/tests/0086-purge.c +368 -0
  518. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
  519. package/deps/librdkafka/tests/0089-max_poll_interval.c +511 -0
  520. package/deps/librdkafka/tests/0090-idempotence.c +171 -0
  521. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +295 -0
  522. package/deps/librdkafka/tests/0092-mixed_msgver.c +103 -0
  523. package/deps/librdkafka/tests/0093-holb.c +200 -0
  524. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +231 -0
  525. package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
  526. package/deps/librdkafka/tests/0097-ssl_verify.cpp +658 -0
  527. package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
  528. package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
  529. package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
  530. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
  531. package/deps/librdkafka/tests/0102-static_group_rebalance.c +836 -0
  532. package/deps/librdkafka/tests/0103-transactions.c +1383 -0
  533. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +625 -0
  534. package/deps/librdkafka/tests/0105-transactions_mock.c +3930 -0
  535. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +318 -0
  536. package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
  537. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +278 -0
  538. package/deps/librdkafka/tests/0110-batch_size.cpp +182 -0
  539. package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
  540. package/deps/librdkafka/tests/0112-assign_unknown_part.c +87 -0
  541. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3473 -0
  542. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
  543. package/deps/librdkafka/tests/0115-producer_auth.cpp +182 -0
  544. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +216 -0
  545. package/deps/librdkafka/tests/0117-mock_errors.c +331 -0
  546. package/deps/librdkafka/tests/0118-commit_rebalance.c +154 -0
  547. package/deps/librdkafka/tests/0119-consumer_auth.cpp +167 -0
  548. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +185 -0
  549. package/deps/librdkafka/tests/0121-clusterid.c +115 -0
  550. package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
  551. package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
  552. package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
  553. package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
  554. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +528 -0
  555. package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
  556. package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +125 -0
  557. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +79 -0
  558. package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
  559. package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
  560. package/deps/librdkafka/tests/0132-strategy_ordering.c +179 -0
  561. package/deps/librdkafka/tests/0133-ssl_keys.c +150 -0
  562. package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
  563. package/deps/librdkafka/tests/0135-sasl_credentials.cpp +143 -0
  564. package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
  565. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +619 -0
  566. package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
  567. package/deps/librdkafka/tests/0139-offset_validation_mock.c +950 -0
  568. package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
  569. package/deps/librdkafka/tests/0142-reauthentication.c +515 -0
  570. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +552 -0
  571. package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
  572. package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
  573. package/deps/librdkafka/tests/0146-metadata_mock.c +505 -0
  574. package/deps/librdkafka/tests/0147-consumer_group_consumer_mock.c +952 -0
  575. package/deps/librdkafka/tests/0148-offset_fetch_commit_error_mock.c +563 -0
  576. package/deps/librdkafka/tests/0149-broker-same-host-port.c +140 -0
  577. package/deps/librdkafka/tests/0150-telemetry_mock.c +651 -0
  578. package/deps/librdkafka/tests/0151-purge-brokers.c +566 -0
  579. package/deps/librdkafka/tests/0152-rebootstrap.c +59 -0
  580. package/deps/librdkafka/tests/0153-memberid.c +128 -0
  581. package/deps/librdkafka/tests/1000-unktopic.c +164 -0
  582. package/deps/librdkafka/tests/8000-idle.cpp +60 -0
  583. package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
  584. package/deps/librdkafka/tests/CMakeLists.txt +170 -0
  585. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +291 -0
  586. package/deps/librdkafka/tests/Makefile +182 -0
  587. package/deps/librdkafka/tests/README.md +509 -0
  588. package/deps/librdkafka/tests/autotest.sh +33 -0
  589. package/deps/librdkafka/tests/backtrace.gdb +30 -0
  590. package/deps/librdkafka/tests/broker_version_tests.py +315 -0
  591. package/deps/librdkafka/tests/buildbox.sh +17 -0
  592. package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
  593. package/deps/librdkafka/tests/cluster_testing.py +191 -0
  594. package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
  595. package/deps/librdkafka/tests/fixtures/oauthbearer/jwt_assertion_template.json +10 -0
  596. package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
  597. package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
  598. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.intermediate.p12 +0 -0
  599. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  600. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.intermediate.pem +72 -0
  601. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +50 -0
  602. package/deps/librdkafka/tests/fixtures/ssl/client2.intermediate.key +46 -0
  603. package/deps/librdkafka/tests/fixtures/ssl/client2.key +46 -0
  604. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +168 -0
  605. package/deps/librdkafka/tests/fuzzers/Makefile +12 -0
  606. package/deps/librdkafka/tests/fuzzers/README.md +31 -0
  607. package/deps/librdkafka/tests/fuzzers/fuzz_regex.c +74 -0
  608. package/deps/librdkafka/tests/fuzzers/helpers.h +90 -0
  609. package/deps/librdkafka/tests/gen-ssl-certs.sh +165 -0
  610. package/deps/librdkafka/tests/interactive_broker_version.py +170 -0
  611. package/deps/librdkafka/tests/interceptor_test/CMakeLists.txt +16 -0
  612. package/deps/librdkafka/tests/interceptor_test/Makefile +22 -0
  613. package/deps/librdkafka/tests/interceptor_test/interceptor_test.c +314 -0
  614. package/deps/librdkafka/tests/interceptor_test/interceptor_test.h +54 -0
  615. package/deps/librdkafka/tests/java/IncrementalRebalanceCli.java +97 -0
  616. package/deps/librdkafka/tests/java/Makefile +13 -0
  617. package/deps/librdkafka/tests/java/Murmur2Cli.java +46 -0
  618. package/deps/librdkafka/tests/java/README.md +14 -0
  619. package/deps/librdkafka/tests/java/TransactionProducerCli.java +162 -0
  620. package/deps/librdkafka/tests/java/run-class.sh +11 -0
  621. package/deps/librdkafka/tests/librdkafka.suppressions +483 -0
  622. package/deps/librdkafka/tests/lz4_manual_test.sh +59 -0
  623. package/deps/librdkafka/tests/multi-broker-version-test.sh +50 -0
  624. package/deps/librdkafka/tests/parse-refcnt.sh +43 -0
  625. package/deps/librdkafka/tests/performance_plot.py +115 -0
  626. package/deps/librdkafka/tests/plugin_test/Makefile +19 -0
  627. package/deps/librdkafka/tests/plugin_test/plugin_test.c +58 -0
  628. package/deps/librdkafka/tests/requirements.txt +2 -0
  629. package/deps/librdkafka/tests/run-all-tests.sh +79 -0
  630. package/deps/librdkafka/tests/run-consumer-tests.sh +16 -0
  631. package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
  632. package/deps/librdkafka/tests/run-test-batches.py +157 -0
  633. package/deps/librdkafka/tests/run-test.sh +140 -0
  634. package/deps/librdkafka/tests/rusage.c +249 -0
  635. package/deps/librdkafka/tests/sasl_test.py +289 -0
  636. package/deps/librdkafka/tests/scenarios/README.md +6 -0
  637. package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
  638. package/deps/librdkafka/tests/scenarios/default.json +5 -0
  639. package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
  640. package/deps/librdkafka/tests/sockem.c +801 -0
  641. package/deps/librdkafka/tests/sockem.h +85 -0
  642. package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
  643. package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
  644. package/deps/librdkafka/tests/test.c +7778 -0
  645. package/deps/librdkafka/tests/test.conf.example +27 -0
  646. package/deps/librdkafka/tests/test.h +1028 -0
  647. package/deps/librdkafka/tests/testcpp.cpp +131 -0
  648. package/deps/librdkafka/tests/testcpp.h +388 -0
  649. package/deps/librdkafka/tests/testshared.h +416 -0
  650. package/deps/librdkafka/tests/tools/README.md +4 -0
  651. package/deps/librdkafka/tests/tools/stats/README.md +21 -0
  652. package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
  653. package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
  654. package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
  655. package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
  656. package/deps/librdkafka/tests/trivup/trivup-0.14.0.tar.gz +0 -0
  657. package/deps/librdkafka/tests/until-fail.sh +87 -0
  658. package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
  659. package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
  660. package/deps/librdkafka/vcpkg.json +23 -0
  661. package/deps/librdkafka/win32/README.md +5 -0
  662. package/deps/librdkafka/win32/build-package.bat +3 -0
  663. package/deps/librdkafka/win32/build.bat +19 -0
  664. package/deps/librdkafka/win32/common.vcxproj +84 -0
  665. package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
  666. package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
  667. package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
  668. package/deps/librdkafka/win32/librdkafka.sln +226 -0
  669. package/deps/librdkafka/win32/librdkafka.vcxproj +276 -0
  670. package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
  671. package/deps/librdkafka/win32/msbuild.ps1 +15 -0
  672. package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
  673. package/deps/librdkafka/win32/package-zip.ps1 +46 -0
  674. package/deps/librdkafka/win32/packages/repositories.config +4 -0
  675. package/deps/librdkafka/win32/push-package.bat +4 -0
  676. package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
  677. package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
  678. package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
  679. package/deps/librdkafka/win32/setup-msys2.ps1 +47 -0
  680. package/deps/librdkafka/win32/setup-vcpkg.ps1 +34 -0
  681. package/deps/librdkafka/win32/tests/test.conf.example +25 -0
  682. package/deps/librdkafka/win32/tests/tests.vcxproj +253 -0
  683. package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
  684. package/deps/librdkafka/win32/wingetopt.c +564 -0
  685. package/deps/librdkafka/win32/wingetopt.h +101 -0
  686. package/deps/librdkafka/win32/wintime.h +33 -0
  687. package/deps/librdkafka.gyp +62 -0
  688. package/lib/admin.js +233 -0
  689. package/lib/client.js +573 -0
  690. package/lib/error.js +500 -0
  691. package/lib/index.js +34 -0
  692. package/lib/kafka-consumer-stream.js +397 -0
  693. package/lib/kafka-consumer.js +698 -0
  694. package/lib/producer/high-level-producer.js +323 -0
  695. package/lib/producer-stream.js +307 -0
  696. package/lib/producer.js +375 -0
  697. package/lib/tools/ref-counter.js +52 -0
  698. package/lib/topic-partition.js +88 -0
  699. package/lib/topic.js +42 -0
  700. package/lib/util.js +29 -0
  701. package/package.json +61 -0
  702. package/prebuilds/darwin-arm64/@point3+node-rdkafka.node +0 -0
  703. package/prebuilds/linux-x64/@point3+node-rdkafka.node +0 -0
  704. package/util/configure.js +30 -0
  705. package/util/get-env.js +6 -0
  706. package/util/test-compile.js +11 -0
  707. package/util/test-producer-delivery.js +100 -0
@@ -0,0 +1,1666 @@
1
+ /*
2
+ * librdkafka - The Apache Kafka C/C++ library
3
+ *
4
+ * Copyright (c) 2021-2022, Magnus Edenhill
5
+ * 2023, Confluent Inc.
6
+
7
+ * All rights reserved.
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted provided that the following conditions are met:
11
+ *
12
+ * 1. Redistributions of source code must retain the above copyright notice,
13
+ * this list of conditions and the following disclaimer.
14
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
15
+ * this list of conditions and the following disclaimer in the documentation
16
+ * and/or other materials provided with the distribution.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ * POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+
32
+ /**
33
+ * Builtin SASL OAUTHBEARER OIDC support
34
+ */
35
+ #include "rdkafka_int.h"
36
+ #include "rdkafka_sasl_int.h"
37
+ #include "rdunittest.h"
38
+ #include "cJSON.h"
39
+ #include <curl/curl.h>
40
+ #include "rdhttp.h"
41
+ #include "rdkafka_sasl_oauthbearer_oidc.h"
42
+ #include "rdbase64.h"
43
+
44
+
45
+ /**
46
+ * @brief Generate Authorization field for HTTP header.
47
+ * The field contains base64-encoded string which
48
+ * is generated from \p client_id and \p client_secret.
49
+ *
50
+ * @returns Return the authorization field.
51
+ *
52
+ * @locality Any thread.
53
+ */
54
+ static char *
55
+ rd_kafka_oidc_client_credentials_build_auth_header(const char *client_id,
56
+ const char *client_secret) {
57
+
58
+ rd_chariov_t client_authorization_in;
59
+ rd_chariov_t client_authorization_out;
60
+
61
+ size_t authorization_base64_header_size;
62
+ char *authorization_base64_header;
63
+
64
+ client_authorization_in.size =
65
+ strlen(client_id) + strlen(client_secret) + 2;
66
+ client_authorization_in.ptr = rd_malloc(client_authorization_in.size);
67
+ rd_snprintf(client_authorization_in.ptr, client_authorization_in.size,
68
+ "%s:%s", client_id, client_secret);
69
+
70
+ client_authorization_in.size--;
71
+ rd_base64_encode(&client_authorization_in, &client_authorization_out);
72
+ rd_assert(client_authorization_out.ptr);
73
+
74
+ authorization_base64_header_size =
75
+ strlen("Authorization: Basic ") + client_authorization_out.size + 1;
76
+ authorization_base64_header =
77
+ rd_malloc(authorization_base64_header_size);
78
+ rd_snprintf(authorization_base64_header,
79
+ authorization_base64_header_size, "Authorization: Basic %s",
80
+ client_authorization_out.ptr);
81
+
82
+ rd_free(client_authorization_in.ptr);
83
+ rd_free(client_authorization_out.ptr);
84
+ return authorization_base64_header;
85
+ }
86
+
87
+
88
+ /**
89
+ * @brief Build headers for HTTP(S) requests based on \p client_id
90
+ * and \p client_secret. The result will be returned in \p *headersp.
91
+ *
92
+ * @locality Any thread.
93
+ */
94
+ static void
95
+ rd_kafka_oidc_client_credentials_build_headers(const char *client_id,
96
+ const char *client_secret,
97
+ struct curl_slist **headersp) {
98
+ char *authorization_base64_header;
99
+
100
+ authorization_base64_header =
101
+ rd_kafka_oidc_client_credentials_build_auth_header(client_id,
102
+ client_secret);
103
+
104
+ *headersp = curl_slist_append(*headersp, "Accept: application/json");
105
+ *headersp = curl_slist_append(*headersp, authorization_base64_header);
106
+
107
+ *headersp = curl_slist_append(
108
+ *headersp, "Content-Type: application/x-www-form-urlencoded");
109
+
110
+ rd_free(authorization_base64_header);
111
+ }
112
+
113
+ /**
114
+ * @brief The format of JWT is Header.Payload.Signature.
115
+ * Extract and decode payloads from JWT \p src.
116
+ * The decoded payloads will be returned in \p *bufplainp.
117
+ *
118
+ * @returns Return error message while decoding the payload.
119
+ */
120
+ static const char *rd_kafka_jwt_b64_decode_payload(const char *src,
121
+ char **bufplainp) {
122
+ char *converted_src;
123
+ char *payload = NULL;
124
+
125
+ const char *errstr = NULL;
126
+
127
+ int i, padding, len;
128
+
129
+ int payload_len;
130
+ int nbytesdecoded;
131
+
132
+ int payloads_start = 0;
133
+ int payloads_end = 0;
134
+
135
+ len = (int)strlen(src);
136
+ converted_src = rd_malloc(len + 4);
137
+
138
+ for (i = 0; i < len; i++) {
139
+ switch (src[i]) {
140
+ case '-':
141
+ converted_src[i] = '+';
142
+ break;
143
+
144
+ case '_':
145
+ converted_src[i] = '/';
146
+ break;
147
+
148
+ case '.':
149
+ if (payloads_start == 0)
150
+ payloads_start = i + 1;
151
+ else {
152
+ if (payloads_end > 0) {
153
+ errstr =
154
+ "The token is invalid with more "
155
+ "than 2 delimiters";
156
+ goto done;
157
+ }
158
+ payloads_end = i;
159
+ }
160
+ /* FALLTHRU */
161
+
162
+ default:
163
+ converted_src[i] = src[i];
164
+ }
165
+ }
166
+
167
+ if (payloads_start == 0 || payloads_end == 0) {
168
+ errstr = "The token is invalid with less than 2 delimiters";
169
+ goto done;
170
+ }
171
+
172
+ payload_len = payloads_end - payloads_start;
173
+ payload = rd_malloc(payload_len + 4);
174
+ strncpy(payload, (converted_src + payloads_start), payload_len);
175
+
176
+ padding = 4 - (payload_len % 4);
177
+ if (padding < 4) {
178
+ while (padding--)
179
+ payload[payload_len++] = '=';
180
+ }
181
+
182
+ nbytesdecoded = ((payload_len + 3) / 4) * 3;
183
+ *bufplainp = rd_malloc(nbytesdecoded + 1);
184
+
185
+ if (EVP_DecodeBlock((uint8_t *)(*bufplainp), (uint8_t *)payload,
186
+ (int)payload_len) == -1) {
187
+ errstr = "Failed to decode base64 payload";
188
+ }
189
+
190
+ done:
191
+ RD_IF_FREE(payload, rd_free);
192
+ RD_IF_FREE(converted_src, rd_free);
193
+ return errstr;
194
+ }
195
+
196
+ /**
197
+ * @brief Build post_fields with \p scope.
198
+ * The format of the post_fields is
199
+ * `grant_type=client_credentials&scope=scope`
200
+ * The post_fields will be returned in \p *post_fields.
201
+ * The post_fields_size will be returned in \p post_fields_size.
202
+ *
203
+ */
204
+ static void
205
+ rd_kafka_oidc_client_credentials_build_post_fields(const char *scope,
206
+ char **post_fields,
207
+ size_t *post_fields_size) {
208
+ size_t scope_size = 0;
209
+
210
+ if (scope)
211
+ scope_size = strlen(scope);
212
+ if (scope_size == 0) {
213
+ *post_fields = rd_strdup("grant_type=client_credentials");
214
+ *post_fields_size = strlen("grant_type=client_credentials");
215
+ } else {
216
+ *post_fields_size =
217
+ strlen("grant_type=client_credentials&scope=") + scope_size;
218
+ *post_fields = rd_malloc(*post_fields_size + 1);
219
+ rd_snprintf(*post_fields, *post_fields_size + 1,
220
+ "grant_type=client_credentials&scope=%s", scope);
221
+ }
222
+ }
223
+
224
+ /**
225
+ * @brief Get JWT algorithm label string for the specified signing algorithm.
226
+ *
227
+ * @param token_signing_algo The algorithm enum value
228
+ *
229
+ * @returns String representation of the algorithm.
230
+ *
231
+ * @locality Any thread.
232
+ */
233
+ static char *rd_kafka_oidc_assertion_get_algo_label(
234
+ const rd_kafka_oauthbearer_assertion_algorithm_t token_signing_algo) {
235
+ switch (token_signing_algo) {
236
+ case RD_KAFKA_SASL_OAUTHBEARER_ASSERTION_ALGORITHM_RS256:
237
+ return "RS256";
238
+ case RD_KAFKA_SASL_OAUTHBEARER_ASSERTION_ALGORITHM_ES256:
239
+ return "ES256";
240
+ default:
241
+ rd_assert(!*"Unknown JOSE algorithm");
242
+ return NULL;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * @brief Parse a JWT template file and extract header and payload JSON
248
+ * objects.
249
+ *
250
+ * Reads and parses the JWT template file, which should contain a JSON object
251
+ * with "header" and "payload" properties.
252
+ *
253
+ * @param rk
254
+ * @param jwt_template_file_path Path to the template file
255
+ * @param header Pointer to store the parsed header JSON object
256
+ * @param payload Pointer to store the parsed payload JSON object
257
+ *
258
+ * @returns 0 on success, -1 on failure
259
+ *
260
+ * @locality Any thread.
261
+ */
262
+ static int
263
+ rd_kafka_oidc_assertion_parse_template_file(rd_kafka_t *rk,
264
+ const char *jwt_template_file_path,
265
+ cJSON **header,
266
+ cJSON **payload) {
267
+ char *template_content = NULL;
268
+ cJSON *template_json = NULL;
269
+ int ret = -1;
270
+ size_t file_size;
271
+
272
+ *header = NULL;
273
+ *payload = NULL;
274
+
275
+ template_content =
276
+ rd_file_read(jwt_template_file_path, &file_size, 1024 * 1024);
277
+ if (!template_content) {
278
+ rd_kafka_log(rk, LOG_ERR, "JWT",
279
+ "Failed to open JWT template file: %s",
280
+ jwt_template_file_path);
281
+ return -1;
282
+ }
283
+
284
+ if (file_size == 0) {
285
+ rd_kafka_log(rk, LOG_ERR, "JWT",
286
+ "JWT template file is empty or invalid");
287
+ rd_free(template_content);
288
+ return -1;
289
+ }
290
+
291
+ template_json = cJSON_Parse((char *)template_content);
292
+ if (!template_json) {
293
+ rd_kafka_log(rk, LOG_ERR, "JWT",
294
+ "Failed to parse JWT template JSON");
295
+ goto cleanup;
296
+ }
297
+
298
+ cJSON *header_item = cJSON_GetObjectItem(template_json, "header");
299
+ cJSON *payload_item = cJSON_GetObjectItem(template_json, "payload");
300
+
301
+ if (!header_item || !payload_item) {
302
+ rd_kafka_log(rk, LOG_ERR, "JWT",
303
+ "JWT template must contain both 'header' "
304
+ "and 'payload' objects");
305
+ goto cleanup;
306
+ }
307
+
308
+ *header = cJSON_Duplicate(header_item, 1);
309
+ *payload = cJSON_Duplicate(payload_item, 1);
310
+
311
+ if (!*header || !*payload) {
312
+ rd_kafka_log(rk, LOG_ERR, "JWT",
313
+ "Failed to duplicate header or payload objects");
314
+ if (*header) {
315
+ cJSON_Delete(*header);
316
+ *header = NULL;
317
+ }
318
+ goto cleanup;
319
+ }
320
+
321
+ ret = 0;
322
+
323
+ cleanup:
324
+ if (template_content)
325
+ rd_free(template_content);
326
+ if (template_json)
327
+ cJSON_Delete(template_json);
328
+
329
+ return ret;
330
+ }
331
+
332
+ /**
333
+ * @brief Create JWT assertion.
334
+ *
335
+ * Creates a JWT token signed with the specified private key using the
336
+ * algorithm specified. The token can be created from a template file or
337
+ * will create a minimal default token if no template is provided.
338
+ *
339
+ * @param rk The rd_kafka_t instance for logging
340
+ * @param private_key_pem PEM formatted private key string (mutually exclusive
341
+ * with key_file_location)
342
+ * @param key_file_location Path to private key file (mutually exclusive with
343
+ * private_key_pem)
344
+ * @param passphrase Optional passphrase for encrypted private key
345
+ * @param token_signing_algo Algorithm to use for signing (RS256 or ES256)
346
+ * @param jwt_template_file Optional path to JWT template file
347
+ * @param subject Optional subject claim value.
348
+ * @param issuer Optional issuer claim value.
349
+ * @param audience Optional audience claim value.
350
+ * @param nbf `nbf` claim value to express seconds of validity in the past.
351
+ * @param exp `exp` claim value to express seconds of validity in the future.
352
+ * @param jti_include Whether to include a JTI claim (UUID)
353
+ *
354
+ * @returns Newly allocated JWT string, caller must free with rd_free(). NULL on
355
+ * error.
356
+ *
357
+ * @locality Any thread.
358
+ */
359
+ static char *rd_kafka_oidc_assertion_create(
360
+ rd_kafka_t *rk,
361
+ const char *private_key_pem,
362
+ const char *key_file_location,
363
+ const char *passphrase,
364
+ const rd_kafka_oauthbearer_assertion_algorithm_t token_signing_algo,
365
+ const char *jwt_template_file,
366
+ const char *subject,
367
+ const char *issuer,
368
+ const char *audience,
369
+ const int nbf,
370
+ const int exp,
371
+ const rd_bool_t jti_include) {
372
+
373
+ char *encoded_header = NULL;
374
+ char *encoded_payload = NULL;
375
+ char *encoded_signature = NULL;
376
+ char *unsigned_token = NULL;
377
+ char *result = NULL;
378
+ char *header_str = NULL;
379
+ char *payload_str = NULL;
380
+ EVP_PKEY *pkey = NULL;
381
+ BIO *bio = NULL;
382
+ cJSON *header_json_obj = NULL;
383
+ cJSON *payload_json_obj = NULL;
384
+ EVP_MD_CTX *mdctx = NULL;
385
+ unsigned char *sig = NULL;
386
+ rd_chariov_t header_iov;
387
+ rd_chariov_t payload_iov;
388
+ rd_chariov_t sig_iov;
389
+ rd_kafka_Uuid_t jti_uuid;
390
+ char *jti_uuid_str = NULL;
391
+
392
+ rd_ts_t issued_at = rd_uclock() / 1000000;
393
+ rd_ts_t not_before = issued_at - nbf;
394
+ rd_ts_t expiration_time = issued_at + exp;
395
+
396
+ if (jwt_template_file) {
397
+ if (rd_kafka_oidc_assertion_parse_template_file(
398
+ rk, jwt_template_file, &header_json_obj,
399
+ &payload_json_obj) != 0) {
400
+ rd_kafka_log(rk, LOG_ERR, "JWT",
401
+ "Failed to process JWT template file %s",
402
+ jwt_template_file);
403
+ return NULL;
404
+ }
405
+ } else {
406
+ header_json_obj = cJSON_CreateObject();
407
+ payload_json_obj = cJSON_CreateObject();
408
+ }
409
+
410
+ /* Add required header fields */
411
+ cJSON_DeleteItemFromObjectCaseSensitive(header_json_obj, "alg");
412
+ cJSON_DeleteItemFromObjectCaseSensitive(header_json_obj, "typ");
413
+ cJSON_DeleteItemFromObjectCaseSensitive(payload_json_obj, "iat");
414
+ cJSON_DeleteItemFromObjectCaseSensitive(payload_json_obj, "exp");
415
+ cJSON_DeleteItemFromObjectCaseSensitive(payload_json_obj, "nbf");
416
+ cJSON_AddStringToObject(
417
+ header_json_obj, "alg",
418
+ rd_kafka_oidc_assertion_get_algo_label(token_signing_algo));
419
+ cJSON_AddStringToObject(header_json_obj, "typ", "JWT");
420
+
421
+ /* Add required payload fields */
422
+ cJSON_AddNumberToObject(payload_json_obj, "iat", (double)issued_at);
423
+ cJSON_AddNumberToObject(payload_json_obj, "exp",
424
+ (double)expiration_time);
425
+ cJSON_AddNumberToObject(payload_json_obj, "nbf", (double)not_before);
426
+
427
+ if (subject) {
428
+ cJSON_DeleteItemFromObjectCaseSensitive(payload_json_obj,
429
+ "sub");
430
+ cJSON_AddStringToObject(payload_json_obj, "sub", subject);
431
+ }
432
+
433
+ if (issuer) {
434
+ cJSON_DeleteItemFromObjectCaseSensitive(payload_json_obj,
435
+ "iss");
436
+ cJSON_AddStringToObject(payload_json_obj, "iss", issuer);
437
+ }
438
+
439
+ if (audience) {
440
+ cJSON_DeleteItemFromObjectCaseSensitive(payload_json_obj,
441
+ "aud");
442
+ cJSON_AddStringToObject(payload_json_obj, "aud", audience);
443
+ }
444
+
445
+ if (jti_include) {
446
+ jti_uuid = rd_kafka_Uuid_random();
447
+ jti_uuid_str = rd_kafka_Uuid_str(&jti_uuid);
448
+ cJSON_DeleteItemFromObjectCaseSensitive(payload_json_obj,
449
+ "jti");
450
+ cJSON_AddStringToObject(payload_json_obj, "jti", jti_uuid_str);
451
+ rd_free(jti_uuid_str);
452
+ }
453
+
454
+ header_str = cJSON_PrintUnformatted(header_json_obj);
455
+ payload_str = cJSON_PrintUnformatted(payload_json_obj);
456
+
457
+ if (!header_str || !payload_str) {
458
+ rd_kafka_log(rk, LOG_ERR, "JWT",
459
+ "Failed to convert template objects to JSON");
460
+ goto cleanup;
461
+ }
462
+
463
+ header_iov.ptr = header_str;
464
+ header_iov.size = strlen(header_str);
465
+ encoded_header = rd_base64_encode_str_urlsafe(&header_iov);
466
+
467
+ payload_iov.ptr = payload_str;
468
+ payload_iov.size = strlen(payload_str);
469
+ encoded_payload = rd_base64_encode_str_urlsafe(&payload_iov);
470
+ if (!encoded_header || !encoded_payload)
471
+ goto cleanup;
472
+
473
+ size_t unsigned_token_len =
474
+ strlen(encoded_header) + strlen(encoded_payload) + 2;
475
+ unsigned_token = rd_malloc(unsigned_token_len);
476
+
477
+ if (!unsigned_token)
478
+ goto cleanup;
479
+ rd_snprintf(unsigned_token, unsigned_token_len, "%s.%s", encoded_header,
480
+ encoded_payload);
481
+
482
+ if (private_key_pem) {
483
+ bio = BIO_new_mem_buf((void *)private_key_pem, -1);
484
+ } else if (key_file_location) {
485
+ bio = BIO_new_file(key_file_location, "r");
486
+ }
487
+
488
+ if (!bio) {
489
+ rd_kafka_log(rk, LOG_ERR, "JWT",
490
+ "Failed to create BIO for private key");
491
+ goto cleanup;
492
+ }
493
+
494
+ if (passphrase) {
495
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
496
+ (void *)passphrase);
497
+ } else {
498
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
499
+ }
500
+ BIO_free(bio);
501
+ bio = NULL;
502
+
503
+ if (!pkey) {
504
+ rd_kafka_log(rk, LOG_ERR, "JWT", "Failed to load private key");
505
+ goto cleanup;
506
+ }
507
+
508
+ mdctx = EVP_MD_CTX_new();
509
+ if (!mdctx) {
510
+ rd_kafka_log(rk, LOG_ERR, "JWT",
511
+ "Failed to create message digest context");
512
+ goto cleanup;
513
+ }
514
+
515
+ const EVP_MD *md = EVP_sha256(); /* Both RS256 and ES256 use SHA-256 */
516
+
517
+ if (EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey) != 1) {
518
+ rd_kafka_log(rk, LOG_ERR, "JWT",
519
+ "Failed to initialize signing context");
520
+ goto cleanup;
521
+ }
522
+
523
+ if (EVP_DigestSignUpdate(mdctx, unsigned_token,
524
+ strlen(unsigned_token)) != 1) {
525
+ rd_kafka_log(rk, LOG_ERR, "JWT",
526
+ "Failed to update digest with token data");
527
+ goto cleanup;
528
+ }
529
+
530
+ size_t siglen = 0;
531
+ if (EVP_DigestSignFinal(mdctx, NULL, &siglen) != 1) {
532
+ rd_kafka_log(rk, LOG_ERR, "JWT",
533
+ "Failed to get signature length");
534
+ goto cleanup;
535
+ }
536
+
537
+ sig = rd_malloc(siglen);
538
+ if (!sig) {
539
+ rd_kafka_log(rk, LOG_ERR, "JWT",
540
+ "Failed to allocate memory for signature");
541
+ goto cleanup;
542
+ }
543
+
544
+ if (EVP_DigestSignFinal(mdctx, sig, &siglen) != 1) {
545
+ rd_kafka_log(rk, LOG_ERR, "JWT", "Failed to create signature");
546
+ goto cleanup;
547
+ }
548
+
549
+ sig_iov.ptr = (char *)sig;
550
+ sig_iov.size = siglen;
551
+ encoded_signature = rd_base64_encode_str_urlsafe(&sig_iov);
552
+
553
+ if (!encoded_signature)
554
+ goto cleanup;
555
+
556
+ size_t jwt_len = strlen(encoded_header) + strlen(encoded_payload) +
557
+ strlen(encoded_signature) + 3;
558
+ result = rd_malloc(jwt_len);
559
+ if (!result)
560
+ goto cleanup;
561
+ rd_snprintf(result, jwt_len, "%s.%s.%s", encoded_header,
562
+ encoded_payload, encoded_signature);
563
+
564
+ cleanup:
565
+ if (encoded_header)
566
+ rd_free(encoded_header);
567
+ if (encoded_payload)
568
+ rd_free(encoded_payload);
569
+ if (encoded_signature)
570
+ rd_free(encoded_signature);
571
+ if (unsigned_token)
572
+ rd_free(unsigned_token);
573
+ if (sig)
574
+ rd_free(sig);
575
+
576
+ if (header_json_obj) {
577
+ if (header_str)
578
+ free(header_str); /* cJSON_PrintUnformatted uses malloc
579
+ */
580
+ cJSON_Delete(header_json_obj);
581
+ } else if (header_str) {
582
+ rd_free(header_str); /* rd_malloc was used */
583
+ }
584
+
585
+ if (payload_json_obj) {
586
+ if (payload_str)
587
+ free(payload_str); /* cJSON_PrintUnformatted uses malloc
588
+ */
589
+ cJSON_Delete(payload_json_obj);
590
+ } else if (payload_str) {
591
+ rd_free(payload_str); /* rd_malloc was used */
592
+ }
593
+
594
+ if (pkey)
595
+ EVP_PKEY_free(pkey);
596
+ if (mdctx)
597
+ EVP_MD_CTX_free(mdctx);
598
+
599
+ return result;
600
+ }
601
+
602
+
603
+ /**
604
+ * @brief Build request body for JWT bearer token request.
605
+ *
606
+ * Creates a URL-encoded request body for token exchange with the JWT assertion
607
+ * and optional scope.
608
+ *
609
+ * @param assertion The JWT assertion to include in the request.
610
+ * @param scope Optional scope to include in the request (will be URL encoded).
611
+ *
612
+ * @returns Newly allocated string with the URL-encoded request body.
613
+ * Caller must free with rd_free(). NULL on memory allocation failure.
614
+ *
615
+ * @locality Any thread.
616
+ */
617
+ static char *rd_kafka_oidc_jwt_bearer_build_request_body(const char *assertion,
618
+ const char *scope) {
619
+ const char *assertion_prefix =
620
+ "grant_type=urn:ietf:params:oauth:"
621
+ "grant-type:jwt-bearer"
622
+ "&assertion=";
623
+ int assertion_prefix_len = strlen(assertion_prefix) + strlen(assertion);
624
+ int body_size = assertion_prefix_len + 1;
625
+ char *scope_escaped = NULL;
626
+ if (scope) {
627
+ scope_escaped = curl_easy_escape(NULL, scope, 0);
628
+ body_size += strlen("&scope=") + strlen(scope_escaped);
629
+ }
630
+
631
+ char *body = rd_malloc(body_size);
632
+
633
+ rd_snprintf(body, body_size, "%s%s", assertion_prefix, assertion);
634
+ if (scope) {
635
+ rd_snprintf(&body[assertion_prefix_len],
636
+ body_size - assertion_prefix_len, "&scope=%s",
637
+ scope_escaped);
638
+ rd_free(scope_escaped);
639
+ }
640
+ return body;
641
+ }
642
+
643
+ /**
644
+ * @brief JWT assertion from file
645
+ *
646
+ * @param file_path Path to the file containing the JWT assertion.
647
+ *
648
+ * @returns Newly allocated string with the JWT assertion.
649
+ * Caller must free with rd_free(). NULL on error.
650
+ */
651
+ static char *rd_kafka_oidc_assertion_read_from_file(const char *file_path) {
652
+ if (!file_path)
653
+ return NULL;
654
+ const size_t max_size = 1024 * 1024; /* 1MB limit */
655
+ return rd_file_read(file_path, NULL, max_size);
656
+ }
657
+
658
+ /**
659
+ * @brief Try to validate a token field from the JSON response.
660
+ * Extracts and validates the token, then decodes its payload to get
661
+ * subject and expiration.
662
+ *
663
+ * @param rk The rd_kafka_t instance
664
+ * @param json The JSON response from the token endpoint
665
+ * @param field_name The name of the field to extract (e.g., "access_token" or
666
+ * "id_token")
667
+ * @param token_out Pointer to store the extracted token
668
+ * @param sub_out Pointer to store the subject from the token
669
+ * @param exp_out Pointer to store the expiration from the token
670
+ * @param errstr_out Buffer to store error message
671
+ * @param errstr_size Size of error message buffer
672
+ *
673
+ * @returns The extracted token or NULL on failure.
674
+ */
675
+ static char *rd_kafka_oidc_token_try_validate(cJSON *json,
676
+ const char *field,
677
+ char **sub,
678
+ double *exp,
679
+ char *errstr,
680
+ size_t errstr_size) {
681
+ cJSON *access_token_json, *jwt_exp, *jwt_sub, *payloads = NULL;
682
+ char *jwt_token = NULL, *decoded_payloads = NULL;
683
+ const char *decode_errstr = NULL;
684
+ *sub = NULL;
685
+
686
+ access_token_json = cJSON_GetObjectItem(json, field);
687
+
688
+ if (!access_token_json) {
689
+ rd_snprintf(errstr, errstr_size,
690
+ "Expected JSON response with \"%s\" field", field);
691
+ goto fail;
692
+ }
693
+
694
+ jwt_token = cJSON_GetStringValue(access_token_json);
695
+ if (!jwt_token) {
696
+ rd_snprintf(errstr, errstr_size,
697
+ "Expected token as a string value");
698
+ goto fail;
699
+ }
700
+
701
+ decode_errstr =
702
+ rd_kafka_jwt_b64_decode_payload(jwt_token, &decoded_payloads);
703
+ if (decode_errstr != NULL) {
704
+ rd_snprintf(errstr, errstr_size,
705
+ "Failed to decode JWT payload: %s", decode_errstr);
706
+ goto fail;
707
+ }
708
+
709
+ payloads = cJSON_Parse(decoded_payloads);
710
+ if (payloads == NULL) {
711
+ rd_snprintf(errstr, errstr_size,
712
+ "Failed to parse JSON JWT payload");
713
+ goto fail;
714
+ }
715
+
716
+ jwt_exp = cJSON_GetObjectItem(payloads, "exp");
717
+ if (jwt_exp == NULL) {
718
+ rd_snprintf(errstr, errstr_size,
719
+ "Expected JSON JWT response with "
720
+ "\"exp\" field");
721
+ goto fail;
722
+ }
723
+
724
+ *exp = cJSON_GetNumberValue(jwt_exp);
725
+ if (*exp <= 0) {
726
+ rd_snprintf(errstr, errstr_size,
727
+ "Expected JSON JWT response with "
728
+ "valid \"exp\" field");
729
+ goto fail;
730
+ }
731
+
732
+ jwt_sub = cJSON_GetObjectItem(payloads, "sub");
733
+ if (jwt_sub == NULL) {
734
+ rd_snprintf(errstr, errstr_size,
735
+ "Expected JSON JWT response with "
736
+ "\"sub\" field");
737
+ goto fail;
738
+ }
739
+
740
+ *sub = cJSON_GetStringValue(jwt_sub);
741
+ if (*sub == NULL) {
742
+ rd_snprintf(errstr, errstr_size,
743
+ "Expected JSON JWT response with "
744
+ "valid \"sub\" field");
745
+ goto fail;
746
+ }
747
+ *sub = rd_strdup(*sub);
748
+ done:
749
+ if (payloads)
750
+ cJSON_Delete(payloads);
751
+ if (decoded_payloads)
752
+ rd_free(decoded_payloads);
753
+ return jwt_token;
754
+ fail:
755
+ jwt_token = NULL;
756
+ goto done;
757
+ }
758
+
759
+ /**
760
+ * @brief Implementation of JWT token refresh callback function.
761
+ * Creates a JWT assertion, exchanges it for an access token,
762
+ * and sets the token for SASL OAUTHBEARER authentication.
763
+ *
764
+ * @param rk The rd_kafka_t instance.
765
+ * @param oauthbearer_config The OAUTHBEARER configuration.
766
+ * @param opaque Opaque pointer passed to the callback.
767
+ *
768
+ * @locality rdkafka main thread
769
+ */
770
+ void rd_kafka_oidc_token_jwt_bearer_refresh_cb(rd_kafka_t *rk,
771
+ const char *oauthbearer_config,
772
+ void *opaque) {
773
+ const int timeout_s = 20;
774
+ const int retry = 4;
775
+ const int retry_ms = 5 * 1000;
776
+
777
+ char *jwt_assertion = NULL;
778
+ char *request_body = NULL;
779
+ struct curl_slist *headers = NULL;
780
+ rd_http_error_t *herr = NULL;
781
+ cJSON *json = NULL;
782
+ char *jwt_token = NULL;
783
+ char set_token_errstr[512];
784
+ double exp = 0;
785
+ char **extensions = NULL;
786
+ char **extension_key_value = NULL;
787
+ size_t extension_key_value_cnt = 0;
788
+ size_t extension_cnt;
789
+ char *sub = NULL;
790
+ char validate_errstr[512];
791
+
792
+ if (rd_kafka_terminating(rk))
793
+ return;
794
+
795
+ if (rk->rk_conf.sasl.oauthbearer.assertion.file) {
796
+ jwt_assertion = rd_kafka_oidc_assertion_read_from_file(
797
+ rk->rk_conf.sasl.oauthbearer.assertion.file);
798
+ } else {
799
+ jwt_assertion = rd_kafka_oidc_assertion_create(
800
+ rk, rk->rk_conf.sasl.oauthbearer.assertion.private_key.pem,
801
+ rk->rk_conf.sasl.oauthbearer.assertion.private_key.file,
802
+ rk->rk_conf.sasl.oauthbearer.assertion.private_key
803
+ .passphrase,
804
+ rk->rk_conf.sasl.oauthbearer.assertion.algorithm,
805
+ rk->rk_conf.sasl.oauthbearer.assertion.jwt_template_file,
806
+ rk->rk_conf.sasl.oauthbearer.assertion.claim.subject,
807
+ rk->rk_conf.sasl.oauthbearer.assertion.claim.issuer,
808
+ rk->rk_conf.sasl.oauthbearer.assertion.claim.audience,
809
+ rk->rk_conf.sasl.oauthbearer.assertion.claim.not_before_s,
810
+ rk->rk_conf.sasl.oauthbearer.assertion.claim.expiration_s,
811
+ rk->rk_conf.sasl.oauthbearer.assertion.claim.jti_include);
812
+ }
813
+
814
+ if (!jwt_assertion) {
815
+ rd_kafka_oauthbearer_set_token_failure(
816
+ rk, "Failed to create JWT assertion");
817
+ goto done;
818
+ }
819
+
820
+ request_body = rd_kafka_oidc_jwt_bearer_build_request_body(
821
+ jwt_assertion, rk->rk_conf.sasl.oauthbearer.scope);
822
+
823
+ if (!request_body) {
824
+ rd_kafka_oauthbearer_set_token_failure(
825
+ rk, "Failed to build JWT request body");
826
+ goto done;
827
+ }
828
+
829
+ headers = curl_slist_append(
830
+ headers, "Content-Type: application/x-www-form-urlencoded");
831
+ headers = curl_slist_append(headers, "Accept: application/json");
832
+
833
+ herr = rd_http_post_expect_json(
834
+ rk, rk->rk_conf.sasl.oauthbearer.token_endpoint_url, headers,
835
+ request_body, strlen(request_body), timeout_s, retry, retry_ms,
836
+ &json);
837
+
838
+ if (unlikely(herr != NULL)) {
839
+ rd_kafka_log(
840
+ rk, LOG_ERR, "JWT",
841
+ "Failed to retrieve JWT token from \"%s\": %s (%d)",
842
+ rk->rk_conf.sasl.oauthbearer.token_endpoint_url,
843
+ herr->errstr, herr->code);
844
+ rd_kafka_oauthbearer_set_token_failure(rk, herr->errstr);
845
+ rd_http_error_destroy(herr);
846
+ goto done;
847
+ }
848
+
849
+ /*
850
+ * RFC 7523 Section 1 says that an access token should be returned
851
+ * https://datatracker.ietf.org/doc/html/rfc7523#section-1
852
+ * Some providers (e.g. GCP) return an `id_token` instead, depending
853
+ * on the configured `target_audience` in the request JWT bearer token.
854
+ * This may be because the validation endpoint is not accessible
855
+ * for validating the `access_token` while the `id_token` is validated
856
+ * through the JWKS URL.
857
+ * This function will try to validate the `access_token` and then the
858
+ * `id_token`.
859
+ */
860
+ jwt_token = rd_kafka_oidc_token_try_validate(json, "access_token", &sub,
861
+ &exp, validate_errstr,
862
+ sizeof(validate_errstr));
863
+ if (!jwt_token)
864
+ jwt_token = rd_kafka_oidc_token_try_validate(
865
+ json, "id_token", &sub, &exp, validate_errstr,
866
+ sizeof(validate_errstr));
867
+
868
+ if (!jwt_token) {
869
+ rd_kafka_oauthbearer_set_token_failure(rk, validate_errstr);
870
+ goto done;
871
+ }
872
+
873
+
874
+ if (rk->rk_conf.sasl.oauthbearer.extensions_str) {
875
+ extensions =
876
+ rd_string_split(rk->rk_conf.sasl.oauthbearer.extensions_str,
877
+ ',', rd_true, &extension_cnt);
878
+
879
+ extension_key_value = rd_kafka_conf_kv_split(
880
+ (const char **)extensions, extension_cnt,
881
+ &extension_key_value_cnt);
882
+ }
883
+
884
+ if (rd_kafka_oauthbearer_set_token(
885
+ rk, jwt_token, (int64_t)exp * 1000, sub,
886
+ (const char **)extension_key_value, extension_key_value_cnt,
887
+ set_token_errstr,
888
+ sizeof(set_token_errstr)) != RD_KAFKA_RESP_ERR_NO_ERROR) {
889
+ rd_kafka_oauthbearer_set_token_failure(rk, validate_errstr);
890
+ }
891
+
892
+ done:
893
+ RD_IF_FREE(sub, rd_free);
894
+ RD_IF_FREE(jwt_assertion, rd_free);
895
+ RD_IF_FREE(request_body, rd_free);
896
+ RD_IF_FREE(headers, curl_slist_free_all);
897
+ RD_IF_FREE(json, cJSON_Delete);
898
+ RD_IF_FREE(extensions, rd_free);
899
+ RD_IF_FREE(extension_key_value, rd_free);
900
+ /* jwt_token is freed as part of the json object */
901
+ }
902
+
903
+ /**
904
+ * @brief Implementation of Oauth/OIDC token refresh callback function,
905
+ * will receive the JSON response after HTTP call to token provider,
906
+ * then extract the jwt from the JSON response, and forward it to
907
+ * the broker.
908
+ */
909
+ void rd_kafka_oidc_token_client_credentials_refresh_cb(
910
+ rd_kafka_t *rk,
911
+ const char *oauthbearer_config,
912
+ void *opaque) {
913
+ const int timeout_s = 20;
914
+ const int retry = 4;
915
+ const int retry_ms = 5 * 1000;
916
+
917
+ double exp;
918
+
919
+ cJSON *json = NULL;
920
+
921
+ rd_http_error_t *herr;
922
+
923
+ char *jwt_token;
924
+ char *post_fields = NULL;
925
+
926
+ struct curl_slist *headers = NULL;
927
+
928
+ const char *token_url;
929
+ char *sub = NULL;
930
+
931
+ size_t post_fields_size;
932
+ size_t extension_cnt;
933
+ size_t extension_key_value_cnt = 0;
934
+
935
+ char set_token_errstr[512];
936
+
937
+ char **extensions = NULL;
938
+ char **extension_key_value = NULL;
939
+
940
+ if (rd_kafka_terminating(rk))
941
+ return;
942
+
943
+ rd_kafka_oidc_client_credentials_build_headers(
944
+ rk->rk_conf.sasl.oauthbearer.client_id,
945
+ rk->rk_conf.sasl.oauthbearer.client_secret, &headers);
946
+
947
+ /* Build post fields */
948
+ rd_kafka_oidc_client_credentials_build_post_fields(
949
+ rk->rk_conf.sasl.oauthbearer.scope, &post_fields,
950
+ &post_fields_size);
951
+
952
+ token_url = rk->rk_conf.sasl.oauthbearer.token_endpoint_url;
953
+
954
+ herr = rd_http_post_expect_json(rk, token_url, headers, post_fields,
955
+ post_fields_size, timeout_s, retry,
956
+ retry_ms, &json);
957
+
958
+ if (unlikely(herr != NULL)) {
959
+ rd_kafka_log(rk, LOG_ERR, "OIDC",
960
+ "Failed to retrieve OIDC "
961
+ "token from \"%s\": %s (%d)",
962
+ token_url, herr->errstr, herr->code);
963
+ rd_kafka_oauthbearer_set_token_failure(rk, herr->errstr);
964
+ rd_http_error_destroy(herr);
965
+ goto done;
966
+ }
967
+
968
+ jwt_token = rd_kafka_oidc_token_try_validate(json, "access_token", &sub,
969
+ &exp, set_token_errstr,
970
+ sizeof(set_token_errstr));
971
+ if (!jwt_token) {
972
+ rd_kafka_oauthbearer_set_token_failure(rk, set_token_errstr);
973
+ goto done;
974
+ }
975
+
976
+ if (rk->rk_conf.sasl.oauthbearer.extensions_str) {
977
+ extensions =
978
+ rd_string_split(rk->rk_conf.sasl.oauthbearer.extensions_str,
979
+ ',', rd_true, &extension_cnt);
980
+
981
+ extension_key_value = rd_kafka_conf_kv_split(
982
+ (const char **)extensions, extension_cnt,
983
+ &extension_key_value_cnt);
984
+ }
985
+
986
+ if (rd_kafka_oauthbearer_set_token(
987
+ rk, jwt_token, (int64_t)exp * 1000, sub,
988
+ (const char **)extension_key_value, extension_key_value_cnt,
989
+ set_token_errstr,
990
+ sizeof(set_token_errstr)) != RD_KAFKA_RESP_ERR_NO_ERROR)
991
+ rd_kafka_oauthbearer_set_token_failure(rk, set_token_errstr);
992
+
993
+ done:
994
+ RD_IF_FREE(sub, rd_free);
995
+ RD_IF_FREE(post_fields, rd_free);
996
+ RD_IF_FREE(json, cJSON_Delete);
997
+ RD_IF_FREE(headers, curl_slist_free_all);
998
+ RD_IF_FREE(extensions, rd_free);
999
+ RD_IF_FREE(extension_key_value, rd_free);
1000
+ }
1001
+
1002
+ /**
1003
+ * @brief Implementation of Oauth/OIDC token refresh callback function
1004
+ * for Azure IMDS,
1005
+ * will receive the JSON response after HTTP(S) GET call to token
1006
+ * provider, then extract the jwt from the JSON response, and
1007
+ * forward it to the broker.
1008
+ */
1009
+ void rd_kafka_oidc_token_metadata_azure_imds_refresh_cb(
1010
+ rd_kafka_t *rk,
1011
+ const char *oauthbearer_config,
1012
+ void *opaque) {
1013
+ const int timeout_s = 20;
1014
+ const int retries = 4;
1015
+ const int retry_ms = 5 * 1000;
1016
+
1017
+ double exp;
1018
+
1019
+ cJSON *json = NULL;
1020
+
1021
+ rd_http_error_t *herr;
1022
+
1023
+ char *jwt_token;
1024
+
1025
+ struct curl_slist *headers = NULL;
1026
+
1027
+ const char *token_endpoint_url_initial = NULL;
1028
+ char *token_endpoint_url = NULL;
1029
+ char *sub = NULL;
1030
+
1031
+ size_t extension_cnt;
1032
+ size_t extension_key_value_cnt = 0;
1033
+
1034
+ char set_token_errstr[512];
1035
+
1036
+ char **extensions = NULL;
1037
+ char **extension_key_value = NULL;
1038
+ char *query = NULL;
1039
+ static char *headers_array[] = {"Metadata: true"};
1040
+
1041
+ if (rd_kafka_terminating(rk))
1042
+ return;
1043
+
1044
+ if (rk->rk_conf.sasl.oauthbearer_config)
1045
+ query = rd_kafka_conf_kv_get(
1046
+ rk->rk_conf.sasl.oauthbearer_config, "query", ',');
1047
+ token_endpoint_url_initial =
1048
+ rk->rk_conf.sasl.oauthbearer.token_endpoint_url;
1049
+ if (!token_endpoint_url_initial)
1050
+ token_endpoint_url_initial =
1051
+ RD_KAFKA_SASL_OAUTHBEARER_METADATA_AUTHENTICATION_URL_AZURE_IMDS;
1052
+ if (query && *query) {
1053
+ token_endpoint_url = rd_http_get_params_append(
1054
+ token_endpoint_url_initial, query);
1055
+
1056
+ if (token_endpoint_url == NULL) {
1057
+ rd_snprintf(
1058
+ set_token_errstr, sizeof(set_token_errstr),
1059
+ "Failed to append params \"%s\" to token endpoint "
1060
+ "URL \"%s\"",
1061
+ query,
1062
+ rk->rk_conf.sasl.oauthbearer.token_endpoint_url);
1063
+ rd_kafka_log(rk, LOG_ERR, "OIDC", "%s",
1064
+ set_token_errstr);
1065
+ rd_kafka_oauthbearer_set_token_failure(
1066
+ rk, set_token_errstr);
1067
+ goto done;
1068
+ }
1069
+ } else {
1070
+ token_endpoint_url = rd_strdup(token_endpoint_url_initial);
1071
+ }
1072
+
1073
+ herr = rd_http_get_json(rk, token_endpoint_url, headers_array, 1,
1074
+ timeout_s, retries, retry_ms, &json);
1075
+
1076
+ if (unlikely(herr != NULL)) {
1077
+ rd_kafka_log(rk, LOG_ERR, "OIDC",
1078
+ "Failed to retrieve OIDC "
1079
+ "token from \"%s\": %s (%d)",
1080
+ token_endpoint_url, herr->errstr, herr->code);
1081
+ rd_kafka_oauthbearer_set_token_failure(rk, herr->errstr);
1082
+ rd_http_error_destroy(herr);
1083
+ goto done;
1084
+ }
1085
+
1086
+ jwt_token = rd_kafka_oidc_token_try_validate(json, "access_token", &sub,
1087
+ &exp, set_token_errstr,
1088
+ sizeof(set_token_errstr));
1089
+ if (!jwt_token) {
1090
+ rd_kafka_oauthbearer_set_token_failure(rk, set_token_errstr);
1091
+ goto done;
1092
+ }
1093
+
1094
+ if (rk->rk_conf.sasl.oauthbearer.extensions_str) {
1095
+ extensions =
1096
+ rd_string_split(rk->rk_conf.sasl.oauthbearer.extensions_str,
1097
+ ',', rd_true, &extension_cnt);
1098
+
1099
+ extension_key_value = rd_kafka_conf_kv_split(
1100
+ (const char **)extensions, extension_cnt,
1101
+ &extension_key_value_cnt);
1102
+ }
1103
+
1104
+ if (rd_kafka_oauthbearer_set_token(
1105
+ rk, jwt_token, (int64_t)exp * 1000, sub,
1106
+ (const char **)extension_key_value, extension_key_value_cnt,
1107
+ set_token_errstr,
1108
+ sizeof(set_token_errstr)) != RD_KAFKA_RESP_ERR_NO_ERROR)
1109
+ rd_kafka_oauthbearer_set_token_failure(rk, set_token_errstr);
1110
+
1111
+ done:
1112
+ RD_IF_FREE(sub, rd_free);
1113
+ RD_IF_FREE(json, cJSON_Delete);
1114
+ RD_IF_FREE(headers, curl_slist_free_all);
1115
+ RD_IF_FREE(extensions, rd_free);
1116
+ RD_IF_FREE(extension_key_value, rd_free);
1117
+ RD_IF_FREE(token_endpoint_url, rd_free);
1118
+ RD_IF_FREE(query, rd_free);
1119
+ }
1120
+
1121
+ /**
1122
+ * @brief Make sure the jwt is able to be extracted from HTTP(S) response.
1123
+ * The JSON response after HTTP(S) call to token provider will be in
1124
+ * rd_http_req_t.hreq_buf and jwt is the value of field "access_token",
1125
+ * the format is {"access_token":"*******"}.
1126
+ * This function mocks up the rd_http_req_t.hreq_buf using an dummy
1127
+ * jwt. The rd_http_parse_json will extract the jwt from rd_http_req_t
1128
+ * and make sure the extracted jwt is same with the dummy one.
1129
+ */
1130
+ static int ut_sasl_oauthbearer_oidc_should_succeed(void) {
1131
+ /* Generate a token in the https://jwt.io/ website by using the
1132
+ * following steps:
1133
+ * 1. Select the algorithm RS256 from the Algorithm drop-down menu.
1134
+ * 2. Enter the header and the payload.
1135
+ * payload should contains "exp", "iat", "sub", for example:
1136
+ * payloads = {"exp": 1636532769,
1137
+ "iat": 1516239022,
1138
+ "sub": "sub"}
1139
+ header should contains "kid", for example:
1140
+ headers={"kid": "abcedfg"} */
1141
+ static const char *expected_jwt_token =
1142
+ "eyJhbGciOiJIUzI1NiIsInR5"
1143
+ "cCI6IkpXVCIsImtpZCI6ImFiY2VkZmcifQ"
1144
+ "."
1145
+ "eyJpYXQiOjE2MzIzNzUzMjAsInN1YiI6InN"
1146
+ "1YiIsImV4cCI6MTYzMjM3NTYyMH0"
1147
+ "."
1148
+ "bT5oY8K-rS2gQ7Awc40844bK3zhzBhZb7sputErqQHY";
1149
+ char *expected_token_value;
1150
+ size_t token_len;
1151
+ rd_http_req_t hreq;
1152
+ rd_http_error_t *herr;
1153
+ cJSON *json = NULL;
1154
+ char *token;
1155
+ cJSON *parsed_token;
1156
+ rd_kafka_t *rk = rd_calloc(1, sizeof(*rk));
1157
+
1158
+ RD_UT_BEGIN();
1159
+
1160
+ herr = rd_http_req_init(rk, &hreq, "");
1161
+
1162
+ RD_UT_ASSERT(!herr,
1163
+ "Expected initialize to succeed, "
1164
+ "but failed with error code: %d, error string: %s",
1165
+ herr->code, herr->errstr);
1166
+
1167
+ token_len = strlen("access_token") + strlen(expected_jwt_token) + 8;
1168
+
1169
+ expected_token_value = rd_malloc(token_len);
1170
+ rd_snprintf(expected_token_value, token_len, "{\"%s\":\"%s\"}",
1171
+ "access_token", expected_jwt_token);
1172
+ rd_buf_write(hreq.hreq_buf, expected_token_value, token_len);
1173
+
1174
+ herr = rd_http_parse_json(&hreq, &json);
1175
+ RD_UT_ASSERT(!herr,
1176
+ "Failed to parse JSON token: error code: %d, "
1177
+ "error string: %s",
1178
+ herr->code, herr->errstr);
1179
+
1180
+ RD_UT_ASSERT(json, "Expected non-empty json.");
1181
+
1182
+ parsed_token = cJSON_GetObjectItem(json, "access_token");
1183
+
1184
+ RD_UT_ASSERT(parsed_token, "Expected access_token in JSON response.");
1185
+ token = parsed_token->valuestring;
1186
+
1187
+ RD_UT_ASSERT(!strcmp(expected_jwt_token, token),
1188
+ "Incorrect token received: "
1189
+ "expected=%s; received=%s",
1190
+ expected_jwt_token, token);
1191
+
1192
+ rd_free(expected_token_value);
1193
+ rd_http_error_destroy(herr);
1194
+ rd_http_req_destroy(&hreq);
1195
+ cJSON_Delete(json);
1196
+ rd_free(rk);
1197
+
1198
+ RD_UT_PASS();
1199
+ }
1200
+
1201
+
1202
+ /**
1203
+ * @brief Make sure JSON doesn't include the "access_token" key,
1204
+ * it will fail and return an empty token.
1205
+ */
1206
+ static int ut_sasl_oauthbearer_oidc_with_empty_key(void) {
1207
+ static const char *empty_token_format = "{}";
1208
+ size_t token_len;
1209
+ rd_http_req_t hreq;
1210
+ rd_http_error_t *herr;
1211
+ cJSON *json = NULL;
1212
+ cJSON *parsed_token;
1213
+ rd_kafka_t *rk = rd_calloc(1, sizeof(*rk));
1214
+
1215
+ RD_UT_BEGIN();
1216
+
1217
+ herr = rd_http_req_init(rk, &hreq, "");
1218
+ RD_UT_ASSERT(!herr,
1219
+ "Expected initialization to succeed, "
1220
+ "but it failed with error code: %d, error string: %s",
1221
+ herr->code, herr->errstr);
1222
+
1223
+ token_len = strlen(empty_token_format);
1224
+
1225
+ rd_buf_write(hreq.hreq_buf, empty_token_format, token_len);
1226
+
1227
+ herr = rd_http_parse_json(&hreq, &json);
1228
+
1229
+ RD_UT_ASSERT(!herr,
1230
+ "Expected JSON token parsing to succeed, "
1231
+ "but it failed with error code: %d, error string: %s",
1232
+ herr->code, herr->errstr);
1233
+
1234
+ RD_UT_ASSERT(json, "Expected non-empty json.");
1235
+
1236
+ parsed_token = cJSON_GetObjectItem(json, "access_token");
1237
+
1238
+ RD_UT_ASSERT(!parsed_token,
1239
+ "Did not expecte access_token in JSON response");
1240
+
1241
+ rd_http_req_destroy(&hreq);
1242
+ rd_http_error_destroy(herr);
1243
+ cJSON_Delete(json);
1244
+ cJSON_Delete(parsed_token);
1245
+ rd_free(rk);
1246
+ RD_UT_PASS();
1247
+ }
1248
+
1249
+ /**
1250
+ * @brief Make sure the post_fields return correct with the scope.
1251
+ */
1252
+ static int ut_sasl_oauthbearer_oidc_post_fields(void) {
1253
+ static const char *scope = "test-scope";
1254
+ static const char *expected_post_fields =
1255
+ "grant_type=client_credentials&scope=test-scope";
1256
+
1257
+ size_t expected_post_fields_size = strlen(expected_post_fields);
1258
+
1259
+ size_t post_fields_size;
1260
+
1261
+ char *post_fields;
1262
+
1263
+ RD_UT_BEGIN();
1264
+
1265
+ rd_kafka_oidc_client_credentials_build_post_fields(scope, &post_fields,
1266
+ &post_fields_size);
1267
+
1268
+ RD_UT_ASSERT(expected_post_fields_size == post_fields_size,
1269
+ "Expected expected_post_fields_size is %" PRIusz
1270
+ " received post_fields_size is %" PRIusz,
1271
+ expected_post_fields_size, post_fields_size);
1272
+ RD_UT_ASSERT(!strcmp(expected_post_fields, post_fields),
1273
+ "Expected expected_post_fields is %s"
1274
+ " received post_fields is %s",
1275
+ expected_post_fields, post_fields);
1276
+
1277
+ rd_free(post_fields);
1278
+
1279
+ RD_UT_PASS();
1280
+ }
1281
+
1282
+ /**
1283
+ * @brief Make sure the post_fields return correct with the empty scope.
1284
+ */
1285
+ static int ut_sasl_oauthbearer_oidc_post_fields_with_empty_scope(void) {
1286
+ static const char *scope = NULL;
1287
+ static const char *expected_post_fields =
1288
+ "grant_type=client_credentials";
1289
+
1290
+ size_t expected_post_fields_size = strlen(expected_post_fields);
1291
+
1292
+ size_t post_fields_size;
1293
+
1294
+ char *post_fields;
1295
+
1296
+ RD_UT_BEGIN();
1297
+
1298
+ rd_kafka_oidc_client_credentials_build_post_fields(scope, &post_fields,
1299
+ &post_fields_size);
1300
+
1301
+ RD_UT_ASSERT(expected_post_fields_size == post_fields_size,
1302
+ "Expected expected_post_fields_size is %" PRIusz
1303
+ " received post_fields_size is %" PRIusz,
1304
+ expected_post_fields_size, post_fields_size);
1305
+ RD_UT_ASSERT(!strcmp(expected_post_fields, post_fields),
1306
+ "Expected expected_post_fields is %s"
1307
+ " received post_fields is %s",
1308
+ expected_post_fields, post_fields);
1309
+
1310
+ rd_free(post_fields);
1311
+
1312
+ RD_UT_PASS();
1313
+ }
1314
+
1315
+
1316
+ /**
1317
+ * @brief make sure the jwt is able to be extracted from HTTP(S) requests
1318
+ * or fail as expected.
1319
+ */
1320
+ int unittest_sasl_oauthbearer_oidc(void) {
1321
+ int fails = 0;
1322
+ fails += ut_sasl_oauthbearer_oidc_should_succeed();
1323
+ fails += ut_sasl_oauthbearer_oidc_with_empty_key();
1324
+ fails += ut_sasl_oauthbearer_oidc_post_fields();
1325
+ fails += ut_sasl_oauthbearer_oidc_post_fields_with_empty_scope();
1326
+ return fails;
1327
+ }
1328
+
1329
+ /**
1330
+ * @brief Test the Base64Url encoding functionality.
1331
+ * Verifies that the encoding correctly handles special characters
1332
+ * and padding removal.
1333
+ */
1334
+ static int ut_sasl_oauthbearer_oidc_jwt_bearer_base64url_encode(void) {
1335
+ /* Test cases with expected inputs and outputs */
1336
+ static const struct {
1337
+ const char *input;
1338
+ const char *expected_output;
1339
+ } test_cases[] = {
1340
+ /* Regular case */
1341
+ {"Hello, world!", "SGVsbG8sIHdvcmxkIQ"},
1342
+ /* Case with padding characters that should be removed */
1343
+ {"test", "dGVzdA"},
1344
+ /* Empty string */
1345
+ {"", ""},
1346
+ /* Special characters that trigger Base64 padding */
1347
+ {"f", "Zg"},
1348
+ {"fo", "Zm8"},
1349
+ {"foo", "Zm9v"},
1350
+ {"foob", "Zm9vYg"},
1351
+ {"fooba", "Zm9vYmE"},
1352
+ {"foobar", "Zm9vYmFy"},
1353
+ /* Characters that produce + and / in standard Base64 */
1354
+ {"\x3E\x3F",
1355
+ "Pj8"}, /* encodes to ">?" in standard Base64 with + and / */
1356
+ };
1357
+ unsigned int i;
1358
+
1359
+ RD_UT_BEGIN();
1360
+
1361
+ for (i = 0; i < RD_ARRAYSIZE(test_cases); i++) {
1362
+ rd_chariov_t input_iov;
1363
+ input_iov.ptr = (char *)test_cases[i].input;
1364
+ input_iov.size = strlen(test_cases[i].input);
1365
+ char *output = rd_base64_encode_str_urlsafe(&input_iov);
1366
+
1367
+ RD_UT_ASSERT(output != NULL,
1368
+ "Expected non-NULL output for input: %s",
1369
+ test_cases[i].input);
1370
+
1371
+ RD_UT_ASSERT(!strcmp(output, test_cases[i].expected_output),
1372
+ "Base64Url encoding failed: expected %s, got %s",
1373
+ test_cases[i].expected_output, output);
1374
+
1375
+ rd_free(output);
1376
+ }
1377
+
1378
+ RD_UT_PASS();
1379
+ }
1380
+
1381
+ /**
1382
+ * @brief Test JWT request body building.
1383
+ * Verifies that the request body is correctly formatted with
1384
+ * the required parameters.
1385
+ */
1386
+ static int ut_sasl_oauthbearer_oidc_jwt_bearer_build_request_body(void) {
1387
+ const char *assertion = "test.jwt.assertion";
1388
+ const char *scope = "test.scope";
1389
+ const char *expected =
1390
+ "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion="
1391
+ "test.jwt.assertion&scope=test.scope";
1392
+ char *body;
1393
+
1394
+ RD_UT_BEGIN();
1395
+
1396
+ body = rd_kafka_oidc_jwt_bearer_build_request_body(assertion, scope);
1397
+
1398
+ RD_UT_ASSERT(body != NULL, "Expected non-NULL request body");
1399
+
1400
+ RD_UT_ASSERT(!strcmp(body, expected),
1401
+ "Request body incorrect: expected '%s', got '%s'",
1402
+ expected, body);
1403
+
1404
+ rd_free(body);
1405
+
1406
+ RD_UT_PASS();
1407
+ }
1408
+
1409
+ /**
1410
+ * @brief Test JWT assertion file parsing.
1411
+ * Verifies that the function correctly reads a JWT from a file.
1412
+ */
1413
+ static int ut_sasl_oauthbearer_oidc_assertion_parse_from_file(void) {
1414
+
1415
+ char tempfile_path[512];
1416
+ FILE *tempfile;
1417
+ const char *test_jwt = "header.payload.signature";
1418
+ char *result;
1419
+
1420
+ RD_UT_BEGIN();
1421
+
1422
+ tempfile = rd_file_mkstemp("rdtmp", "wb", tempfile_path,
1423
+ sizeof(tempfile_path));
1424
+ fprintf(tempfile, "%s", test_jwt);
1425
+ fclose(tempfile);
1426
+
1427
+ /* Test parsing from file */
1428
+ result = rd_kafka_oidc_assertion_read_from_file(tempfile_path);
1429
+ RD_UT_ASSERT(result != NULL,
1430
+ "Expected non-NULL result from parsing file");
1431
+ RD_UT_ASSERT(!strcmp(result, test_jwt),
1432
+ "Incorrect JWT parsed: expected '%s', got '%s'", test_jwt,
1433
+ result);
1434
+
1435
+ rd_free(result);
1436
+
1437
+ /* Test with NULL path */
1438
+ result = rd_kafka_oidc_assertion_read_from_file(NULL);
1439
+ RD_UT_ASSERT(result == NULL, "Expected NULL result with NULL path");
1440
+
1441
+ /* Test with non-existent file */
1442
+ result =
1443
+ rd_kafka_oidc_assertion_read_from_file("/non/existent/file/path");
1444
+ RD_UT_ASSERT(result == NULL,
1445
+ "Expected NULL result with non-existent file");
1446
+
1447
+ remove(tempfile_path);
1448
+
1449
+ RD_UT_PASS();
1450
+ }
1451
+
1452
+ /**
1453
+ * @brief Mock function for testing JWT template processing.
1454
+ * Creates a file with valid JWT template JSON.
1455
+ */
1456
+ static char *ut_create_mock_jwt_template_file(void) {
1457
+ FILE *tempfile;
1458
+ char tempfile_path[512];
1459
+
1460
+ const char *template_json =
1461
+ "{\n"
1462
+ " \"header\": {\n"
1463
+ " \"kid\": \"test-key-id\"\n"
1464
+ " },\n"
1465
+ " \"payload\": {\n"
1466
+ " \"sub\": \"test-subject\",\n"
1467
+ " \"aud\": \"test-audience\"\n"
1468
+ " }\n"
1469
+ "}";
1470
+
1471
+ tempfile = rd_file_mkstemp("rdtmp", "wb", tempfile_path,
1472
+ sizeof(tempfile_path));
1473
+ if (!tempfile)
1474
+ return NULL;
1475
+
1476
+ fprintf(tempfile, "%s", template_json);
1477
+ fclose(tempfile);
1478
+
1479
+ return rd_strdup(tempfile_path);
1480
+ }
1481
+
1482
+ /**
1483
+ * @brief Test JWT template file processing.
1484
+ * Verifies that the function correctly parses header and payload from
1485
+ * template.
1486
+ */
1487
+ static int ut_sasl_oauthbearer_oidc_assertion_process_template_file(void) {
1488
+ char *template_path;
1489
+ rd_kafka_t *rk;
1490
+ cJSON *header = NULL, *payload = NULL;
1491
+ int result;
1492
+
1493
+ RD_UT_BEGIN();
1494
+
1495
+ rk = rd_calloc(1, sizeof(*rk));
1496
+
1497
+ template_path = ut_create_mock_jwt_template_file();
1498
+ RD_UT_ASSERT(template_path != NULL, "Failed to create template file");
1499
+
1500
+ /* Test template processing */
1501
+ result = rd_kafka_oidc_assertion_parse_template_file(rk, template_path,
1502
+ &header, &payload);
1503
+ RD_UT_ASSERT(result == 0, "Expected success from template processing");
1504
+ RD_UT_ASSERT(header != NULL, "Expected non-NULL header JSON");
1505
+ RD_UT_ASSERT(payload != NULL, "Expected non-NULL payload JSON");
1506
+
1507
+ /* Verify header contents */
1508
+ cJSON *kid = cJSON_GetObjectItem(header, "kid");
1509
+ RD_UT_ASSERT(kid != NULL, "Expected kid in header");
1510
+ RD_UT_ASSERT(cJSON_IsString(kid), "Expected kid to be string");
1511
+ RD_UT_ASSERT(!strcmp(cJSON_GetStringValue(kid), "test-key-id"),
1512
+ "Incorrect kid value");
1513
+
1514
+ /* Verify payload contents */
1515
+ cJSON *sub = cJSON_GetObjectItem(payload, "sub");
1516
+ RD_UT_ASSERT(sub != NULL, "Expected sub in payload");
1517
+ RD_UT_ASSERT(cJSON_IsString(sub), "Expected sub to be string");
1518
+ RD_UT_ASSERT(!strcmp(cJSON_GetStringValue(sub), "test-subject"),
1519
+ "Incorrect sub value");
1520
+
1521
+ cJSON *aud = cJSON_GetObjectItem(payload, "aud");
1522
+ RD_UT_ASSERT(aud != NULL, "Expected aud in payload");
1523
+ RD_UT_ASSERT(cJSON_IsString(aud), "Expected aud to be string");
1524
+ RD_UT_ASSERT(!strcmp(cJSON_GetStringValue(aud), "test-audience"),
1525
+ "Incorrect aud value");
1526
+
1527
+ /* Test with non-existent file */
1528
+ cJSON_Delete(header);
1529
+ cJSON_Delete(payload);
1530
+ header = NULL;
1531
+ payload = NULL;
1532
+
1533
+ result = rd_kafka_oidc_assertion_parse_template_file(
1534
+ rk, "/non/existent/file", &header, &payload);
1535
+ RD_UT_ASSERT(result == -1, "Expected failure with non-existent file");
1536
+ RD_UT_ASSERT(header == NULL,
1537
+ "Expected NULL header with failed processing");
1538
+ RD_UT_ASSERT(payload == NULL,
1539
+ "Expected NULL payload with failed processing");
1540
+
1541
+ unlink(template_path);
1542
+ rd_free(template_path);
1543
+ rd_free(rk);
1544
+ if (header)
1545
+ cJSON_Delete(header);
1546
+ if (payload)
1547
+ cJSON_Delete(payload);
1548
+
1549
+ RD_UT_PASS();
1550
+ }
1551
+
1552
+ /**
1553
+ * @brief Test JWT assertion creation with minimal approach.
1554
+ * Creates a simplified test that validates the format of the created
1555
+ * JWT.
1556
+ */
1557
+ static int ut_sasl_oauthbearer_oidc_assertion_create(void) {
1558
+ rd_kafka_t *rk;
1559
+ char *private_key_pem;
1560
+ char *jwt;
1561
+ char *header_part, *payload_part, *signature_part;
1562
+ char *dot1, *dot2;
1563
+
1564
+ RD_UT_BEGIN();
1565
+
1566
+ rk = rd_calloc(1, sizeof(*rk));
1567
+
1568
+ /* Random key for signing */
1569
+ private_key_pem =
1570
+ "-----BEGIN PRIVATE KEY-----\n"
1571
+ "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCuBS7qG5Cd2voa\n"
1572
+ "7nSU2xaDbe6QOYU2P4bIY58SKHbFyq1iB517r61ImsWD+UfZuVxCqXRaWdxxnG/D\n"
1573
+ "5VGTQzBOZYlgSYxdJ1KvITXO8kj5i2zBT/LI9R9MTQ7nLFh+vQm1aM8Ts1PmA5t9\n"
1574
+ "zFtR9B8RfqN9kbt+2LnLY57aJxEkFC3D89D0WWT97UJWKo7/vxMqp9K9uAIL2Efo\n"
1575
+ "5rp9qwyPbx9LmTbfZ8Vog6mG6tAQQHSUqw0PnfhADCVCkYtkzYcyDZy3qZQFu1bY\n"
1576
+ "KuuMoMjssyCUL5tTHyNZju0p3Z0bSfOV/nkqHpSSjHKCeQkSKS18/7In6cfY/M4k\n"
1577
+ "8rM4HWkdAgMBAAECggEAFsTo2YrXxj/Dn8h5ioyMCpBUuZw9GNcBDLE0PAz9VW3q\n"
1578
+ "d7wlV+ypkKlnlJgGVa+SKcrARZ4iYN8mJIyZutn8tRVF/0pASmP9xppizvwWnkgm\n"
1579
+ "57hNPQwNl08x1v+PaK3VWl4nUh2RqbPpIXGetT9q3UAjpiduT++Nh9Y2D7cy3/Ro\n"
1580
+ "ritnpBDs1R6y5J3rxiE1s8kLYwhDRCPsgUg/ZtKPDTTFz42ArrFeqM91FmjHYP3t\n"
1581
+ "p9Uh6CIZ80D6CsMX/TnZFfhKe6EvKBSl4W6tcdFlnXW52fm/670iKSmcJ09+fzPO\n"
1582
+ "T1BLrkXGv51bFnlvUyJqQGVEv5+0+HUX/oTpTknMQQKBgQDbYhqip5e8r1f5v32B\n"
1583
+ "k1r3xtEiWU2mZoTHJu6bVeuigzVhz4pTMVZChElJ4QnhwwO0t5Oe4Su1MZtjMRw7\n"
1584
+ "qIE+YM2pXss25LRXbmWItuRWINzpe8omlxQSOj2tNO/67l0P4vmmrT5wkU2cG6TR\n"
1585
+ "ddzorO3NDA4MY4+Xdli+SHXwUQKBgQDLEMqlwyvaGjuZ30l6F13fWnEt9PNCtJsa\n"
1586
+ "nsdKJKyFMThdysY/PK40o2GTRRhgYa2jigN3OCYSSznRRZRlqznqL1bOLlYV6zS8\n"
1587
+ "TGhdLXuApyLAjZYIK4RtZJYGR9+yg8rH13uNektgW8KnHh5Ko/ptRVoEukf3SBsh\n"
1588
+ "f0Fib3ylDQKBgE11Bth0+bMJ6bLpNEPiphSjosVQ6ISe37R8/3Pi0y5uyxM8tqcG\n"
1589
+ "3WDg2gt2pAmM1CsjQcCv2cHAwQ81kLVTmkZO4W4yZOd9ulrARKMPh/EM61KYfVhA\n"
1590
+ "sTp6S7py3WQocr0gM2rw8gHGm7NJY1j9F0EjhVaHMhKXuGQOyehtJw7xAoGAPwuA\n"
1591
+ "jwRQSg+Y74XmbxRwHZcbynPhTpV6DkK7huZp9ZQ5ds0szZdOUqNi+PEbx1isKzj/\n"
1592
+ "KHVzRHy8f5+FmicV/QIjhjHWokl6/vcN89faHzBE1tleejzgiYIQHfUUm3zVaUQa\n"
1593
+ "ZOtSGaGDhpUQPIY6itBcSVl4XGqzmavDpgcNAMUCgYBFFGtG+RbSySzKfRUp3vc5\n"
1594
+ "8YqIdrtXfW9gc9s1+Pw8wfgrY0Rrvy+e3ClSwgGENxgxBvWvhzq2m0S8x2jdLAl1\n"
1595
+ "b+VLGCOpUvS4iN2yrHkoHS7BSW40wLuVooJUAaNOIEPqiv1JC75q2dhTRrANp6WB\n"
1596
+ "bm+7yWVTNlXYuKQqtuOkNQ==\n"
1597
+ "-----END PRIVATE KEY-----\n";
1598
+
1599
+ jwt = rd_kafka_oidc_assertion_create(
1600
+ rk, private_key_pem, NULL, NULL,
1601
+ RD_KAFKA_SASL_OAUTHBEARER_ASSERTION_ALGORITHM_RS256, NULL,
1602
+ "test-subject", "test-issuer", "test-audience", 2, 300, rd_true);
1603
+
1604
+ RD_UT_ASSERT(jwt != NULL, "Failed to create JWT assertion");
1605
+
1606
+ dot1 = strchr(jwt, '.');
1607
+ RD_UT_ASSERT(dot1 != NULL, "JWT missing first dot separator");
1608
+
1609
+ dot2 = strchr(dot1 + 1, '.');
1610
+ RD_UT_ASSERT(dot2 != NULL, "JWT missing second dot separator");
1611
+
1612
+ header_part = rd_strndup(jwt, dot1 - jwt);
1613
+ payload_part = rd_strndup(dot1 + 1, dot2 - (dot1 + 1));
1614
+ signature_part = rd_strdup(dot2 + 1);
1615
+
1616
+ RD_UT_ASSERT(strlen(header_part) > 0, "JWT header part is empty");
1617
+ RD_UT_ASSERT(strlen(payload_part) > 0, "JWT payload part is empty");
1618
+ RD_UT_ASSERT(strlen(signature_part) > 0, "JWT signature part is empty");
1619
+
1620
+ RD_UT_ASSERT(!strchr(header_part, '='),
1621
+ "JWT header contains padding character");
1622
+ RD_UT_ASSERT(!strchr(payload_part, '='),
1623
+ "JWT payload contains padding character");
1624
+ RD_UT_ASSERT(!strchr(signature_part, '='),
1625
+ "JWT signature contains padding character");
1626
+
1627
+ RD_UT_ASSERT(!strchr(header_part, '+'),
1628
+ "JWT header contains '+' character");
1629
+ RD_UT_ASSERT(!strchr(header_part, '/'),
1630
+ "JWT header contains '/' character");
1631
+ RD_UT_ASSERT(!strchr(payload_part, '+'),
1632
+ "JWT payload contains '+' character");
1633
+ RD_UT_ASSERT(!strchr(payload_part, '/'),
1634
+ "JWT payload contains '/' character");
1635
+ RD_UT_ASSERT(!strchr(signature_part, '+'),
1636
+ "JWT signature contains '+' character");
1637
+ RD_UT_ASSERT(!strchr(signature_part, '/'),
1638
+ "JWT signature contains '/' character");
1639
+
1640
+ rd_free(header_part);
1641
+ rd_free(payload_part);
1642
+ rd_free(signature_part);
1643
+ rd_free(jwt);
1644
+ rd_free(rk);
1645
+
1646
+ RD_UT_PASS();
1647
+ }
1648
+
1649
+ int unittest_sasl_oauthbearer_oidc_jwt_bearer(void) {
1650
+ int fails = 0;
1651
+
1652
+ fails += ut_sasl_oauthbearer_oidc_jwt_bearer_base64url_encode();
1653
+ fails += ut_sasl_oauthbearer_oidc_jwt_bearer_build_request_body();
1654
+
1655
+ return fails;
1656
+ }
1657
+
1658
+ int unittest_sasl_oauthbearer_oidc_assertion(void) {
1659
+ int fails = 0;
1660
+
1661
+ fails += ut_sasl_oauthbearer_oidc_assertion_parse_from_file();
1662
+ fails += ut_sasl_oauthbearer_oidc_assertion_process_template_file();
1663
+ fails += ut_sasl_oauthbearer_oidc_assertion_create();
1664
+
1665
+ return fails;
1666
+ }