From 055c0e1d0b6cca03418f8885c15ca27c3f914407 Mon Sep 17 00:00:00 2001 From: DanielePalaia Date: Tue, 18 Mar 2025 09:56:29 +0100 Subject: [PATCH 1/7] improving automation --- .ci/certs/ca.p12 | Bin 2734 -> 0 bytes .ci/certs/ca_certificate.pem | 38 ++-- .ci/certs/ca_key.pem | 52 +++--- .ci/certs/client.p12 | Bin 3870 -> 0 bytes .ci/certs/client_certificate.pem | 22 --- .ci/certs/client_key.pem | 28 --- .ci/certs/client_localhost.p12 | Bin 0 -> 3667 bytes .ci/certs/client_localhost_certificate.pem | 22 +++ .ci/certs/client_localhost_key.pem | 28 +++ .ci/certs/server.p12 | Bin 3902 -> 0 bytes .ci/certs/server_certificate.pem | 23 --- .ci/certs/server_key.pem | 28 --- .ci/certs/server_localhost.p12 | Bin 0 -> 3667 bytes .ci/certs/server_localhost_certificate.pem | 22 +++ .ci/certs/server_localhost_key.pem | 28 +++ .ci/conf/enabled_plugins | 1 - .ci/conf/rabbitmq.conf | 9 - .ci/publish-documentation-to-github-pages.sh | 49 ++++++ .ci/ubuntu/advanced.config | 13 ++ .ci/ubuntu/enabled_plugins | 1 + .ci/ubuntu/gha-log-check.sh | 16 ++ .ci/ubuntu/gha-setup.sh | 174 +++++++++++++++++++ .ci/ubuntu/log/.gitkeep | 0 .ci/ubuntu/rabbitmq.conf | 29 ++++ .github/workflows/build-test.yaml | 35 +--- Dockerfile | 8 - Makefile | 9 +- tests/conftest.py | 8 +- 28 files changed, 438 insertions(+), 205 deletions(-) delete mode 100644 .ci/certs/ca.p12 delete mode 100644 .ci/certs/client.p12 delete mode 100644 .ci/certs/client_certificate.pem delete mode 100644 .ci/certs/client_key.pem create mode 100644 .ci/certs/client_localhost.p12 create mode 100644 .ci/certs/client_localhost_certificate.pem create mode 100644 .ci/certs/client_localhost_key.pem delete mode 100644 .ci/certs/server.p12 delete mode 100644 .ci/certs/server_certificate.pem delete mode 100644 .ci/certs/server_key.pem create mode 100644 .ci/certs/server_localhost.p12 create mode 100644 .ci/certs/server_localhost_certificate.pem create mode 100644 .ci/certs/server_localhost_key.pem delete mode 100644 .ci/conf/enabled_plugins delete mode 100644 .ci/conf/rabbitmq.conf create mode 100755 .ci/publish-documentation-to-github-pages.sh create mode 100644 .ci/ubuntu/advanced.config create mode 100644 .ci/ubuntu/enabled_plugins create mode 100755 .ci/ubuntu/gha-log-check.sh create mode 100755 .ci/ubuntu/gha-setup.sh create mode 100644 .ci/ubuntu/log/.gitkeep create mode 100644 .ci/ubuntu/rabbitmq.conf delete mode 100644 Dockerfile diff --git a/.ci/certs/ca.p12 b/.ci/certs/ca.p12 deleted file mode 100644 index 5900f69af2a7a91c841bbf58d85e29fff9ffdcc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2734 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 S>~F~U^hdUw?9}+b2>KVKv;gn` diff --git a/.ci/certs/ca_certificate.pem b/.ci/certs/ca_certificate.pem index 77f380a..a67df16 100644 --- a/.ci/certs/ca_certificate.pem +++ b/.ci/certs/ca_certificate.pem @@ -1,21 +1,21 @@ -----BEGIN CERTIFICATE----- -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 -----END CERTIFICATE----- diff --git a/.ci/certs/ca_key.pem b/.ci/certs/ca_key.pem index ebbda3c..ffd51ee 100644 --- a/.ci/certs/ca_key.pem +++ b/.ci/certs/ca_key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCZek5iHZU3WaXd -2SWk2n62ItDAHBxORRHw0IBpEyYG3lxvNzE1A9jWI5RoK29b+/dz4jt/4mEitrhr -+QAEHb1JiIwD/MriUxYiBaVr5YxEWg3d7IPkZ4lDeGGsSNMZzPNgNlAVl6XQG0tg -EjHT0mOvlWV/sWwWmPx+xwy+84a0BJJdThoMm1/rHoIzk19Y5DSe0EGfduAxy7yV -gzSCAbfEvGmFW3+ldjBc4sA/fIbHyEYBdtk9m4BDJCOTNB+YzuIS5Hk2BOzIaW+0 -33mQki3lQ/75jG5zr4FybdMLyC8JbR+jAL4gEE4yiF4jGxAk1/NbZhyJ1EPjyk4s -/LeZlUi3AgMBAAECggEABfZ+hDsi5P69U3GpOofEcBVXh9EBjdx8rYKBnj4kNk1w -Ae6bdtC4x/kVdv+Drk7EPf94JovPSW37fvn5n4Smf142Tto9sJHR0sM7nhQ1fZQg -Vq9moGw8elhe/cTNq0mdaURr06rvUH4bbV3kC3rF+vFLbR6hxqffawvBoMtisbrY -xIp1MfsguOjHLhEDp9crJ+1N5XkqWKZPMpMgPI0mW4Yk+O409+hT5yg/ziNQ5a7o -o86tK3axtPNiaSTPkxoU+sCVu2ILZVTbfjMk2lh7OCgoAA3A9jQ3ulRz+Cl4sXqr -1Ze5pPuRseBL10xmOmoNHR5kvqSNG3Kp6bxyTGiqIQKBgQDPYT2VyaSD4NSA5Es3 -p1DjJa/gItWWIsSSDnpBm5zF908g9rAVxLvx3JLUI4YPFY82o57DCi34jDrE6O0k -SsjuZA2SiuqSqrHxP02RYdAh7/9S/LLM9kakj7QKUU2f92QoyQvKn8M3cygBBz3x -G0uwLE0EU2wgm58SBdnAR6zHuwKBgQC9deipcKT+OG6MZWGhjYsnBiaK8XxxPl9v -Kf2hBmImVDDdOkwthPLKJhP4VhjLETKo8Zi28Nxo6ueOpfn2Q5+0XrI18VNQZI/G -ip6adbezgdIKB0OcWvkXH0Fwl7P7fgNWAPdla9jznSvGj7UnSgt7tFp1xJkXzEfU -n1NEXDNdNQKBgDlOR7RimkGPGWncrCRe6e069tTbC2aHiQZLVeFXXQUfiBA12wbI -7J6zMyfIAT2d2Ythv3dqErYCGiNbslw7BjdKEq4SESwiWzWtJoQsIVWfelC2X7pf -u7mxtDC9stOni1fx5n5Bk7J48e8Gz0kXH905ALdXTiPcnSJf14JYzBgNAoGBAITB -dBAWkGZaYIwcFfc/2Tu1AZjmcY5gaDrar4//ixLUd5Ds4qgauo2PdPrUSXcxS9A5 -ygqWZ7tUroC0KJy48dVPbYyC1yBD9sLmKxCMX/Z2hxjj0ipjTJs5GX+trT4SJIBF -GRWGJnU9sojl9cfcCIPb8m8HHUchq0t/gLcr7AnpAoGARNnUh19fK+8ldKx/h9jN -svJZK1I615OXXRCAY2BWl4k7pbufseVVhtSHxkAfzhmv5gIqojfUGf4WCfcf0eZ9 -xWBXpuWgMwnWuMlPJLwIzlaU1phDsSaHdd2iuAYfZEKWmIIIxT7+vXDO4UaVpXs6 -kso6qBkSwQTymY4m5RATlK4= +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDqAwl11OZzzMDh +1oaaA/IbnU39VCDE3BsKKg3arhVGhYaSbYEtaJWhNbB12qkw2GEFeSl0mZCSorTJ +mQHmcUjcO0yHzRIM5vzEscPOffUBfIxXiVehPyyNJa9P2IRE65i3d7mcmR62dG6E +Wtj1tW0VLKGcd3STpmGoA9b8tuJZq9vt6ivDTv7OECCLmDR2IHKoAXKZQmsDgI1D +y0UuLCEWIzOqr8WAq1at28AAiDL9Rh0bxyQ8oREx86zjLOXOsJ8CNNWFRheAFh65 +hWWMpM4SavEVpW0kE9qCfopBGl4xpbBLE/gzkhMkUZVwri6cGakzvA+dmdCsS5D3 +t2ZHWIkzAgMBAAECggEAZMk+D9PMFV/ASwQcIMVGRwJvDoZnPqIVu0D1ipOjciYc +GYC0PBxpJW98OqYcbH8k+jh+1Es3axBMkO8nVFrCKKgZg/ucpJXvk7+EN7EkDqnX +v/PVHAubYocyhE8aWJynv4z/EiUYhziKSNLf0qN7Ab2hNUR1nwnv0W8l7t3NixSY +4sIuGhm2QbqfHKvvG//GWOmvRIYLdJPZ69tJR8sOidIpNY2LI4tNXlC2fdPI+RaT +pOJcULSi+AZItyxHwELDR3u5xuWJ3KMcrBRiMees//dhg8Sga0tmBIW1vN33eKtW +wOkq48hBGUi8sfrRfVSiJBquZFURYrzC1J2EZQOcwQKBgQD3DuZl4NQiGaL3afY6 +fp2hstVjRm8Xdy2AdCPXx5w+R8CJUpLDpHfYavT7pFUx7W1ERfbsqHujMbb2Zaq9 +FyYdXvIpcqFjCJl16dLaDmzvDn98v9mWEB9I+NeqXSBVbbPhCFSuKElpx5OrrxeQ +CUMfofoTtQlHvSYUsz0vm/aiMQKBgQDye0HNNd41NiaXVYUQenNbwOBO+POUBxj2 +pccNTpQulZEXug8IomfDLQ+cA3Dsqlf16tran4wVPUO53n2By07nof/tHV6y0IF9 +oQPznCrbaKl35e4MlvDf0+FfGKNFWExwVeKJJGDVUWgBa+cXFvtUJHYDGb7Bo6+C +5NyqHw6EowKBgCyS056t4ZgFaBGbXIFRNr9ltHokywZAykTSr2TO7rGN4H7mFvSV +R8oUAf8ktvo7C+u1c8de3m+jGI976EIVWxsRdj9kHxnvA0Dy3sfYsm6u/vFS677X +Sc2wl7h09NB06m8/QYfqXNRo3YusG2QxR5r9blD/6Jy405YIgJGGYgkBAoGAGaAp +DhTZTOpSHcAt9dXbByFVE0OACm7NlpNie+eIBXxM/yLsn876BEho0+YRMxG1hgmx +41TlKwF0fNokjWj9B8G5GEf4UBF0/d/cWQxyAwoGjuM/yxjQj/cGZFRoPNXeDikl +bbTofuLBiRTsMSZ+nR/VUPKRlElGLSEeqOPrVt0CgYEAugfHj4AqmDfL1F3rbw+D +XwiyvRqwLBYzxZ0t8Hbm0uht0MKjTgJ/G2fkC7Y8aJgEn8jstfoVSh9sXUKgUnCA +MAuil2220ctEh04bp/na1z/9igJWGiJNbRVXjF+BRAbSJ25RY8BX5dDydcWbqzyr +eT5xfQPC5smWZlI0l0JK1bs= -----END PRIVATE KEY----- diff --git a/.ci/certs/client.p12 b/.ci/certs/client.p12 deleted file mode 100644 index b6b4a0f21bdf307a3693a9201ba9401967f4d99a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3870 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 Y(dJIF1Q`W_LtA%SUOUH;|F>%Y1K`!Z`~Uy| literal 0 HcmV?d00001 diff --git a/.ci/certs/client_localhost_certificate.pem b/.ci/certs/client_localhost_certificate.pem new file mode 100644 index 0000000..b049ba1 --- /dev/null +++ b/.ci/certs/client_localhost_certificate.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBLMTowOAYDVQQDDDFUTFNH +ZW5TZWxmU2lnbmVkUm9vdENBIDIwMjUtMDItMjdUMTU6NDQ6NTguODgwNTMwMQ0w +CwYDVQQHDAQkJCQkMB4XDTI1MDIyNzE0NDQ1OVoXDTM1MDIyNTE0NDQ1OVowJTES +MBAGA1UEAwwJbG9jYWxob3N0MQ8wDQYDVQQKDAZjbGllbnQwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC7L/xjD4iHTCf2IfXd/fayxkX0+dI+Z2y+latM +UFvn4GpDIz0Acfqjp3/NhShbWoHqOhR/w5l20J9Ljt2RmecpybK717Flst8Q0g0C +xm3GaN7fVLAxoWAIbzU7cAZMv0SRuu2RIo2HTt5i2xBljA5Bf6wMZqMFxvnNWNGt +TIWVUzCjeqWqPUi84XdHu0GWyQ11rIjCnw5zY3D8EFc+HoTgI33y81EABps7ybmH +BdUtMsAFEXgk3lJplaLeIvlM/HzBk+ffkqpcwC6kTnoR7Nww8a2aE6wHq91Hj+R7 +mmAo8Hpx0grott/pmwWOd2Ld1w3gxC3I7D6yqjfT4Rjc6FyxAgMBAAGjgdAwgc0w +CQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwKwYD +VR0RBCQwIoIJbG9jYWxob3N0ggpGMjNOMDQ5MlhUgglsb2NhbGhvc3QwMQYDVR0f +BCowKDAmoCSgIoYgaHR0cDovL2NybC1zZXJ2ZXI6ODAwMC9iYXNpYy5jcmwwHQYD +VR0OBBYEFLmThoy0pKufr0QWZRwg1FJGdcFRMB8GA1UdIwQYMBaAFDJd0t924S/4 +0cxm/LgBIUfoEhlaMA0GCSqGSIb3DQEBCwUAA4IBAQCk4Ytqqtymc8h0M2HiIyhK +p2Dkf7GZRjBPvC6ULIxMEixslcDCkVTkLaYKRJL7xv37RNfc6kgi9K1IjPfDUtEm +IDm56hRhIvLkH/BsUbhhJsZnYBN1GbqmFNtNP7Zj2Yt6uAwFkFB6gnK7RflSwVaG +EYZhs8QEmZ1VhGymJorp5HGI6EcVkOhG3pScp5yaAqM2cKy7CLnZJfpCzQ12LZ7/ +2UEKRtfILvN8kWaWOaGCM7t3Z2i6bfEh/1WZBmZnyK+zDBxv/YDp2iave/i7r/dY +tOZA1KB2OMWZY4pHmiEior05yf0o7xNctPdwy3+IvRYAH6FJhMA29XoizPW8Cvtk +-----END CERTIFICATE----- diff --git a/.ci/certs/client_localhost_key.pem b/.ci/certs/client_localhost_key.pem new file mode 100644 index 0000000..9f6dcf4 --- /dev/null +++ b/.ci/certs/client_localhost_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7L/xjD4iHTCf2 +IfXd/fayxkX0+dI+Z2y+latMUFvn4GpDIz0Acfqjp3/NhShbWoHqOhR/w5l20J9L +jt2RmecpybK717Flst8Q0g0Cxm3GaN7fVLAxoWAIbzU7cAZMv0SRuu2RIo2HTt5i +2xBljA5Bf6wMZqMFxvnNWNGtTIWVUzCjeqWqPUi84XdHu0GWyQ11rIjCnw5zY3D8 +EFc+HoTgI33y81EABps7ybmHBdUtMsAFEXgk3lJplaLeIvlM/HzBk+ffkqpcwC6k +TnoR7Nww8a2aE6wHq91Hj+R7mmAo8Hpx0grott/pmwWOd2Ld1w3gxC3I7D6yqjfT +4Rjc6FyxAgMBAAECggEAAvFuHrGbFC4rRQMDg7NvRPV57/Awm84SUeHLtnC0rTiO ++ydrRAicEqV6zISu3dbWYD7RsoY6XA72KODiFMdjxiQCH9LJmtTSjd1mRSL7uAj5 +6MQtsVi9SDdVZy3rpMUaGHolAOlB6pIfzClFFfpQgWZMPSACVAAs+SClH/wqGoRU +LBt8uAwwx9QWqId8nuP4OorAFQYqmmzFb6Q42CanSNObaWcutmIuziOv/P9hRKcx +WbUei3Q5+DjU4ScFGXmyKzP4DxYMJM42jqocZdggHk+eL2yjdR5TmUpnR5WDcjtM +pf5lXzbPsCaFpVsQgHTZgA5OWcaztEtObnINrryb5QKBgQDtOpp5K0kO6HafC9CI +sPDmYyEtfg+IIv9rdEzHmpuj3uyeFBxO3fNE51m1pxGr2DmfekeWzG17lIFIrOkf +t9SAMVPiI5m5mKsPHt3bRE3CjJNjHTvj3tQyF7xDEsJdYyTvEGB5tTKl+t338Wq8 +1H2B0szEr8dEbt1Hf2WFz/lA1QKBgQDJ/7lQnXPC50+U0IhdFk9K/YPE1FOo3ck8 +EIi0S4A0F97N5bCoQ1n+PSCLMGDp3f/QQfX6dh/dnX+SXXlOVNbquKuy5/uIj1Lq +glA0Jj9wKFDVpZG6wziB79TQWQP6TltsQJ4NGwpuPUbyxUQBBg2t3cZy9BJpTJjQ +LUYbSnm6bQKBgQDBi6eOJjeT9ysYdc4sR5gzjzr5X7kSS+Nx6s/dphFHcFBCZIv3 ++HNKiyoQ3362YlIY/+26ZY0JX07fWVtVqmiwMg6LGJqJ5rnhO0CsbRy4FnMFUUuU +jS84s07AtmRnRsVSWl0rzx7Edll0ub1o1ECVk8PG0NbVyVG1zIWq19Q3BQKBgEOa +8LzIVawPmpTlzh3Jj7Q7cNR5c556zBTsO7SL6FaG/qzOiPdnw0DR2Ih9IpJjGHDt +ApRW4IddZQrpeeX7gwp/0AdKmOa1gTy3bHxnqKey9orqpQFqwQjL6d/pSumFPBfY +8IzWVgFbRNmPqBjnm8BrDzX99gOD/Uj/Pg14OZFpAoGAfDfDCsKbW6TJnvbIFkw3 +/V4v6WAwaUS9mECtRb00yzNtn7YbEveQ2/pKPLPZ5z8Vz9pMpuzXfoqFYUEJNsz/ +F2qNaYrvREsDbsLVqFdTTyNHPicilcM8bfmaspI72Tb/YkJNH0/cVhF6H8/J02rr +ValHWT50FbbgAY337QwDjO8= +-----END PRIVATE KEY----- diff --git a/.ci/certs/server.p12 b/.ci/certs/server.p12 deleted file mode 100644 index cc47a6c4c844d020a65f39fad5a787287aefdecd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3902 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 T`JDien|2(JFC(4Qf2;OCL$bih literal 0 HcmV?d00001 diff --git a/.ci/certs/server_localhost_certificate.pem b/.ci/certs/server_localhost_certificate.pem new file mode 100644 index 0000000..0e72b16 --- /dev/null +++ b/.ci/certs/server_localhost_certificate.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIBATANBgkqhkiG9w0BAQsFADBLMTowOAYDVQQDDDFUTFNH +ZW5TZWxmU2lnbmVkUm9vdENBIDIwMjUtMDItMjdUMTU6NDQ6NTguODgwNTMwMQ0w +CwYDVQQHDAQkJCQkMB4XDTI1MDIyNzE0NDQ1OVoXDTM1MDIyNTE0NDQ1OVowJTES +MBAGA1UEAwwJbG9jYWxob3N0MQ8wDQYDVQQKDAZzZXJ2ZXIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCn1MRZTV3ATEvS8jFXhci/HGup4acSa1AduNak +8fpGHSFFmrywY6cl00rmPa95nfGloqbkRydqOwMn1Pv3XfHc3UeaiBgU+FNRj9u6 +NOwJ0zR3QkqLxvQqbjrvxMN/IaZ2WL0Zem+j8YIY9yHytjkLEX2AH9AZLwHpdBLI +vSVeS3BNF/gKpXYExGNNfG47/Lo0fIgwboN069pHY/Ff80SAzUkzRcOxDplJoMWp +wym15ssmAnGzAzTrMhKIJ7rUyaE0ZNAIcid7KQ1VzB+yMpeYz5pdbx0G4U/DuVXf +j8FnwlGwGAw05CckDjZcgrWNgLz1kqEcMV/UEFlbQuEzl5kTAgMBAAGjgdAwgc0w +CQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwKwYD +VR0RBCQwIoIJbG9jYWxob3N0ggpGMjNOMDQ5MlhUgglsb2NhbGhvc3QwHQYDVR0O +BBYEFGv69aUODEtJA5QWU4KalMtGvuGYMB8GA1UdIwQYMBaAFDJd0t924S/40cxm +/LgBIUfoEhlaMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwtc2VydmVyOjgw +MDAvYmFzaWMuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQBQxX+IwLmt9emhC/of3riN +wQaLXGYKKMHcsimGkBsQbitWlwWtBZwR2F9aOlvcOAlFbQ2Enldbdpkens1YwR4k +Fsx2VdOnumSYbq6DKZg0mMrg3AqufYLBGVPSGNksQ6qERZVD5NGATLh0kA9R3q0h +eGKJbHyrdI6fkSELkmBGbuetjmGIfmYh+OjYZhqvU5mutjdOfY9k1t08eRvdNiIB +4HxFVEk/S0opA98LkjY0wjPSAMZAWPNxHD5vHoaI6VwYnxLadD1NcasfEpae6uLW +t7CT+v6rtfBXvczfdd9rmhCmcHR5ckrL/wbpnvgkloQqxclw5IpDt/JkPyGghWx3 +-----END CERTIFICATE----- diff --git a/.ci/certs/server_localhost_key.pem b/.ci/certs/server_localhost_key.pem new file mode 100644 index 0000000..93189d7 --- /dev/null +++ b/.ci/certs/server_localhost_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCn1MRZTV3ATEvS +8jFXhci/HGup4acSa1AduNak8fpGHSFFmrywY6cl00rmPa95nfGloqbkRydqOwMn +1Pv3XfHc3UeaiBgU+FNRj9u6NOwJ0zR3QkqLxvQqbjrvxMN/IaZ2WL0Zem+j8YIY +9yHytjkLEX2AH9AZLwHpdBLIvSVeS3BNF/gKpXYExGNNfG47/Lo0fIgwboN069pH +Y/Ff80SAzUkzRcOxDplJoMWpwym15ssmAnGzAzTrMhKIJ7rUyaE0ZNAIcid7KQ1V +zB+yMpeYz5pdbx0G4U/DuVXfj8FnwlGwGAw05CckDjZcgrWNgLz1kqEcMV/UEFlb +QuEzl5kTAgMBAAECggEAEaH/jRhdSLZbYwrSF011hWqxfxQ3ru46aR0B5CuOLW6j +D8KNn4Sgy48S9/S0KnVnLY1UtngpUnZnwvgUDu2+WwOeocQ5r35VlqSkI8Cqqe+Y +PA1pcp0RCyIwq/9CwOkiqZ1yJKqh7xoRHplcZjkx7hFE28C75uFy9Hme/ZstwWXF +E+6Puia3YcE1CAYiIzrdKDGL+uIVjMfXQue3JybST9CzSPk2mgTq4tGLDON82V3u +RC80YmhSrzgi9/CPBQwE2YtD3zO0RTqTE1s2efP1ApfWZDL09rBWj6P4lplFnjzk +IAW35SbP8zEtnFuMLEui2cSr0ewAPks5x5HflitxhQKBgQDSP6R2iDa1XsxsMCO+ +hAgvIKelzrI1vdOs5OmpQQonL6t0xfFbesAEKxhoRQe73nvgQechLrbTjcAMDemj +F98TC39f3TGMVi2XQMaAkJMt+3NGtYj7OTrfwIB7sFZXg9guO1EG4hEsQbP0P11S +aFEoRp+/0dRVDc5PvHz70sNz1wKBgQDMWiqENzhuk1Ha2XzRpmgLvDqZ5x1rS+2p +LvwcVAEFuK1EoOqcGy8KBYz2HHQg3dbdDlM/ptSaV1YFqB8DGW+pfAHFqiS47YQf +QHSgoYXfHm9rSDkS2gnPLK0V8rN8Ft5umWx5FkT8x7ormaxUVcSg2Dxhe3J4UCh+ +EwJhoXudJQKBgQCpceVIKkt9LOOvpbSJDLvTz4uNk+IIce6w/uRaJjLalg6m1AjK +40jxkxHepxOuk4ZenH58PbvXD/zhOi075jdAkBmd1xTht2qS5f+VCe+0NV0YdaHq +ZptOTUS/asSLT5Tg3alV1MhmVKWFibPagHw364NAAwoPaksF9DD+e0ROjQKBgH4q +VQGYTkEGt4zUphmSEb7dEZkfdaxfDnZbyc97lb4AjQlICFEk/1/CmYsBejkofZWx +WHh9+djofvWzHKJ/O895/mYZa9641c+trdPWpZ5hXgzwZDxdXZ0JSju4wlOkkuPZ +2XzQ4ProHOr6T8kpwuJDXtQYsU3Sv41HEztPxc/5AoGBAIbELsuD0WsEEmQu10hp +fCzzUan8tS5cFYEBXYI6XoUBTHv/TM5Mx+hpEqZFYOALVmYyLEC6eFKYFFZVDZ6t +Up6L91J0AhsInnON3RotUekx4l77woMufYmOSuARqU/+UjkXUfrCXnjK/064HNEO +rRdolD9MXCQidIrqwsPyHprv +-----END PRIVATE KEY----- diff --git a/.ci/conf/enabled_plugins b/.ci/conf/enabled_plugins deleted file mode 100644 index 9d0383d..0000000 --- a/.ci/conf/enabled_plugins +++ /dev/null @@ -1 +0,0 @@ -[rabbitmq_management, rabbitmq_stream, rabbitmq_stream_management]. \ No newline at end of file diff --git a/.ci/conf/rabbitmq.conf b/.ci/conf/rabbitmq.conf deleted file mode 100644 index 6d1d180..0000000 --- a/.ci/conf/rabbitmq.conf +++ /dev/null @@ -1,9 +0,0 @@ -loopback_users.guest = false - -ssl_options.cacertfile = /etc/rabbitmq/certs/ca_certificate.pem -ssl_options.certfile = /etc/rabbitmq/certs/server_certificate.pem -ssl_options.keyfile = /etc/rabbitmq/certs/server_key.pem -listeners.ssl.default = 5671 -stream.listeners.ssl.default = 5551 -ssl_options.verify = verify_peer -ssl_options.fail_if_no_peer_cert = false diff --git a/.ci/publish-documentation-to-github-pages.sh b/.ci/publish-documentation-to-github-pages.sh new file mode 100755 index 0000000..76a54c2 --- /dev/null +++ b/.ci/publish-documentation-to-github-pages.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +. $(pwd)/release-versions.txt + +MESSAGE=$(git log -1 --pretty=%B) +./mvnw buildnumber:create pre-site --no-transfer-progress + +./mvnw javadoc:javadoc -Dmaven.javadoc.skip=false --no-transfer-progress + +if [ -e target/site/apidocs/element-list ] + then cp target/site/apidocs/element-list target/site/apidocs/package-list +fi + +RELEASE_VERSION=$(cat pom.xml | grep -oPm1 "(?<=)[^<]+") + +# GHA does shallow clones, so need the next 2 commands to have the gh-pages branch +git remote set-branches origin 'gh-pages' +git fetch -v + +git checkout gh-pages +mkdir -p $RELEASE_VERSION/htmlsingle +cp target/generated-docs/index.html $RELEASE_VERSION/htmlsingle +mkdir -p $RELEASE_VERSION/api +cp -r target/site/apidocs/* $RELEASE_VERSION/api/ +git add $RELEASE_VERSION/ + +if [[ $LATEST == "true" ]] + then + if [[ $RELEASE_VERSION == *[RCM]* ]] + then + DOC_DIR="milestone" + elif [[ $RELEASE_VERSION == *SNAPSHOT* ]] + then + DOC_DIR="snapshot" + else + DOC_DIR="stable" + fi + + mkdir -p $DOC_DIR/htmlsingle + cp target/generated-docs/index.html $DOC_DIR/htmlsingle + mkdir -p $DOC_DIR/api + cp -r target/site/apidocs/* $DOC_DIR/api/ + git add $DOC_DIR/ + +fi + +git commit -m "$MESSAGE" +git push origin gh-pages +git checkout main diff --git a/.ci/ubuntu/advanced.config b/.ci/ubuntu/advanced.config new file mode 100644 index 0000000..fd7d0fd --- /dev/null +++ b/.ci/ubuntu/advanced.config @@ -0,0 +1,13 @@ +[ + {rabbitmq_auth_backend_oauth2, [{key_config, + [{signing_keys, + #{<<"token-key">> => + {map, + #{<<"alg">> => <<"HS256">>, + <<"k">> => <<"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGH">>, + <<"kid">> => <<"token-key">>, + <<"kty">> => <<"oct">>, + <<"use">> => <<"sig">>, + <<"value">> => <<"token-key">>}}}}]}, + {resource_server_id,<<"rabbitmq">>}]} +]. \ No newline at end of file diff --git a/.ci/ubuntu/enabled_plugins b/.ci/ubuntu/enabled_plugins new file mode 100644 index 0000000..1f453bb --- /dev/null +++ b/.ci/ubuntu/enabled_plugins @@ -0,0 +1 @@ +[rabbitmq_auth_mechanism_ssl,rabbitmq_management,rabbitmq_stream,rabbitmq_stream_management,rabbitmq_top,rabbitmq_auth_backend_oauth2]. diff --git a/.ci/ubuntu/gha-log-check.sh b/.ci/ubuntu/gha-log-check.sh new file mode 100755 index 0000000..fef23a8 --- /dev/null +++ b/.ci/ubuntu/gha-log-check.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o xtrace +set -o nounset + +readonly docker_name_prefix='rabbitmq-amqp-go-client' + +declare -r rabbitmq_docker_name="$docker_name_prefix-rabbitmq" + +if docker logs "$rabbitmq_docker_name" | grep -iF inet_error +then + echo '[ERROR] found inet_error in RabbitMQ logs' 1>&2 + exit 1 +fi diff --git a/.ci/ubuntu/gha-setup.sh b/.ci/ubuntu/gha-setup.sh new file mode 100755 index 0000000..6eb91c8 --- /dev/null +++ b/.ci/ubuntu/gha-setup.sh @@ -0,0 +1,174 @@ +#!/usr/bin/env bash + +set -o errexit +set -o pipefail +set -o xtrace + +script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +readonly script_dir +echo "[INFO] script_dir: '$script_dir'" +readonly rabbitmq_image=rabbitmq:4.1.0-beta.4-management-alpine + + +readonly docker_name_prefix='rabbitmq-amqp-python-client' +readonly docker_network_name="$docker_name_prefix-network" + +if [[ ! -v GITHUB_ACTIONS ]] +then + GITHUB_ACTIONS='false' +fi + +if [[ -d $GITHUB_WORKSPACE ]] +then + echo "[INFO] GITHUB_WORKSPACE is set: '$GITHUB_WORKSPACE'" +else + GITHUB_WORKSPACE="$(cd "$script_dir/../.." && pwd)" + echo "[INFO] set GITHUB_WORKSPACE to: '$GITHUB_WORKSPACE'" +fi + +if [[ $1 == 'toxiproxy' ]] +then + readonly run_toxiproxy='true' +else + readonly run_toxiproxy='false' +fi + +if [[ $2 == 'pull' ]] +then + readonly docker_pull_args='--pull always' +else + readonly docker_pull_args='' +fi + +if [[ $1 == 'stop' ]] +then + docker stop "$rabbitmq_docker_name" + docker stop "$toxiproxy_docker_name" + exit 0 +fi + +set -o nounset + +declare -r rabbitmq_docker_name="$docker_name_prefix-rabbitmq" +declare -r toxiproxy_docker_name="$docker_name_prefix-toxiproxy" + +function start_toxiproxy +{ + if [[ $run_toxiproxy == 'true' ]] + then + # sudo ss -4nlp + echo "[INFO] starting Toxiproxy server docker container" + docker rm --force "$toxiproxy_docker_name" 2>/dev/null || echo "[INFO] $toxiproxy_docker_name was not running" + # shellcheck disable=SC2086 + docker run --detach $docker_pull_args \ + --name "$toxiproxy_docker_name" \ + --hostname "$toxiproxy_docker_name" \ + --publish 8474:8474 \ + --publish 55670-55680:55670-55680 \ + --network "$docker_network_name" \ + 'ghcr.io/shopify/toxiproxy:latest' + fi +} + +function start_rabbitmq +{ + echo "[INFO] starting RabbitMQ server docker container" + chmod 0777 "$GITHUB_WORKSPACE/.ci/ubuntu/log" + docker rm --force "$rabbitmq_docker_name" 2>/dev/null || echo "[INFO] $rabbitmq_docker_name was not running" + # shellcheck disable=SC2086 + docker run --detach $docker_pull_args \ + --name "$rabbitmq_docker_name" \ + --hostname "$rabbitmq_docker_name" \ + --publish 5671:5671 \ + --publish 5672:5672 \ + --publish 15672:15672 \ + --network "$docker_network_name" \ + --volume "$GITHUB_WORKSPACE/.ci/ubuntu/enabled_plugins:/etc/rabbitmq/enabled_plugins" \ + --volume "$GITHUB_WORKSPACE/.ci/ubuntu/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro" \ + --volume "$GITHUB_WORKSPACE/.ci/ubuntu/advanced.config:/etc/rabbitmq/advanced.config:ro" \ + --volume "$GITHUB_WORKSPACE/.ci/certs:/etc/rabbitmq/certs:ro" \ + --volume "$GITHUB_WORKSPACE/.ci/ubuntu/log:/var/log/rabbitmq" \ + "$rabbitmq_image" +} + +function wait_rabbitmq +{ + set +o errexit + set +o xtrace + + declare -i count=12 + while (( count > 0 )) && [[ "$(docker inspect --format='{{.State.Running}}' "$rabbitmq_docker_name")" != 'true' ]] + do + echo '[WARNING] RabbitMQ container is not yet running...' + sleep 5 + (( count-- )) + done + + declare -i count=12 + while (( count > 0 )) && ! docker exec "$rabbitmq_docker_name" epmd -names | grep -F 'name rabbit' + do + echo '[WARNING] epmd is not reporting rabbit name just yet...' + sleep 5 + (( count-- )) + done + + set -o xtrace + + docker exec "$rabbitmq_docker_name" rabbitmqctl await_startup + docker exec "$rabbitmq_docker_name" rabbitmq-diagnostics erlang_version + docker exec "$rabbitmq_docker_name" rabbitmqctl version + + set -o errexit +} + +function get_rabbitmq_id +{ + local rabbitmq_docker_id + rabbitmq_docker_id="$(docker inspect --format='{{.Id}}' "$rabbitmq_docker_name")" + echo "[INFO] '$rabbitmq_docker_name' docker id is '$rabbitmq_docker_id'" + if [[ -v GITHUB_OUTPUT ]] + then + if [[ -f $GITHUB_OUTPUT ]] + then + echo "[INFO] GITHUB_OUTPUT file: '$GITHUB_OUTPUT'" + fi + echo "id=$rabbitmq_docker_id" >> "$GITHUB_OUTPUT" + fi +} + +function install_ca_certificate +{ + set +o errexit + hostname + hostname -s + hostname -f + openssl version + openssl version -d + set -o errexit + + if [[ $GITHUB_ACTIONS == 'true' ]] + then + readonly openssl_store_dir='/usr/lib/ssl/certs' + sudo cp -vf "$GITHUB_WORKSPACE/.ci/certs/ca_certificate.pem" "$openssl_store_dir" + sudo ln -vsf "$openssl_store_dir/ca_certificate.pem" "$openssl_store_dir/$(openssl x509 -hash -noout -in $openssl_store_dir/ca_certificate.pem).0" + else + echo "[WARNING] you must install '$GITHUB_WORKSPACE/.ci/certs/ca_certificate.pem' manually into your trusted root store" + fi + + openssl s_client -connect localhost:5671 \ + -CAfile "$GITHUB_WORKSPACE/.ci/certs/ca_certificate.pem" \ + -cert "$GITHUB_WORKSPACE/.ci/certs/client_localhost_certificate.pem" \ + -key "$GITHUB_WORKSPACE/.ci/certs/client_localhost_key.pem" +} + +docker network create "$docker_network_name" || echo "[INFO] network '$docker_network_name' is already created" + +start_toxiproxy + +start_rabbitmq + +wait_rabbitmq + +get_rabbitmq_id + +install_ca_certificate diff --git a/.ci/ubuntu/log/.gitkeep b/.ci/ubuntu/log/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.ci/ubuntu/rabbitmq.conf b/.ci/ubuntu/rabbitmq.conf new file mode 100644 index 0000000..89b64f4 --- /dev/null +++ b/.ci/ubuntu/rabbitmq.conf @@ -0,0 +1,29 @@ +loopback_users = none +loopback_users.guest = true + +log.console = true +log.console.level = debug +log.file = /var/log/rabbitmq/rabbitmq.log +log.file.level = debug +log.exchange = false + +listeners.tcp.default = 5672 +listeners.ssl.default = 5671 +reverse_dns_lookups = false + +deprecated_features.permit.amqp_address_v1 = false + +ssl_options.cacertfile = /etc/rabbitmq/certs/ca_certificate.pem +ssl_options.certfile = /etc/rabbitmq/certs/server_localhost_certificate.pem +ssl_options.keyfile = /etc/rabbitmq/certs/server_localhost_key.pem +ssl_options.verify = verify_peer +ssl_options.depth = 1 +ssl_options.fail_if_no_peer_cert = false + +#auth_mechanisms.1 = PLAIN +#auth_mechanisms.2 = ANONYMOUS +#auth_mechanisms.3 = EXTERNAL + + +auth_backends.1 = internal +auth_backends.2 = rabbit_auth_backend_oauth2 diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index b6b9108..fdd9930 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -24,38 +24,9 @@ jobs: - uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build and export - uses: docker/build-push-action@v6 - with: - context: . - tags: rabbitmq_tls:latest - outputs: type=docker,dest=/tmp/rabbitmq_tls.tar - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: rabbitmq_tls - path: /tmp/rabbitmq_tls.tar - - name: Download artifact - uses: actions/download-artifact@v4 - with: - name: rabbitmq_tls - path: /tmp - - name: Load image - run: | - docker load --input /tmp/rabbitmq_tls.tar - docker image ls -a - docker run -d --rm --name rabbitmq-stream-client-test \ - -p 5552:5552 -p 5672:5672 -p 5671:5671 -p 5551:5551 -p 15672:15672 \ - -e RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="-rabbitmq_stream advertised_host localhost" \ - rabbitmq_tls - - name: wait for running - run: | - docker exec rabbitmq-stream-client-test /bin/bash -c 'ps -aux' - docker exec rabbitmq-stream-client-test /bin/bash -c 'sleep 10' - docker exec rabbitmq-stream-client-test /bin/bash -c 'rabbitmqctl status' - docker exec rabbitmq-stream-client-test /bin/bash -c 'rabbitmqctl wait --pid 1 --timeout 70' + - name: Start RabbitMQ + id: start-rabbitmq + run: ${{ github.workspace }}/.ci/ubuntu/gha-setup.sh - name: Install and configure Poetry uses: snok/install-poetry@v1 with: diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 5adcbfb..0000000 --- a/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM rabbitmq:4-management -#FROM pivotalrabbitmq/rabbitmq:sha-ae9fbb7bd5982aff099293adbb1edcd616ef806f - - -COPY .ci/conf/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf -COPY .ci/conf/enabled_plugins /etc/rabbitmq/enabled_plugins - -COPY .ci/certs /etc/rabbitmq/certs diff --git a/Makefile b/Makefile index 3cc9675..616547b 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,10 @@ all: test build rabbitmq-server: - docker build -t rabbitmq-tls-test . - docker run -it --rm --name rabbitmq-tls-test \ - -p 5672:5672 -p 5671:5671 -p 15672:15672 \ - -e RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="-rabbitmq_stream advertised_host localhost" \ - rabbitmq-tls-test + ./.ci/ubuntu/gha-setup.sh start pull + +rabbitmq-server-stop: + ./.ci/ubuntu/gha-setup.sh stop help: cat Makefile diff --git a/tests/conftest.py b/tests/conftest.py index 859340c..fbaabd8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -67,9 +67,9 @@ def connection_with_reconnect(pytestconfig): def ssl_context(pytestconfig): if sys.platform == "win32": return WinSslConfigurationContext( - ca_store=PKCS12Store(path=".ci/certs/ca.p12"), + ca_store=PKCS12Store(path=".ci/certs/server_localhost.p12"), client_cert=WinClientCert( - store=PKCS12Store(path=".ci/certs/client.p12"), + store=PKCS12Store(path=".ci/certs/client_localhost.p12"), disambiguation_method=FriendlyName(name="1"), ), ) @@ -77,8 +77,8 @@ def ssl_context(pytestconfig): return PosixSslConfigurationContext( ca_cert=".ci/certs/ca_certificate.pem", client_cert=PosixClientCert( - client_cert=".ci/certs/client_certificate.pem", - client_key=".ci/certs/client_key.pem", + client_cert=".ci/certs/client_localhost_certificate.pem", + client_key=".ci/certs/client_localhost_key.pem", ), ) From a6dbdde8cdb2fa60c708a3ad0b1028e4334fdbdc Mon Sep 17 00:00:00 2001 From: DanielePalaia Date: Wed, 19 Mar 2025 09:37:07 +0100 Subject: [PATCH 2/7] adding oauth configuration --- poetry.lock | 87 +++++++++++++++++++++- pyproject.toml | 2 + rabbitmq_amqp_python_client/__init__.py | 2 + rabbitmq_amqp_python_client/connection.py | 57 ++++++++++---- rabbitmq_amqp_python_client/entities.py | 5 ++ rabbitmq_amqp_python_client/environment.py | 5 +- tests/conftest.py | 17 +++++ tests/test_connection.py | 7 ++ tests/utils.py | 33 ++++++++ 9 files changed, 196 insertions(+), 19 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7dafe77..44189aa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -262,6 +262,55 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "cryptography" +version = "43.0.3" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] +nox = ["nox"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -331,6 +380,19 @@ files = [ [package.extras] colors = ["colorama (>=0.4.6)"] +[[package]] +name = "jwt" +version = "1.3.1" +description = "JSON Web Token library for Python 3." +optional = false +python-versions = ">= 3.6" +files = [ + {file = "jwt-1.3.1-py3-none-any.whl", hash = "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494"}, +] + +[package.dependencies] +cryptography = ">=3.1,<3.4.0 || >3.4.0" + [[package]] name = "mccabe" version = "0.7.0" @@ -479,15 +541,32 @@ files = [ {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, ] +[[package]] +name = "pyjwt" +version = "2.10.1" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + [[package]] name = "pytest" -version = "8.3.4" +version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, - {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, + {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, + {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, ] [package.dependencies] @@ -623,4 +702,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "9436dade4f0387b0b81013c2b05a4d42241fb0fd9274213567b078447611dd37" +content-hash = "bb7a06bbf007a9ad6b1e9d790070648964138074b0472e6fd0b4d5a4f69033a0" diff --git a/pyproject.toml b/pyproject.toml index 11a8e87..413e45a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,8 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.9" python-qpid-proton = "^0.39.0" +jwt = "^1.3.1" +pyjwt = "^2.10.1" [tool.poetry.group.dev.dependencies] flake8 = "^7.1.1" diff --git a/rabbitmq_amqp_python_client/__init__.py b/rabbitmq_amqp_python_client/__init__.py index a41a13d..cdb623a 100644 --- a/rabbitmq_amqp_python_client/__init__.py +++ b/rabbitmq_amqp_python_client/__init__.py @@ -10,6 +10,7 @@ ExchangeSpecification, ExchangeToExchangeBindingSpecification, ExchangeToQueueBindingSpecification, + OAuth2Options, OffsetSpecification, RecoveryConfiguration, StreamOptions, @@ -89,4 +90,5 @@ "Environment", "ExchangeCustomSpecification", "RecoveryConfiguration", + "OAuth2Options", ] diff --git a/rabbitmq_amqp_python_client/connection.py b/rabbitmq_amqp_python_client/connection.py index 884c82f..cdb18bf 100644 --- a/rabbitmq_amqp_python_client/connection.py +++ b/rabbitmq_amqp_python_client/connection.py @@ -14,7 +14,11 @@ from .address_helper import validate_address from .consumer import Consumer -from .entities import RecoveryConfiguration, StreamOptions +from .entities import ( + OAuth2Options, + RecoveryConfiguration, + StreamOptions, +) from .exceptions import ( ArgumentOutOfRangeException, ValidationCodeException, @@ -60,6 +64,7 @@ def __init__( ssl_context: Union[ PosixSslConfigurationContext, WinSslConfigurationContext, None ] = None, + oauth2_options: Optional[OAuth2Options] = None, recovery_configuration: RecoveryConfiguration = RecoveryConfiguration(), ): """ @@ -93,6 +98,7 @@ def __init__( self._index: int = -1 self._publishers: list[Publisher] = [] self._consumers: list[Consumer] = [] + self._oauth2_options = oauth2_options # Some recovery_configuration validation if recovery_configuration.back_off_reconnect_interval < timedelta(seconds=1): @@ -109,19 +115,8 @@ def _set_environment_connection_list(self, connections: []): # type: ignore def _open_connections(self, reconnect_handlers: bool = False) -> None: logger.debug("inside connection._open_connections creating connection") - if self._recovery_configuration.active_recovery is False: - self._conn = BlockingConnection( - url=self._addr, - urls=self._addrs, - ssl_domain=self._ssl_domain, - ) - else: - self._conn = BlockingConnection( - url=self._addr, - urls=self._addrs, - ssl_domain=self._ssl_domain, - on_disconnection_handler=self._on_disconnection, - ) + + self._create_connection() if reconnect_handlers is True: logger.debug("reconnecting managements, publishers and consumers handlers") @@ -137,6 +132,40 @@ def _open_connections(self, reconnect_handlers: bool = False) -> None: # Update the broken connection and sender in the consumer self._consumers[i]._update_connection(self._conn) + def _create_connection(self) -> None: + + user = None + password = None + mechs = None + + if self._oauth2_options is not None: + user = "" + password = self._oauth2_options.token + mechs = "PLAIN" + print("password, mechs: " + user + " " + password) + + if self._recovery_configuration.active_recovery is False: + self._conn = BlockingConnection( + url=self._addr, + urls=self._addrs, + oauth2_options=self._oauth2_options, + ssl_domain=self._ssl_domain, + allowed_mechs=mechs, + user=user, + password=password, + ) + else: + self._conn = BlockingConnection( + url=self._addr, + urls=self._addrs, + oauth2_options=self._oauth2_options, + ssl_domain=self._ssl_domain, + on_disconnection_handler=self._on_disconnection, + allowed_mechs=mechs, + user=user, + password=password, + ) + def dial(self) -> None: """ Establish a connection to the AMQP server. diff --git a/rabbitmq_amqp_python_client/entities.py b/rabbitmq_amqp_python_client/entities.py index 0577375..a9c6a65 100644 --- a/rabbitmq_amqp_python_client/entities.py +++ b/rabbitmq_amqp_python_client/entities.py @@ -257,3 +257,8 @@ class RecoveryConfiguration: active_recovery: bool = True back_off_reconnect_interval: timedelta = timedelta(seconds=5) MaxReconnectAttempts: int = 5 + + +@dataclass +class OAuth2Options: + token: str diff --git a/rabbitmq_amqp_python_client/environment.py b/rabbitmq_amqp_python_client/environment.py index c2adef9..657c7a2 100644 --- a/rabbitmq_amqp_python_client/environment.py +++ b/rabbitmq_amqp_python_client/environment.py @@ -9,7 +9,7 @@ ) from .connection import Connection -from .entities import RecoveryConfiguration +from .entities import OAuth2Options, RecoveryConfiguration from .ssl_configuration import ( PosixSslConfigurationContext, WinSslConfigurationContext, @@ -41,6 +41,7 @@ def __init__( ssl_context: Union[ PosixSslConfigurationContext, WinSslConfigurationContext, None ] = None, + oauth2_options: Optional[OAuth2Options] = None, recovery_configuration: RecoveryConfiguration = RecoveryConfiguration(), ): """ @@ -66,6 +67,7 @@ def __init__( self._ssl_context = ssl_context self._recovery_configuration = recovery_configuration self._connections: list[Connection] = [] + self._oauth2_options = oauth2_options def connection( self, @@ -86,6 +88,7 @@ def connection( uri=self._uri, uris=self._uris, ssl_context=self._ssl_context, + oauth2_options=self._oauth2_options, recovery_configuration=self._recovery_configuration, ) logger.debug("Environment: Creating and returning a new connection") diff --git a/tests/conftest.py b/tests/conftest.py index fbaabd8..2552463 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ import os import sys +from datetime import datetime, timedelta from typing import Optional import pytest @@ -9,6 +10,7 @@ AMQPMessagingHandler, Environment, Event, + OAuth2Options, PKCS12Store, PosixClientCert, PosixSslConfigurationContext, @@ -22,6 +24,7 @@ ) from .http_requests import delete_all_connections +from .utils import token os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -36,6 +39,20 @@ def environment(pytestconfig): environment.close() +@pytest.fixture() +def environment_auth(pytestconfig): + token_string = token(datetime.now() + timedelta(milliseconds=2500)) + environment = Environment( + uri="amqp://localhost:5672", + oauth2_options=OAuth2Options(token=token_string), + ) + try: + yield environment + + finally: + environment.close() + + @pytest.fixture() def connection(pytestconfig): environment = Environment(uri="amqp://guest:guest@localhost:5672/") diff --git a/tests/test_connection.py b/tests/test_connection.py index 0f18410..4a9ef44 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -43,6 +43,13 @@ def test_connection_ssl(ssl_context) -> None: environment.close() +def test_connection_auth(environment_auth: Environment) -> None: + + connection = environment_auth.connection() + connection.dial() + connection.close() + + def test_environment_connections_management() -> None: environment = Environment(uri="amqp://guest:guest@localhost:5672/") diff --git a/tests/utils.py b/tests/utils.py index bc4ecca..dfc32f6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,5 +1,9 @@ +import base64 +from datetime import datetime from typing import Optional +import jwt + from rabbitmq_amqp_python_client import ( AddressHelper, Connection, @@ -92,3 +96,32 @@ def cleanup_dead_lettering(management: Management, bind_path: str) -> None: management.unbind(bind_path) management.delete_exchange(exchange_dead_lettering) management.delete_queue(queue_dead_lettering) + + +def token(duration: datetime) -> str: + # Decode the base64 key + decoded_key = base64.b64decode("abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGH") + + # Define the claims + claims = { + "iss": "unit_test", + "aud": "rabbitmq", + "exp": duration, + "scope": ["rabbitmq.configure:*/*", "rabbitmq.write:*/*", "rabbitmq.read:*/*"], + "random": random_string(6), + } + + # Create the token with the claims and sign it + token = jwt.encode( + claims, decoded_key, algorithm="HS256", headers={"kid": "token-key"} + ) + + return token + + +# Helper function to generate a random string (replace with your implementation) +def random_string(length: int) -> str: + import random + import string + + return "".join(random.choices(string.ascii_letters + string.digits, k=length)) From 2651308af431d828090e9c39442de19e4de443af Mon Sep 17 00:00:00 2001 From: Gabriele Santomaggio Date: Mon, 24 Mar 2025 14:05:47 +0100 Subject: [PATCH 3/7] Fix (#58) * Fix Signed-off-by: Gabriele Santomaggio * formatting --------- Signed-off-by: Gabriele Santomaggio Co-authored-by: Daniele --- poetry.lock | 102 +++++++----------- pyproject.toml | 1 - rabbitmq_amqp_python_client/connection.py | 2 +- .../qpid/proton/_utils.py | 3 +- tests/conftest.py | 8 +- tests/utils.py | 6 +- 6 files changed, 46 insertions(+), 76 deletions(-) diff --git a/poetry.lock b/poetry.lock index 44189aa..2068e43 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "black" @@ -6,6 +6,7 @@ version = "24.10.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, @@ -52,6 +53,7 @@ version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, @@ -63,6 +65,7 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -142,6 +145,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -243,6 +247,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -257,66 +262,21 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "cryptography" -version = "43.0.3" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, - {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, - {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, - {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, - {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, - {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, - {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, - {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, - {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, - {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, - {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, - {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, - {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, - {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, - {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, -] - -[package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] -nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] -sdist = ["build"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] -test-randomorder = ["pytest-randomly"] - [[package]] name = "exceptiongroup" version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -331,6 +291,7 @@ version = "7.1.2" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" +groups = ["dev"] files = [ {file = "flake8-7.1.2-py2.py3-none-any.whl", hash = "sha256:1cbc62e65536f65e6d754dfe6f1bada7f5cf392d6f5db3c2b85892466c3e7c1a"}, {file = "flake8-7.1.2.tar.gz", hash = "sha256:c586ffd0b41540951ae41af572e6790dbd49fc12b3aa2541685d253d9bd504bd"}, @@ -347,6 +308,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -361,6 +323,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -372,6 +335,7 @@ version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" +groups = ["dev"] files = [ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, @@ -380,25 +344,13 @@ files = [ [package.extras] colors = ["colorama (>=0.4.6)"] -[[package]] -name = "jwt" -version = "1.3.1" -description = "JSON Web Token library for Python 3." -optional = false -python-versions = ">= 3.6" -files = [ - {file = "jwt-1.3.1-py3-none-any.whl", hash = "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494"}, -] - -[package.dependencies] -cryptography = ">=3.1,<3.4.0 || >3.4.0" - [[package]] name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -410,6 +362,7 @@ version = "0.910" description = "Optional static typing for Python" optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, @@ -451,6 +404,7 @@ version = "0.4.4" description = "Experimental type system extensions for programs checked with the mypy typechecker." optional = false python-versions = ">=2.7" +groups = ["dev"] files = [ {file = "mypy_extensions-0.4.4.tar.gz", hash = "sha256:c8b707883a96efe9b4bb3aaf0dcc07e7e217d7d8368eec4db4049ee9e142f4fd"}, ] @@ -461,6 +415,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -472,6 +427,7 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -483,6 +439,7 @@ version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, @@ -499,6 +456,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -514,6 +472,7 @@ version = "2.12.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, @@ -525,6 +484,7 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -536,6 +496,7 @@ version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, @@ -547,6 +508,7 @@ version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, @@ -564,6 +526,7 @@ version = "8.3.5" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, @@ -586,6 +549,7 @@ version = "0.39.0" description = "An AMQP based messaging library." optional = false python-versions = "*" +groups = ["main", "dev"] files = [ {file = "python-qpid-proton-0.39.0.tar.gz", hash = "sha256:362055ae6ab4c7f1437247c602757f30328d55c0a6986d5b68ca9798de9fce02"}, {file = "python_qpid_proton-0.39.0-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:f69da296ffa9e3b22f88a53fe9e27c4f4844e088a9f041061bd4f75f74f2a0af"}, @@ -604,6 +568,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -625,6 +590,7 @@ version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["dev"] files = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, @@ -636,6 +602,8 @@ version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, @@ -677,6 +645,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -688,18 +657,19 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["dev"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.9" -content-hash = "bb7a06bbf007a9ad6b1e9d790070648964138074b0472e6fd0b4d5a4f69033a0" +content-hash = "3daaf4d89df7cd9bbd363a611db81f1339f4dfb78f4760b454d939b2b57bdfba" diff --git a/pyproject.toml b/pyproject.toml index 413e45a..2a28892 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.9" python-qpid-proton = "^0.39.0" -jwt = "^1.3.1" pyjwt = "^2.10.1" [tool.poetry.group.dev.dependencies] diff --git a/rabbitmq_amqp_python_client/connection.py b/rabbitmq_amqp_python_client/connection.py index cdb18bf..b00f940 100644 --- a/rabbitmq_amqp_python_client/connection.py +++ b/rabbitmq_amqp_python_client/connection.py @@ -139,7 +139,7 @@ def _create_connection(self) -> None: mechs = None if self._oauth2_options is not None: - user = "" + user = "no" password = self._oauth2_options.token mechs = "PLAIN" print("password, mechs: " + user + " " + password) diff --git a/rabbitmq_amqp_python_client/qpid/proton/_utils.py b/rabbitmq_amqp_python_client/qpid/proton/_utils.py index ff0b504..4be2ff2 100644 --- a/rabbitmq_amqp_python_client/qpid/proton/_utils.py +++ b/rabbitmq_amqp_python_client/qpid/proton/_utils.py @@ -467,7 +467,8 @@ def __init__( ) except ConnectionException: - self.conn.close() + if self.conn is not None: + self.conn.close() if attempt == len(urls): raise continue diff --git a/tests/conftest.py b/tests/conftest.py index 2552463..3617556 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -46,11 +46,11 @@ def environment_auth(pytestconfig): uri="amqp://localhost:5672", oauth2_options=OAuth2Options(token=token_string), ) - try: - yield environment + # try: + return environment - finally: - environment.close() + # finally: + # environment.close() @pytest.fixture() diff --git a/tests/utils.py b/tests/utils.py index dfc32f6..2b0a7f0 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -106,17 +106,17 @@ def token(duration: datetime) -> str: claims = { "iss": "unit_test", "aud": "rabbitmq", - "exp": duration, + "exp": int(duration.timestamp()), "scope": ["rabbitmq.configure:*/*", "rabbitmq.write:*/*", "rabbitmq.read:*/*"], "random": random_string(6), } # Create the token with the claims and sign it - token = jwt.encode( + jwt_token = jwt.encode( claims, decoded_key, algorithm="HS256", headers={"kid": "token-key"} ) - return token + return jwt_token # Helper function to generate a random string (replace with your implementation) From c3a35ea28d9d801cb776625bc750ce613f12ea44 Mon Sep 17 00:00:00 2001 From: DanielePalaia Date: Mon, 24 Mar 2025 14:11:30 +0100 Subject: [PATCH 4/7] test --- tests/conftest.py | 8 ++++---- tests/test_connection.py | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 3617556..2552463 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -46,11 +46,11 @@ def environment_auth(pytestconfig): uri="amqp://localhost:5672", oauth2_options=OAuth2Options(token=token_string), ) - # try: - return environment + try: + yield environment - # finally: - # environment.close() + finally: + environment.close() @pytest.fixture() diff --git a/tests/test_connection.py b/tests/test_connection.py index 4a9ef44..e776d83 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -4,6 +4,7 @@ from rabbitmq_amqp_python_client import ( ConnectionClosed, Environment, + QuorumQueueSpecification, RecoveryConfiguration, StreamSpecification, ValidationCodeException, @@ -47,6 +48,27 @@ def test_connection_auth(environment_auth: Environment) -> None: connection = environment_auth.connection() connection.dial() + management = connection.management() + management.declare_queue(QuorumQueueSpecification(name="test-queue")) + management.close() + connection.close() + + +def test_connection_auth_with_timeout(environment_auth: Environment) -> None: + + connection = environment_auth.connection() + connection.dial() + # let the token expire + time.sleep(3) + raised = False + # token expired + try: + management = connection.management() + management.declare_queue(QuorumQueueSpecification(name="test-queue")) + except Exception: + raised = True + + assert raised is True connection.close() From 797b6f33d0b41f6c3ed6bb80622f05afe91a67c7 Mon Sep 17 00:00:00 2001 From: DanielePalaia Date: Mon, 24 Mar 2025 14:44:44 +0100 Subject: [PATCH 5/7] refresh_token --- rabbitmq_amqp_python_client/common.py | 1 + rabbitmq_amqp_python_client/connection.py | 47 ++++++++++++++++------- rabbitmq_amqp_python_client/management.py | 11 ++++++ tests/test_connection.py | 29 ++++++++++++-- 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/rabbitmq_amqp_python_client/common.py b/rabbitmq_amqp_python_client/common.py index 1aa8f73..84a4346 100644 --- a/rabbitmq_amqp_python_client/common.py +++ b/rabbitmq_amqp_python_client/common.py @@ -18,6 +18,7 @@ class CommonValues(enum.Enum): key = "key" queue = "queues" bindings = "bindings" + path_tokens = "/auth/tokens" class ExchangeType(enum.Enum): diff --git a/rabbitmq_amqp_python_client/connection.py b/rabbitmq_amqp_python_client/connection.py index b00f940..6c51a71 100644 --- a/rabbitmq_amqp_python_client/connection.py +++ b/rabbitmq_amqp_python_client/connection.py @@ -134,15 +134,14 @@ def _open_connections(self, reconnect_handlers: bool = False) -> None: def _create_connection(self) -> None: - user = None - password = None - mechs = None + self._user = None + self._password = None + self._mechs = None if self._oauth2_options is not None: - user = "no" - password = self._oauth2_options.token - mechs = "PLAIN" - print("password, mechs: " + user + " " + password) + self._user = "no" + self._password = self._oauth2_options.token + self._mechs = "PLAIN" if self._recovery_configuration.active_recovery is False: self._conn = BlockingConnection( @@ -150,9 +149,9 @@ def _create_connection(self) -> None: urls=self._addrs, oauth2_options=self._oauth2_options, ssl_domain=self._ssl_domain, - allowed_mechs=mechs, - user=user, - password=password, + allowed_mechs=self._mechs, + user=self._user, + password=self._password, ) else: self._conn = BlockingConnection( @@ -161,9 +160,9 @@ def _create_connection(self) -> None: oauth2_options=self._oauth2_options, ssl_domain=self._ssl_domain, on_disconnection_handler=self._on_disconnection, - allowed_mechs=mechs, - user=user, - password=password, + allowed_mechs=self._mechs, + user=self._user, + password=self._password, ) def dial(self) -> None: @@ -383,3 +382,25 @@ def active_producers(self) -> int: def active_consumers(self) -> int: """Returns the number of active consumers""" return len(self._consumers) + + def refresh_token(self, token: str) -> None: + """ + Refresh the oauth token + + Args: + token: the oauth token to refresh + + Raises: + ValidationCodeException: If oauth is not enabled + """ + + if self._oauth2_options is None: + raise ValidationCodeException("the connection is not oauth enabled") + + # update credentials (for reconnection) + self._user = "no" + self._password = self._oauth2_options.token + self._mechs = "PLAIN" + + management = self.management() + management.refresh_token(token) diff --git a/rabbitmq_amqp_python_client/management.py b/rabbitmq_amqp_python_client/management.py index 1c6550b..9ba75ac 100644 --- a/rabbitmq_amqp_python_client/management.py +++ b/rabbitmq_amqp_python_client/management.py @@ -573,3 +573,14 @@ def queue_info(self, name: str) -> QueueInfo: message_count=queue_info["message_count"], consumer_count=queue_info["consumer_count"], ) + + def refresh_token(self, token: str) -> None: + + self.request( + token.encode(), + CommonValues.path_tokens.value, + CommonValues.command_put.value, + [ + CommonValues.response_code_204.value, + ], + ) diff --git a/tests/test_connection.py b/tests/test_connection.py index e776d83..10f933b 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1,5 +1,5 @@ import time -from datetime import timedelta +from datetime import datetime, timedelta from rabbitmq_amqp_python_client import ( ConnectionClosed, @@ -11,6 +11,7 @@ ) from .http_requests import delete_all_connections +from .utils import token def on_disconnected(): @@ -44,7 +45,7 @@ def test_connection_ssl(ssl_context) -> None: environment.close() -def test_connection_auth(environment_auth: Environment) -> None: +def test_connection_oauth(environment_auth: Environment) -> None: connection = environment_auth.connection() connection.dial() @@ -54,7 +55,7 @@ def test_connection_auth(environment_auth: Environment) -> None: connection.close() -def test_connection_auth_with_timeout(environment_auth: Environment) -> None: +def test_connection_oauth_with_timeout(environment_auth: Environment) -> None: connection = environment_auth.connection() connection.dial() @@ -65,10 +66,32 @@ def test_connection_auth_with_timeout(environment_auth: Environment) -> None: try: management = connection.management() management.declare_queue(QuorumQueueSpecification(name="test-queue")) + management.close() except Exception: raised = True assert raised is True + + connection.close() + + +def test_connection_oauth_refresh_token(environment_auth: Environment) -> None: + + connection = environment_auth.connection() + connection.dial() + # let the token expire + time.sleep(1) + raised = False + # token expired, refresh + connection.refresh_token(token(datetime.now() + timedelta(milliseconds=5000))) + time.sleep(3) + try: + management = connection.management() + management.declare_queue(QuorumQueueSpecification(name="test-queue")) + except Exception: + raised = True + + assert raised is False connection.close() From 6ba0c2e4c1c79063e762a911f33cec33941a3d84 Mon Sep 17 00:00:00 2001 From: Daniele Palaia Date: Tue, 25 Mar 2025 09:53:00 +0100 Subject: [PATCH 6/7] adding oauth example --- examples/README.md | 3 +- examples/oauth/oaut.py | 220 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 examples/oauth/oaut.py diff --git a/examples/README.md b/examples/README.md index 4c12d6b..123539c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,4 +3,5 @@ Client examples - [Getting started](./getting_started/getting_started.py) - Producer and Consumer example without reconnection - [Reconnection](./reconnection/reconnection_example.py) - Producer and Consumer example with reconnection - [TLS](./tls/tls_example.py) - Producer and Consumer using a TLS connection - - [Streams](./streams/example_with_streams.py) - Example supporting stream capabilities \ No newline at end of file + - [Streams](./streams/example_with_streams.py) - Example supporting stream capabilities + - [Oauth](./oauth/oauth.py) - Connection through Oauth token \ No newline at end of file diff --git a/examples/oauth/oaut.py b/examples/oauth/oaut.py new file mode 100644 index 0000000..56f16e8 --- /dev/null +++ b/examples/oauth/oaut.py @@ -0,0 +1,220 @@ +# type: ignore + + +import base64 +from datetime import datetime, timedelta + +import jwt + +from rabbitmq_amqp_python_client import ( # PosixSSlConfigurationContext,; PosixClientCert, + AddressHelper, + AMQPMessagingHandler, + Connection, + Environment, + Event, + ExchangeSpecification, + ExchangeToQueueBindingSpecification, + Message, + OAuth2Options, + OutcomeState, + QuorumQueueSpecification, +) + +MESSAGES_TO_PUBLISH = 100 + + +class MyMessageHandler(AMQPMessagingHandler): + + def __init__(self): + super().__init__() + self._count = 0 + + def on_amqp_message(self, event: Event): + print("received message: " + str(event.message.body)) + + # accepting + self.delivery_context.accept(event) + + # in case of rejection (+eventually deadlettering) + # self.delivery_context.discard(event) + + # in case of requeuing + # self.delivery_context.requeue(event) + + # annotations = {} + # annotations[symbol('x-opt-string')] = 'x-test1' + # in case of requeuing with annotations added + # self.delivery_context.requeue_with_annotations(event, annotations) + + # in case of rejection with annotations added + # self.delivery_context.discard_with_annotations(event) + + print("count " + str(self._count)) + + self._count = self._count + 1 + + if self._count == MESSAGES_TO_PUBLISH: + print("closing receiver") + # if you want you can add cleanup operations here + + def on_connection_closed(self, event: Event): + # if you want you can add cleanup operations here + print("connection closed") + + def on_link_closed(self, event: Event) -> None: + # if you want you can add cleanup operations here + print("link closed") + + +def create_connection(environment: Environment) -> Connection: + connection = environment.connection() + # in case of SSL enablement + # ca_cert_file = ".ci/certs/ca_certificate.pem" + # client_cert = ".ci/certs/client_certificate.pem" + # client_key = ".ci/certs/client_key.pem" + # connection = Connection( + # "amqps://guest:guest@localhost:5671/", + # ssl_context=PosixSslConfigurationContext( + # ca_cert=ca_cert_file, + # client_cert=ClientCert(client_cert=client_cert, client_key=client_key), + # ), + # ) + connection.dial() + + return connection + + +def main() -> None: + + exchange_name = "test-exchange" + queue_name = "example-queue" + routing_key = "routing-key" + + print("connection to amqp server") + oaut_token = token( + datetime.now() + timedelta(milliseconds=2500), + "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGH", + ) + environment = Environment( + uri="amqp://localhost:5672", oauth2_options=OAuth2Options(token=oaut_token) + ) + connection = create_connection(environment) + + # you can refresh the oaut token with the connection api + oaut_token = token( + datetime.now() + timedelta(milliseconds=10000), + "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGH", + ) + + connection.refresh_token( + oaut_token, + ) + + management = connection.management() + + print("declaring exchange and queue") + management.declare_exchange(ExchangeSpecification(name=exchange_name)) + + management.declare_queue( + QuorumQueueSpecification(name=queue_name) + # QuorumQueueSpecification(name=queue_name, dead_letter_exchange="dead-letter") + ) + + print("binding queue to exchange") + bind_name = management.bind( + ExchangeToQueueBindingSpecification( + source_exchange=exchange_name, + destination_queue=queue_name, + binding_key=routing_key, + ) + ) + + addr = AddressHelper.exchange_address(exchange_name, routing_key) + + addr_queue = AddressHelper.queue_address(queue_name) + + print("create a publisher and publish a test message") + publisher = connection.publisher(addr) + + print("purging the queue") + messages_purged = management.purge_queue(queue_name) + + print("messages purged: " + str(messages_purged)) + # management.close() + + # publish 10 messages + for i in range(MESSAGES_TO_PUBLISH): + print("publishing") + status = publisher.publish(Message(body="test")) + if status.remote_state == OutcomeState.ACCEPTED: + print("message accepted") + elif status.remote_state == OutcomeState.RELEASED: + print("message not routed") + elif status.remote_state == OutcomeState.REJECTED: + print("message not rejected") + + publisher.close() + + print( + "create a consumer and consume the test message - press control + c to terminate to consume" + ) + consumer = connection.consumer(addr_queue, message_handler=MyMessageHandler()) + + try: + consumer.run() + except KeyboardInterrupt: + pass + + print("cleanup") + consumer.close() + # once we finish consuming if we close the connection we need to create a new one + # connection = create_connection() + management = connection.management() + + print("unbind") + management.unbind(bind_name) + + print("delete queue") + management.delete_queue(queue_name) + + print("delete exchange") + management.delete_exchange(exchange_name) + + print("closing connections") + management.close() + print("after management closing") + environment.close() + print("after connection closing") + + +def token(duration: datetime, token: str) -> str: + # Decode the base64 key + decoded_key = base64.b64decode(token) + + # Define the claims + claims = { + "iss": "unit_test", + "aud": "rabbitmq", + "exp": int(duration.timestamp()), + "scope": ["rabbitmq.configure:*/*", "rabbitmq.write:*/*", "rabbitmq.read:*/*"], + "random": random_string(6), + } + + # Create the token with the claims and sign it + jwt_token = jwt.encode( + claims, decoded_key, algorithm="HS256", headers={"kid": "token-key"} + ) + + return jwt_token + + +# Helper function to generate a random string (replace with your implementation) +def random_string(length: int) -> str: + import random + import string + + return "".join(random.choices(string.ascii_letters + string.digits, k=length)) + + +if __name__ == "__main__": + main() From 61a094c4dd5de45e174693a39aaa30e33db1cef7 Mon Sep 17 00:00:00 2001 From: Daniele Palaia Date: Wed, 26 Mar 2025 09:25:28 +0100 Subject: [PATCH 7/7] review comments --- .ci/ubuntu/gha-log-check.sh | 2 +- rabbitmq_amqp_python_client/connection.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.ci/ubuntu/gha-log-check.sh b/.ci/ubuntu/gha-log-check.sh index fef23a8..3b68178 100755 --- a/.ci/ubuntu/gha-log-check.sh +++ b/.ci/ubuntu/gha-log-check.sh @@ -5,7 +5,7 @@ set -o pipefail set -o xtrace set -o nounset -readonly docker_name_prefix='rabbitmq-amqp-go-client' +readonly docker_name_prefix='rabbitmq-amqp-python-client' declare -r rabbitmq_docker_name="$docker_name_prefix-rabbitmq" diff --git a/rabbitmq_amqp_python_client/connection.py b/rabbitmq_amqp_python_client/connection.py index 6c51a71..00e96c7 100644 --- a/rabbitmq_amqp_python_client/connection.py +++ b/rabbitmq_amqp_python_client/connection.py @@ -139,6 +139,7 @@ def _create_connection(self) -> None: self._mechs = None if self._oauth2_options is not None: + # To investigate: normally in case of oauth user should be "" but the internal library gives error self._user = "no" self._password = self._oauth2_options.token self._mechs = "PLAIN" @@ -397,10 +398,9 @@ def refresh_token(self, token: str) -> None: if self._oauth2_options is None: raise ValidationCodeException("the connection is not oauth enabled") + management = self.management() + management.refresh_token(token) + # update credentials (for reconnection) self._user = "no" self._password = self._oauth2_options.token - self._mechs = "PLAIN" - - management = self.management() - management.refresh_token(token)