diff --git a/source/auth/auth.rst b/source/auth/auth.rst index 6b16be5bc2..3740a49ba5 100644 --- a/source/auth/auth.rst +++ b/source/auth/auth.rst @@ -1252,7 +1252,12 @@ mechanism mechanism_properties PROVIDER_NAME Drivers MUST allow the user to specify a name for using a service - to obtain credentials that is one of ["aws"]. + to obtain credentials that is one of ["aws", "azure"]. + TOKEN_AUDIENCE + The authorization token audience claim, needed for the "azure" + provider. + TOKEN_CLIENT_ID + The client id to associate with a token, needed for the "azure" provider. REQUEST_TOKEN_CALLBACK Drivers MUST allow the user to specify a callback of the form "onRequest" (defined below), if the driver supports @@ -1349,8 +1354,8 @@ the driver MUST raise an error. Supported Service Providers ``````````````````````````` -Drivers MUST support obtaining credentials for a service for "aws", given -by the PROVIDER_NAME mechanism property. In all cases the acquired token +Drivers MUST support obtaining credentials for a service for "aws" and "azure", +given by the PROVIDER_NAME mechanism property. In all cases the acquired token will be given as the ``jwt`` argument and the JwtStepRequest MUST be made immediately, as part of speculative authentication if appropriate, skipping the PrincipalStepRequest. Drivers MUST raise an error if both a PROVIDER_NAME and username are given, since using a service will not use the username. @@ -1363,6 +1368,52 @@ attempt to read the value given by the ``AWS_WEB_IDENTITY_TOKEN_FILE`` and interpret it as a file path. The contents of the file are read as the access token. If the path does not exist or cannot be read, or the environment variable does not exist, the driver MUST raise an error. +AZURE +_____ +When the PROVIDER_NAME mechanism property is set to "azure", the driver MUST +attempt to retrieve a credential from the Azure Instance Metadata Service (IMDS). `See this documentation for more information`__ + +The driver MUST ensure that the TOKEN_AUDIENCE mechanism property is set when +the PROVIDER_NAME is "azure". The TOKEN_AUDIENCE will typically be an encoded +Application ID URI of the form: ``api%3A%2F%2F``. + +__ https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http + +.. default-role:: math + +To obtain an Azure token, the below steps should be taken: + +1. Let `U` be a new URL, initialized from the URL string + :ts:`"http://169.254.169.254/metadata/identity/oauth2/token"` +2. Add a query parameter ``api-version=2018-02-01`` to `U`. +3. Add a query parameter ``resource=TOKEN_AUDIENCE`` to `U`. +4. If TOKEN_CLIENT_ID is given, add a query parameter ``client_id=TOKEN_CLIENT_ID`` to `U`. +5. Prepare an HTTP GET request `Req` based on `U`. + + .. note:: All query parameters on `U` should be appropriately percent-encoded + +6. Add HTTP headers ``Metadata: true`` and ``Accept: application/json`` to + `Req`. +7. Issue `Req` to the Azure IMDS server ``169.254.169.254:80``. Let `Resp` be + the response from the server. If the HTTP response is not completely received + within ten seconds, consider the request to have timed out, and return an + error instead of an access token. +8. If `Resp_{status} ≠ 200`, obtaining the access token has failed, and the HTTP + response body of `Resp` encodes information about the error that occurred. + Return an error including the HTTP response body instead of an access token. +9. Otherwise, let `J` be the JSON document encoded in the HTTP response body of + `Resp`. +10. The result access token `T` is given as the ``access_token`` string property + of `J`. Return `T` as the resulting access token. +12. The resulting "expires in" duration `d_{exp}` is a count of seconds given as + an ASCII-encoded integer string ``expires_in`` property of `J`. + +.. note:: + + If JSON decoding of `Resp` fails, or the ``access_token`` property is absent + from `J`, this is a protocol error from IMDS. Indicate this error to the + requester of the access token. + Caching Credentials ``````````````````` diff --git a/source/auth/tests/mongodb-oidc.rst b/source/auth/tests/mongodb-oidc.rst index 724841e0e0..4a5f4468e1 100644 --- a/source/auth/tests/mongodb-oidc.rst +++ b/source/auth/tests/mongodb-oidc.rst @@ -6,6 +6,7 @@ Drivers MUST test the following scenarios: - ``Callback-Driven Auth`` - ``AWS Automatic Auth`` +- ``Azure Automatic Auth`` - ``Callback Validation`` - ``Cached Credentials`` - ``Speculative Authentication`` @@ -141,6 +142,83 @@ Allowed Hosts Ignored - Assert that a ``find`` operation succeeds. - Close the client. +Azure Automatic Auth +================== + +Drivers MUST be able to authenticate using the "azure" provider workflow, using +an Azure VM provisioned using the helper scripts in Drivers Evergreen Tools. +These tests will most likely need to be run in a separate test file from the +rest of the tests, to avoid needing to skip multiple tests. + +Connect +~~~~~~~ +- Create a client with a url of the form ``mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=PROVIDER_NAME:azure,TOKEN_AUDIENCE:``. +- Assert that a ``find`` operation succeeds. +- Close the client. + +Allowed Hosts Ignored +~~~~~~~~~~~~~~~~~~~~~ +- Create a client with a url of the form ``mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=PROVIDER_NAME:azure,TOKEN_AUDIENCE:``, and an + ``ALLOWED_HOSTS`` that is an empty list. +- Assert that a ``find`` operation succeeds. +- Close the client. + +Main Cache Not Used +~~~~~~~~~~~~~~~~~~~ +- Clear the main OIDC cache. +- Create a client with a url of the form ``mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=PROVIDER_NAME:azure,TOKEN_AUDIENCE:``. +- Assert that a ``find`` operation succeeds. +- Close the client. +- Assert that the main OIDC cache is empty. + +Azure Cache is Used +~~~~~~~~~~~~~~~~~~~ +- Clear the Azure OIDC cache. +- Create a client with a url of the form ``mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=PROVIDER_NAME:azure,TOKEN_AUDIENCE:``. +- Assert that a ``find`` operation succeeds. +- Close the client. +- Assert that the Azure OIDC cache has one entry. + +Reauthentication Succeeds +~~~~~~~~~~~~~~~~~~~~~~~~~ +- Clear the Azure OIDC cache. +- Create a client with an event listener. The following + assumes that the driver does not emit ``saslStart`` or ``saslContinue`` + events. If the driver does emit those events, ignore/filter them for the + purposes of this test. +- Perform a ``find`` operation that succeeds. +- Clear the listener state if possible. +- Force a reauthenication using a ``failCommand`` of the form: + +.. code:: javascript + + { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "errorCode": 391 + } + } + +.. note:: + + the driver MUST either use a unique ``appName`` or explicitly + remove the ``failCommand`` after the test to prevent leakage. + +- Perform another find operation that succeeds. +- Assert that the ordering of list started events is [``find``], + , ``find``. Note that if the listener stat could not be cleared then there + will and be extra ``find`` command. +- Assert that the list of command succeeded events is [``find``]. +- Assert that a ``find`` operation failed once during the command execution. +- Close the client. + + Callback Validation ===================