From 3526b8dab7cf82118ebf4bfcad570e7d8f2577b2 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Thu, 21 Nov 2024 09:36:24 -0800 Subject: [PATCH 01/11] add oidc info and examples --- source/fundamentals/enterprise-auth.txt | 122 ++++++++++++++++++ .../code-snippets/enterprise-auth.rs | 86 ++++++++++++ 2 files changed, 208 insertions(+) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index e3a5da67..d28f1e0c 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -108,6 +108,128 @@ a connection string URI by using the following placeholders: let uri = "mongodb://:@/?authSource=$external&authMechanism=PLAIN"; +.. _rust-mongodb-oidc: + +MONGODB-OIDC +------------ + +.. important:: + + The MONGODB-OIDC authentication mechanism requires MongoDB Server + v7.0 or later running on a Linux platform. + +The {+driver-short+} supports OpenID Connect (**OIDC**) authentication for **workload +identities**. A workload identity is an identity you assign to a +software workload, such as an application, service, script, or +container, to authenticate and access other services and resources. + +The following sections describe how to use the MONGODB-OIDC +authentication mechanism to authenticate to various platforms. + +To learn more about the MONGODB-OIDC authentication mechanism, see +:manual:`OpenID Connect Authentication ` and +:manual:`MongoDB Server Parameters ` +in the server manual. + +.. _rust-mongodb-oidc-azure-imds: + +Azure IMDS +~~~~~~~~~~ + +If your application runs on an Azure VM, or otherwise uses the +`Azure Instance Metadata Service `__ +(IMDS), you can authenticate to MongoDB by using the {+driver-short+}'s +built-in Azure support. + +You can configure OIDC for Azure IMDS by setting the ``mechanism`` field of your +``Credential`` struct to ``AuthMechanism::MongoDBOidc``. The following example +specifies the authentication mechanism by using the following placeholders: + +- ``username``: If you're using an Azure managed identity, set this to the + client ID of the managed identity. If you're using a service principal to + represent an enterprise application, set this to the application ID of the + service principal. +- ``mechanism_properties``: Set the ``ENVIRONMENT`` property to ``azure`` and + the ``TOKEN_RESOURCE`` to with the value of the audience parameter configured + on your MongoDB deployment. + +.. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs + :language: rust + :dedent: + :start-after: start-azure-imds + :end-before: end-azure-imds + :emphasize-lines: 2-5 + +.. _rust-mongodb-oidc-gcp-imds: + +GCP IMDS +~~~~~~~~ + +If your application runs on a Google Compute Engine VM, or otherwise uses the +`GCP Instance Metadata Service `__, +you can authenticate to MongoDB by using the {+driver-short+}'s built-in GCP +support. + +You can configure the OIDC for GCP IMDS by setting the ``mechanism`` field of your +``Credential`` struct to ``AuthMechanism::MongoDBOidc``. The following example +specifies the authentication mechaism by using the following placeholders in the +``mechanism_properties`` field: + +- ``ENVIRONMENT``: Set this to ``gcp``. +- ``TOKEN_RESOURCE``: Set this to the value of the audience parameter configured + on your MongoDB deployment. + +.. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs + :language: rust + :dedent: + :start-after: start-gcp-imds + :end-before: end-gcp-imds + :emphasize-lines: 2-3 + +.. _rust-mongodb-oidc-custom-callback: + +Custom Callback +~~~~~~~~~~~~~~~ + +The {+driver-short+} doesn't offer built-in support for all platforms, +including the AWS Elastic Kubernetes Service (EKS). To authenticate +against unsupported platforms, you must define a custom callback +function to use OIDC to authenticate. + +The following example defines a custom callback for an EKS +cluster with a configured IAM OIDC provider. The access token is +read from a path set in the ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment +variable. Then, you can set the ``oidc_callback`` field of your ``Credential`` +struct to ``oidc::Callback::machine``: + +.. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs + :language: rust + :dedent: + :start-after: start-custom-callback-machine + :end-before: end-custom-callback-machine + +For workforce identity, you must configure the client by setting the +``oidc_callback`` field of your ``Credential`` struct to +``oidc::Callback::human`` instead of ``oidc::Callback::machine``. The +{+driver-short+} uses the callback in the following process: + +1. The driver retrieves the Identiy Provider Information (IDPInfo) for the + provided username. +2. The callback negotiates with the IDP to obtain an ``AccessToken``, possible + ``RefreshToken``, and any times. Then, it returns them, similar to the + ``OIDCMachineCallbacks``. + +The following example defines a custom callback to handle workforce identity. +The callback retrieves the IDPInfo for the provided username and negotiates with +the IDP to obtain the necessary tokens: + +.. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs + :language: rust + :dedent: + :start-after: start-custom-callback-user + :end-before: end-custom-callback-user + :emphasize-lines: 3-7, 12 + Additional Information ---------------------- diff --git a/source/includes/fundamentals/code-snippets/enterprise-auth.rs b/source/includes/fundamentals/code-snippets/enterprise-auth.rs index 74a8dc24..09105b59 100644 --- a/source/includes/fundamentals/code-snippets/enterprise-auth.rs +++ b/source/includes/fundamentals/code-snippets/enterprise-auth.rs @@ -1,4 +1,5 @@ use mongodb::{ bson::doc, options::{ ClientOptions, Credential, AuthMechanism }, Client }; +use mongodb::options::oidc::{self, CallbackContext, IdpServerResponse}; #[tokio::main] async fn main() -> mongodb::error::Result<()> { @@ -17,5 +18,90 @@ async fn main() -> mongodb::error::Result<()> { let client = Client::with_options(client_options)?; // end-ldap + // start-azure-imds + client_options.credential = Credential::builder() + .username("".to_owned()) + .mechanism(AuthMechanism::MongoDbOidc) + .mechanism_properties( + doc! {"ENVIRONMENT": "azure", "TOKEN_RESOURCE": ""} + ) + .build() + .into(); // Convert the builder into a Credential object + + let client = Client::with_options(client_options)?; + let res = client + .database("test") + .collection::("test") + .find_one(doc! {}) + .await?; + // end-azure-imds + + // start-gcp-imds + opts.credential = Credential::builder() + .mechanism(AuthMechanism::MongoDbOidc) + .mechanism_properties( + doc! {"ENVIRONMENT": "gcp", "TOKEN_RESOURCE": ""} + ) + .build() + .into(); + let client = Client::with_options(opts)?; + let res = client + .database("test") + .collection::("test") + .find_one(doc! {}) + .await?; + // end-gcp-imds + + // start-custom-callback-machine + opts.credential = Credential::builder() + .mechanism(AuthMechanism::MongoDbOidc) + .oidc_callback(oidc::Callback::machine(move |_| { + async move { + let token_file_path = std::env::var("AWS_WEB_IDENTITY_TOKEN_FILE")?; + let access_token = tokio::fs::read_to_string(token_file_path).await?; + Ok(IdpServerResponse { + access_token, + expires: None, + refresh_token: None, + }) + } + .boxed() + })) + .build() + .into(); + + let client = Client::with_options(opts)?; + + let res = client + .database("test") + .collection::("test") + .find_one(doc! {}, None) + .await?; + // end-custom-callback-machine + + // start-custom-callback-user + async fn cb(params: CallbackContext) -> mongodb::error::Result { + idp_info := params.idp_info.ok_or(Error::NoIDPInfo)?; + let (access_token, expires, refresh_token) = negotiate_with_idp(ctx, idpInfo.Issuer).await?; + Ok(oidc::IdpServerResponse { + access_token, + expires: Some(expires), + refresh_token: Some(refresh_token), + }) + } + opts.credential = Credential::builder() + .mechanism(AuthMechanism::MongoDbOidc) + .oidc_callback(oidc::Callback::human(move|c| { + async move { cb(c).await }.boxed() + })) + .build() + .into(); + let res = client + .database("test") + .collection::("test") + .find_one(doc! {}) + .await; + // end-custom-callback-user + Ok(()) } From 23594872a88189fdacc070c417d2af9bd787852b Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Thu, 21 Nov 2024 11:57:47 -0800 Subject: [PATCH 02/11] edits --- source/fundamentals/enterprise-auth.txt | 24 ++++++++++--------- .../code-snippets/enterprise-auth.rs | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index d28f1e0c..4fefd625 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -175,8 +175,8 @@ You can configure the OIDC for GCP IMDS by setting the ``mechanism`` field of yo specifies the authentication mechaism by using the following placeholders in the ``mechanism_properties`` field: -- ``ENVIRONMENT``: Set this to ``gcp``. -- ``TOKEN_RESOURCE``: Set this to the value of the audience parameter configured +- ``ENVIRONMENT``: Set this property to ``gcp``. +- ``TOKEN_RESOURCE``: Set this property to the value of the audience parameter configured on your MongoDB deployment. .. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs @@ -196,9 +196,9 @@ including the AWS Elastic Kubernetes Service (EKS). To authenticate against unsupported platforms, you must define a custom callback function to use OIDC to authenticate. -The following example defines a custom callback for an EKS -cluster with a configured IAM OIDC provider. The access token is -read from a path set in the ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment +The following example defines a custom callback for an EKS cluster with a +configured Identity and Access Management (IAM) OIDC provider. The access token +is read from a path set in the ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment variable. Then, you can set the ``oidc_callback`` field of your ``Credential`` struct to ``oidc::Callback::machine``: @@ -207,16 +207,18 @@ struct to ``oidc::Callback::machine``: :dedent: :start-after: start-custom-callback-machine :end-before: end-custom-callback-machine + :emphasize-lines: 3, 5-10 -For workforce identity, you must configure the client by setting the -``oidc_callback`` field of your ``Credential`` struct to -``oidc::Callback::human`` instead of ``oidc::Callback::machine``. The -{+driver-short+} uses the callback in the following process: +When the workforce identity authentication process involves human interaction, +you must configure the client by setting the ``oidc_callback`` field of your +``Credential`` struct to ``oidc::Callback::human`` instead of +``oidc::Callback::machine``. The {+driver-short+} uses the callback in the +following process: -1. The driver retrieves the Identiy Provider Information (IDPInfo) for the +1. The driver retrieves the Identity Provider Information (IDPInfo) for the provided username. 2. The callback negotiates with the IDP to obtain an ``AccessToken``, possible - ``RefreshToken``, and any times. Then, it returns them, similar to the + ``RefreshToken``, and any timeouts. Then, it returns them, similar to the ``OIDCMachineCallbacks``. The following example defines a custom callback to handle workforce identity. diff --git a/source/includes/fundamentals/code-snippets/enterprise-auth.rs b/source/includes/fundamentals/code-snippets/enterprise-auth.rs index 09105b59..70f5ee68 100644 --- a/source/includes/fundamentals/code-snippets/enterprise-auth.rs +++ b/source/includes/fundamentals/code-snippets/enterprise-auth.rs @@ -83,7 +83,7 @@ async fn main() -> mongodb::error::Result<()> { async fn cb(params: CallbackContext) -> mongodb::error::Result { idp_info := params.idp_info.ok_or(Error::NoIDPInfo)?; let (access_token, expires, refresh_token) = negotiate_with_idp(ctx, idpInfo.Issuer).await?; - Ok(oidc::IdpServerResponse { + Ok(oidc::IdpServerResponse { access_token, expires: Some(expires), refresh_token: Some(refresh_token), From d563156ab85eff95b9b4449283820423bfe185ec Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Thu, 21 Nov 2024 12:12:57 -0800 Subject: [PATCH 03/11] fix typo and refine content --- source/fundamentals/enterprise-auth.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index 4fefd625..546738da 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -170,21 +170,24 @@ If your application runs on a Google Compute Engine VM, or otherwise uses the you can authenticate to MongoDB by using the {+driver-short+}'s built-in GCP support. -You can configure the OIDC for GCP IMDS by setting the ``mechanism`` field of your -``Credential`` struct to ``AuthMechanism::MongoDBOidc``. The following example -specifies the authentication mechaism by using the following placeholders in the +You can configure OIDC for GCP IMDS by setting the ``mechanism`` field of your +``Credential`` struct to ``AuthMechanism::MongoDBOidc``. Then, specify the +authentication mechanism by setting the following values in the ``mechanism_properties`` field: - ``ENVIRONMENT``: Set this property to ``gcp``. - ``TOKEN_RESOURCE``: Set this property to the value of the audience parameter configured on your MongoDB deployment. +The following code example shows how to set these options when creating a +``Client``: + .. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs :language: rust :dedent: :start-after: start-gcp-imds :end-before: end-gcp-imds - :emphasize-lines: 2-3 + :emphasize-lines: 2-4 .. _rust-mongodb-oidc-custom-callback: @@ -218,8 +221,7 @@ following process: 1. The driver retrieves the Identity Provider Information (IDPInfo) for the provided username. 2. The callback negotiates with the IDP to obtain an ``AccessToken``, possible - ``RefreshToken``, and any timeouts. Then, it returns them, similar to the - ``OIDCMachineCallbacks``. + ``RefreshToken``, and any timeouts, then returns them. The following example defines a custom callback to handle workforce identity. The callback retrieves the IDPInfo for the provided username and negotiates with From e3aa4a158ae919d97e9f9b67962fba7ca836892c Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Fri, 22 Nov 2024 11:25:03 -0800 Subject: [PATCH 04/11] MW feedback --- source/fundamentals/enterprise-auth.txt | 34 ++++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index 546738da..9532de5f 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -129,7 +129,7 @@ authentication mechanism to authenticate to various platforms. To learn more about the MONGODB-OIDC authentication mechanism, see :manual:`OpenID Connect Authentication ` and :manual:`MongoDB Server Parameters ` -in the server manual. +in the {+server+} manual. .. _rust-mongodb-oidc-azure-imds: @@ -142,17 +142,21 @@ If your application runs on an Azure VM, or otherwise uses the built-in Azure support. You can configure OIDC for Azure IMDS by setting the ``mechanism`` field of your -``Credential`` struct to ``AuthMechanism::MongoDBOidc``. The following example -specifies the authentication mechanism by using the following placeholders: +``Credential`` struct to ``AuthMechanism::MongoDBOidc``. Then, specify the +authentication mechanism by seting the following values in the +``mechanism_properties`` field: - ``username``: If you're using an Azure managed identity, set this to the client ID of the managed identity. If you're using a service principal to represent an enterprise application, set this to the application ID of the service principal. - ``mechanism_properties``: Set the ``ENVIRONMENT`` property to ``azure`` and - the ``TOKEN_RESOURCE`` to with the value of the audience parameter configured + the ``TOKEN_RESOURCE`` to the value of the audience parameter configured on your MongoDB deployment. +The following code example shows how to set these options when creating a +``Client``: + .. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs :language: rust :dedent: @@ -194,16 +198,15 @@ The following code example shows how to set these options when creating a Custom Callback ~~~~~~~~~~~~~~~ -The {+driver-short+} doesn't offer built-in support for all platforms, -including the AWS Elastic Kubernetes Service (EKS). To authenticate -against unsupported platforms, you must define a custom callback -function to use OIDC to authenticate. +The {+driver-short+} doesn't offer built-in support for all platforms, including +the AWS Elastic Kubernetes Service (EKS). To use OIDC to authenticate against +unsupported platforms, you must define a custom callback function. -The following example defines a custom callback for an EKS cluster with a -configured Identity and Access Management (IAM) OIDC provider. The access token -is read from a path set in the ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment -variable. Then, you can set the ``oidc_callback`` field of your ``Credential`` -struct to ``oidc::Callback::machine``: +First, define a custom callback for an EKS cluster with a configured Identity +and Access Management (IAM) OIDC provider. Then, read the access token from a +path set in the ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment variable. Finally, +set the ``oidc_callback`` field of your ``Credential`` struct to +``oidc::Callback::machine`` as shown in the following example: .. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs :language: rust @@ -220,8 +223,9 @@ following process: 1. The driver retrieves the Identity Provider Information (IDPInfo) for the provided username. -2. The callback negotiates with the IDP to obtain an ``AccessToken``, possible - ``RefreshToken``, and any timeouts, then returns them. +#. The callback negotiates with the IDP to obtain an ``AccessToken``, and any + potential ``RefreshToken`` and timeout values, if configured, then returns + them. The following example defines a custom callback to handle workforce identity. The callback retrieves the IDPInfo for the provided username and negotiates with From b477176e71334c8ca22ece1e79b24d15f248e720 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Fri, 22 Nov 2024 11:41:49 -0800 Subject: [PATCH 05/11] edit --- source/fundamentals/enterprise-auth.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index 9532de5f..7b38e886 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -129,7 +129,7 @@ authentication mechanism to authenticate to various platforms. To learn more about the MONGODB-OIDC authentication mechanism, see :manual:`OpenID Connect Authentication ` and :manual:`MongoDB Server Parameters ` -in the {+server+} manual. +in the Server manual. .. _rust-mongodb-oidc-azure-imds: From faf3d9b1fa89aaab2759f299e963871c92d3052f Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Mon, 25 Nov 2024 09:31:08 -0800 Subject: [PATCH 06/11] edits for clarity and add resources --- source/fundamentals/enterprise-auth.txt | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index 7b38e886..63155f20 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -142,9 +142,8 @@ If your application runs on an Azure VM, or otherwise uses the built-in Azure support. You can configure OIDC for Azure IMDS by setting the ``mechanism`` field of your -``Credential`` struct to ``AuthMechanism::MongoDBOidc``. Then, specify the -authentication mechanism by seting the following values in the -``mechanism_properties`` field: +``Credential`` struct to ``AuthMechanism::MongoDBOidc``. This example specifies +the authentication mechanism by using the following placeholders: - ``username``: If you're using an Azure managed identity, set this to the client ID of the managed identity. If you're using a service principal to @@ -202,11 +201,12 @@ The {+driver-short+} doesn't offer built-in support for all platforms, including the AWS Elastic Kubernetes Service (EKS). To use OIDC to authenticate against unsupported platforms, you must define a custom callback function. -First, define a custom callback for an EKS cluster with a configured Identity -and Access Management (IAM) OIDC provider. Then, read the access token from a -path set in the ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment variable. Finally, -set the ``oidc_callback`` field of your ``Credential`` struct to -``oidc::Callback::machine`` as shown in the following example: +The following code is an example implementation of custom callback for an EKS +cluster. First, set the ``oidc_callback`` field of your ``Credential`` struct to +``oidc::Callback::machine``. Then, read the access token from a path set in the +``AWS_WEB_IDENTITY_TOKEN_FILE`` environment variable. Finally, set the value of +the ``access_token`` field of the ``IdpServerResponse`` struct. Optionally, set +the values of the ``expires`` and ``refresh_token`` fields. .. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs :language: rust @@ -223,8 +223,8 @@ following process: 1. The driver retrieves the Identity Provider Information (IDPInfo) for the provided username. -#. The callback negotiates with the IDP to obtain an ``AccessToken``, and any - potential ``RefreshToken`` and timeout values, if configured, then returns +#. The callback negotiates with the IDP to obtain an ``access_token``, and any + potential ``refresh_token`` and timeout values, if configured, then returns them. The following example defines a custom callback to handle workforce identity. @@ -259,3 +259,5 @@ guide, see the following API documentation: - `ClientOptions <{+api+}/options/struct.ClientOptions.html>`__ - `Client <{+api+}/struct.Client.html>`__ - `with_options() <{+api+}/struct.Client.html#method.with_options>`__ +- `CallbackContext <{+api+}/options/oidc/struct.CallbackContext.html>`__ +- `IdpServerResponse <{+api+}/options/oidc/struct.IdpServerResponse.html>`__ From e11bfcb6bf55713a41bc47a65a9adb2774f7a499 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Mon, 25 Nov 2024 09:48:46 -0800 Subject: [PATCH 07/11] add missing word --- source/fundamentals/enterprise-auth.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index 63155f20..3c078695 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -201,7 +201,7 @@ The {+driver-short+} doesn't offer built-in support for all platforms, including the AWS Elastic Kubernetes Service (EKS). To use OIDC to authenticate against unsupported platforms, you must define a custom callback function. -The following code is an example implementation of custom callback for an EKS +The following code is an example implementation of a custom callback for an EKS cluster. First, set the ``oidc_callback`` field of your ``Credential`` struct to ``oidc::Callback::machine``. Then, read the access token from a path set in the ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment variable. Finally, set the value of From b23dd0384b351c2887a26a0fab009ccf9a63087d Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Tue, 3 Dec 2024 10:19:46 -0800 Subject: [PATCH 08/11] technical feedback --- source/fundamentals/enterprise-auth.txt | 4 +-- .../code-snippets/enterprise-auth.rs | 35 ++++++++++++------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index 3c078695..2566e804 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -142,7 +142,7 @@ If your application runs on an Azure VM, or otherwise uses the built-in Azure support. You can configure OIDC for Azure IMDS by setting the ``mechanism`` field of your -``Credential`` struct to ``AuthMechanism::MongoDBOidc``. This example specifies +``Credential`` struct to ``AuthMechanism::MongoDbOidc``. This example specifies the authentication mechanism by using the following placeholders: - ``username``: If you're using an Azure managed identity, set this to the @@ -174,7 +174,7 @@ you can authenticate to MongoDB by using the {+driver-short+}'s built-in GCP support. You can configure OIDC for GCP IMDS by setting the ``mechanism`` field of your -``Credential`` struct to ``AuthMechanism::MongoDBOidc``. Then, specify the +``Credential`` struct to ``AuthMechanism::MongoDbOidc``. Then, specify the authentication mechanism by setting the following values in the ``mechanism_properties`` field: diff --git a/source/includes/fundamentals/code-snippets/enterprise-auth.rs b/source/includes/fundamentals/code-snippets/enterprise-auth.rs index 70f5ee68..90d41a5a 100644 --- a/source/includes/fundamentals/code-snippets/enterprise-auth.rs +++ b/source/includes/fundamentals/code-snippets/enterprise-auth.rs @@ -1,5 +1,12 @@ -use mongodb::{ bson::doc, options::{ ClientOptions, Credential, AuthMechanism }, Client }; use mongodb::options::oidc::{self, CallbackContext, IdpServerResponse}; +use mongodb::{ + bson::doc, + bson::Document, + options::{ClientOptions, Credential, AuthMechanism}, + Client, +}; +use std::error::Error; +use futures::FutureExt; #[tokio::main] async fn main() -> mongodb::error::Result<()> { @@ -19,15 +26,16 @@ async fn main() -> mongodb::error::Result<()> { // end-ldap // start-azure-imds - client_options.credential = Credential::builder() + let credential = Credential::builder() .username("".to_owned()) .mechanism(AuthMechanism::MongoDbOidc) .mechanism_properties( doc! {"ENVIRONMENT": "azure", "TOKEN_RESOURCE": ""} ) .build() - .into(); // Convert the builder into a Credential object + .into(); + client_options.credential = Some(credential); let client = Client::with_options(client_options)?; let res = client .database("test") @@ -37,14 +45,16 @@ async fn main() -> mongodb::error::Result<()> { // end-azure-imds // start-gcp-imds - opts.credential = Credential::builder() + let credential = Credential::builder() .mechanism(AuthMechanism::MongoDbOidc) .mechanism_properties( doc! {"ENVIRONMENT": "gcp", "TOKEN_RESOURCE": ""} ) .build() .into(); - let client = Client::with_options(opts)?; + + client_options.credential = Some(credential); + let client = Client::with_options(client_options)?; let res = client .database("test") .collection::("test") @@ -53,11 +63,11 @@ async fn main() -> mongodb::error::Result<()> { // end-gcp-imds // start-custom-callback-machine - opts.credential = Credential::builder() + let credential = Credential::builder() .mechanism(AuthMechanism::MongoDbOidc) .oidc_callback(oidc::Callback::machine(move |_| { async move { - let token_file_path = std::env::var("AWS_WEB_IDENTITY_TOKEN_FILE")?; + let token_file_path = std::env::var("AWS_WEB_IDENTITY_TOKEN_FILE").map_err(mongodb::error::Error::custom)?; let access_token = tokio::fs::read_to_string(token_file_path).await?; Ok(IdpServerResponse { access_token, @@ -70,18 +80,19 @@ async fn main() -> mongodb::error::Result<()> { .build() .into(); - let client = Client::with_options(opts)?; + credential_options.credentials = Some(credential); + let client = Client::with_options(client_options)?; let res = client .database("test") - .collection::("test") - .find_one(doc! {}, None) + .collection::("test") + .find_one(doc! {}) .await?; // end-custom-callback-machine // start-custom-callback-user async fn cb(params: CallbackContext) -> mongodb::error::Result { - idp_info := params.idp_info.ok_or(Error::NoIDPInfo)?; + let idp_info = params.idp_info.ok_or(Error::NoIDPInfo)?; let (access_token, expires, refresh_token) = negotiate_with_idp(ctx, idpInfo.Issuer).await?; Ok(oidc::IdpServerResponse { access_token, @@ -89,7 +100,7 @@ async fn main() -> mongodb::error::Result<()> { refresh_token: Some(refresh_token), }) } - opts.credential = Credential::builder() + client_options.credential = Credential::builder() .mechanism(AuthMechanism::MongoDbOidc) .oidc_callback(oidc::Callback::human(move|c| { async move { cb(c).await }.boxed() From 349db38aa2dbb35a9ba0a58bace61a792942e252 Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Tue, 3 Dec 2024 10:24:32 -0800 Subject: [PATCH 09/11] fixes --- .../fundamentals/code-snippets/enterprise-auth.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/source/includes/fundamentals/code-snippets/enterprise-auth.rs b/source/includes/fundamentals/code-snippets/enterprise-auth.rs index 90d41a5a..6b68277f 100644 --- a/source/includes/fundamentals/code-snippets/enterprise-auth.rs +++ b/source/includes/fundamentals/code-snippets/enterprise-auth.rs @@ -69,18 +69,14 @@ async fn main() -> mongodb::error::Result<()> { async move { let token_file_path = std::env::var("AWS_WEB_IDENTITY_TOKEN_FILE").map_err(mongodb::error::Error::custom)?; let access_token = tokio::fs::read_to_string(token_file_path).await?; - Ok(IdpServerResponse { - access_token, - expires: None, - refresh_token: None, - }) + Ok(IdpServerResponse::builder().access_token(access_token).build()) } .boxed() })) .build() .into(); - credential_options.credentials = Some(credential); + client_options.credential = Some(credential); let client = Client::with_options(client_options)?; let res = client @@ -94,11 +90,7 @@ async fn main() -> mongodb::error::Result<()> { async fn cb(params: CallbackContext) -> mongodb::error::Result { let idp_info = params.idp_info.ok_or(Error::NoIDPInfo)?; let (access_token, expires, refresh_token) = negotiate_with_idp(ctx, idpInfo.Issuer).await?; - Ok(oidc::IdpServerResponse { - access_token, - expires: Some(expires), - refresh_token: Some(refresh_token), - }) + Ok(IdpServerResponse::builder().access_token(access_token).expires(expires).refresh_token(refresh_token).build()) } client_options.credential = Credential::builder() .mechanism(AuthMechanism::MongoDbOidc) From a5e0082684b407c3473b5b34d7633e9d3239a6dc Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Wed, 4 Dec 2024 14:12:31 -0800 Subject: [PATCH 10/11] IA feedback --- source/fundamentals/enterprise-auth.txt | 12 +++--- .../code-snippets/enterprise-auth.rs | 38 +++++++++---------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index 2566e804..dfc90fa3 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -213,7 +213,7 @@ the values of the ``expires`` and ``refresh_token`` fields. :dedent: :start-after: start-custom-callback-machine :end-before: end-custom-callback-machine - :emphasize-lines: 3, 5-10 + :emphasize-lines: 3, 5-7 When the workforce identity authentication process involves human interaction, you must configure the client by setting the ``oidc_callback`` field of your @@ -227,16 +227,18 @@ following process: potential ``refresh_token`` and timeout values, if configured, then returns them. -The following example defines a custom callback to handle workforce identity. -The callback retrieves the IDPInfo for the provided username and negotiates with -the IDP to obtain the necessary tokens: +The following example defines a custom callback to handle workforce identity. To +customize this example for your use case, replace ```` with your own +custom flow. Refer to `Authorization Code Flow with OIDC +`__ +for more details. .. literalinclude:: /includes/fundamentals/code-snippets/enterprise-auth.rs :language: rust :dedent: :start-after: start-custom-callback-user :end-before: end-custom-callback-user - :emphasize-lines: 3-7, 12 + :emphasize-lines: 3 Additional Information ---------------------- diff --git a/source/includes/fundamentals/code-snippets/enterprise-auth.rs b/source/includes/fundamentals/code-snippets/enterprise-auth.rs index 6b68277f..9a33077a 100644 --- a/source/includes/fundamentals/code-snippets/enterprise-auth.rs +++ b/source/includes/fundamentals/code-snippets/enterprise-auth.rs @@ -30,10 +30,9 @@ async fn main() -> mongodb::error::Result<()> { .username("".to_owned()) .mechanism(AuthMechanism::MongoDbOidc) .mechanism_properties( - doc! {"ENVIRONMENT": "azure", "TOKEN_RESOURCE": ""} + doc! { "ENVIRONMENT": "azure", "TOKEN_RESOURCE": "" } ) - .build() - .into(); + .build(); client_options.credential = Some(credential); let client = Client::with_options(client_options)?; @@ -48,10 +47,9 @@ async fn main() -> mongodb::error::Result<()> { let credential = Credential::builder() .mechanism(AuthMechanism::MongoDbOidc) .mechanism_properties( - doc! {"ENVIRONMENT": "gcp", "TOKEN_RESOURCE": ""} + doc! { "ENVIRONMENT": "gcp", "TOKEN_RESOURCE": "" } ) - .build() - .into(); + .build(); client_options.credential = Some(credential); let client = Client::with_options(client_options)?; @@ -87,23 +85,25 @@ async fn main() -> mongodb::error::Result<()> { // end-custom-callback-machine // start-custom-callback-user - async fn cb(params: CallbackContext) -> mongodb::error::Result { - let idp_info = params.idp_info.ok_or(Error::NoIDPInfo)?; - let (access_token, expires, refresh_token) = negotiate_with_idp(ctx, idpInfo.Issuer).await?; - Ok(IdpServerResponse::builder().access_token(access_token).expires(expires).refresh_token(refresh_token).build()) - } - client_options.credential = Credential::builder() - .mechanism(AuthMechanism::MongoDbOidc) - .oidc_callback(oidc::Callback::human(move|c| { - async move { cb(c).await }.boxed() - })) - .build() - .into(); + let callback = Callback::human(move |context| { + async move { + "" + todo!() + } + .boxed() + }); + let credential = Credential::builder() + .mechanism(AuthMechanism::MongoDbOidc) + .oidc_callback(callback) + .build(); + client_options.credential = Some(credential); + let client = Client::with_options(client_options)?; + let res = client .database("test") .collection::("test") .find_one(doc! {}) - .await; + .await?; // end-custom-callback-user Ok(()) From 03309a4cc00b9ef013cf82ba19a93e24ef303f1a Mon Sep 17 00:00:00 2001 From: Stephanie Aurelio Date: Thu, 5 Dec 2024 13:28:19 -0800 Subject: [PATCH 11/11] refining edits --- source/fundamentals/enterprise-auth.txt | 5 ++-- .../code-snippets/enterprise-auth.rs | 24 +++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/source/fundamentals/enterprise-auth.txt b/source/fundamentals/enterprise-auth.txt index dfc90fa3..1d7065fa 100644 --- a/source/fundamentals/enterprise-auth.txt +++ b/source/fundamentals/enterprise-auth.txt @@ -224,8 +224,8 @@ following process: 1. The driver retrieves the Identity Provider Information (IDPInfo) for the provided username. #. The callback negotiates with the IDP to obtain an ``access_token``, and any - potential ``refresh_token`` and timeout values, if configured, then returns - them. + potential ``refresh_token`` and timeout values, if configured. The callback + returns a ``Result``. The following example defines a custom callback to handle workforce identity. To customize this example for your use case, replace ```` with your own @@ -263,3 +263,4 @@ guide, see the following API documentation: - `with_options() <{+api+}/struct.Client.html#method.with_options>`__ - `CallbackContext <{+api+}/options/oidc/struct.CallbackContext.html>`__ - `IdpServerResponse <{+api+}/options/oidc/struct.IdpServerResponse.html>`__ +- `IdpServerInfo <{+api+}/options/oidc/struct.IdpServerInfo.html>`__ diff --git a/source/includes/fundamentals/code-snippets/enterprise-auth.rs b/source/includes/fundamentals/code-snippets/enterprise-auth.rs index 9a33077a..ae0373da 100644 --- a/source/includes/fundamentals/code-snippets/enterprise-auth.rs +++ b/source/includes/fundamentals/code-snippets/enterprise-auth.rs @@ -1,4 +1,4 @@ -use mongodb::options::oidc::{self, CallbackContext, IdpServerResponse}; +use mongodb::options::oidc::{self, Callback, CallbackContext, IdpServerResponse}; use mongodb::{ bson::doc, bson::Document, @@ -78,17 +78,17 @@ async fn main() -> mongodb::error::Result<()> { let client = Client::with_options(client_options)?; let res = client - .database("test") - .collection::("test") - .find_one(doc! {}) - .await?; + .database("test") + .collection::("test") + .find_one(doc! {}) + .await?; // end-custom-callback-machine // start-custom-callback-user let callback = Callback::human(move |context| { async move { - "" - todo!() + ""; + todo!("human flow") } .boxed() }); @@ -98,12 +98,12 @@ async fn main() -> mongodb::error::Result<()> { .build(); client_options.credential = Some(credential); let client = Client::with_options(client_options)?; - + let res = client - .database("test") - .collection::("test") - .find_one(doc! {}) - .await?; + .database("test") + .collection::("test") + .find_one(doc! {}) + .await?; // end-custom-callback-user Ok(())