@point3/node-rdkafka 3.6.0-1

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