diff --git a/PhpAmqpLib/Connection/AMQPStreamConnection.php b/PhpAmqpLib/Connection/AMQPStreamConnection.php index f9f5c377f..43622eb43 100644 --- a/PhpAmqpLib/Connection/AMQPStreamConnection.php +++ b/PhpAmqpLib/Connection/AMQPStreamConnection.php @@ -131,4 +131,12 @@ protected static function try_create_connection($host, $port, $user, $password, $channel_rpc_timeout ); } + + /** + * @param string $password + */ + protected function replace_password_in_construct_params($password) + { + $this->construct_params[3] = $password; + } } diff --git a/PhpAmqpLib/Connection/AbstractConnection.php b/PhpAmqpLib/Connection/AbstractConnection.php index aa3f7fdb3..ba8dc6b27 100644 --- a/PhpAmqpLib/Connection/AbstractConnection.php +++ b/PhpAmqpLib/Connection/AbstractConnection.php @@ -323,8 +323,26 @@ public function reconnect() */ public function updatePassword($password): void { - // send new secret to broker - $this->x_update_secret($password); + if ($this->login_method !== 'EXTERNAL') { + // password is always latest in response for PLAIN and AMQPPLAIN + // for EXTERNAL mechanism this has to be handled by calling user + $login_response_parts = explode("\0", $this->login_response); + $login_response_parts[count($login_response_parts) - 1] = $password; + $this->login_response = implode("\0", $login_response_parts); + } + + if ($this->is_connected) { + // send new secret to broker if currently connected + $this->x_update_secret($password); + } + } + + /** + * @param string $password + */ + protected function replace_password_in_construct_params($password) + { + $this->construct_params[1] = $password; } /** diff --git a/demo/oauth2_authorization.php b/demo/oauth2_authorization.php index a9c4e1265..0a04d6758 100644 --- a/demo/oauth2_authorization.php +++ b/demo/oauth2_authorization.php @@ -30,6 +30,8 @@ function getNextOauth2Token() { pcntl_signal(SIGALRM, function () use ($connection) { echo "Refreshing token...\n"; $connection->updatePassword(getNextOauth2Token()); // this will fail on 2nd attempt - see getNextOauth2Token + sleep(1); + $connection->reconnect(); // reconnect should use new token too so this is working for lazy connections too! pcntl_alarm(5); }, true); pcntl_alarm(5); diff --git a/tests/Functional/Connection/OAuth2ConnectionTest.php b/tests/Functional/Connection/OAuth2ConnectionTest.php index 8bf67e067..2362a64ee 100644 --- a/tests/Functional/Connection/OAuth2ConnectionTest.php +++ b/tests/Functional/Connection/OAuth2ConnectionTest.php @@ -24,6 +24,38 @@ public function update_password() self::assertTrue($conn->isConnected()); } + /** + * @test + * @covers \PhpAmqpLib\Connection\AbstractConnection::updatePassword() + */ + public function update_password_should_replace_password_for_reconnect() + { + $conn = new AMQPStreamConnection(HOST, PORT, 'oauth', JWT_TOKEN_1, '/', false, 'PLAIN', null, 'en_US', 1); + $conn->updatePassword(JWT_TOKEN_2); + + $loginResponse = (new \ReflectionClass($conn))->getProperty('login_response'); + $loginResponse->setAccessible(true); + + self::assertContains(JWT_TOKEN_2, $loginResponse->getValue($conn)); + self::assertNotContains(JWT_TOKEN_1, $loginResponse->getValue($conn)); + } + + /** + * @test + * @covers \PhpAmqpLib\Connection\AbstractConnection::updatePassword() + */ + public function update_password_should_replace_password_for_clone() + { + $conn = new AMQPStreamConnection(HOST, PORT, 'oauth', JWT_TOKEN_1, '/', false, 'PLAIN', null, 'en_US', 1); + $conn->updatePassword(JWT_TOKEN_2); + + $constructorParams = (new \ReflectionClass($conn))->getProperty('constructor_param'); + $constructorParams->setAccessible(true); + + self::assertContains(JWT_TOKEN_2, $constructorParams->getValue($conn)); + self::assertNotContains(JWT_TOKEN_1, $constructorParams->getValue($conn)); + } + /** * @test * @covers \PhpAmqpLib\Connection\AbstractConnection::x_update_secret()