From bb7d914618f0c10a764bf9d599e4abb5f7d7c5d8 Mon Sep 17 00:00:00 2001 From: Jakub Adamus Date: Fri, 9 Feb 2024 11:38:29 +0100 Subject: [PATCH] Implement updatePassword method to allow long-running connections to reauthenticate --- PhpAmqpLib/Connection/AbstractConnection.php | 11 +++++ README.md | 1 + demo/oauth2_authorization.php | 44 +++++++++++++++++++ .../Connection/OAuth2ConnectionTest.php | 40 +++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 demo/oauth2_authorization.php create mode 100644 tests/Functional/Connection/OAuth2ConnectionTest.php diff --git a/PhpAmqpLib/Connection/AbstractConnection.php b/PhpAmqpLib/Connection/AbstractConnection.php index 941626cdc..aa3f7fdb3 100644 --- a/PhpAmqpLib/Connection/AbstractConnection.php +++ b/PhpAmqpLib/Connection/AbstractConnection.php @@ -316,6 +316,17 @@ public function reconnect() $this->connect(); } + /** + * Sets new password for this connection. + * Should be used for RabbitMQ's OAuth2 authentication backend to update current token. + * @param string $password + */ + public function updatePassword($password): void + { + // send new secret to broker + $this->x_update_secret($password); + } + /** * Cloning will use the old properties to make a new connection to the same server */ diff --git a/README.md b/README.md index 4c3840086..6da65963f 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ please refer to the [official RabbitMQ tutorials](http://www.rabbitmq.com/tutori - `amqp_consumer_fanout_{1,2}.php` and `amqp_publisher_fanout.php`: demos fanout exchanges with named queues. - `amqp_consumer_pcntl_heartbeat.php`: demos signal-based heartbeat sender usage. - `basic_get.php`: demos obtaining messages from the queues by using the _basic get_ AMQP call. +- `oauth2_authorization.php`: demo for use of OAuth 2.0 authorization using the _update-secret_ AMQP call. ## Multiple hosts connections ## diff --git a/demo/oauth2_authorization.php b/demo/oauth2_authorization.php new file mode 100644 index 000000000..a9c4e1265 --- /dev/null +++ b/demo/oauth2_authorization.php @@ -0,0 +1,44 @@ +updatePassword(getNextOauth2Token()); // this will fail on 2nd attempt - see getNextOauth2Token + pcntl_alarm(5); +}, true); +pcntl_alarm(5); + +register_shutdown_function(function () use ($connection) { + $connection->close(); +}); + +while (true) { + echo "Connection is ", ($connection->isConnected() ? "connected" : "not connected"), "\n"; + sleep(1); +} diff --git a/tests/Functional/Connection/OAuth2ConnectionTest.php b/tests/Functional/Connection/OAuth2ConnectionTest.php new file mode 100644 index 000000000..8bf67e067 --- /dev/null +++ b/tests/Functional/Connection/OAuth2ConnectionTest.php @@ -0,0 +1,40 @@ +updatePassword(JWT_TOKEN_2); + self::assertTrue($conn->isConnected()); + } + + /** + * @test + * @covers \PhpAmqpLib\Connection\AbstractConnection::x_update_secret() + * @covers \PhpAmqpLib\Connection\AbstractConnection::updatePassword() + */ + public function update_password_invalid() + { + $this->expectException(AMQPConnectionClosedException::class); + $this->expectExceptionMessage('New secret was refused'); + + $conn = new AMQPStreamConnection(HOST, PORT, 'oauth', JWT_TOKEN_1, '/', false, 'PLAIN', null, 'en_US', 1); + $conn->updatePassword('invalidJwt'); + } +}