@platformatic/rdkafka 4.0.0

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 (767) hide show
  1. package/.editorconfig +5 -0
  2. package/.jshintignore +1 -0
  3. package/.jshintrc +23 -0
  4. package/CONTRIBUTING.md +237 -0
  5. package/LICENSE.txt +21 -0
  6. package/Makefile +94 -0
  7. package/README.md +630 -0
  8. package/bench/consumer-raw-rdkafka.js +76 -0
  9. package/bench/consumer-subscribe.js +77 -0
  10. package/bench/kafka-consumer-stream.js +100 -0
  11. package/bench/producer-raw-rdkafka.js +125 -0
  12. package/bench/producer-rdkafka.js +117 -0
  13. package/bench/seed.sh +38 -0
  14. package/binding.gyp +155 -0
  15. package/ci/checks/librdkafka-correct-version.js +67 -0
  16. package/ci/checks/librdkafka-exists.js +13 -0
  17. package/ci/librdkafka-defs-generator.js +193 -0
  18. package/ci/prepublish.js +3 -0
  19. package/config.d.ts +1132 -0
  20. package/configure +15 -0
  21. package/cpplint.py +6325 -0
  22. package/deploy.enc +0 -0
  23. package/deps/librdkafka/.clang-format +136 -0
  24. package/deps/librdkafka/.clang-format-cpp +103 -0
  25. package/deps/librdkafka/.dir-locals.el +10 -0
  26. package/deps/librdkafka/.formatignore +33 -0
  27. package/deps/librdkafka/.gdbmacros +19 -0
  28. package/deps/librdkafka/.semaphore/project.yml +43 -0
  29. package/deps/librdkafka/.semaphore/project_public.yml +20 -0
  30. package/deps/librdkafka/.semaphore/semaphore.yml +355 -0
  31. package/deps/librdkafka/CHANGELOG.md +1738 -0
  32. package/deps/librdkafka/CMakeLists.txt +291 -0
  33. package/deps/librdkafka/CODE_OF_CONDUCT.md +46 -0
  34. package/deps/librdkafka/CONFIGURATION.md +189 -0
  35. package/deps/librdkafka/CONTRIBUTING.md +431 -0
  36. package/deps/librdkafka/Doxyfile +2375 -0
  37. package/deps/librdkafka/INTRODUCTION.md +2173 -0
  38. package/deps/librdkafka/LICENSE +26 -0
  39. package/deps/librdkafka/LICENSE.cjson +22 -0
  40. package/deps/librdkafka/LICENSE.crc32c +28 -0
  41. package/deps/librdkafka/LICENSE.fnv1a +18 -0
  42. package/deps/librdkafka/LICENSE.hdrhistogram +27 -0
  43. package/deps/librdkafka/LICENSE.lz4 +26 -0
  44. package/deps/librdkafka/LICENSE.murmur2 +25 -0
  45. package/deps/librdkafka/LICENSE.nanopb +22 -0
  46. package/deps/librdkafka/LICENSE.opentelemetry +203 -0
  47. package/deps/librdkafka/LICENSE.pycrc +23 -0
  48. package/deps/librdkafka/LICENSE.queue +31 -0
  49. package/deps/librdkafka/LICENSE.regexp +5 -0
  50. package/deps/librdkafka/LICENSE.snappy +36 -0
  51. package/deps/librdkafka/LICENSE.tinycthread +26 -0
  52. package/deps/librdkafka/LICENSE.wingetopt +49 -0
  53. package/deps/librdkafka/LICENSES.txt +625 -0
  54. package/deps/librdkafka/Makefile +124 -0
  55. package/deps/librdkafka/README.md +199 -0
  56. package/deps/librdkafka/README.win32 +26 -0
  57. package/deps/librdkafka/STATISTICS.md +624 -0
  58. package/deps/librdkafka/configure +214 -0
  59. package/deps/librdkafka/configure.self +331 -0
  60. package/deps/librdkafka/debian/changelog +111 -0
  61. package/deps/librdkafka/debian/compat +1 -0
  62. package/deps/librdkafka/debian/control +71 -0
  63. package/deps/librdkafka/debian/copyright +99 -0
  64. package/deps/librdkafka/debian/gbp.conf +9 -0
  65. package/deps/librdkafka/debian/librdkafka++1.install +1 -0
  66. package/deps/librdkafka/debian/librdkafka-dev.examples +2 -0
  67. package/deps/librdkafka/debian/librdkafka-dev.install +9 -0
  68. package/deps/librdkafka/debian/librdkafka1.docs +5 -0
  69. package/deps/librdkafka/debian/librdkafka1.install +1 -0
  70. package/deps/librdkafka/debian/librdkafka1.symbols +135 -0
  71. package/deps/librdkafka/debian/rules +19 -0
  72. package/deps/librdkafka/debian/source/format +1 -0
  73. package/deps/librdkafka/debian/watch +2 -0
  74. package/deps/librdkafka/dev-conf.sh +123 -0
  75. package/deps/librdkafka/examples/CMakeLists.txt +79 -0
  76. package/deps/librdkafka/examples/Makefile +167 -0
  77. package/deps/librdkafka/examples/README.md +42 -0
  78. package/deps/librdkafka/examples/alter_consumer_group_offsets.c +338 -0
  79. package/deps/librdkafka/examples/consumer.c +261 -0
  80. package/deps/librdkafka/examples/delete_records.c +233 -0
  81. package/deps/librdkafka/examples/describe_cluster.c +322 -0
  82. package/deps/librdkafka/examples/describe_consumer_groups.c +436 -0
  83. package/deps/librdkafka/examples/describe_topics.c +427 -0
  84. package/deps/librdkafka/examples/elect_leaders.c +317 -0
  85. package/deps/librdkafka/examples/globals.json +11 -0
  86. package/deps/librdkafka/examples/idempotent_producer.c +344 -0
  87. package/deps/librdkafka/examples/incremental_alter_configs.c +348 -0
  88. package/deps/librdkafka/examples/kafkatest_verifiable_client.cpp +961 -0
  89. package/deps/librdkafka/examples/list_consumer_group_offsets.c +359 -0
  90. package/deps/librdkafka/examples/list_consumer_groups.c +365 -0
  91. package/deps/librdkafka/examples/list_offsets.c +327 -0
  92. package/deps/librdkafka/examples/misc.c +287 -0
  93. package/deps/librdkafka/examples/openssl_engine_example.cpp +249 -0
  94. package/deps/librdkafka/examples/producer.c +251 -0
  95. package/deps/librdkafka/examples/producer.cpp +228 -0
  96. package/deps/librdkafka/examples/rdkafka_complex_consumer_example.c +617 -0
  97. package/deps/librdkafka/examples/rdkafka_complex_consumer_example.cpp +467 -0
  98. package/deps/librdkafka/examples/rdkafka_consume_batch.cpp +264 -0
  99. package/deps/librdkafka/examples/rdkafka_example.c +853 -0
  100. package/deps/librdkafka/examples/rdkafka_example.cpp +679 -0
  101. package/deps/librdkafka/examples/rdkafka_performance.c +1781 -0
  102. package/deps/librdkafka/examples/transactions-older-broker.c +668 -0
  103. package/deps/librdkafka/examples/transactions.c +665 -0
  104. package/deps/librdkafka/examples/user_scram.c +492 -0
  105. package/deps/librdkafka/examples/win_ssl_cert_store.cpp +395 -0
  106. package/deps/librdkafka/lds-gen.py +73 -0
  107. package/deps/librdkafka/mainpage.doxy +40 -0
  108. package/deps/librdkafka/mklove/Makefile.base +329 -0
  109. package/deps/librdkafka/mklove/modules/configure.atomics +144 -0
  110. package/deps/librdkafka/mklove/modules/configure.base +2484 -0
  111. package/deps/librdkafka/mklove/modules/configure.builtin +70 -0
  112. package/deps/librdkafka/mklove/modules/configure.cc +186 -0
  113. package/deps/librdkafka/mklove/modules/configure.cxx +8 -0
  114. package/deps/librdkafka/mklove/modules/configure.fileversion +65 -0
  115. package/deps/librdkafka/mklove/modules/configure.gitversion +29 -0
  116. package/deps/librdkafka/mklove/modules/configure.good_cflags +18 -0
  117. package/deps/librdkafka/mklove/modules/configure.host +132 -0
  118. package/deps/librdkafka/mklove/modules/configure.lib +49 -0
  119. package/deps/librdkafka/mklove/modules/configure.libcurl +99 -0
  120. package/deps/librdkafka/mklove/modules/configure.libsasl2 +36 -0
  121. package/deps/librdkafka/mklove/modules/configure.libssl +147 -0
  122. package/deps/librdkafka/mklove/modules/configure.libzstd +58 -0
  123. package/deps/librdkafka/mklove/modules/configure.parseversion +95 -0
  124. package/deps/librdkafka/mklove/modules/configure.pic +16 -0
  125. package/deps/librdkafka/mklove/modules/configure.socket +20 -0
  126. package/deps/librdkafka/mklove/modules/configure.zlib +61 -0
  127. package/deps/librdkafka/mklove/modules/patches/README.md +8 -0
  128. package/deps/librdkafka/mklove/modules/patches/libcurl.0000-no-runtime-linking-check.patch +11 -0
  129. package/deps/librdkafka/mklove/modules/patches/libssl.0000-osx-rand-include-fix-OpenSSL-PR16409.patch +56 -0
  130. package/deps/librdkafka/packaging/RELEASE.md +311 -0
  131. package/deps/librdkafka/packaging/alpine/build-alpine.sh +38 -0
  132. package/deps/librdkafka/packaging/archlinux/PKGBUILD +30 -0
  133. package/deps/librdkafka/packaging/cmake/Config.cmake.in +37 -0
  134. package/deps/librdkafka/packaging/cmake/Modules/FindLZ4.cmake +38 -0
  135. package/deps/librdkafka/packaging/cmake/Modules/FindZSTD.cmake +27 -0
  136. package/deps/librdkafka/packaging/cmake/Modules/LICENSE.FindZstd +178 -0
  137. package/deps/librdkafka/packaging/cmake/README.md +38 -0
  138. package/deps/librdkafka/packaging/cmake/config.h.in +52 -0
  139. package/deps/librdkafka/packaging/cmake/parseversion.cmake +60 -0
  140. package/deps/librdkafka/packaging/cmake/rdkafka.pc.in +12 -0
  141. package/deps/librdkafka/packaging/cmake/try_compile/atomic_32_test.c +8 -0
  142. package/deps/librdkafka/packaging/cmake/try_compile/atomic_64_test.c +8 -0
  143. package/deps/librdkafka/packaging/cmake/try_compile/c11threads_test.c +14 -0
  144. package/deps/librdkafka/packaging/cmake/try_compile/crc32c_hw_test.c +27 -0
  145. package/deps/librdkafka/packaging/cmake/try_compile/dlopen_test.c +11 -0
  146. package/deps/librdkafka/packaging/cmake/try_compile/libsasl2_test.c +7 -0
  147. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_darwin_test.c +6 -0
  148. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_freebsd_test.c +7 -0
  149. package/deps/librdkafka/packaging/cmake/try_compile/pthread_setname_gnu_test.c +5 -0
  150. package/deps/librdkafka/packaging/cmake/try_compile/rand_r_test.c +7 -0
  151. package/deps/librdkafka/packaging/cmake/try_compile/rdkafka_setup.cmake +122 -0
  152. package/deps/librdkafka/packaging/cmake/try_compile/regex_test.c +10 -0
  153. package/deps/librdkafka/packaging/cmake/try_compile/strndup_test.c +5 -0
  154. package/deps/librdkafka/packaging/cmake/try_compile/sync_32_test.c +8 -0
  155. package/deps/librdkafka/packaging/cmake/try_compile/sync_64_test.c +8 -0
  156. package/deps/librdkafka/packaging/cp/README.md +13 -0
  157. package/deps/librdkafka/packaging/cp/check_features.c +64 -0
  158. package/deps/librdkafka/packaging/cp/verify-deb.sh +33 -0
  159. package/deps/librdkafka/packaging/cp/verify-packages.sh +48 -0
  160. package/deps/librdkafka/packaging/cp/verify-rpm.sh +39 -0
  161. package/deps/librdkafka/packaging/debian/changelog +66 -0
  162. package/deps/librdkafka/packaging/debian/compat +1 -0
  163. package/deps/librdkafka/packaging/debian/control +49 -0
  164. package/deps/librdkafka/packaging/debian/copyright +84 -0
  165. package/deps/librdkafka/packaging/debian/gbp.conf +9 -0
  166. package/deps/librdkafka/packaging/debian/librdkafka-dev.dirs +2 -0
  167. package/deps/librdkafka/packaging/debian/librdkafka-dev.examples +2 -0
  168. package/deps/librdkafka/packaging/debian/librdkafka-dev.install +6 -0
  169. package/deps/librdkafka/packaging/debian/librdkafka-dev.substvars +1 -0
  170. package/deps/librdkafka/packaging/debian/librdkafka.dsc +16 -0
  171. package/deps/librdkafka/packaging/debian/librdkafka1-dbg.substvars +1 -0
  172. package/deps/librdkafka/packaging/debian/librdkafka1.dirs +1 -0
  173. package/deps/librdkafka/packaging/debian/librdkafka1.install +2 -0
  174. package/deps/librdkafka/packaging/debian/librdkafka1.postinst.debhelper +5 -0
  175. package/deps/librdkafka/packaging/debian/librdkafka1.postrm.debhelper +5 -0
  176. package/deps/librdkafka/packaging/debian/librdkafka1.symbols +64 -0
  177. package/deps/librdkafka/packaging/debian/rules +19 -0
  178. package/deps/librdkafka/packaging/debian/source/format +1 -0
  179. package/deps/librdkafka/packaging/debian/watch +2 -0
  180. package/deps/librdkafka/packaging/get_version.py +21 -0
  181. package/deps/librdkafka/packaging/homebrew/README.md +15 -0
  182. package/deps/librdkafka/packaging/homebrew/brew-update-pr.sh +31 -0
  183. package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw-static.sh +52 -0
  184. package/deps/librdkafka/packaging/mingw-w64/configure-build-msys2-mingw.sh +21 -0
  185. package/deps/librdkafka/packaging/mingw-w64/run-tests.sh +6 -0
  186. package/deps/librdkafka/packaging/mingw-w64/semaphoreci-build.sh +38 -0
  187. package/deps/librdkafka/packaging/mingw-w64/travis-before-install.sh +20 -0
  188. package/deps/librdkafka/packaging/nuget/README.md +84 -0
  189. package/deps/librdkafka/packaging/nuget/artifact.py +177 -0
  190. package/deps/librdkafka/packaging/nuget/cleanup-s3.py +143 -0
  191. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr120.zip +0 -0
  192. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-win32__bldtype-Release/msvcr140.zip +0 -0
  193. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr120.zip +0 -0
  194. package/deps/librdkafka/packaging/nuget/common/p-common__plat-windows__arch-x64__bldtype-Release/msvcr140.zip +0 -0
  195. package/deps/librdkafka/packaging/nuget/nuget.sh +21 -0
  196. package/deps/librdkafka/packaging/nuget/nugetpackage.py +278 -0
  197. package/deps/librdkafka/packaging/nuget/packaging.py +448 -0
  198. package/deps/librdkafka/packaging/nuget/push-to-nuget.sh +21 -0
  199. package/deps/librdkafka/packaging/nuget/release.py +167 -0
  200. package/deps/librdkafka/packaging/nuget/requirements.txt +3 -0
  201. package/deps/librdkafka/packaging/nuget/staticpackage.py +178 -0
  202. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.nuspec +21 -0
  203. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.props +18 -0
  204. package/deps/librdkafka/packaging/nuget/templates/librdkafka.redist.targets +19 -0
  205. package/deps/librdkafka/packaging/nuget/zfile/__init__.py +0 -0
  206. package/deps/librdkafka/packaging/nuget/zfile/zfile.py +98 -0
  207. package/deps/librdkafka/packaging/rpm/Makefile +92 -0
  208. package/deps/librdkafka/packaging/rpm/README.md +23 -0
  209. package/deps/librdkafka/packaging/rpm/el7-x86_64.cfg +40 -0
  210. package/deps/librdkafka/packaging/rpm/librdkafka.spec +118 -0
  211. package/deps/librdkafka/packaging/rpm/mock-on-docker.sh +96 -0
  212. package/deps/librdkafka/packaging/rpm/tests/Makefile +25 -0
  213. package/deps/librdkafka/packaging/rpm/tests/README.md +8 -0
  214. package/deps/librdkafka/packaging/rpm/tests/run-test.sh +42 -0
  215. package/deps/librdkafka/packaging/rpm/tests/test-on-docker.sh +56 -0
  216. package/deps/librdkafka/packaging/rpm/tests/test.c +77 -0
  217. package/deps/librdkafka/packaging/rpm/tests/test.cpp +34 -0
  218. package/deps/librdkafka/packaging/tools/build-configurations-checks.sh +10 -0
  219. package/deps/librdkafka/packaging/tools/build-deb-package.sh +64 -0
  220. package/deps/librdkafka/packaging/tools/build-debian.sh +65 -0
  221. package/deps/librdkafka/packaging/tools/build-manylinux.sh +68 -0
  222. package/deps/librdkafka/packaging/tools/build-release-artifacts.sh +139 -0
  223. package/deps/librdkafka/packaging/tools/distro-build.sh +38 -0
  224. package/deps/librdkafka/packaging/tools/gh-release-checksums.py +39 -0
  225. package/deps/librdkafka/packaging/tools/rdutcoverage.sh +25 -0
  226. package/deps/librdkafka/packaging/tools/requirements.txt +2 -0
  227. package/deps/librdkafka/packaging/tools/style-format.sh +148 -0
  228. package/deps/librdkafka/service.yml +18 -0
  229. package/deps/librdkafka/src/CMakeLists.txt +374 -0
  230. package/deps/librdkafka/src/Makefile +103 -0
  231. package/deps/librdkafka/src/README.lz4.md +30 -0
  232. package/deps/librdkafka/src/cJSON.c +2834 -0
  233. package/deps/librdkafka/src/cJSON.h +398 -0
  234. package/deps/librdkafka/src/crc32c.c +430 -0
  235. package/deps/librdkafka/src/crc32c.h +38 -0
  236. package/deps/librdkafka/src/generate_proto.sh +66 -0
  237. package/deps/librdkafka/src/librdkafka_cgrp_synch.png +0 -0
  238. package/deps/librdkafka/src/lz4.c +2727 -0
  239. package/deps/librdkafka/src/lz4.h +842 -0
  240. package/deps/librdkafka/src/lz4frame.c +2078 -0
  241. package/deps/librdkafka/src/lz4frame.h +692 -0
  242. package/deps/librdkafka/src/lz4frame_static.h +47 -0
  243. package/deps/librdkafka/src/lz4hc.c +1631 -0
  244. package/deps/librdkafka/src/lz4hc.h +413 -0
  245. package/deps/librdkafka/src/nanopb/pb.h +917 -0
  246. package/deps/librdkafka/src/nanopb/pb_common.c +388 -0
  247. package/deps/librdkafka/src/nanopb/pb_common.h +49 -0
  248. package/deps/librdkafka/src/nanopb/pb_decode.c +1727 -0
  249. package/deps/librdkafka/src/nanopb/pb_decode.h +193 -0
  250. package/deps/librdkafka/src/nanopb/pb_encode.c +1000 -0
  251. package/deps/librdkafka/src/nanopb/pb_encode.h +185 -0
  252. package/deps/librdkafka/src/opentelemetry/common.pb.c +32 -0
  253. package/deps/librdkafka/src/opentelemetry/common.pb.h +170 -0
  254. package/deps/librdkafka/src/opentelemetry/metrics.options +2 -0
  255. package/deps/librdkafka/src/opentelemetry/metrics.pb.c +67 -0
  256. package/deps/librdkafka/src/opentelemetry/metrics.pb.h +966 -0
  257. package/deps/librdkafka/src/opentelemetry/resource.pb.c +12 -0
  258. package/deps/librdkafka/src/opentelemetry/resource.pb.h +58 -0
  259. package/deps/librdkafka/src/queue.h +850 -0
  260. package/deps/librdkafka/src/rd.h +441 -0
  261. package/deps/librdkafka/src/rdaddr.c +255 -0
  262. package/deps/librdkafka/src/rdaddr.h +203 -0
  263. package/deps/librdkafka/src/rdatomic.h +226 -0
  264. package/deps/librdkafka/src/rdavg.h +259 -0
  265. package/deps/librdkafka/src/rdavl.c +210 -0
  266. package/deps/librdkafka/src/rdavl.h +250 -0
  267. package/deps/librdkafka/src/rdbase64.c +169 -0
  268. package/deps/librdkafka/src/rdbase64.h +41 -0
  269. package/deps/librdkafka/src/rdbuf.c +1884 -0
  270. package/deps/librdkafka/src/rdbuf.h +375 -0
  271. package/deps/librdkafka/src/rdcrc32.c +114 -0
  272. package/deps/librdkafka/src/rdcrc32.h +170 -0
  273. package/deps/librdkafka/src/rddl.c +179 -0
  274. package/deps/librdkafka/src/rddl.h +43 -0
  275. package/deps/librdkafka/src/rdendian.h +174 -0
  276. package/deps/librdkafka/src/rdfloat.h +67 -0
  277. package/deps/librdkafka/src/rdfnv1a.c +113 -0
  278. package/deps/librdkafka/src/rdfnv1a.h +35 -0
  279. package/deps/librdkafka/src/rdgz.c +120 -0
  280. package/deps/librdkafka/src/rdgz.h +46 -0
  281. package/deps/librdkafka/src/rdhdrhistogram.c +721 -0
  282. package/deps/librdkafka/src/rdhdrhistogram.h +87 -0
  283. package/deps/librdkafka/src/rdhttp.c +512 -0
  284. package/deps/librdkafka/src/rdhttp.h +83 -0
  285. package/deps/librdkafka/src/rdinterval.h +177 -0
  286. package/deps/librdkafka/src/rdkafka.c +5351 -0
  287. package/deps/librdkafka/src/rdkafka.h +10603 -0
  288. package/deps/librdkafka/src/rdkafka_admin.c +9417 -0
  289. package/deps/librdkafka/src/rdkafka_admin.h +619 -0
  290. package/deps/librdkafka/src/rdkafka_assignment.c +1010 -0
  291. package/deps/librdkafka/src/rdkafka_assignment.h +73 -0
  292. package/deps/librdkafka/src/rdkafka_assignor.c +1786 -0
  293. package/deps/librdkafka/src/rdkafka_assignor.h +402 -0
  294. package/deps/librdkafka/src/rdkafka_aux.c +409 -0
  295. package/deps/librdkafka/src/rdkafka_aux.h +174 -0
  296. package/deps/librdkafka/src/rdkafka_background.c +221 -0
  297. package/deps/librdkafka/src/rdkafka_broker.c +6186 -0
  298. package/deps/librdkafka/src/rdkafka_broker.h +686 -0
  299. package/deps/librdkafka/src/rdkafka_buf.c +540 -0
  300. package/deps/librdkafka/src/rdkafka_buf.h +1524 -0
  301. package/deps/librdkafka/src/rdkafka_cert.c +552 -0
  302. package/deps/librdkafka/src/rdkafka_cert.h +61 -0
  303. package/deps/librdkafka/src/rdkafka_cgrp.c +7262 -0
  304. package/deps/librdkafka/src/rdkafka_cgrp.h +443 -0
  305. package/deps/librdkafka/src/rdkafka_conf.c +4456 -0
  306. package/deps/librdkafka/src/rdkafka_conf.h +668 -0
  307. package/deps/librdkafka/src/rdkafka_confval.h +97 -0
  308. package/deps/librdkafka/src/rdkafka_coord.c +623 -0
  309. package/deps/librdkafka/src/rdkafka_coord.h +132 -0
  310. package/deps/librdkafka/src/rdkafka_error.c +228 -0
  311. package/deps/librdkafka/src/rdkafka_error.h +80 -0
  312. package/deps/librdkafka/src/rdkafka_event.c +502 -0
  313. package/deps/librdkafka/src/rdkafka_event.h +126 -0
  314. package/deps/librdkafka/src/rdkafka_feature.c +461 -0
  315. package/deps/librdkafka/src/rdkafka_feature.h +102 -0
  316. package/deps/librdkafka/src/rdkafka_fetcher.c +1402 -0
  317. package/deps/librdkafka/src/rdkafka_fetcher.h +44 -0
  318. package/deps/librdkafka/src/rdkafka_header.c +220 -0
  319. package/deps/librdkafka/src/rdkafka_header.h +76 -0
  320. package/deps/librdkafka/src/rdkafka_idempotence.c +807 -0
  321. package/deps/librdkafka/src/rdkafka_idempotence.h +144 -0
  322. package/deps/librdkafka/src/rdkafka_int.h +1222 -0
  323. package/deps/librdkafka/src/rdkafka_interceptor.c +819 -0
  324. package/deps/librdkafka/src/rdkafka_interceptor.h +104 -0
  325. package/deps/librdkafka/src/rdkafka_lz4.c +450 -0
  326. package/deps/librdkafka/src/rdkafka_lz4.h +49 -0
  327. package/deps/librdkafka/src/rdkafka_metadata.c +2124 -0
  328. package/deps/librdkafka/src/rdkafka_metadata.h +341 -0
  329. package/deps/librdkafka/src/rdkafka_metadata_cache.c +977 -0
  330. package/deps/librdkafka/src/rdkafka_mock.c +2885 -0
  331. package/deps/librdkafka/src/rdkafka_mock.h +491 -0
  332. package/deps/librdkafka/src/rdkafka_mock_cgrp.c +710 -0
  333. package/deps/librdkafka/src/rdkafka_mock_handlers.c +2817 -0
  334. package/deps/librdkafka/src/rdkafka_mock_int.h +591 -0
  335. package/deps/librdkafka/src/rdkafka_msg.c +2573 -0
  336. package/deps/librdkafka/src/rdkafka_msg.h +614 -0
  337. package/deps/librdkafka/src/rdkafka_msgbatch.h +62 -0
  338. package/deps/librdkafka/src/rdkafka_msgset.h +98 -0
  339. package/deps/librdkafka/src/rdkafka_msgset_reader.c +1806 -0
  340. package/deps/librdkafka/src/rdkafka_msgset_writer.c +1470 -0
  341. package/deps/librdkafka/src/rdkafka_offset.c +1537 -0
  342. package/deps/librdkafka/src/rdkafka_offset.h +150 -0
  343. package/deps/librdkafka/src/rdkafka_op.c +997 -0
  344. package/deps/librdkafka/src/rdkafka_op.h +834 -0
  345. package/deps/librdkafka/src/rdkafka_partition.c +4801 -0
  346. package/deps/librdkafka/src/rdkafka_partition.h +1173 -0
  347. package/deps/librdkafka/src/rdkafka_pattern.c +228 -0
  348. package/deps/librdkafka/src/rdkafka_pattern.h +70 -0
  349. package/deps/librdkafka/src/rdkafka_plugin.c +213 -0
  350. package/deps/librdkafka/src/rdkafka_plugin.h +41 -0
  351. package/deps/librdkafka/src/rdkafka_proto.h +733 -0
  352. package/deps/librdkafka/src/rdkafka_protocol.h +127 -0
  353. package/deps/librdkafka/src/rdkafka_queue.c +1153 -0
  354. package/deps/librdkafka/src/rdkafka_queue.h +1201 -0
  355. package/deps/librdkafka/src/rdkafka_range_assignor.c +1748 -0
  356. package/deps/librdkafka/src/rdkafka_request.c +6817 -0
  357. package/deps/librdkafka/src/rdkafka_request.h +709 -0
  358. package/deps/librdkafka/src/rdkafka_roundrobin_assignor.c +123 -0
  359. package/deps/librdkafka/src/rdkafka_sasl.c +528 -0
  360. package/deps/librdkafka/src/rdkafka_sasl.h +63 -0
  361. package/deps/librdkafka/src/rdkafka_sasl_cyrus.c +722 -0
  362. package/deps/librdkafka/src/rdkafka_sasl_int.h +89 -0
  363. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.c +1829 -0
  364. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer.h +52 -0
  365. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.c +589 -0
  366. package/deps/librdkafka/src/rdkafka_sasl_oauthbearer_oidc.h +37 -0
  367. package/deps/librdkafka/src/rdkafka_sasl_plain.c +142 -0
  368. package/deps/librdkafka/src/rdkafka_sasl_scram.c +857 -0
  369. package/deps/librdkafka/src/rdkafka_sasl_win32.c +550 -0
  370. package/deps/librdkafka/src/rdkafka_ssl.c +1904 -0
  371. package/deps/librdkafka/src/rdkafka_ssl.h +64 -0
  372. package/deps/librdkafka/src/rdkafka_sticky_assignor.c +4781 -0
  373. package/deps/librdkafka/src/rdkafka_subscription.c +278 -0
  374. package/deps/librdkafka/src/rdkafka_telemetry.c +703 -0
  375. package/deps/librdkafka/src/rdkafka_telemetry.h +52 -0
  376. package/deps/librdkafka/src/rdkafka_telemetry_decode.c +1053 -0
  377. package/deps/librdkafka/src/rdkafka_telemetry_decode.h +59 -0
  378. package/deps/librdkafka/src/rdkafka_telemetry_encode.c +993 -0
  379. package/deps/librdkafka/src/rdkafka_telemetry_encode.h +301 -0
  380. package/deps/librdkafka/src/rdkafka_timer.c +402 -0
  381. package/deps/librdkafka/src/rdkafka_timer.h +117 -0
  382. package/deps/librdkafka/src/rdkafka_topic.c +2078 -0
  383. package/deps/librdkafka/src/rdkafka_topic.h +328 -0
  384. package/deps/librdkafka/src/rdkafka_transport.c +1297 -0
  385. package/deps/librdkafka/src/rdkafka_transport.h +94 -0
  386. package/deps/librdkafka/src/rdkafka_transport_int.h +100 -0
  387. package/deps/librdkafka/src/rdkafka_txnmgr.c +3251 -0
  388. package/deps/librdkafka/src/rdkafka_txnmgr.h +171 -0
  389. package/deps/librdkafka/src/rdkafka_zstd.c +226 -0
  390. package/deps/librdkafka/src/rdkafka_zstd.h +57 -0
  391. package/deps/librdkafka/src/rdlist.c +576 -0
  392. package/deps/librdkafka/src/rdlist.h +434 -0
  393. package/deps/librdkafka/src/rdlog.c +89 -0
  394. package/deps/librdkafka/src/rdlog.h +41 -0
  395. package/deps/librdkafka/src/rdmap.c +503 -0
  396. package/deps/librdkafka/src/rdmap.h +492 -0
  397. package/deps/librdkafka/src/rdmurmur2.c +167 -0
  398. package/deps/librdkafka/src/rdmurmur2.h +35 -0
  399. package/deps/librdkafka/src/rdports.c +61 -0
  400. package/deps/librdkafka/src/rdports.h +38 -0
  401. package/deps/librdkafka/src/rdposix.h +250 -0
  402. package/deps/librdkafka/src/rdrand.c +70 -0
  403. package/deps/librdkafka/src/rdrand.h +43 -0
  404. package/deps/librdkafka/src/rdregex.c +156 -0
  405. package/deps/librdkafka/src/rdregex.h +43 -0
  406. package/deps/librdkafka/src/rdsignal.h +57 -0
  407. package/deps/librdkafka/src/rdstring.c +645 -0
  408. package/deps/librdkafka/src/rdstring.h +98 -0
  409. package/deps/librdkafka/src/rdsysqueue.h +404 -0
  410. package/deps/librdkafka/src/rdtime.h +325 -0
  411. package/deps/librdkafka/src/rdtypes.h +86 -0
  412. package/deps/librdkafka/src/rdunittest.c +532 -0
  413. package/deps/librdkafka/src/rdunittest.h +230 -0
  414. package/deps/librdkafka/src/rdvarint.c +134 -0
  415. package/deps/librdkafka/src/rdvarint.h +165 -0
  416. package/deps/librdkafka/src/rdwin32.h +382 -0
  417. package/deps/librdkafka/src/rdxxhash.c +1030 -0
  418. package/deps/librdkafka/src/rdxxhash.h +328 -0
  419. package/deps/librdkafka/src/regexp.c +1347 -0
  420. package/deps/librdkafka/src/regexp.h +41 -0
  421. package/deps/librdkafka/src/snappy.c +1866 -0
  422. package/deps/librdkafka/src/snappy.h +62 -0
  423. package/deps/librdkafka/src/snappy_compat.h +138 -0
  424. package/deps/librdkafka/src/statistics_schema.json +444 -0
  425. package/deps/librdkafka/src/tinycthread.c +932 -0
  426. package/deps/librdkafka/src/tinycthread.h +503 -0
  427. package/deps/librdkafka/src/tinycthread_extra.c +175 -0
  428. package/deps/librdkafka/src/tinycthread_extra.h +208 -0
  429. package/deps/librdkafka/src/win32_config.h +58 -0
  430. package/deps/librdkafka/src-cpp/CMakeLists.txt +90 -0
  431. package/deps/librdkafka/src-cpp/ConfImpl.cpp +84 -0
  432. package/deps/librdkafka/src-cpp/ConsumerImpl.cpp +244 -0
  433. package/deps/librdkafka/src-cpp/HandleImpl.cpp +436 -0
  434. package/deps/librdkafka/src-cpp/HeadersImpl.cpp +48 -0
  435. package/deps/librdkafka/src-cpp/KafkaConsumerImpl.cpp +296 -0
  436. package/deps/librdkafka/src-cpp/Makefile +55 -0
  437. package/deps/librdkafka/src-cpp/MessageImpl.cpp +38 -0
  438. package/deps/librdkafka/src-cpp/MetadataImpl.cpp +170 -0
  439. package/deps/librdkafka/src-cpp/ProducerImpl.cpp +197 -0
  440. package/deps/librdkafka/src-cpp/QueueImpl.cpp +70 -0
  441. package/deps/librdkafka/src-cpp/README.md +16 -0
  442. package/deps/librdkafka/src-cpp/RdKafka.cpp +59 -0
  443. package/deps/librdkafka/src-cpp/TopicImpl.cpp +124 -0
  444. package/deps/librdkafka/src-cpp/TopicPartitionImpl.cpp +57 -0
  445. package/deps/librdkafka/src-cpp/rdkafkacpp.h +3771 -0
  446. package/deps/librdkafka/src-cpp/rdkafkacpp_int.h +1641 -0
  447. package/deps/librdkafka/tests/0000-unittests.c +72 -0
  448. package/deps/librdkafka/tests/0001-multiobj.c +98 -0
  449. package/deps/librdkafka/tests/0002-unkpart.c +244 -0
  450. package/deps/librdkafka/tests/0003-msgmaxsize.c +173 -0
  451. package/deps/librdkafka/tests/0004-conf.c +867 -0
  452. package/deps/librdkafka/tests/0005-order.c +133 -0
  453. package/deps/librdkafka/tests/0006-symbols.c +163 -0
  454. package/deps/librdkafka/tests/0007-autotopic.c +136 -0
  455. package/deps/librdkafka/tests/0008-reqacks.c +179 -0
  456. package/deps/librdkafka/tests/0009-mock_cluster.c +96 -0
  457. package/deps/librdkafka/tests/0011-produce_batch.c +752 -0
  458. package/deps/librdkafka/tests/0012-produce_consume.c +537 -0
  459. package/deps/librdkafka/tests/0013-null-msgs.c +473 -0
  460. package/deps/librdkafka/tests/0014-reconsume-191.c +512 -0
  461. package/deps/librdkafka/tests/0015-offset_seeks.c +172 -0
  462. package/deps/librdkafka/tests/0016-client_swname.c +166 -0
  463. package/deps/librdkafka/tests/0017-compression.c +142 -0
  464. package/deps/librdkafka/tests/0018-cgrp_term.c +333 -0
  465. package/deps/librdkafka/tests/0019-list_groups.c +289 -0
  466. package/deps/librdkafka/tests/0020-destroy_hang.c +162 -0
  467. package/deps/librdkafka/tests/0021-rkt_destroy.c +71 -0
  468. package/deps/librdkafka/tests/0022-consume_batch.c +276 -0
  469. package/deps/librdkafka/tests/0025-timers.c +147 -0
  470. package/deps/librdkafka/tests/0026-consume_pause.c +549 -0
  471. package/deps/librdkafka/tests/0028-long_topicnames.c +79 -0
  472. package/deps/librdkafka/tests/0029-assign_offset.c +204 -0
  473. package/deps/librdkafka/tests/0030-offset_commit.c +589 -0
  474. package/deps/librdkafka/tests/0031-get_offsets.c +235 -0
  475. package/deps/librdkafka/tests/0033-regex_subscribe.c +520 -0
  476. package/deps/librdkafka/tests/0034-offset_reset.c +377 -0
  477. package/deps/librdkafka/tests/0035-api_version.c +73 -0
  478. package/deps/librdkafka/tests/0036-partial_fetch.c +86 -0
  479. package/deps/librdkafka/tests/0037-destroy_hang_local.c +85 -0
  480. package/deps/librdkafka/tests/0038-performance.c +120 -0
  481. package/deps/librdkafka/tests/0039-event.c +284 -0
  482. package/deps/librdkafka/tests/0040-io_event.c +251 -0
  483. package/deps/librdkafka/tests/0041-fetch_max_bytes.c +96 -0
  484. package/deps/librdkafka/tests/0042-many_topics.c +252 -0
  485. package/deps/librdkafka/tests/0043-no_connection.c +77 -0
  486. package/deps/librdkafka/tests/0044-partition_cnt.c +93 -0
  487. package/deps/librdkafka/tests/0045-subscribe_update.c +746 -0
  488. package/deps/librdkafka/tests/0046-rkt_cache.c +65 -0
  489. package/deps/librdkafka/tests/0047-partial_buf_tmout.c +97 -0
  490. package/deps/librdkafka/tests/0048-partitioner.c +283 -0
  491. package/deps/librdkafka/tests/0049-consume_conn_close.c +162 -0
  492. package/deps/librdkafka/tests/0050-subscribe_adds.c +144 -0
  493. package/deps/librdkafka/tests/0051-assign_adds.c +125 -0
  494. package/deps/librdkafka/tests/0052-msg_timestamps.c +220 -0
  495. package/deps/librdkafka/tests/0053-stats_cb.cpp +535 -0
  496. package/deps/librdkafka/tests/0054-offset_time.cpp +236 -0
  497. package/deps/librdkafka/tests/0055-producer_latency.c +366 -0
  498. package/deps/librdkafka/tests/0056-balanced_group_mt.c +311 -0
  499. package/deps/librdkafka/tests/0057-invalid_topic.cpp +112 -0
  500. package/deps/librdkafka/tests/0058-log.cpp +123 -0
  501. package/deps/librdkafka/tests/0059-bsearch.cpp +237 -0
  502. package/deps/librdkafka/tests/0060-op_prio.cpp +163 -0
  503. package/deps/librdkafka/tests/0061-consumer_lag.cpp +275 -0
  504. package/deps/librdkafka/tests/0062-stats_event.c +126 -0
  505. package/deps/librdkafka/tests/0063-clusterid.cpp +180 -0
  506. package/deps/librdkafka/tests/0064-interceptors.c +481 -0
  507. package/deps/librdkafka/tests/0065-yield.cpp +140 -0
  508. package/deps/librdkafka/tests/0066-plugins.cpp +129 -0
  509. package/deps/librdkafka/tests/0067-empty_topic.cpp +148 -0
  510. package/deps/librdkafka/tests/0068-produce_timeout.c +138 -0
  511. package/deps/librdkafka/tests/0069-consumer_add_parts.c +123 -0
  512. package/deps/librdkafka/tests/0070-null_empty.cpp +197 -0
  513. package/deps/librdkafka/tests/0072-headers_ut.c +448 -0
  514. package/deps/librdkafka/tests/0073-headers.c +381 -0
  515. package/deps/librdkafka/tests/0074-producev.c +87 -0
  516. package/deps/librdkafka/tests/0075-retry.c +253 -0
  517. package/deps/librdkafka/tests/0076-produce_retry.c +450 -0
  518. package/deps/librdkafka/tests/0077-compaction.c +357 -0
  519. package/deps/librdkafka/tests/0078-c_from_cpp.cpp +96 -0
  520. package/deps/librdkafka/tests/0079-fork.c +93 -0
  521. package/deps/librdkafka/tests/0080-admin_ut.c +3065 -0
  522. package/deps/librdkafka/tests/0081-admin.c +5333 -0
  523. package/deps/librdkafka/tests/0082-fetch_max_bytes.cpp +133 -0
  524. package/deps/librdkafka/tests/0083-cb_event.c +228 -0
  525. package/deps/librdkafka/tests/0084-destroy_flags.c +212 -0
  526. package/deps/librdkafka/tests/0085-headers.cpp +388 -0
  527. package/deps/librdkafka/tests/0086-purge.c +335 -0
  528. package/deps/librdkafka/tests/0088-produce_metadata_timeout.c +162 -0
  529. package/deps/librdkafka/tests/0089-max_poll_interval.c +506 -0
  530. package/deps/librdkafka/tests/0090-idempotence.c +172 -0
  531. package/deps/librdkafka/tests/0091-max_poll_interval_timeout.c +297 -0
  532. package/deps/librdkafka/tests/0092-mixed_msgver.c +97 -0
  533. package/deps/librdkafka/tests/0093-holb.c +197 -0
  534. package/deps/librdkafka/tests/0094-idempotence_msg_timeout.c +230 -0
  535. package/deps/librdkafka/tests/0095-all_brokers_down.cpp +122 -0
  536. package/deps/librdkafka/tests/0097-ssl_verify.cpp +466 -0
  537. package/deps/librdkafka/tests/0098-consumer-txn.cpp +1218 -0
  538. package/deps/librdkafka/tests/0099-commit_metadata.c +194 -0
  539. package/deps/librdkafka/tests/0100-thread_interceptors.cpp +195 -0
  540. package/deps/librdkafka/tests/0101-fetch-from-follower.cpp +446 -0
  541. package/deps/librdkafka/tests/0102-static_group_rebalance.c +535 -0
  542. package/deps/librdkafka/tests/0103-transactions.c +1383 -0
  543. package/deps/librdkafka/tests/0104-fetch_from_follower_mock.c +624 -0
  544. package/deps/librdkafka/tests/0105-transactions_mock.c +3923 -0
  545. package/deps/librdkafka/tests/0106-cgrp_sess_timeout.c +297 -0
  546. package/deps/librdkafka/tests/0107-topic_recreate.c +259 -0
  547. package/deps/librdkafka/tests/0109-auto_create_topics.cpp +218 -0
  548. package/deps/librdkafka/tests/0110-batch_size.cpp +183 -0
  549. package/deps/librdkafka/tests/0111-delay_create_topics.cpp +127 -0
  550. package/deps/librdkafka/tests/0112-assign_unknown_part.c +98 -0
  551. package/deps/librdkafka/tests/0113-cooperative_rebalance.cpp +3329 -0
  552. package/deps/librdkafka/tests/0114-sticky_partitioning.cpp +176 -0
  553. package/deps/librdkafka/tests/0115-producer_auth.cpp +179 -0
  554. package/deps/librdkafka/tests/0116-kafkaconsumer_close.cpp +214 -0
  555. package/deps/librdkafka/tests/0117-mock_errors.c +321 -0
  556. package/deps/librdkafka/tests/0118-commit_rebalance.c +121 -0
  557. package/deps/librdkafka/tests/0119-consumer_auth.cpp +148 -0
  558. package/deps/librdkafka/tests/0120-asymmetric_subscription.c +180 -0
  559. package/deps/librdkafka/tests/0121-clusterid.c +115 -0
  560. package/deps/librdkafka/tests/0122-buffer_cleaning_after_rebalance.c +227 -0
  561. package/deps/librdkafka/tests/0123-connections_max_idle.c +98 -0
  562. package/deps/librdkafka/tests/0124-openssl_invalid_engine.c +69 -0
  563. package/deps/librdkafka/tests/0125-immediate_flush.c +144 -0
  564. package/deps/librdkafka/tests/0126-oauthbearer_oidc.c +213 -0
  565. package/deps/librdkafka/tests/0127-fetch_queue_backoff.cpp +165 -0
  566. package/deps/librdkafka/tests/0128-sasl_callback_queue.cpp +125 -0
  567. package/deps/librdkafka/tests/0129-fetch_aborted_msgs.c +78 -0
  568. package/deps/librdkafka/tests/0130-store_offsets.c +178 -0
  569. package/deps/librdkafka/tests/0131-connect_timeout.c +81 -0
  570. package/deps/librdkafka/tests/0132-strategy_ordering.c +171 -0
  571. package/deps/librdkafka/tests/0133-ssl_keys.c +128 -0
  572. package/deps/librdkafka/tests/0134-ssl_provider.c +92 -0
  573. package/deps/librdkafka/tests/0135-sasl_credentials.cpp +143 -0
  574. package/deps/librdkafka/tests/0136-resolve_cb.c +181 -0
  575. package/deps/librdkafka/tests/0137-barrier_batch_consume.c +609 -0
  576. package/deps/librdkafka/tests/0138-admin_mock.c +281 -0
  577. package/deps/librdkafka/tests/0139-offset_validation_mock.c +442 -0
  578. package/deps/librdkafka/tests/0140-commit_metadata.cpp +108 -0
  579. package/deps/librdkafka/tests/0142-reauthentication.c +495 -0
  580. package/deps/librdkafka/tests/0143-exponential_backoff_mock.c +553 -0
  581. package/deps/librdkafka/tests/0144-idempotence_mock.c +373 -0
  582. package/deps/librdkafka/tests/0145-pause_resume_mock.c +119 -0
  583. package/deps/librdkafka/tests/0146-metadata_mock.c +444 -0
  584. package/deps/librdkafka/tests/0150-telemetry_mock.c +648 -0
  585. package/deps/librdkafka/tests/1000-unktopic.c +164 -0
  586. package/deps/librdkafka/tests/8000-idle.cpp +60 -0
  587. package/deps/librdkafka/tests/8001-fetch_from_follower_mock_manual.c +113 -0
  588. package/deps/librdkafka/tests/CMakeLists.txt +164 -0
  589. package/deps/librdkafka/tests/LibrdkafkaTestApp.py +266 -0
  590. package/deps/librdkafka/tests/Makefile +182 -0
  591. package/deps/librdkafka/tests/README.md +509 -0
  592. package/deps/librdkafka/tests/autotest.sh +33 -0
  593. package/deps/librdkafka/tests/backtrace.gdb +30 -0
  594. package/deps/librdkafka/tests/broker_version_tests.py +315 -0
  595. package/deps/librdkafka/tests/buildbox.sh +17 -0
  596. package/deps/librdkafka/tests/cleanup-checker-tests.sh +20 -0
  597. package/deps/librdkafka/tests/cluster_testing.py +191 -0
  598. package/deps/librdkafka/tests/delete-test-topics.sh +56 -0
  599. package/deps/librdkafka/tests/fixtures/ssl/Makefile +8 -0
  600. package/deps/librdkafka/tests/fixtures/ssl/README.md +13 -0
  601. package/deps/librdkafka/tests/fixtures/ssl/client.keystore.p12 +0 -0
  602. package/deps/librdkafka/tests/fixtures/ssl/client2.certificate.pem +109 -0
  603. package/deps/librdkafka/tests/fixtures/ssl/client2.key +34 -0
  604. package/deps/librdkafka/tests/fixtures/ssl/create_keys.sh +93 -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 +12 -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-consumer-tests.sh +16 -0
  630. package/deps/librdkafka/tests/run-producer-tests.sh +16 -0
  631. package/deps/librdkafka/tests/run-test.sh +140 -0
  632. package/deps/librdkafka/tests/rusage.c +249 -0
  633. package/deps/librdkafka/tests/sasl_test.py +289 -0
  634. package/deps/librdkafka/tests/scenarios/README.md +6 -0
  635. package/deps/librdkafka/tests/scenarios/ak23.json +6 -0
  636. package/deps/librdkafka/tests/scenarios/default.json +5 -0
  637. package/deps/librdkafka/tests/scenarios/noautocreate.json +5 -0
  638. package/deps/librdkafka/tests/sockem.c +801 -0
  639. package/deps/librdkafka/tests/sockem.h +85 -0
  640. package/deps/librdkafka/tests/sockem_ctrl.c +145 -0
  641. package/deps/librdkafka/tests/sockem_ctrl.h +61 -0
  642. package/deps/librdkafka/tests/test.c +7318 -0
  643. package/deps/librdkafka/tests/test.conf.example +27 -0
  644. package/deps/librdkafka/tests/test.h +979 -0
  645. package/deps/librdkafka/tests/testcpp.cpp +126 -0
  646. package/deps/librdkafka/tests/testcpp.h +360 -0
  647. package/deps/librdkafka/tests/testshared.h +402 -0
  648. package/deps/librdkafka/tests/tools/README.md +4 -0
  649. package/deps/librdkafka/tests/tools/stats/README.md +21 -0
  650. package/deps/librdkafka/tests/tools/stats/filter.jq +42 -0
  651. package/deps/librdkafka/tests/tools/stats/graph.py +150 -0
  652. package/deps/librdkafka/tests/tools/stats/requirements.txt +3 -0
  653. package/deps/librdkafka/tests/tools/stats/to_csv.py +124 -0
  654. package/deps/librdkafka/tests/until-fail.sh +87 -0
  655. package/deps/librdkafka/tests/xxxx-assign_partition.c +122 -0
  656. package/deps/librdkafka/tests/xxxx-metadata.cpp +159 -0
  657. package/deps/librdkafka/vcpkg.json +23 -0
  658. package/deps/librdkafka/win32/README.md +5 -0
  659. package/deps/librdkafka/win32/build-package.bat +3 -0
  660. package/deps/librdkafka/win32/build.bat +19 -0
  661. package/deps/librdkafka/win32/common.vcxproj +84 -0
  662. package/deps/librdkafka/win32/install-openssl.ps1 +33 -0
  663. package/deps/librdkafka/win32/interceptor_test/interceptor_test.vcxproj +87 -0
  664. package/deps/librdkafka/win32/librdkafka.autopkg.template +54 -0
  665. package/deps/librdkafka/win32/librdkafka.master.testing.targets +13 -0
  666. package/deps/librdkafka/win32/librdkafka.sln +226 -0
  667. package/deps/librdkafka/win32/librdkafka.vcxproj +276 -0
  668. package/deps/librdkafka/win32/librdkafkacpp/librdkafkacpp.vcxproj +104 -0
  669. package/deps/librdkafka/win32/msbuild.ps1 +15 -0
  670. package/deps/librdkafka/win32/openssl_engine_example/openssl_engine_example.vcxproj +132 -0
  671. package/deps/librdkafka/win32/package-zip.ps1 +46 -0
  672. package/deps/librdkafka/win32/packages/repositories.config +4 -0
  673. package/deps/librdkafka/win32/push-package.bat +4 -0
  674. package/deps/librdkafka/win32/rdkafka_complex_consumer_example_cpp/rdkafka_complex_consumer_example_cpp.vcxproj +67 -0
  675. package/deps/librdkafka/win32/rdkafka_example/rdkafka_example.vcxproj +97 -0
  676. package/deps/librdkafka/win32/rdkafka_performance/rdkafka_performance.vcxproj +97 -0
  677. package/deps/librdkafka/win32/setup-msys2.ps1 +31 -0
  678. package/deps/librdkafka/win32/setup-vcpkg.ps1 +12 -0
  679. package/deps/librdkafka/win32/tests/test.conf.example +25 -0
  680. package/deps/librdkafka/win32/tests/tests.vcxproj +247 -0
  681. package/deps/librdkafka/win32/win_ssl_cert_store/win_ssl_cert_store.vcxproj +132 -0
  682. package/deps/librdkafka/win32/wingetopt.c +564 -0
  683. package/deps/librdkafka/win32/wingetopt.h +100 -0
  684. package/deps/librdkafka/win32/wintime.h +33 -0
  685. package/deps/librdkafka.gyp +62 -0
  686. package/deps/windows-install.py +73 -0
  687. package/docker-compose.yml +23 -0
  688. package/e2e/admin.spec.js +187 -0
  689. package/e2e/both.spec.js +726 -0
  690. package/e2e/consumer.spec.js +386 -0
  691. package/e2e/groups.spec.js +132 -0
  692. package/e2e/listener.js +51 -0
  693. package/e2e/producer-transaction.spec.js +333 -0
  694. package/e2e/producer.spec.js +283 -0
  695. package/errors.d.ts +347 -0
  696. package/examples/consumer-flow.md +76 -0
  697. package/examples/consumer.md +45 -0
  698. package/examples/docker-alpine.md +30 -0
  699. package/examples/high-level-producer.md +32 -0
  700. package/examples/metadata.md +27 -0
  701. package/examples/oauthbearer-default-flow.md +80 -0
  702. package/examples/producer-cluster.md +103 -0
  703. package/examples/producer.md +73 -0
  704. package/index.d.ts +357 -0
  705. package/lib/admin.js +233 -0
  706. package/lib/client.js +578 -0
  707. package/lib/error.js +472 -0
  708. package/lib/index.js +34 -0
  709. package/lib/kafka-consumer-stream.js +397 -0
  710. package/lib/kafka-consumer.js +698 -0
  711. package/lib/producer/high-level-producer.js +323 -0
  712. package/lib/producer-stream.js +307 -0
  713. package/lib/producer.js +375 -0
  714. package/lib/tools/ref-counter.js +52 -0
  715. package/lib/topic-partition.js +88 -0
  716. package/lib/topic.js +42 -0
  717. package/lib/util.js +29 -0
  718. package/librdkafka.js +12 -0
  719. package/make_docs.sh +59 -0
  720. package/package.json +53 -0
  721. package/renovate.json +30 -0
  722. package/run_docker.sh +42 -0
  723. package/src/admin.cc +624 -0
  724. package/src/admin.h +78 -0
  725. package/src/binding.cc +73 -0
  726. package/src/binding.h +25 -0
  727. package/src/callbacks.cc +614 -0
  728. package/src/callbacks.h +265 -0
  729. package/src/common.cc +582 -0
  730. package/src/common.h +134 -0
  731. package/src/config.cc +167 -0
  732. package/src/config.h +45 -0
  733. package/src/connection.cc +482 -0
  734. package/src/connection.h +108 -0
  735. package/src/errors.cc +96 -0
  736. package/src/errors.h +53 -0
  737. package/src/kafka-consumer.cc +1457 -0
  738. package/src/kafka-consumer.h +136 -0
  739. package/src/per-isolate-data.cc +57 -0
  740. package/src/per-isolate-data.h +39 -0
  741. package/src/producer.cc +873 -0
  742. package/src/producer.h +125 -0
  743. package/src/topic.cc +180 -0
  744. package/src/topic.h +56 -0
  745. package/src/workers.cc +1245 -0
  746. package/src/workers.h +511 -0
  747. package/test/binding.spec.js +66 -0
  748. package/test/consumer.spec.js +91 -0
  749. package/test/error.spec.js +8 -0
  750. package/test/index.spec.js +8 -0
  751. package/test/kafka-consumer-stream.spec.js +298 -0
  752. package/test/kafka-consumer-worker.js +51 -0
  753. package/test/kafka-consumer.spec.js +86 -0
  754. package/test/mocha.opts +1 -0
  755. package/test/mock.js +55 -0
  756. package/test/producer/high-level-producer.spec.js +496 -0
  757. package/test/producer-stream.spec.js +723 -0
  758. package/test/producer-worker.js +53 -0
  759. package/test/producer.spec.js +120 -0
  760. package/test/tools/ref-counter.spec.js +53 -0
  761. package/test/topic-partition.spec.js +104 -0
  762. package/test/util.spec.js +46 -0
  763. package/util/configure.js +30 -0
  764. package/util/get-env.js +6 -0
  765. package/util/test-compile.js +11 -0
  766. package/util/test-producer-delivery.js +100 -0
  767. package/win_install.ps1 +2 -0
@@ -0,0 +1,1829 @@
1
+ /*
2
+ * librdkafka - The Apache Kafka C/C++ library
3
+ *
4
+ * Copyright (c) 2019-2022, Magnus Edenhill
5
+ * 2023, Confluent Inc.
6
+ * All rights reserved.
7
+ *
8
+ * Redistribution and use in source and binary forms, with or without
9
+ * modification, are permitted provided that the following conditions are met:
10
+ *
11
+ * 1. Redistributions of source code must retain the above copyright notice,
12
+ * this list of conditions and the following disclaimer.
13
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
14
+ * this list of conditions and the following disclaimer in the documentation
15
+ * and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ * POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+
31
+ /**
32
+ * Builtin SASL OAUTHBEARER support
33
+ */
34
+ #include "rdkafka_int.h"
35
+ #include "rdkafka_transport_int.h"
36
+ #include "rdkafka_sasl_int.h"
37
+ #include <openssl/evp.h>
38
+ #include "rdunittest.h"
39
+
40
+ #if WITH_OAUTHBEARER_OIDC
41
+ #include "rdkafka_sasl_oauthbearer_oidc.h"
42
+ #endif
43
+
44
+
45
+ /**
46
+ * @struct Per-client-instance SASL/OAUTHBEARER handle.
47
+ */
48
+ typedef struct rd_kafka_sasl_oauthbearer_handle_s {
49
+ /**< Read-write lock for fields in the handle. */
50
+ rwlock_t lock;
51
+
52
+ /**< The b64token value as defined in RFC 6750 Section 2.1
53
+ * https://tools.ietf.org/html/rfc6750#section-2.1
54
+ */
55
+ char *token_value;
56
+
57
+ /**< When the token expires, in terms of the number of
58
+ * milliseconds since the epoch. Wall clock time.
59
+ */
60
+ rd_ts_t wts_md_lifetime;
61
+
62
+ /**< The point after which this token should be replaced with a
63
+ * new one, in terms of the number of milliseconds since the
64
+ * epoch. Wall clock time.
65
+ */
66
+ rd_ts_t wts_refresh_after;
67
+
68
+ /**< When the last token refresh was equeued (0 = never)
69
+ * in terms of the number of milliseconds since the epoch.
70
+ * Wall clock time.
71
+ */
72
+ rd_ts_t wts_enqueued_refresh;
73
+
74
+ /**< The name of the principal to which this token applies. */
75
+ char *md_principal_name;
76
+
77
+ /**< The SASL extensions, as per RFC 7628 Section 3.1
78
+ * https://tools.ietf.org/html/rfc7628#section-3.1
79
+ */
80
+ rd_list_t extensions; /* rd_strtup_t list */
81
+
82
+ /**< Error message for validation and/or token retrieval problems. */
83
+ char *errstr;
84
+
85
+ /**< Back-pointer to client instance. */
86
+ rd_kafka_t *rk;
87
+
88
+ /**< Token refresh timer */
89
+ rd_kafka_timer_t token_refresh_tmr;
90
+
91
+ /** Queue to enqueue token_refresh_cb ops on. */
92
+ rd_kafka_q_t *callback_q;
93
+
94
+ /** Using internal refresh callback (sasl.oauthbearer.method=oidc) */
95
+ rd_bool_t internal_refresh;
96
+
97
+ } rd_kafka_sasl_oauthbearer_handle_t;
98
+
99
+
100
+ /**
101
+ * @struct Unsecured JWS info populated when sasl.oauthbearer.config is parsed
102
+ */
103
+ struct rd_kafka_sasl_oauthbearer_parsed_ujws {
104
+ char *principal_claim_name;
105
+ char *principal;
106
+ char *scope_claim_name;
107
+ char *scope_csv_text;
108
+ int life_seconds;
109
+ rd_list_t extensions; /* rd_strtup_t list */
110
+ };
111
+
112
+ /**
113
+ * @struct Unsecured JWS token to be set on the client handle
114
+ */
115
+ struct rd_kafka_sasl_oauthbearer_token {
116
+ char *token_value;
117
+ int64_t md_lifetime_ms;
118
+ char *md_principal_name;
119
+ char **extensions;
120
+ size_t extension_size;
121
+ };
122
+
123
+ /**
124
+ * @brief Per-connection state
125
+ */
126
+ struct rd_kafka_sasl_oauthbearer_state {
127
+ enum { RD_KAFKA_SASL_OAUTHB_STATE_SEND_CLIENT_FIRST_MESSAGE,
128
+ RD_KAFKA_SASL_OAUTHB_STATE_RECV_SERVER_FIRST_MSG,
129
+ RD_KAFKA_SASL_OAUTHB_STATE_RECV_SERVER_MSG_AFTER_FAIL,
130
+ } state;
131
+ char *server_error_msg;
132
+
133
+ /*
134
+ * A place to store a consistent view of the token and extensions
135
+ * throughout the authentication process -- even if it is refreshed
136
+ * midway through this particular authentication.
137
+ */
138
+ char *token_value;
139
+ char *md_principal_name;
140
+ rd_list_t extensions; /* rd_strtup_t list */
141
+ };
142
+
143
+
144
+
145
+ /**
146
+ * @brief free memory inside the given token
147
+ */
148
+ static void rd_kafka_sasl_oauthbearer_token_free(
149
+ struct rd_kafka_sasl_oauthbearer_token *token) {
150
+ size_t i;
151
+
152
+ RD_IF_FREE(token->token_value, rd_free);
153
+ RD_IF_FREE(token->md_principal_name, rd_free);
154
+
155
+ for (i = 0; i < token->extension_size; i++)
156
+ rd_free(token->extensions[i]);
157
+
158
+ RD_IF_FREE(token->extensions, rd_free);
159
+
160
+ memset(token, 0, sizeof(*token));
161
+ }
162
+
163
+
164
+ /**
165
+ * @brief Op callback for RD_KAFKA_OP_OAUTHBEARER_REFRESH
166
+ *
167
+ * @locality Application thread
168
+ */
169
+ static rd_kafka_op_res_t rd_kafka_oauthbearer_refresh_op(rd_kafka_t *rk,
170
+ rd_kafka_q_t *rkq,
171
+ rd_kafka_op_t *rko) {
172
+ /* The op callback is invoked when the op is destroyed via
173
+ * rd_kafka_op_destroy() or rd_kafka_event_destroy(), so
174
+ * make sure we don't refresh upon destruction since
175
+ * the op has already been handled by this point.
176
+ */
177
+ if (rko->rko_err != RD_KAFKA_RESP_ERR__DESTROY &&
178
+ rk->rk_conf.sasl.oauthbearer.token_refresh_cb)
179
+ rk->rk_conf.sasl.oauthbearer.token_refresh_cb(
180
+ rk, rk->rk_conf.sasl.oauthbearer_config,
181
+ rk->rk_conf.opaque);
182
+ return RD_KAFKA_OP_RES_HANDLED;
183
+ }
184
+
185
+ /**
186
+ * @brief Enqueue a token refresh.
187
+ * @locks rwlock_wrlock(&handle->lock) MUST be held
188
+ */
189
+ static void rd_kafka_oauthbearer_enqueue_token_refresh(
190
+ rd_kafka_sasl_oauthbearer_handle_t *handle) {
191
+ rd_kafka_op_t *rko;
192
+
193
+ rko = rd_kafka_op_new_cb(handle->rk, RD_KAFKA_OP_OAUTHBEARER_REFRESH,
194
+ rd_kafka_oauthbearer_refresh_op);
195
+ rd_kafka_op_set_prio(rko, RD_KAFKA_PRIO_FLASH);
196
+
197
+ /* For internal OIDC refresh callback:
198
+ * Force op to be handled by internal callback on the
199
+ * receiving queue, rather than being passed as an event to
200
+ * the application. */
201
+ if (handle->internal_refresh)
202
+ rko->rko_flags |= RD_KAFKA_OP_F_FORCE_CB;
203
+
204
+ handle->wts_enqueued_refresh = rd_uclock();
205
+ rd_kafka_q_enq(handle->callback_q, rko);
206
+ }
207
+
208
+ /**
209
+ * @brief Enqueue a token refresh if necessary.
210
+ *
211
+ * The method rd_kafka_oauthbearer_enqueue_token_refresh() is invoked
212
+ * if necessary; the required lock is acquired and released. This method
213
+ * returns immediately when SASL/OAUTHBEARER is not in use by the client.
214
+ */
215
+ static void rd_kafka_oauthbearer_enqueue_token_refresh_if_necessary(
216
+ rd_kafka_sasl_oauthbearer_handle_t *handle) {
217
+ rd_ts_t now_wallclock;
218
+
219
+ now_wallclock = rd_uclock();
220
+
221
+ rwlock_wrlock(&handle->lock);
222
+ if (handle->wts_refresh_after < now_wallclock &&
223
+ handle->wts_enqueued_refresh <= handle->wts_refresh_after)
224
+ /* Refresh required and not yet scheduled; refresh it */
225
+ rd_kafka_oauthbearer_enqueue_token_refresh(handle);
226
+ rwlock_wrunlock(&handle->lock);
227
+ }
228
+
229
+ /**
230
+ * @returns \c rd_true if SASL/OAUTHBEARER is the configured authentication
231
+ * mechanism and a token is available, otherwise \c rd_false.
232
+ *
233
+ * @locks none
234
+ * @locality any
235
+ */
236
+ static rd_bool_t
237
+ rd_kafka_oauthbearer_has_token(rd_kafka_sasl_oauthbearer_handle_t *handle) {
238
+ rd_bool_t retval_has_token;
239
+
240
+ rwlock_rdlock(&handle->lock);
241
+ retval_has_token = handle->token_value != NULL;
242
+ rwlock_rdunlock(&handle->lock);
243
+
244
+ return retval_has_token;
245
+ }
246
+
247
+ /**
248
+ * @brief Verify that the provided \p key is valid.
249
+ * @returns 0 on success or -1 if \p key is invalid.
250
+ */
251
+ static int check_oauthbearer_extension_key(const char *key,
252
+ char *errstr,
253
+ size_t errstr_size) {
254
+ const char *c;
255
+
256
+ if (!strcmp(key, "auth")) {
257
+ rd_snprintf(errstr, errstr_size,
258
+ "Cannot explicitly set the reserved `auth` "
259
+ "SASL/OAUTHBEARER extension key");
260
+ return -1;
261
+ }
262
+
263
+ /*
264
+ * https://tools.ietf.org/html/rfc7628#section-3.1
265
+ * key = 1*(ALPHA)
266
+ *
267
+ * https://tools.ietf.org/html/rfc5234#appendix-B.1
268
+ * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
269
+ */
270
+ if (!*key) {
271
+ rd_snprintf(errstr, errstr_size,
272
+ "SASL/OAUTHBEARER extension keys "
273
+ "must not be empty");
274
+ return -1;
275
+ }
276
+
277
+ for (c = key; *c; c++) {
278
+ if (!(*c >= 'A' && *c <= 'Z') && !(*c >= 'a' && *c <= 'z')) {
279
+ rd_snprintf(errstr, errstr_size,
280
+ "SASL/OAUTHBEARER extension keys must "
281
+ "only consist of A-Z or "
282
+ "a-z characters: %s (%c)",
283
+ key, *c);
284
+ return -1;
285
+ }
286
+ }
287
+
288
+ return 0;
289
+ }
290
+
291
+ /**
292
+ * @brief Verify that the provided \p value is valid.
293
+ * @returns 0 on success or -1 if \p value is invalid.
294
+ */
295
+ static int check_oauthbearer_extension_value(const char *value,
296
+ char *errstr,
297
+ size_t errstr_size) {
298
+ const char *c;
299
+
300
+ /*
301
+ * https://tools.ietf.org/html/rfc7628#section-3.1
302
+ * value = *(VCHAR / SP / HTAB / CR / LF )
303
+ *
304
+ * https://tools.ietf.org/html/rfc5234#appendix-B.1
305
+ * VCHAR = %x21-7E ; visible (printing) characters
306
+ * SP = %x20 ; space
307
+ * HTAB = %x09 ; horizontal tab
308
+ * CR = %x0D ; carriage return
309
+ * LF = %x0A ; linefeed
310
+ */
311
+ for (c = value; *c; c++) {
312
+ if (!(*c >= '\x21' && *c <= '\x7E') && *c != '\x20' &&
313
+ *c != '\x09' && *c != '\x0D' && *c != '\x0A') {
314
+ rd_snprintf(errstr, errstr_size,
315
+ "SASL/OAUTHBEARER extension values must "
316
+ "only consist of space, horizontal tab, "
317
+ "CR, LF, and "
318
+ "visible characters (%%x21-7E): %s (%c)",
319
+ value, *c);
320
+ return -1;
321
+ }
322
+ }
323
+
324
+ return 0;
325
+ }
326
+
327
+ /**
328
+ * @brief Set SASL/OAUTHBEARER token and metadata
329
+ *
330
+ * @param rk Client instance.
331
+ * @param token_value the mandatory token value to set, often (but not
332
+ * necessarily) a JWS compact serialization as per
333
+ * https://tools.ietf.org/html/rfc7515#section-3.1.
334
+ * Use rd_kafka_sasl_oauthbearer_token_free() to free members if
335
+ * return value is not -1.
336
+ * @param md_lifetime_ms when the token expires, in terms of the number of
337
+ * milliseconds since the epoch. See https://currentmillis.com/.
338
+ * @param md_principal_name the mandatory Kafka principal name associated
339
+ * with the token.
340
+ * @param extensions optional SASL extensions key-value array with
341
+ * \p extensions_size elements (number of keys * 2), where [i] is the key and
342
+ * [i+1] is the key's value, to be communicated to the broker
343
+ * as additional key-value pairs during the initial client response as per
344
+ * https://tools.ietf.org/html/rfc7628#section-3.1.
345
+ * @param extension_size the number of SASL extension keys plus values,
346
+ * which should be a non-negative multiple of 2.
347
+ *
348
+ * The SASL/OAUTHBEARER token refresh callback or event handler should cause
349
+ * this method to be invoked upon success, via
350
+ * rd_kafka_oauthbearer_set_token(). The extension keys must not include the
351
+ * reserved key "`auth`", and all extension keys and values must conform to the
352
+ * required format as per https://tools.ietf.org/html/rfc7628#section-3.1:
353
+ *
354
+ * key = 1*(ALPHA)
355
+ * value = *(VCHAR / SP / HTAB / CR / LF )
356
+ *
357
+ * @returns \c RD_KAFKA_RESP_ERR_NO_ERROR on success, otherwise errstr set and:
358
+ * \c RD_KAFKA_RESP_ERR__INVALID_ARG if any of the arguments are
359
+ * invalid;
360
+ * \c RD_KAFKA_RESP_ERR__STATE if SASL/OAUTHBEARER is not configured as
361
+ * the client's authentication mechanism.
362
+ *
363
+ * @sa rd_kafka_oauthbearer_set_token_failure0
364
+ */
365
+ rd_kafka_resp_err_t
366
+ rd_kafka_oauthbearer_set_token0(rd_kafka_t *rk,
367
+ const char *token_value,
368
+ int64_t md_lifetime_ms,
369
+ const char *md_principal_name,
370
+ const char **extensions,
371
+ size_t extension_size,
372
+ char *errstr,
373
+ size_t errstr_size) {
374
+ rd_kafka_sasl_oauthbearer_handle_t *handle = rk->rk_sasl.handle;
375
+ size_t i;
376
+ rd_ts_t now_wallclock;
377
+ rd_ts_t wts_md_lifetime = md_lifetime_ms * 1000;
378
+
379
+ /* Check if SASL/OAUTHBEARER is the configured auth mechanism */
380
+ if (rk->rk_conf.sasl.provider != &rd_kafka_sasl_oauthbearer_provider ||
381
+ !handle) {
382
+ rd_snprintf(errstr, errstr_size,
383
+ "SASL/OAUTHBEARER is not the "
384
+ "configured authentication mechanism");
385
+ return RD_KAFKA_RESP_ERR__STATE;
386
+ }
387
+
388
+ /* Check if there is an odd number of extension keys + values */
389
+ if (extension_size & 1) {
390
+ rd_snprintf(errstr, errstr_size,
391
+ "Incorrect extension size "
392
+ "(must be a non-negative multiple of 2): %" PRIusz,
393
+ extension_size);
394
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
395
+ }
396
+
397
+ /* Check args for correct format/value */
398
+ now_wallclock = rd_uclock();
399
+ if (wts_md_lifetime <= now_wallclock) {
400
+ rd_snprintf(errstr, errstr_size,
401
+ "Must supply an unexpired token: "
402
+ "now=%" PRId64 "ms, exp=%" PRId64 "ms",
403
+ now_wallclock / 1000, wts_md_lifetime / 1000);
404
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
405
+ }
406
+
407
+ if (check_oauthbearer_extension_value(token_value, errstr,
408
+ errstr_size) == -1)
409
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
410
+
411
+ for (i = 0; i + 1 < extension_size; i += 2) {
412
+ if (check_oauthbearer_extension_key(extensions[i], errstr,
413
+ errstr_size) == -1 ||
414
+ check_oauthbearer_extension_value(extensions[i + 1], errstr,
415
+ errstr_size) == -1)
416
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
417
+ }
418
+
419
+ rwlock_wrlock(&handle->lock);
420
+
421
+ RD_IF_FREE(handle->md_principal_name, rd_free);
422
+ handle->md_principal_name = rd_strdup(md_principal_name);
423
+
424
+ RD_IF_FREE(handle->token_value, rd_free);
425
+ handle->token_value = rd_strdup(token_value);
426
+
427
+ handle->wts_md_lifetime = wts_md_lifetime;
428
+
429
+ /* Schedule a refresh 80% through its remaining lifetime */
430
+ handle->wts_refresh_after =
431
+ (rd_ts_t)(now_wallclock + 0.8 * (wts_md_lifetime - now_wallclock));
432
+
433
+ rd_list_clear(&handle->extensions);
434
+ for (i = 0; i + 1 < extension_size; i += 2)
435
+ rd_list_add(&handle->extensions,
436
+ rd_strtup_new(extensions[i], extensions[i + 1]));
437
+
438
+ RD_IF_FREE(handle->errstr, rd_free);
439
+ handle->errstr = NULL;
440
+
441
+ rwlock_wrunlock(&handle->lock);
442
+
443
+ rd_kafka_dbg(rk, SECURITY, "BRKMAIN",
444
+ "Waking up waiting broker threads after "
445
+ "setting OAUTHBEARER token");
446
+ rd_kafka_all_brokers_wakeup(rk, RD_KAFKA_BROKER_STATE_TRY_CONNECT,
447
+ "OAUTHBEARER token update");
448
+
449
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
450
+ }
451
+
452
+ /**
453
+ * @brief SASL/OAUTHBEARER token refresh failure indicator.
454
+ *
455
+ * @param rk Client instance.
456
+ * @param errstr mandatory human readable error reason for failing to acquire
457
+ * a token.
458
+ *
459
+ * The SASL/OAUTHBEARER token refresh callback or event handler should cause
460
+ * this method to be invoked upon failure, via
461
+ * rd_kafka_oauthbearer_set_token_failure().
462
+ *
463
+ * @returns \c RD_KAFKA_RESP_ERR_NO_ERROR on success, otherwise
464
+ * \c RD_KAFKA_RESP_ERR__STATE if SASL/OAUTHBEARER is enabled but is
465
+ * not configured to be the client's authentication mechanism,
466
+ * \c RD_KAFKA_RESP_ERR__INVALID_ARG if no error string is supplied.
467
+
468
+ * @sa rd_kafka_oauthbearer_set_token0
469
+ */
470
+ rd_kafka_resp_err_t
471
+ rd_kafka_oauthbearer_set_token_failure0(rd_kafka_t *rk, const char *errstr) {
472
+ rd_kafka_sasl_oauthbearer_handle_t *handle = rk->rk_sasl.handle;
473
+ rd_bool_t error_changed;
474
+
475
+ /* Check if SASL/OAUTHBEARER is the configured auth mechanism */
476
+ if (rk->rk_conf.sasl.provider != &rd_kafka_sasl_oauthbearer_provider ||
477
+ !handle)
478
+ return RD_KAFKA_RESP_ERR__STATE;
479
+
480
+ if (!errstr || !*errstr)
481
+ return RD_KAFKA_RESP_ERR__INVALID_ARG;
482
+
483
+ rwlock_wrlock(&handle->lock);
484
+ error_changed = !handle->errstr || strcmp(handle->errstr, errstr);
485
+ RD_IF_FREE(handle->errstr, rd_free);
486
+ handle->errstr = rd_strdup(errstr);
487
+ /* Leave any existing token because it may have some life left,
488
+ * schedule a refresh for 10 seconds later. */
489
+ handle->wts_refresh_after = rd_uclock() + (10 * 1000 * 1000);
490
+ rwlock_wrunlock(&handle->lock);
491
+
492
+ /* Trigger an ERR__AUTHENTICATION error if the error changed. */
493
+ if (error_changed)
494
+ rd_kafka_op_err(rk, RD_KAFKA_RESP_ERR__AUTHENTICATION,
495
+ "Failed to acquire SASL OAUTHBEARER token: %s",
496
+ errstr);
497
+
498
+ return RD_KAFKA_RESP_ERR_NO_ERROR;
499
+ }
500
+
501
+ /**
502
+ * @brief Parse a config value from the string pointed to by \p loc and starting
503
+ * with the given \p prefix and ending with the given \p value_end_char, storing
504
+ * the newly-allocated memory result in the string pointed to by \p value.
505
+ * @returns -1 if string pointed to by \p value is non-empty (\p errstr set, no
506
+ * memory allocated), else 0 (caller must free allocated memory).
507
+ */
508
+ static int parse_ujws_config_value_for_prefix(char **loc,
509
+ const char *prefix,
510
+ const char value_end_char,
511
+ char **value,
512
+ char *errstr,
513
+ size_t errstr_size) {
514
+ if (*value) {
515
+ rd_snprintf(errstr, errstr_size,
516
+ "Invalid sasl.oauthbearer.config: "
517
+ "multiple '%s' entries",
518
+ prefix);
519
+ return -1;
520
+ }
521
+
522
+ *loc += strlen(prefix);
523
+ *value = *loc;
524
+ while (**loc != '\0' && **loc != value_end_char)
525
+ ++*loc;
526
+
527
+ if (**loc == value_end_char) {
528
+ /* End the string and skip the character */
529
+ **loc = '\0';
530
+ ++*loc;
531
+ }
532
+
533
+ /* return new allocated memory */
534
+ *value = rd_strdup(*value);
535
+
536
+ return 0;
537
+ }
538
+
539
+ /*
540
+ * @brief Parse Unsecured JWS config, allocates strings that must be freed
541
+ * @param cfg the config to parse (typically from `sasl.oauthbearer.config`)
542
+ * @param parsed holds the parsed output; it must be all zeros to start.
543
+ * @returns -1 on failure (\p errstr set), else 0.
544
+ */
545
+ static int
546
+ parse_ujws_config(const char *cfg,
547
+ struct rd_kafka_sasl_oauthbearer_parsed_ujws *parsed,
548
+ char *errstr,
549
+ size_t errstr_size) {
550
+ /*
551
+ * Extensions:
552
+ *
553
+ * https://tools.ietf.org/html/rfc7628#section-3.1
554
+ * key = 1*(ALPHA)
555
+ * value = *(VCHAR / SP / HTAB / CR / LF )
556
+ *
557
+ * https://tools.ietf.org/html/rfc5234#appendix-B.1
558
+ * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
559
+ * VCHAR = %x21-7E ; visible (printing) characters
560
+ * SP = %x20 ; space
561
+ * HTAB = %x09 ; horizontal tab
562
+ * CR = %x0D ; carriage return
563
+ * LF = %x0A ; linefeed
564
+ */
565
+
566
+ static const char *prefix_principal_claim_name = "principalClaimName=";
567
+ static const char *prefix_principal = "principal=";
568
+ static const char *prefix_scope_claim_name = "scopeClaimName=";
569
+ static const char *prefix_scope = "scope=";
570
+ static const char *prefix_life_seconds = "lifeSeconds=";
571
+ static const char *prefix_extension = "extension_";
572
+
573
+ char *cfg_copy = rd_strdup(cfg);
574
+ char *loc = cfg_copy;
575
+ int r = 0;
576
+
577
+ while (*loc != '\0' && !r) {
578
+ if (*loc == ' ')
579
+ ++loc;
580
+ else if (!strncmp(prefix_principal_claim_name, loc,
581
+ strlen(prefix_principal_claim_name))) {
582
+ r = parse_ujws_config_value_for_prefix(
583
+ &loc, prefix_principal_claim_name, ' ',
584
+ &parsed->principal_claim_name, errstr, errstr_size);
585
+
586
+ if (!r && !*parsed->principal_claim_name) {
587
+ rd_snprintf(errstr, errstr_size,
588
+ "Invalid sasl.oauthbearer.config: "
589
+ "empty '%s'",
590
+ prefix_principal_claim_name);
591
+ r = -1;
592
+ }
593
+
594
+ } else if (!strncmp(prefix_principal, loc,
595
+ strlen(prefix_principal))) {
596
+ r = parse_ujws_config_value_for_prefix(
597
+ &loc, prefix_principal, ' ', &parsed->principal,
598
+ errstr, errstr_size);
599
+
600
+ if (!r && !*parsed->principal) {
601
+ rd_snprintf(errstr, errstr_size,
602
+ "Invalid sasl.oauthbearer.config: "
603
+ "empty '%s'",
604
+ prefix_principal);
605
+ r = -1;
606
+ }
607
+
608
+ } else if (!strncmp(prefix_scope_claim_name, loc,
609
+ strlen(prefix_scope_claim_name))) {
610
+ r = parse_ujws_config_value_for_prefix(
611
+ &loc, prefix_scope_claim_name, ' ',
612
+ &parsed->scope_claim_name, errstr, errstr_size);
613
+
614
+ if (!r && !*parsed->scope_claim_name) {
615
+ rd_snprintf(errstr, errstr_size,
616
+ "Invalid sasl.oauthbearer.config: "
617
+ "empty '%s'",
618
+ prefix_scope_claim_name);
619
+ r = -1;
620
+ }
621
+
622
+ } else if (!strncmp(prefix_scope, loc, strlen(prefix_scope))) {
623
+ r = parse_ujws_config_value_for_prefix(
624
+ &loc, prefix_scope, ' ', &parsed->scope_csv_text,
625
+ errstr, errstr_size);
626
+
627
+ if (!r && !*parsed->scope_csv_text) {
628
+ rd_snprintf(errstr, errstr_size,
629
+ "Invalid sasl.oauthbearer.config: "
630
+ "empty '%s'",
631
+ prefix_scope);
632
+ r = -1;
633
+ }
634
+
635
+ } else if (!strncmp(prefix_life_seconds, loc,
636
+ strlen(prefix_life_seconds))) {
637
+ char *life_seconds_text = NULL;
638
+
639
+ r = parse_ujws_config_value_for_prefix(
640
+ &loc, prefix_life_seconds, ' ', &life_seconds_text,
641
+ errstr, errstr_size);
642
+
643
+ if (!r && !*life_seconds_text) {
644
+ rd_snprintf(errstr, errstr_size,
645
+ "Invalid "
646
+ "sasl.oauthbearer.config: "
647
+ "empty '%s'",
648
+ prefix_life_seconds);
649
+ r = -1;
650
+ } else if (!r) {
651
+ long long life_seconds_long;
652
+ char *end_ptr;
653
+ life_seconds_long =
654
+ strtoll(life_seconds_text, &end_ptr, 10);
655
+ if (*end_ptr != '\0') {
656
+ rd_snprintf(errstr, errstr_size,
657
+ "Invalid "
658
+ "sasl.oauthbearer.config: "
659
+ "non-integral '%s': %s",
660
+ prefix_life_seconds,
661
+ life_seconds_text);
662
+ r = -1;
663
+ } else if (life_seconds_long <= 0 ||
664
+ life_seconds_long > INT_MAX) {
665
+ rd_snprintf(errstr, errstr_size,
666
+ "Invalid "
667
+ "sasl.oauthbearer.config: "
668
+ "value out of range of "
669
+ "positive int '%s': %s",
670
+ prefix_life_seconds,
671
+ life_seconds_text);
672
+ r = -1;
673
+ } else {
674
+ parsed->life_seconds =
675
+ (int)life_seconds_long;
676
+ }
677
+ }
678
+
679
+ RD_IF_FREE(life_seconds_text, rd_free);
680
+
681
+ } else if (!strncmp(prefix_extension, loc,
682
+ strlen(prefix_extension))) {
683
+ char *extension_key = NULL;
684
+
685
+ r = parse_ujws_config_value_for_prefix(
686
+ &loc, prefix_extension, '=', &extension_key, errstr,
687
+ errstr_size);
688
+
689
+ if (!r && !*extension_key) {
690
+ rd_snprintf(errstr, errstr_size,
691
+ "Invalid "
692
+ "sasl.oauthbearer.config: "
693
+ "empty '%s' key",
694
+ prefix_extension);
695
+ r = -1;
696
+ } else if (!r) {
697
+ char *extension_value = NULL;
698
+ r = parse_ujws_config_value_for_prefix(
699
+ &loc, "", ' ', &extension_value, errstr,
700
+ errstr_size);
701
+ if (!r) {
702
+ rd_list_add(
703
+ &parsed->extensions,
704
+ rd_strtup_new(extension_key,
705
+ extension_value));
706
+ rd_free(extension_value);
707
+ }
708
+ }
709
+
710
+ RD_IF_FREE(extension_key, rd_free);
711
+
712
+ } else {
713
+ rd_snprintf(errstr, errstr_size,
714
+ "Unrecognized sasl.oauthbearer.config "
715
+ "beginning at: %s",
716
+ loc);
717
+ r = -1;
718
+ }
719
+ }
720
+
721
+ rd_free(cfg_copy);
722
+
723
+ return r;
724
+ }
725
+
726
+ /**
727
+ * @brief Create unsecured JWS compact serialization
728
+ * from the given information.
729
+ * @returns allocated memory that the caller must free.
730
+ */
731
+ static char *create_jws_compact_serialization(
732
+ const struct rd_kafka_sasl_oauthbearer_parsed_ujws *parsed,
733
+ rd_ts_t now_wallclock) {
734
+ static const char *jose_header_encoded =
735
+ "eyJhbGciOiJub25lIn0"; // {"alg":"none"}
736
+ int scope_json_length = 0;
737
+ int max_json_length;
738
+ double now_wallclock_seconds;
739
+ char *scope_json;
740
+ char *scope_curr;
741
+ int i;
742
+ char *claims_json;
743
+ char *jws_claims;
744
+ size_t encode_len;
745
+ char *jws_last_char;
746
+ char *jws_maybe_non_url_char;
747
+ char *retval_jws;
748
+ size_t retval_size;
749
+ rd_list_t scope;
750
+
751
+ rd_list_init(&scope, 0, rd_free);
752
+ if (parsed->scope_csv_text) {
753
+ /* Convert from csv to rd_list_t and
754
+ * calculate json length. */
755
+ char *start = parsed->scope_csv_text;
756
+ char *curr = start;
757
+
758
+ while (*curr != '\0') {
759
+ /* Ignore empty elements (e.g. ",,") */
760
+ while (*curr == ',') {
761
+ ++curr;
762
+ ++start;
763
+ }
764
+
765
+ while (*curr != '\0' && *curr != ',')
766
+ ++curr;
767
+
768
+ if (curr == start)
769
+ continue;
770
+
771
+ if (*curr == ',') {
772
+ *curr = '\0';
773
+ ++curr;
774
+ }
775
+
776
+ if (!rd_list_find(&scope, start, (void *)strcmp))
777
+ rd_list_add(&scope, rd_strdup(start));
778
+
779
+ if (scope_json_length == 0) {
780
+ scope_json_length =
781
+ 2 + // ,"
782
+ (int)strlen(parsed->scope_claim_name) +
783
+ 4 + // ":["
784
+ (int)strlen(start) + 1 + // "
785
+ 1; // ]
786
+ } else {
787
+ scope_json_length += 2; // ,"
788
+ scope_json_length += (int)strlen(start);
789
+ scope_json_length += 1; // "
790
+ }
791
+
792
+ start = curr;
793
+ }
794
+ }
795
+
796
+ now_wallclock_seconds = now_wallclock / 1000000.0;
797
+
798
+ /* Generate json */
799
+ max_json_length = 2 + // {"
800
+ (int)strlen(parsed->principal_claim_name) +
801
+ 3 + // ":"
802
+ (int)strlen(parsed->principal) + 8 + // ","iat":
803
+ 14 + // iat NumericDate (e.g. 1549251467.546)
804
+ 7 + // ,"exp":
805
+ 14 + // exp NumericDate (e.g. 1549252067.546)
806
+ scope_json_length + 1; // }
807
+
808
+ /* Generate scope portion of json */
809
+ scope_json = rd_malloc(scope_json_length + 1);
810
+ *scope_json = '\0';
811
+ scope_curr = scope_json;
812
+
813
+ for (i = 0; i < rd_list_cnt(&scope); i++) {
814
+ if (i == 0)
815
+ scope_curr += rd_snprintf(
816
+ scope_curr,
817
+ (size_t)(scope_json + scope_json_length + 1 -
818
+ scope_curr),
819
+ ",\"%s\":[\"", parsed->scope_claim_name);
820
+ else
821
+ scope_curr += sprintf(scope_curr, "%s", ",\"");
822
+ scope_curr += sprintf(scope_curr, "%s\"",
823
+ (const char *)rd_list_elem(&scope, i));
824
+ if (i == rd_list_cnt(&scope) - 1)
825
+ scope_curr += sprintf(scope_curr, "%s", "]");
826
+ }
827
+
828
+ claims_json = rd_malloc(max_json_length + 1);
829
+ rd_snprintf(claims_json, max_json_length + 1,
830
+ "{\"%s\":\"%s\",\"iat\":%.3f,\"exp\":%.3f%s}",
831
+ parsed->principal_claim_name, parsed->principal,
832
+ now_wallclock_seconds,
833
+ now_wallclock_seconds + parsed->life_seconds, scope_json);
834
+ rd_free(scope_json);
835
+
836
+ /* Convert to base64URL format, first to base64, then to base64URL */
837
+ retval_size = strlen(jose_header_encoded) + 1 +
838
+ (((max_json_length + 2) / 3) * 4) + 1 + 1;
839
+ retval_jws = rd_malloc(retval_size);
840
+ rd_snprintf(retval_jws, retval_size, "%s.", jose_header_encoded);
841
+ jws_claims = retval_jws + strlen(retval_jws);
842
+ encode_len =
843
+ EVP_EncodeBlock((uint8_t *)jws_claims, (uint8_t *)claims_json,
844
+ (int)strlen(claims_json));
845
+ rd_free(claims_json);
846
+ jws_last_char = jws_claims + encode_len - 1;
847
+
848
+ /* Convert from padded base64 to unpadded base64URL
849
+ * and eliminate any padding. */
850
+ while (jws_last_char >= jws_claims && *jws_last_char == '=')
851
+ --jws_last_char;
852
+ *(++jws_last_char) = '.';
853
+ *(jws_last_char + 1) = '\0';
854
+
855
+ /* Convert the 2 differing encode characters */
856
+ for (jws_maybe_non_url_char = retval_jws; *jws_maybe_non_url_char;
857
+ jws_maybe_non_url_char++)
858
+ if (*jws_maybe_non_url_char == '+')
859
+ *jws_maybe_non_url_char = '-';
860
+ else if (*jws_maybe_non_url_char == '/')
861
+ *jws_maybe_non_url_char = '_';
862
+
863
+ rd_list_destroy(&scope);
864
+
865
+ return retval_jws;
866
+ }
867
+
868
+ /**
869
+ * @brief Same as rd_kafka_oauthbearer_unsecured_token() except it takes
870
+ * additional explicit arguments and return a status code along with
871
+ * the token to set in order to facilitate unit testing.
872
+ * @param token output defining the token to set
873
+ * @param cfg the config to parse (typically from `sasl.oauthbearer.config`)
874
+ * @param now_wallclock_ms the valued to be used for the `iat` claim
875
+ * (and by implication, the `exp` claim)
876
+ * @returns -1 on failure (\p errstr set), else 0.
877
+ */
878
+ static int rd_kafka_oauthbearer_unsecured_token0(
879
+ struct rd_kafka_sasl_oauthbearer_token *token,
880
+ const char *cfg,
881
+ int64_t now_wallclock_ms,
882
+ char *errstr,
883
+ size_t errstr_size) {
884
+ struct rd_kafka_sasl_oauthbearer_parsed_ujws parsed = RD_ZERO_INIT;
885
+ int r;
886
+ int i;
887
+
888
+ if (!cfg || !*cfg) {
889
+ rd_snprintf(errstr, errstr_size,
890
+ "Invalid sasl.oauthbearer.config: "
891
+ "must not be empty");
892
+ return -1;
893
+ }
894
+
895
+ memset(token, 0, sizeof(*token));
896
+
897
+ rd_list_init(&parsed.extensions, 0,
898
+ (void (*)(void *))rd_strtup_destroy);
899
+
900
+ if (!(r = parse_ujws_config(cfg, &parsed, errstr, errstr_size))) {
901
+ /* Make sure we have required and valid info */
902
+ if (!parsed.principal_claim_name)
903
+ parsed.principal_claim_name = rd_strdup("sub");
904
+ if (!parsed.scope_claim_name)
905
+ parsed.scope_claim_name = rd_strdup("scope");
906
+ if (!parsed.life_seconds)
907
+ parsed.life_seconds = 3600;
908
+ if (!parsed.principal) {
909
+ rd_snprintf(errstr, errstr_size,
910
+ "Invalid sasl.oauthbearer.config: "
911
+ "no principal=<value>");
912
+ r = -1;
913
+ } else if (strchr(parsed.principal, '"')) {
914
+ rd_snprintf(errstr, errstr_size,
915
+ "Invalid sasl.oauthbearer.config: "
916
+ "'\"' cannot appear in principal: %s",
917
+ parsed.principal);
918
+ r = -1;
919
+ } else if (strchr(parsed.principal_claim_name, '"')) {
920
+ rd_snprintf(errstr, errstr_size,
921
+ "Invalid sasl.oauthbearer.config: "
922
+ "'\"' cannot appear in "
923
+ "principalClaimName: %s",
924
+ parsed.principal_claim_name);
925
+ r = -1;
926
+ } else if (strchr(parsed.scope_claim_name, '"')) {
927
+ rd_snprintf(errstr, errstr_size,
928
+ "Invalid sasl.oauthbearer.config: "
929
+ "'\"' cannot appear in scopeClaimName: %s",
930
+ parsed.scope_claim_name);
931
+ r = -1;
932
+ } else if (parsed.scope_csv_text &&
933
+ strchr(parsed.scope_csv_text, '"')) {
934
+ rd_snprintf(errstr, errstr_size,
935
+ "Invalid sasl.oauthbearer.config: "
936
+ "'\"' cannot appear in scope: %s",
937
+ parsed.scope_csv_text);
938
+ r = -1;
939
+ } else {
940
+ char **extensionv;
941
+ int extension_pair_count;
942
+ char *jws = create_jws_compact_serialization(
943
+ &parsed, now_wallclock_ms * 1000);
944
+
945
+ extension_pair_count = rd_list_cnt(&parsed.extensions);
946
+ extensionv = rd_malloc(sizeof(*extensionv) * 2 *
947
+ extension_pair_count);
948
+ for (i = 0; i < extension_pair_count; ++i) {
949
+ rd_strtup_t *strtup =
950
+ (rd_strtup_t *)rd_list_elem(
951
+ &parsed.extensions, i);
952
+ extensionv[2 * i] = rd_strdup(strtup->name);
953
+ extensionv[2 * i + 1] =
954
+ rd_strdup(strtup->value);
955
+ }
956
+ token->token_value = jws;
957
+ token->md_lifetime_ms =
958
+ now_wallclock_ms + parsed.life_seconds * 1000;
959
+ token->md_principal_name = rd_strdup(parsed.principal);
960
+ token->extensions = extensionv;
961
+ token->extension_size = 2 * extension_pair_count;
962
+ }
963
+ }
964
+ RD_IF_FREE(parsed.principal_claim_name, rd_free);
965
+ RD_IF_FREE(parsed.principal, rd_free);
966
+ RD_IF_FREE(parsed.scope_claim_name, rd_free);
967
+ RD_IF_FREE(parsed.scope_csv_text, rd_free);
968
+ rd_list_destroy(&parsed.extensions);
969
+
970
+ if (r == -1)
971
+ rd_kafka_sasl_oauthbearer_token_free(token);
972
+
973
+ return r;
974
+ }
975
+
976
+ /**
977
+ * @brief Default SASL/OAUTHBEARER token refresh callback that generates an
978
+ * unsecured JWS as per https://tools.ietf.org/html/rfc7515#appendix-A.5.
979
+ *
980
+ * This method interprets `sasl.oauthbearer.config` as space-separated
981
+ * name=value pairs with valid names including principalClaimName,
982
+ * principal, scopeClaimName, scope, and lifeSeconds. The default
983
+ * value for principalClaimName is "sub". The principal must be specified.
984
+ * The default value for scopeClaimName is "scope", and the default value
985
+ * for lifeSeconds is 3600. The scope value is CSV format with the
986
+ * default value being no/empty scope. For example:
987
+ * "principalClaimName=azp principal=admin scopeClaimName=roles
988
+ * scope=role1,role2 lifeSeconds=600".
989
+ *
990
+ * SASL extensions can be communicated to the broker via
991
+ * extension_NAME=value. For example:
992
+ * "principal=admin extension_traceId=123". Extension names and values
993
+ * must conform to the required syntax as per
994
+ * https://tools.ietf.org/html/rfc7628#section-3.1
995
+ *
996
+ * All values -- whether extensions, claim names, or scope elements -- must not
997
+ * include a quote (") character. The parsing rules also imply that names
998
+ * and values cannot include a space character, and scope elements cannot
999
+ * include a comma (,) character.
1000
+ *
1001
+ * The existence of any kind of parsing problem -- an unrecognized name,
1002
+ * a quote character in a value, an empty value, etc. -- raises the
1003
+ * \c RD_KAFKA_RESP_ERR__AUTHENTICATION event.
1004
+ *
1005
+ * Unsecured tokens are not to be used in production -- they are only good for
1006
+ * testing and development purposess -- so while the inflexibility of the
1007
+ * parsing rules is acknowledged, it is assumed that this is not problematic.
1008
+ */
1009
+ void rd_kafka_oauthbearer_unsecured_token(rd_kafka_t *rk,
1010
+ const char *oauthbearer_config,
1011
+ void *opaque) {
1012
+ char errstr[512];
1013
+ struct rd_kafka_sasl_oauthbearer_token token = RD_ZERO_INIT;
1014
+
1015
+ rd_kafka_dbg(rk, SECURITY, "OAUTHBEARER", "Creating unsecured token");
1016
+
1017
+ if (rd_kafka_oauthbearer_unsecured_token0(&token, oauthbearer_config,
1018
+ rd_uclock() / 1000, errstr,
1019
+ sizeof(errstr)) == -1 ||
1020
+ rd_kafka_oauthbearer_set_token(
1021
+ rk, token.token_value, token.md_lifetime_ms,
1022
+ token.md_principal_name, (const char **)token.extensions,
1023
+ token.extension_size, errstr, sizeof(errstr)) == -1) {
1024
+ rd_kafka_oauthbearer_set_token_failure(rk, errstr);
1025
+ }
1026
+
1027
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1028
+ }
1029
+
1030
+ /**
1031
+ * @brief Close and free authentication state
1032
+ */
1033
+ static void rd_kafka_sasl_oauthbearer_close(rd_kafka_transport_t *rktrans) {
1034
+ struct rd_kafka_sasl_oauthbearer_state *state =
1035
+ rktrans->rktrans_sasl.state;
1036
+
1037
+ if (!state)
1038
+ return;
1039
+
1040
+ RD_IF_FREE(state->server_error_msg, rd_free);
1041
+ rd_free(state->token_value);
1042
+ rd_free(state->md_principal_name);
1043
+ rd_list_destroy(&state->extensions);
1044
+ rd_free(state);
1045
+ rktrans->rktrans_sasl.state = NULL;
1046
+ }
1047
+
1048
+
1049
+
1050
+ /**
1051
+ * @brief Build client-first-message
1052
+ */
1053
+ static void rd_kafka_sasl_oauthbearer_build_client_first_message(
1054
+ rd_kafka_transport_t *rktrans,
1055
+ rd_chariov_t *out) {
1056
+ struct rd_kafka_sasl_oauthbearer_state *state =
1057
+ rktrans->rktrans_sasl.state;
1058
+
1059
+ /*
1060
+ * https://tools.ietf.org/html/rfc7628#section-3.1
1061
+ * kvsep = %x01
1062
+ * key = 1*(ALPHA)
1063
+ * value = *(VCHAR / SP / HTAB / CR / LF )
1064
+ * kvpair = key "=" value kvsep
1065
+ * ;;gs2-header = See RFC 5801
1066
+ * client-resp = (gs2-header kvsep *kvpair kvsep) / kvsep
1067
+ */
1068
+
1069
+ static const char *gs2_header = "n,,";
1070
+ static const char *kvsep = "\x01";
1071
+ const int kvsep_size = (int)strlen(kvsep);
1072
+ int extension_size = 0;
1073
+ int i;
1074
+ char *buf;
1075
+ int size_written;
1076
+ unsigned long r;
1077
+
1078
+ for (i = 0; i < rd_list_cnt(&state->extensions); i++) {
1079
+ rd_strtup_t *extension = rd_list_elem(&state->extensions, i);
1080
+ // kvpair = key "=" value kvsep
1081
+ extension_size += (int)strlen(extension->name) + 1 // "="
1082
+ + (int)strlen(extension->value) + kvsep_size;
1083
+ }
1084
+
1085
+ // client-resp = (gs2-header kvsep *kvpair kvsep) / kvsep
1086
+ out->size = strlen(gs2_header) + kvsep_size + strlen("auth=Bearer ") +
1087
+ strlen(state->token_value) + kvsep_size + extension_size +
1088
+ kvsep_size;
1089
+ out->ptr = rd_malloc(out->size + 1);
1090
+
1091
+ buf = out->ptr;
1092
+ size_written = 0;
1093
+ r = rd_snprintf(buf, out->size + 1 - size_written,
1094
+ "%s%sauth=Bearer %s%s", gs2_header, kvsep,
1095
+ state->token_value, kvsep);
1096
+ rd_assert(r < out->size + 1 - size_written);
1097
+ size_written += r;
1098
+ buf = out->ptr + size_written;
1099
+
1100
+ for (i = 0; i < rd_list_cnt(&state->extensions); i++) {
1101
+ rd_strtup_t *extension = rd_list_elem(&state->extensions, i);
1102
+ r = rd_snprintf(buf, out->size + 1 - size_written, "%s=%s%s",
1103
+ extension->name, extension->value, kvsep);
1104
+ rd_assert(r < out->size + 1 - size_written);
1105
+ size_written += r;
1106
+ buf = out->ptr + size_written;
1107
+ }
1108
+
1109
+ r = rd_snprintf(buf, out->size + 1 - size_written, "%s", kvsep);
1110
+ rd_assert(r < out->size + 1 - size_written);
1111
+
1112
+ rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY, "OAUTHBEARER",
1113
+ "Built client first message");
1114
+ }
1115
+
1116
+
1117
+
1118
+ /**
1119
+ * @brief SASL OAUTHBEARER client state machine
1120
+ * @returns -1 on failure (\p errstr set), else 0.
1121
+ */
1122
+ static int rd_kafka_sasl_oauthbearer_fsm(rd_kafka_transport_t *rktrans,
1123
+ const rd_chariov_t *in,
1124
+ char *errstr,
1125
+ size_t errstr_size) {
1126
+ static const char *state_names[] = {
1127
+ "client-first-message",
1128
+ "server-first-message",
1129
+ "server-failure-message",
1130
+ };
1131
+ struct rd_kafka_sasl_oauthbearer_state *state =
1132
+ rktrans->rktrans_sasl.state;
1133
+ rd_chariov_t out = RD_ZERO_INIT;
1134
+ int r = -1;
1135
+
1136
+ rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY, "OAUTHBEARER",
1137
+ "SASL OAUTHBEARER client in state %s",
1138
+ state_names[state->state]);
1139
+
1140
+ switch (state->state) {
1141
+ case RD_KAFKA_SASL_OAUTHB_STATE_SEND_CLIENT_FIRST_MESSAGE:
1142
+ rd_dassert(!in); /* Not expecting any server-input */
1143
+
1144
+ rd_kafka_sasl_oauthbearer_build_client_first_message(rktrans,
1145
+ &out);
1146
+ state->state = RD_KAFKA_SASL_OAUTHB_STATE_RECV_SERVER_FIRST_MSG;
1147
+ break;
1148
+
1149
+
1150
+ case RD_KAFKA_SASL_OAUTHB_STATE_RECV_SERVER_FIRST_MSG:
1151
+ if (!in->size || !*in->ptr) {
1152
+ /* Success */
1153
+ rd_rkb_dbg(rktrans->rktrans_rkb,
1154
+ SECURITY | RD_KAFKA_DBG_BROKER,
1155
+ "OAUTHBEARER",
1156
+ "SASL OAUTHBEARER authentication "
1157
+ "successful (principal=%s)",
1158
+ state->md_principal_name);
1159
+ rd_kafka_sasl_auth_done(rktrans);
1160
+ r = 0;
1161
+ break;
1162
+ }
1163
+
1164
+ /* Failure; save error message for later */
1165
+ state->server_error_msg = rd_strndup(in->ptr, in->size);
1166
+
1167
+ /*
1168
+ * https://tools.ietf.org/html/rfc7628#section-3.1
1169
+ * kvsep = %x01
1170
+ * client-resp = (gs2-header kvsep *kvpair kvsep) / kvsep
1171
+ *
1172
+ * Send final kvsep (CTRL-A) character
1173
+ */
1174
+ out.size = 1;
1175
+ out.ptr = rd_malloc(out.size + 1);
1176
+ rd_snprintf(out.ptr, out.size + 1, "\x01");
1177
+ state->state =
1178
+ RD_KAFKA_SASL_OAUTHB_STATE_RECV_SERVER_MSG_AFTER_FAIL;
1179
+ r = 0; // Will fail later in next state after sending response
1180
+ break;
1181
+
1182
+ case RD_KAFKA_SASL_OAUTHB_STATE_RECV_SERVER_MSG_AFTER_FAIL:
1183
+ /* Failure as previosuly communicated by server first message */
1184
+ rd_snprintf(errstr, errstr_size,
1185
+ "SASL OAUTHBEARER authentication failed "
1186
+ "(principal=%s): %s",
1187
+ state->md_principal_name, state->server_error_msg);
1188
+ rd_rkb_dbg(rktrans->rktrans_rkb, SECURITY | RD_KAFKA_DBG_BROKER,
1189
+ "OAUTHBEARER", "%s", errstr);
1190
+ r = -1;
1191
+ break;
1192
+ }
1193
+
1194
+ if (out.ptr) {
1195
+ r = rd_kafka_sasl_send(rktrans, out.ptr, (int)out.size, errstr,
1196
+ errstr_size);
1197
+ rd_free(out.ptr);
1198
+ }
1199
+
1200
+ return r;
1201
+ }
1202
+
1203
+
1204
+ /**
1205
+ * @brief Handle received frame from broker.
1206
+ */
1207
+ static int rd_kafka_sasl_oauthbearer_recv(rd_kafka_transport_t *rktrans,
1208
+ const void *buf,
1209
+ size_t size,
1210
+ char *errstr,
1211
+ size_t errstr_size) {
1212
+ const rd_chariov_t in = {.ptr = (char *)buf, .size = size};
1213
+ return rd_kafka_sasl_oauthbearer_fsm(rktrans, &in, errstr, errstr_size);
1214
+ }
1215
+
1216
+
1217
+ /**
1218
+ * @brief Initialize and start SASL OAUTHBEARER (builtin) authentication.
1219
+ *
1220
+ * Returns 0 on successful init and -1 on error.
1221
+ *
1222
+ * @locality broker thread
1223
+ */
1224
+ static int rd_kafka_sasl_oauthbearer_client_new(rd_kafka_transport_t *rktrans,
1225
+ const char *hostname,
1226
+ char *errstr,
1227
+ size_t errstr_size) {
1228
+ rd_kafka_sasl_oauthbearer_handle_t *handle =
1229
+ rktrans->rktrans_rkb->rkb_rk->rk_sasl.handle;
1230
+ struct rd_kafka_sasl_oauthbearer_state *state;
1231
+
1232
+ state = rd_calloc(1, sizeof(*state));
1233
+ state->state = RD_KAFKA_SASL_OAUTHB_STATE_SEND_CLIENT_FIRST_MESSAGE;
1234
+
1235
+ /*
1236
+ * Save off the state structure now, before any possibility of
1237
+ * returning, so that we will always free up the allocated memory in
1238
+ * rd_kafka_sasl_oauthbearer_close().
1239
+ */
1240
+ rktrans->rktrans_sasl.state = state;
1241
+
1242
+ /*
1243
+ * Make sure we have a consistent view of the token and extensions
1244
+ * throughout the authentication process -- even if it is refreshed
1245
+ * midway through this particular authentication.
1246
+ */
1247
+ rwlock_rdlock(&handle->lock);
1248
+ if (!handle->token_value) {
1249
+ rd_snprintf(errstr, errstr_size,
1250
+ "OAUTHBEARER cannot log in because there "
1251
+ "is no token available; last error: %s",
1252
+ handle->errstr ? handle->errstr
1253
+ : "(not available)");
1254
+ rwlock_rdunlock(&handle->lock);
1255
+ return -1;
1256
+ }
1257
+
1258
+ state->token_value = rd_strdup(handle->token_value);
1259
+ state->md_principal_name = rd_strdup(handle->md_principal_name);
1260
+ rd_list_copy_to(&state->extensions, &handle->extensions,
1261
+ rd_strtup_list_copy, NULL);
1262
+
1263
+ rwlock_rdunlock(&handle->lock);
1264
+
1265
+ /* Kick off the FSM */
1266
+ return rd_kafka_sasl_oauthbearer_fsm(rktrans, NULL, errstr,
1267
+ errstr_size);
1268
+ }
1269
+
1270
+
1271
+ /**
1272
+ * @brief Token refresh timer callback.
1273
+ *
1274
+ * @locality rdkafka main thread
1275
+ */
1276
+ static void
1277
+ rd_kafka_sasl_oauthbearer_token_refresh_tmr_cb(rd_kafka_timers_t *rkts,
1278
+ void *arg) {
1279
+ rd_kafka_t *rk = arg;
1280
+ rd_kafka_sasl_oauthbearer_handle_t *handle = rk->rk_sasl.handle;
1281
+
1282
+ /* Enqueue a token refresh if necessary */
1283
+ rd_kafka_oauthbearer_enqueue_token_refresh_if_necessary(handle);
1284
+ }
1285
+
1286
+
1287
+ /**
1288
+ * @brief Per-client-instance initializer
1289
+ */
1290
+ static int rd_kafka_sasl_oauthbearer_init(rd_kafka_t *rk,
1291
+ char *errstr,
1292
+ size_t errstr_size) {
1293
+ rd_kafka_sasl_oauthbearer_handle_t *handle;
1294
+
1295
+ handle = rd_calloc(1, sizeof(*handle));
1296
+ rk->rk_sasl.handle = handle;
1297
+
1298
+ rwlock_init(&handle->lock);
1299
+
1300
+ handle->rk = rk;
1301
+
1302
+ rd_list_init(&handle->extensions, 0,
1303
+ (void (*)(void *))rd_strtup_destroy);
1304
+
1305
+
1306
+ if (rk->rk_conf.sasl.enable_callback_queue) {
1307
+ /* SASL specific callback queue enabled */
1308
+ rk->rk_sasl.callback_q = rd_kafka_q_new(rk);
1309
+ handle->callback_q = rd_kafka_q_keep(rk->rk_sasl.callback_q);
1310
+ } else {
1311
+ /* Use main queue */
1312
+ handle->callback_q = rd_kafka_q_keep(rk->rk_rep);
1313
+ }
1314
+
1315
+ rd_kafka_timer_start(
1316
+ &rk->rk_timers, &handle->token_refresh_tmr, 1 * 1000 * 1000,
1317
+ rd_kafka_sasl_oauthbearer_token_refresh_tmr_cb, rk);
1318
+
1319
+ /* Automatically refresh the token if using the builtin
1320
+ * unsecure JWS token refresher, to avoid an initial connection
1321
+ * stall as we wait for the application to call poll(). */
1322
+ if (rk->rk_conf.sasl.oauthbearer.token_refresh_cb ==
1323
+ rd_kafka_oauthbearer_unsecured_token) {
1324
+ rk->rk_conf.sasl.oauthbearer.token_refresh_cb(
1325
+ rk, rk->rk_conf.sasl.oauthbearer_config,
1326
+ rk->rk_conf.opaque);
1327
+
1328
+ return 0;
1329
+ }
1330
+
1331
+
1332
+ #if WITH_OAUTHBEARER_OIDC
1333
+ if (rk->rk_conf.sasl.oauthbearer.method ==
1334
+ RD_KAFKA_SASL_OAUTHBEARER_METHOD_OIDC &&
1335
+ rk->rk_conf.sasl.oauthbearer.token_refresh_cb ==
1336
+ rd_kafka_oidc_token_refresh_cb) {
1337
+ handle->internal_refresh = rd_true;
1338
+ rd_kafka_sasl_background_callbacks_enable(rk);
1339
+ }
1340
+ #endif
1341
+
1342
+ /* Otherwise enqueue a refresh callback for the application. */
1343
+ rd_kafka_oauthbearer_enqueue_token_refresh(handle);
1344
+
1345
+ return 0;
1346
+ }
1347
+
1348
+
1349
+ /**
1350
+ * @brief Per-client-instance destructor
1351
+ */
1352
+ static void rd_kafka_sasl_oauthbearer_term(rd_kafka_t *rk) {
1353
+ rd_kafka_sasl_oauthbearer_handle_t *handle = rk->rk_sasl.handle;
1354
+
1355
+ if (!handle)
1356
+ return;
1357
+
1358
+ rk->rk_sasl.handle = NULL;
1359
+
1360
+ rd_kafka_timer_stop(&rk->rk_timers, &handle->token_refresh_tmr, 1);
1361
+
1362
+ RD_IF_FREE(handle->md_principal_name, rd_free);
1363
+ RD_IF_FREE(handle->token_value, rd_free);
1364
+ rd_list_destroy(&handle->extensions);
1365
+ RD_IF_FREE(handle->errstr, rd_free);
1366
+ RD_IF_FREE(handle->callback_q, rd_kafka_q_destroy);
1367
+
1368
+ rwlock_destroy(&handle->lock);
1369
+
1370
+ rd_free(handle);
1371
+ }
1372
+
1373
+
1374
+ /**
1375
+ * @brief SASL/OAUTHBEARER is unable to connect unless a valid
1376
+ * token is available, and a valid token CANNOT be
1377
+ * available unless/until an initial token retrieval
1378
+ * succeeds, so wait for this precondition if necessary.
1379
+ */
1380
+ static rd_bool_t rd_kafka_sasl_oauthbearer_ready(rd_kafka_t *rk) {
1381
+ rd_kafka_sasl_oauthbearer_handle_t *handle = rk->rk_sasl.handle;
1382
+
1383
+ if (!handle)
1384
+ return rd_false;
1385
+
1386
+ return rd_kafka_oauthbearer_has_token(handle);
1387
+ }
1388
+
1389
+
1390
+ /**
1391
+ * @brief Validate OAUTHBEARER config, which is a no-op
1392
+ * (we rely on initial token retrieval)
1393
+ */
1394
+ static int rd_kafka_sasl_oauthbearer_conf_validate(rd_kafka_t *rk,
1395
+ char *errstr,
1396
+ size_t errstr_size) {
1397
+ /*
1398
+ * We must rely on the initial token retrieval as a proxy
1399
+ * for configuration validation because the configuration is
1400
+ * implementation-dependent, and it is not necessarily the case
1401
+ * that the config reflects the default unsecured JWS config
1402
+ * that we know how to parse.
1403
+ */
1404
+ return 0;
1405
+ }
1406
+
1407
+
1408
+
1409
+ const struct rd_kafka_sasl_provider rd_kafka_sasl_oauthbearer_provider = {
1410
+ .name = "OAUTHBEARER (builtin)",
1411
+ .init = rd_kafka_sasl_oauthbearer_init,
1412
+ .term = rd_kafka_sasl_oauthbearer_term,
1413
+ .ready = rd_kafka_sasl_oauthbearer_ready,
1414
+ .client_new = rd_kafka_sasl_oauthbearer_client_new,
1415
+ .recv = rd_kafka_sasl_oauthbearer_recv,
1416
+ .close = rd_kafka_sasl_oauthbearer_close,
1417
+ .conf_validate = rd_kafka_sasl_oauthbearer_conf_validate,
1418
+ };
1419
+
1420
+
1421
+
1422
+ /**
1423
+ * @name Unit tests
1424
+ *
1425
+ *
1426
+ */
1427
+
1428
+ /**
1429
+ * @brief `sasl.oauthbearer.config` test:
1430
+ * should generate correct default values.
1431
+ */
1432
+ static int do_unittest_config_defaults(void) {
1433
+ static const char *sasl_oauthbearer_config =
1434
+ "principal=fubar "
1435
+ "scopeClaimName=whatever";
1436
+ // default scope is empty, default lifetime is 3600 seconds
1437
+ // {"alg":"none"}
1438
+ // .
1439
+ // {"sub":"fubar","iat":1.000,"exp":3601.000}
1440
+ //
1441
+ static const char *expected_token_value =
1442
+ "eyJhbGciOiJub25lIn0"
1443
+ "."
1444
+ "eyJzdWIiOiJmdWJhciIsImlhdCI6MS4wMDAsImV4cCI6MzYwMS4wMDB9"
1445
+ ".";
1446
+ rd_ts_t now_wallclock_ms = 1000;
1447
+ char errstr[512];
1448
+ struct rd_kafka_sasl_oauthbearer_token token;
1449
+ int r;
1450
+
1451
+ r = rd_kafka_oauthbearer_unsecured_token0(
1452
+ &token, sasl_oauthbearer_config, now_wallclock_ms, errstr,
1453
+ sizeof(errstr));
1454
+ if (r == -1)
1455
+ RD_UT_FAIL("Failed to create a token: %s: %s",
1456
+ sasl_oauthbearer_config, errstr);
1457
+
1458
+ RD_UT_ASSERT(token.md_lifetime_ms == now_wallclock_ms + 3600 * 1000,
1459
+ "Invalid md_lifetime_ms %" PRId64, token.md_lifetime_ms);
1460
+ RD_UT_ASSERT(!strcmp(token.md_principal_name, "fubar"),
1461
+ "Invalid md_principal_name %s", token.md_principal_name);
1462
+ RD_UT_ASSERT(!strcmp(token.token_value, expected_token_value),
1463
+ "Invalid token_value %s, expected %s", token.token_value,
1464
+ expected_token_value);
1465
+
1466
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1467
+
1468
+ RD_UT_PASS();
1469
+ }
1470
+
1471
+ /**
1472
+ * @brief `sasl.oauthbearer.config` test:
1473
+ * should generate correct token for explicit scope and lifeSeconds values.
1474
+ */
1475
+ static int do_unittest_config_explicit_scope_and_life(void) {
1476
+ static const char *sasl_oauthbearer_config =
1477
+ "principal=fubar "
1478
+ "scope=role1,role2 lifeSeconds=60";
1479
+ // {"alg":"none"}
1480
+ // .
1481
+ // {"sub":"fubar","iat":1.000,"exp":61.000,"scope":["role1","role2"]}
1482
+ //
1483
+ static const char *expected_token_value =
1484
+ "eyJhbGciOiJub25lIn0"
1485
+ "."
1486
+ "eyJzdWIiOiJmdWJhciIsImlhdCI6MS4wMDAsImV4cCI6NjEuMDAwLCJzY29wZ"
1487
+ "SI6WyJyb2xlMSIsInJvbGUyIl19"
1488
+ ".";
1489
+ rd_ts_t now_wallclock_ms = 1000;
1490
+ char errstr[512];
1491
+ struct rd_kafka_sasl_oauthbearer_token token;
1492
+ int r;
1493
+
1494
+ r = rd_kafka_oauthbearer_unsecured_token0(
1495
+ &token, sasl_oauthbearer_config, now_wallclock_ms, errstr,
1496
+ sizeof(errstr));
1497
+ if (r == -1)
1498
+ RD_UT_FAIL("Failed to create a token: %s: %s",
1499
+ sasl_oauthbearer_config, errstr);
1500
+
1501
+ RD_UT_ASSERT(token.md_lifetime_ms == now_wallclock_ms + 60 * 1000,
1502
+ "Invalid md_lifetime_ms %" PRId64, token.md_lifetime_ms);
1503
+ RD_UT_ASSERT(!strcmp(token.md_principal_name, "fubar"),
1504
+ "Invalid md_principal_name %s", token.md_principal_name);
1505
+ RD_UT_ASSERT(!strcmp(token.token_value, expected_token_value),
1506
+ "Invalid token_value %s, expected %s", token.token_value,
1507
+ expected_token_value);
1508
+
1509
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1510
+
1511
+ RD_UT_PASS();
1512
+ }
1513
+
1514
+ /**
1515
+ * @brief `sasl.oauthbearer.config` test:
1516
+ * should generate correct token when all values are provided explicitly.
1517
+ */
1518
+ static int do_unittest_config_all_explicit_values(void) {
1519
+ static const char *sasl_oauthbearer_config =
1520
+ "principal=fubar "
1521
+ "principalClaimName=azp scope=role1,role2 "
1522
+ "scopeClaimName=roles lifeSeconds=60";
1523
+ // {"alg":"none"}
1524
+ // .
1525
+ // {"azp":"fubar","iat":1.000,"exp":61.000,"roles":["role1","role2"]}
1526
+ //
1527
+ static const char *expected_token_value =
1528
+ "eyJhbGciOiJub25lIn0"
1529
+ "."
1530
+ "eyJhenAiOiJmdWJhciIsImlhdCI6MS4wMDAsImV4cCI6NjEuMDAwLCJyb2xlc"
1531
+ "yI6WyJyb2xlMSIsInJvbGUyIl19"
1532
+ ".";
1533
+ rd_ts_t now_wallclock_ms = 1000;
1534
+ char errstr[512];
1535
+ struct rd_kafka_sasl_oauthbearer_token token;
1536
+ int r;
1537
+
1538
+ r = rd_kafka_oauthbearer_unsecured_token0(
1539
+ &token, sasl_oauthbearer_config, now_wallclock_ms, errstr,
1540
+ sizeof(errstr));
1541
+ if (r == -1)
1542
+ RD_UT_FAIL("Failed to create a token: %s: %s",
1543
+ sasl_oauthbearer_config, errstr);
1544
+
1545
+ RD_UT_ASSERT(token.md_lifetime_ms == now_wallclock_ms + 60 * 1000,
1546
+ "Invalid md_lifetime_ms %" PRId64, token.md_lifetime_ms);
1547
+ RD_UT_ASSERT(!strcmp(token.md_principal_name, "fubar"),
1548
+ "Invalid md_principal_name %s", token.md_principal_name);
1549
+ RD_UT_ASSERT(!strcmp(token.token_value, expected_token_value),
1550
+ "Invalid token_value %s, expected %s", token.token_value,
1551
+ expected_token_value);
1552
+
1553
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1554
+
1555
+ RD_UT_PASS();
1556
+ }
1557
+
1558
+ /**
1559
+ * @brief `sasl.oauthbearer.config` test:
1560
+ * should fail when no principal specified.
1561
+ */
1562
+ static int do_unittest_config_no_principal_should_fail(void) {
1563
+ static const char *expected_msg =
1564
+ "Invalid sasl.oauthbearer.config: "
1565
+ "no principal=<value>";
1566
+ static const char *sasl_oauthbearer_config =
1567
+ "extension_notaprincipal=hi";
1568
+ rd_ts_t now_wallclock_ms = 1000;
1569
+ char errstr[512];
1570
+ struct rd_kafka_sasl_oauthbearer_token token = RD_ZERO_INIT;
1571
+ int r;
1572
+
1573
+ r = rd_kafka_oauthbearer_unsecured_token0(
1574
+ &token, sasl_oauthbearer_config, now_wallclock_ms, errstr,
1575
+ sizeof(errstr));
1576
+ if (r != -1)
1577
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1578
+
1579
+ RD_UT_ASSERT(r == -1, "Did not fail despite missing principal");
1580
+
1581
+ RD_UT_ASSERT(!strcmp(errstr, expected_msg),
1582
+ "Incorrect error message when no principal: "
1583
+ "expected=%s received=%s",
1584
+ expected_msg, errstr);
1585
+ RD_UT_PASS();
1586
+ }
1587
+
1588
+ /**
1589
+ * @brief `sasl.oauthbearer.config` test:
1590
+ * should fail when no sasl.oauthbearer.config is specified.
1591
+ */
1592
+ static int do_unittest_config_empty_should_fail(void) {
1593
+ static const char *expected_msg =
1594
+ "Invalid sasl.oauthbearer.config: "
1595
+ "must not be empty";
1596
+ static const char *sasl_oauthbearer_config = "";
1597
+ rd_ts_t now_wallclock_ms = 1000;
1598
+ char errstr[512];
1599
+ struct rd_kafka_sasl_oauthbearer_token token = RD_ZERO_INIT;
1600
+ int r;
1601
+
1602
+ r = rd_kafka_oauthbearer_unsecured_token0(
1603
+ &token, sasl_oauthbearer_config, now_wallclock_ms, errstr,
1604
+ sizeof(errstr));
1605
+ if (r != -1)
1606
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1607
+
1608
+ RD_UT_ASSERT(r == -1, "Did not fail despite empty config");
1609
+
1610
+ RD_UT_ASSERT(!strcmp(errstr, expected_msg),
1611
+ "Incorrect error message with empty config: "
1612
+ "expected=%s received=%s",
1613
+ expected_msg, errstr);
1614
+ RD_UT_PASS();
1615
+ }
1616
+
1617
+ /**
1618
+ * @brief `sasl.oauthbearer.config` test:
1619
+ * should fail when something unrecognized is specified.
1620
+ */
1621
+ static int do_unittest_config_unrecognized_should_fail(void) {
1622
+ static const char *expected_msg =
1623
+ "Unrecognized "
1624
+ "sasl.oauthbearer.config beginning at: unrecognized";
1625
+ static const char *sasl_oauthbearer_config =
1626
+ "principal=fubar unrecognized";
1627
+ rd_ts_t now_wallclock_ms = 1000;
1628
+ char errstr[512];
1629
+ struct rd_kafka_sasl_oauthbearer_token token;
1630
+ int r;
1631
+
1632
+ r = rd_kafka_oauthbearer_unsecured_token0(
1633
+ &token, sasl_oauthbearer_config, now_wallclock_ms, errstr,
1634
+ sizeof(errstr));
1635
+ if (r != -1)
1636
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1637
+
1638
+ RD_UT_ASSERT(r == -1, "Did not fail with something unrecognized");
1639
+
1640
+ RD_UT_ASSERT(!strcmp(errstr, expected_msg),
1641
+ "Incorrect error message with something unrecognized: "
1642
+ "expected=%s received=%s",
1643
+ expected_msg, errstr);
1644
+ RD_UT_PASS();
1645
+ }
1646
+
1647
+ /**
1648
+ * @brief `sasl.oauthbearer.config` test:
1649
+ * should fail when empty values are specified.
1650
+ */
1651
+ static int do_unittest_config_empty_value_should_fail(void) {
1652
+ static const char *sasl_oauthbearer_configs[] = {
1653
+ "principal=", "principal=fubar principalClaimName=",
1654
+ "principal=fubar scope=", "principal=fubar scopeClaimName=",
1655
+ "principal=fubar lifeSeconds="};
1656
+ static const char *expected_prefix =
1657
+ "Invalid sasl.oauthbearer.config: empty";
1658
+ size_t i;
1659
+ rd_ts_t now_wallclock_ms = 1000;
1660
+ char errstr[512];
1661
+ int r;
1662
+
1663
+ for (i = 0; i < sizeof(sasl_oauthbearer_configs) / sizeof(const char *);
1664
+ i++) {
1665
+ struct rd_kafka_sasl_oauthbearer_token token;
1666
+ r = rd_kafka_oauthbearer_unsecured_token0(
1667
+ &token, sasl_oauthbearer_configs[i], now_wallclock_ms,
1668
+ errstr, sizeof(errstr));
1669
+ if (r != -1)
1670
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1671
+
1672
+ RD_UT_ASSERT(r == -1, "Did not fail with an empty value: %s",
1673
+ sasl_oauthbearer_configs[i]);
1674
+
1675
+ RD_UT_ASSERT(
1676
+ !strncmp(expected_prefix, errstr, strlen(expected_prefix)),
1677
+ "Incorrect error message prefix when empty "
1678
+ "(%s): expected=%s received=%s",
1679
+ sasl_oauthbearer_configs[i], expected_prefix, errstr);
1680
+ }
1681
+ RD_UT_PASS();
1682
+ }
1683
+
1684
+ /**
1685
+ * @brief `sasl.oauthbearer.config` test:
1686
+ * should fail when value with embedded quote is specified.
1687
+ */
1688
+ static int do_unittest_config_value_with_quote_should_fail(void) {
1689
+ static const char *sasl_oauthbearer_configs[] = {
1690
+ "principal=\"fu", "principal=fubar principalClaimName=\"bar",
1691
+ "principal=fubar scope=\"a,b,c",
1692
+ "principal=fubar scopeClaimName=\"baz"};
1693
+ static const char *expected_prefix =
1694
+ "Invalid "
1695
+ "sasl.oauthbearer.config: '\"' cannot appear in ";
1696
+ size_t i;
1697
+ rd_ts_t now_wallclock_ms = 1000;
1698
+ char errstr[512];
1699
+ int r;
1700
+
1701
+ for (i = 0; i < sizeof(sasl_oauthbearer_configs) / sizeof(const char *);
1702
+ i++) {
1703
+ struct rd_kafka_sasl_oauthbearer_token token;
1704
+ r = rd_kafka_oauthbearer_unsecured_token0(
1705
+ &token, sasl_oauthbearer_configs[i], now_wallclock_ms,
1706
+ errstr, sizeof(errstr));
1707
+ if (r != -1)
1708
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1709
+
1710
+ RD_UT_ASSERT(r == -1, "Did not fail with embedded quote: %s",
1711
+ sasl_oauthbearer_configs[i]);
1712
+
1713
+ RD_UT_ASSERT(
1714
+ !strncmp(expected_prefix, errstr, strlen(expected_prefix)),
1715
+ "Incorrect error message prefix with "
1716
+ "embedded quote (%s): expected=%s received=%s",
1717
+ sasl_oauthbearer_configs[i], expected_prefix, errstr);
1718
+ }
1719
+ RD_UT_PASS();
1720
+ }
1721
+
1722
+ /**
1723
+ * @brief `sasl.oauthbearer.config` test:
1724
+ * should generate correct extensions.
1725
+ */
1726
+ static int do_unittest_config_extensions(void) {
1727
+ static const char *sasl_oauthbearer_config =
1728
+ "principal=fubar "
1729
+ "extension_a=b extension_yz=yzval";
1730
+ rd_ts_t now_wallclock_ms = 1000;
1731
+ char errstr[512];
1732
+ struct rd_kafka_sasl_oauthbearer_token token;
1733
+ int r;
1734
+
1735
+ r = rd_kafka_oauthbearer_unsecured_token0(
1736
+ &token, sasl_oauthbearer_config, now_wallclock_ms, errstr,
1737
+ sizeof(errstr));
1738
+
1739
+ if (r == -1)
1740
+ RD_UT_FAIL("Failed to create a token: %s: %s",
1741
+ sasl_oauthbearer_config, errstr);
1742
+
1743
+ RD_UT_ASSERT(token.extension_size == 4,
1744
+ "Incorrect extensions: expected 4, received %" PRIusz,
1745
+ token.extension_size);
1746
+
1747
+ RD_UT_ASSERT(!strcmp(token.extensions[0], "a") &&
1748
+ !strcmp(token.extensions[1], "b") &&
1749
+ !strcmp(token.extensions[2], "yz") &&
1750
+ !strcmp(token.extensions[3], "yzval"),
1751
+ "Incorrect extensions: expected a=b and "
1752
+ "yz=yzval but received %s=%s and %s=%s",
1753
+ token.extensions[0], token.extensions[1],
1754
+ token.extensions[2], token.extensions[3]);
1755
+
1756
+ rd_kafka_sasl_oauthbearer_token_free(&token);
1757
+
1758
+ RD_UT_PASS();
1759
+ }
1760
+
1761
+ /**
1762
+ * @brief make sure illegal extensions keys are rejected
1763
+ */
1764
+ static int do_unittest_illegal_extension_keys_should_fail(void) {
1765
+ static const char *illegal_keys[] = {"", "auth", "a1", " a"};
1766
+ size_t i;
1767
+ char errstr[512];
1768
+ int r;
1769
+
1770
+ for (i = 0; i < sizeof(illegal_keys) / sizeof(const char *); i++) {
1771
+ r = check_oauthbearer_extension_key(illegal_keys[i], errstr,
1772
+ sizeof(errstr));
1773
+ RD_UT_ASSERT(r == -1,
1774
+ "Did not recognize illegal extension key: %s",
1775
+ illegal_keys[i]);
1776
+ }
1777
+ RD_UT_PASS();
1778
+ }
1779
+
1780
+ /**
1781
+ * @brief make sure illegal extensions keys are rejected
1782
+ */
1783
+ static int do_unittest_odd_extension_size_should_fail(void) {
1784
+ static const char *expected_errstr =
1785
+ "Incorrect extension size "
1786
+ "(must be a non-negative multiple of 2): 1";
1787
+ char errstr[512];
1788
+ rd_kafka_resp_err_t err;
1789
+ rd_kafka_t rk = RD_ZERO_INIT;
1790
+ rd_kafka_sasl_oauthbearer_handle_t handle = RD_ZERO_INIT;
1791
+
1792
+ rk.rk_conf.sasl.provider = &rd_kafka_sasl_oauthbearer_provider;
1793
+ rk.rk_sasl.handle = &handle;
1794
+
1795
+ rwlock_init(&handle.lock);
1796
+
1797
+ err = rd_kafka_oauthbearer_set_token0(&rk, "abcd", 1000, "fubar", NULL,
1798
+ 1, errstr, sizeof(errstr));
1799
+
1800
+ rwlock_destroy(&handle.lock);
1801
+
1802
+ RD_UT_ASSERT(err, "Did not recognize illegal extension size");
1803
+ RD_UT_ASSERT(!strcmp(errstr, expected_errstr),
1804
+ "Incorrect error message for illegal "
1805
+ "extension size: expected=%s; received=%s",
1806
+ expected_errstr, errstr);
1807
+ RD_UT_ASSERT(err == RD_KAFKA_RESP_ERR__INVALID_ARG,
1808
+ "Expected ErrInvalidArg, not %s", rd_kafka_err2name(err));
1809
+
1810
+ RD_UT_PASS();
1811
+ }
1812
+
1813
+ int unittest_sasl_oauthbearer(void) {
1814
+ int fails = 0;
1815
+
1816
+ fails += do_unittest_config_no_principal_should_fail();
1817
+ fails += do_unittest_config_empty_should_fail();
1818
+ fails += do_unittest_config_empty_value_should_fail();
1819
+ fails += do_unittest_config_value_with_quote_should_fail();
1820
+ fails += do_unittest_config_unrecognized_should_fail();
1821
+ fails += do_unittest_config_defaults();
1822
+ fails += do_unittest_config_explicit_scope_and_life();
1823
+ fails += do_unittest_config_all_explicit_values();
1824
+ fails += do_unittest_config_extensions();
1825
+ fails += do_unittest_illegal_extension_keys_should_fail();
1826
+ fails += do_unittest_odd_extension_size_should_fail();
1827
+
1828
+ return fails;
1829
+ }