diff --git a/src/Auth.php b/src/Auth.php index fecc25b..3a86e66 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -9,6 +9,7 @@ class Auth private string $authcid; private string $secret; private string $authzid; + private string $authSource; private string $gs2Header; private ?string $cnonce = null; private string $firstMessageBare; @@ -23,6 +24,7 @@ public function __construct(array $options) $this->authcid = $options['authcid'] ?? ''; $this->secret = $options['secret'] ?? ''; $this->authzid = $options['authzid'] ?? ''; + $this->authSource = $options['authSource'] ?? 'admin'; $this->cnonce = base64_encode(random_bytes(32)); } @@ -39,7 +41,7 @@ public function start(): array "autoAuthorize" => 1, "options" => ["skipEmptyExchange" => true], ], - 'admin' + $this->authSource ]; } @@ -61,7 +63,7 @@ public function continue($data): array "conversationId" => $cid, "payload" => $payload, ], - 'admin' + $this->authSource ]; } diff --git a/src/Client.php b/src/Client.php index d54e9a6..f3f05e4 100644 --- a/src/Client.php +++ b/src/Client.php @@ -134,6 +134,11 @@ class Client * @param string $user * @param string $password * @param Boolean $useCoroutine + * @param bool $tls + * @param array $tlsOptions + * @param string|null $authSource Database to authenticate against; defaults to 'admin'. + * Set this when the user was created in a database other than admin (e.g. the + * application database itself). * @throws \Exception */ public function __construct( @@ -144,7 +149,8 @@ public function __construct( string $password, bool $useCoroutine = false, bool $tls = false, - array $tlsOptions = [] + array $tlsOptions = [], + ?string $authSource = null ) { if (empty($database)) { throw new \InvalidArgumentException('Database name cannot be empty'); @@ -210,7 +216,8 @@ public function __construct( $this->auth = new Auth([ 'authcid' => $user, - 'secret' => Auth::encodeCredentials($user, $password) + 'secret' => Auth::encodeCredentials($user, $password), + 'authSource' => $authSource ?? 'admin', ]); } diff --git a/tests/AuthTest.php b/tests/AuthTest.php new file mode 100644 index 0000000..1a95af2 --- /dev/null +++ b/tests/AuthTest.php @@ -0,0 +1,56 @@ + 'root', + 'secret' => Auth::encodeCredentials('root', 'example'), + ]); + + [$payload, $database] = $auth->start(); + + $this->assertSame(1, $payload['saslStart']); + $this->assertSame('admin', $database); + } + + public function testStartUsesProvidedAuthSource(): void + { + $auth = new Auth([ + 'authcid' => 'appuser', + 'secret' => Auth::encodeCredentials('appuser', 'example'), + 'authSource' => 'appdb', + ]); + + [$payload, $database] = $auth->start(); + + $this->assertSame(1, $payload['saslStart']); + $this->assertSame('appdb', $database); + } + + public function testContinueUsesProvidedAuthSource(): void + { + $auth = new Auth([ + 'authcid' => 'appuser', + 'secret' => Auth::encodeCredentials('appuser', 'example'), + 'authSource' => 'appdb', + ]); + + $auth->start(); + + $data = new \stdClass(); + $data->conversationId = 1; + $data->payload = new \MongoDB\BSON\Binary('r=' . $auth->getCnonce() . 'server,s=' . base64_encode('salt') . ',i=4096', 0); + + [$payload, $database] = $auth->continue($data); + + $this->assertSame(1, $payload['saslContinue']); + $this->assertSame('appdb', $database); + } +}