diff --git a/.evergreen/build-static-test-tarball.sh b/.evergreen/build-static-test-tarball.sh new file mode 100644 index 000000000..7567e5318 --- /dev/null +++ b/.evergreen/build-static-test-tarball.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -o errexit +set -o pipefail + +source ./.evergreen/env.sh + +export RUSTFLAGS="-C target-feature=+crt-static" +cargo test ${BUILD_FEATURES} --target x86_64-unknown-linux-gnu get_exe_name -- --ignored +TEST_BINARY=$(cat exe_name.txt) +TEST_TARBALL="/tmp/mongo-rust-driver.tar.gz" +tar czvf ${TEST_TARBALL} ${TEST_BINARY} ./.evergreen + +cat < static-test-tarball-expansion.yml +STATIC_TEST_BINARY: ${TEST_BINARY} +STATIC_TEST_TARBALL: ${TEST_TARBALL} +EOT \ No newline at end of file diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 352e674f9..930b7d5ad 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -291,9 +291,10 @@ buildvariants: AUTH: auth SSL: ssl tasks: - - testoidc_task_group - - testazureoidc_task_group - - testgcpoidc_task_group + - test-oidc-task-group + - test-azure-oidc-task-group + - test-gcp-oidc-task-group + - test-k8s-oidc-task-group - name: oidc-macos display_name: "OIDC Macos" @@ -304,7 +305,7 @@ buildvariants: AUTH: auth SSL: ssl tasks: - - testoidc_task_group + - test-oidc-task-group - name: oidc-windows disable: true @@ -316,9 +317,9 @@ buildvariants: AUTH: auth SSL: ssl tasks: - - testoidc_task_group - - testazureoidc_task_group - - testgcpoidc_task_group + - test-oidc-task-group + - test-azure-oidc-task-group + - test-gcp-oidc-task-group - name: in-use-encryption display_name: "In-Use Encryption" @@ -636,7 +637,7 @@ task_groups: tasks: - test-aws-lambda-deployed - - name: testoidc_task_group + - name: test-oidc-task-group setup_group: - func: fetch source - func: create expansions @@ -665,7 +666,7 @@ task_groups: tasks: - oidc-auth-test-latest - - name: testazureoidc_task_group + - name: test-azure-oidc-task-group setup_group: - func: fetch source - func: create expansions @@ -673,6 +674,7 @@ task_groups: - func: fix absolute paths - func: init test-results - func: make files executable + - func: install rust - command: subprocess.exec params: binary: bash @@ -691,7 +693,7 @@ task_groups: tasks: - oidc-auth-test-azure-latest - - name: testgcpoidc_task_group + - name: test-gcp-oidc-task-group setup_group: - func: fetch source - func: create expansions @@ -699,6 +701,7 @@ task_groups: - func: fix absolute paths - func: init test-results - func: make files executable + - func: install rust - command: subprocess.exec params: binary: bash @@ -717,6 +720,31 @@ task_groups: tasks: - oidc-auth-test-gcp-latest + - name: test-k8s-oidc-task-group + setup_group: + - func: fetch source + - func: create expansions + - func: prepare resources + - func: fix absolute paths + - func: init test-results + - func: make files executable + - func: install rust + - command: subprocess.exec + params: + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/k8s/setup.sh + teardown_task: + - command: subprocess.exec + params: + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/k8s/teardown.sh + setup_group_can_fail_task: true + setup_group_timeout_secs: 1800 + tasks: + - oidc-auth-test-k8s-latest + - name: happy-eyeballs-task-group setup_group_can_fail_task: true setup_group_timeout_secs: 1800 @@ -1156,59 +1184,52 @@ tasks: - name: "oidc-auth-test-azure-latest" commands: - - command: shell.exec + - func: "build static test tarball" + vars: + BUILD_FEATURES: "--features azure-oidc" + - command: subprocess.exec + type: test params: working_dir: src - shell: bash - script: |- - set -o errexit - ${PREPARE_SHELL} - ./.evergreen/install-dependencies.sh rust - source .cargo/env - export AZUREOIDC_DRIVERS_TAR_FILE=/tmp/mongo-rust-driver.tar - rustup default stable - export RUSTFLAGS="-C target-feature=+crt-static" - cargo test --features azure-oidc --target x86_64-unknown-linux-gnu get_exe_name -- --ignored - export TEST_FILE=$(cat exe_name.txt) - rm "$AZUREOIDC_DRIVERS_TAR_FILE" || true - tar -cf $AZUREOIDC_DRIVERS_TAR_FILE $TEST_FILE - tar -uf $AZUREOIDC_DRIVERS_TAR_FILE ./.evergreen - rm "$AZUREOIDC_DRIVERS_TAR_FILE".gz || true - gzip $AZUREOIDC_DRIVERS_TAR_FILE - export AZUREOIDC_DRIVERS_TAR_FILE=/tmp/mongo-rust-driver.tar.gz - # Define the command to run on the azure VM. - # Ensure that we source the environment file created for us, set up any other variables we need, - # and then run our test suite on the vm. - export AZUREOIDC_TEST_CMD="ls -laR data && PROJECT_DIRECTORY='.' OIDC_ENV=azure OIDC=oidc TEST_FILE=./$TEST_FILE ./.evergreen/run-mongodb-oidc-test.sh" - bash $DRIVERS_TOOLS/.evergreen/auth_oidc/azure/run-driver-test.sh + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/azure/run-driver-test.sh + env: + AZUREOIDC_DRIVERS_TAR_FILE: ${STATIC_TEST_TARBALL} + AZUREOIDC_TEST_CMD: "ls -laR data && PROJECT_DIRECTORY='.' OIDC_ENV=azure OIDC=oidc TEST_FILE=./${STATIC_TEST_BINARY} ./.evergreen/run-mongodb-oidc-test.sh" - name: "oidc-auth-test-gcp-latest" commands: - - command: shell.exec + - func: "build static test tarball" + vars: + BUILD_FEATURES: "--features gcp-oidc" + - command: subprocess.exec + type: test params: working_dir: src - shell: bash - script: |- - set -o errexit - ${PREPARE_SHELL} - ./.evergreen/install-dependencies.sh rust - source .cargo/env - export GCPOIDC_DRIVERS_TAR_FILE=/tmp/mongo-rust-driver.tar - rustup default stable - export RUSTFLAGS="-C target-feature=+crt-static" - cargo test --features gcp-oidc --target x86_64-unknown-linux-gnu test::atlas_planned_maintenance_testing::get_exe_name -- --ignored - export TEST_FILE=$(cat exe_name.txt) - rm "$GCPOIDC_DRIVERS_TAR_FILE" || true - tar -cf $GCPOIDC_DRIVERS_TAR_FILE $TEST_FILE - tar -uf $GCPOIDC_DRIVERS_TAR_FILE ./.evergreen - rm "$GCPOIDC_DRIVERS_TAR_FILE".gz || true - gzip $GCPOIDC_DRIVERS_TAR_FILE - export GCPOIDC_DRIVERS_TAR_FILE=/tmp/mongo-rust-driver.tar.gz - # Define the command to run on the gcp VM. - # Ensure that we source the environment file created for us, set up any other variables we need, - # and then run our test suite on the vm. - export GCPOIDC_TEST_CMD="ls -la && PROJECT_DIRECTORY='.' OIDC_ENV=gcp OIDC=oidc TEST_FILE=./$TEST_FILE ./.evergreen/run-mongodb-oidc-test.sh" - bash $DRIVERS_TOOLS/.evergreen/auth_oidc/gcp/run-driver-test.sh + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/gcp/run-driver-test.sh + env: + GCPOIDC_DRIVERS_TAR_FILE: ${STATIC_TEST_TARBALL} + GCPOIDC_TEST_CMD: "ls -la && PROJECT_DIRECTORY='.' OIDC_ENV=gcp OIDC=oidc TEST_FILE=./${STATIC_TEST_BINARY} ./.evergreen/run-mongodb-oidc-test.sh" + + - name: "oidc-auth-test-k8s-latest" + commands: + - func: "build static test tarball" + - command: ec2.assume_role + params: + role_arn: ${aws_test_secrets_role} + duration_seconds: 1800 + - func: "run oidc k8s test" + vars: + VARIANT: eks + - func: "run oidc k8s test" + vars: + VARIANT: gke + - func: "run oidc k8s test" + vars: + VARIANT: aks - name: "test-happy-eyeballs" commands: @@ -1925,3 +1946,56 @@ functions: - command: attach.xunit_results params: file: src/results.xml + + "build static test tarball": + - command: subprocess.exec + params: + working_dir: src + binary: bash + args: + - .evergreen/build-static-test-tarball.sh + include_expansions_in_env: + - PROJECT_DIRECTORY + - BUILD_FEATURES + - command: expansions.update + params: + file: src/static-test-tarball-expansion.yml + + "run oidc k8s test": + - command: subprocess.exec + params: + working_dir: src + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/k8s/setup-pod.sh + env: + K8S_VARIANT: ${VARIANT} + include_expansions_in_env: + - AWS_ACCESS_KEY_ID + - AWS_SECRET_ACCESS_KEY + - AWS_SESSION_TOKEN + - DRIVERS_TOOLS + - command: subprocess.exec + type: test + params: + working_dir: src + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/k8s/run-driver-test.sh + env: + K8S_DRIVERS_TAR_FILE: ${STATIC_TEST_TARBALL} + K8S_TEST_CMD: "ls -la && PROJECT_DIRECTORY='.' OIDC_ENV=k8s OIDC=oidc TEST_FILE=./${STATIC_TEST_BINARY} ./.evergreen/run-mongodb-oidc-test.sh" + include_expansions_in_env: + - AWS_ACCESS_KEY_ID + - AWS_SECRET_ACCESS_KEY + - AWS_SESSION_TOKEN + - command: subprocess.exec + params: + working_dir: src + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/k8s/teardown-pod.sh + include_expansions_in_env: + - AWS_ACCESS_KEY_ID + - AWS_SECRET_ACCESS_KEY + - AWS_SESSION_TOKEN diff --git a/.evergreen/run-mongodb-oidc-test.sh b/.evergreen/run-mongodb-oidc-test.sh index d3dcb875b..50d379622 100755 --- a/.evergreen/run-mongodb-oidc-test.sh +++ b/.evergreen/run-mongodb-oidc-test.sh @@ -35,8 +35,11 @@ elif [ $OIDC_ENV == "gcp" ]; then $TEST_FILE test::spec::oidc::gcp --nocapture RESULT=$? +elif [ $OIDC_ENV == "k8s" ]; then + $TEST_FILE test::spec::oidc::k8s --nocapture + RESULT=$? else - echo "Unrecognized OIDC_ENV $OIDC_ENV" + echo "Unrecognized OIDC_ENV '${OIDC_ENV}'" exit 1 fi diff --git a/Cargo.toml b/Cargo.toml index 3ca3de6fd..5d977aaa1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -143,7 +143,7 @@ version = "0.11.5" [dependencies.tokio] version = "1.17.0" -features = ["io-util", "sync", "macros", "net", "process", "rt", "time"] +features = ["io-util", "sync", "macros", "net", "process", "rt", "time", "fs"] [dependencies.tokio-rustls] version = "0.24.1" diff --git a/src/client/auth.rs b/src/client/auth.rs index 30181a4f0..31f203a34 100644 --- a/src/client/auth.rs +++ b/src/client/auth.rs @@ -37,11 +37,6 @@ const MONGODB_AWS_STR: &str = "MONGODB-AWS"; const MONGODB_X509_STR: &str = "MONGODB-X509"; const PLAIN_STR: &str = "PLAIN"; const MONGODB_OIDC_STR: &str = "MONGODB-OIDC"; -pub(crate) const TOKEN_RESOURCE_PROP_STR: &str = "TOKEN_RESOURCE"; -pub(crate) const ENVIRONMENT_PROP_STR: &str = "ENVIRONMENT"; -pub(crate) const ALLOWED_HOSTS_PROP_STR: &str = "ALLOWED_HOSTS"; -pub(crate) const AZURE_ENVIRONMENT_VALUE_STR: &str = "azure"; -pub(crate) const GCP_ENVIRONMENT_VALUE_STR: &str = "gcp"; /// The authentication mechanisms supported by MongoDB. /// @@ -189,81 +184,7 @@ impl AuthMechanism { Ok(()) } - AuthMechanism::MongoDbOidc => { - let default_document = &Document::new(); - let environment = credential - .mechanism_properties - .as_ref() - .unwrap_or(default_document) - .get_str(ENVIRONMENT_PROP_STR); - if environment.is_ok() && credential.oidc_callback.is_user_provided() { - return Err(Error::invalid_argument(format!( - "OIDC callback cannot be set for {} authentication, if an `{}` is set", - MONGODB_OIDC_STR, ENVIRONMENT_PROP_STR - ))); - } - let has_token_resource = credential - .mechanism_properties - .as_ref() - .unwrap_or(default_document) - .contains_key(TOKEN_RESOURCE_PROP_STR); - match environment { - Ok(AZURE_ENVIRONMENT_VALUE_STR) | Ok(GCP_ENVIRONMENT_VALUE_STR) => { - if !has_token_resource { - return Err(Error::invalid_argument(format!( - "`{}` must be set for {} authentication in the `{}` or `{}` `{}`", - TOKEN_RESOURCE_PROP_STR, - MONGODB_OIDC_STR, - AZURE_ENVIRONMENT_VALUE_STR, - GCP_ENVIRONMENT_VALUE_STR, - ENVIRONMENT_PROP_STR, - ))); - } - } - _ => { - if has_token_resource { - return Err(Error::invalid_argument(format!( - "`{}` must not be set for {} authentication unless using the `{}` \ - or `{}` `{}`", - TOKEN_RESOURCE_PROP_STR, - MONGODB_OIDC_STR, - AZURE_ENVIRONMENT_VALUE_STR, - GCP_ENVIRONMENT_VALUE_STR, - ENVIRONMENT_PROP_STR, - ))); - } - } - } - if credential - .source - .as_ref() - .map_or(false, |s| s != "$external") - { - return Err(Error::invalid_argument(format!( - "source must be $external for {} authentication, found: {:?}", - MONGODB_OIDC_STR, credential.source - ))); - } - if credential.password.is_some() { - return Err(Error::invalid_argument(format!( - "password must not be set for {} authentication", - MONGODB_OIDC_STR - ))); - } - if let Some(allowed_hosts) = credential - .mechanism_properties - .as_ref() - .and_then(|p| p.get(ALLOWED_HOSTS_PROP_STR)) - { - allowed_hosts.as_array().ok_or_else(|| { - Error::invalid_argument(format!( - "`{}` must be an array", - ALLOWED_HOSTS_PROP_STR - )) - })?; - } - Ok(()) - } + AuthMechanism::MongoDbOidc => oidc::validate_credential(credential), _ => Ok(()), } } diff --git a/src/client/auth/oidc.rs b/src/client/auth/oidc.rs index b033c0f4c..b481ccb37 100644 --- a/src/client/auth/oidc.rs +++ b/src/client/auth/oidc.rs @@ -7,29 +7,42 @@ use std::{ use tokio::sync::Mutex; use typed_builder::TypedBuilder; -#[cfg(any(feature = "azure-oidc", feature = "gcp-oidc"))] -use crate::client::auth::{ - AZURE_ENVIRONMENT_VALUE_STR, - ENVIRONMENT_PROP_STR, - GCP_ENVIRONMENT_VALUE_STR, - TOKEN_RESOURCE_PROP_STR, -}; use crate::{ - client::{ - auth::{ - sasl::{SaslResponse, SaslStart}, - AuthMechanism, - ALLOWED_HOSTS_PROP_STR, - }, - options::{ServerAddress, ServerApi}, - }, + client::options::{ServerAddress, ServerApi}, cmap::{Command, Connection}, error::{Error, Result}, BoxFuture, }; use bson::{doc, rawdoc, spec::BinarySubtype, Binary, Document}; -use super::{sasl::SaslContinue, Credential, MONGODB_OIDC_STR}; +use super::{ + sasl::{SaslContinue, SaslResponse, SaslStart}, + AuthMechanism, + Credential, + MONGODB_OIDC_STR, +}; + +pub(crate) const TOKEN_RESOURCE_PROP_STR: &str = "TOKEN_RESOURCE"; +pub(crate) const ENVIRONMENT_PROP_STR: &str = "ENVIRONMENT"; +pub(crate) const ALLOWED_HOSTS_PROP_STR: &str = "ALLOWED_HOSTS"; +const VALID_PROPERTIES: &[&str] = &[ + TOKEN_RESOURCE_PROP_STR, + ENVIRONMENT_PROP_STR, + ALLOWED_HOSTS_PROP_STR, +]; + +pub(crate) const AZURE_ENVIRONMENT_VALUE_STR: &str = "azure"; +pub(crate) const GCP_ENVIRONMENT_VALUE_STR: &str = "gcp"; +const K8S_ENVIRONMENT_VALUE_STR: &str = "k8s"; +#[cfg(test)] +const TEST_ENVIRONMENT_VALUE_STR: &str = "test"; +const VALID_ENVIRONMENTS: &[&str] = &[ + AZURE_ENVIRONMENT_VALUE_STR, + GCP_ENVIRONMENT_VALUE_STR, + K8S_ENVIRONMENT_VALUE_STR, + #[cfg(test)] + TEST_ENVIRONMENT_VALUE_STR, +]; const HUMAN_CALLBACK_TIMEOUT: Duration = Duration::from_secs(5 * 60); const MACHINE_CALLBACK_TIMEOUT: Duration = Duration::from_secs(60); @@ -144,7 +157,7 @@ impl Callback { /// Create azure callback. #[cfg(feature = "azure-oidc")] - fn azure_callback(client_id: Option<&str>, resource: &str) -> CallbackInner { + fn azure_callback(client_id: Option<&str>, resource: &str) -> Function { use futures_util::FutureExt; let resource = resource.to_string(); let client_id = client_id.map(|s| s.to_string()); @@ -155,104 +168,121 @@ impl Callback { if let Some(ref client_id) = client_id { url.push_str(&format!("&client_id={}", client_id)); } - CallbackInner { - function: Self::new_function( - move |_| { + Self::new_function( + move |_| { + let url = url.clone(); + async move { let url = url.clone(); - async move { - let url = url.clone(); - let response = crate::runtime::HttpClient::default() - .get(&url) - .headers(&[("Metadata", "true"), ("Accept", "application/json")]) - .send::() - .await - .map_err(|e| { - Error::authentication_error( - MONGODB_OIDC_STR, - &format!("Failed to get access token from Azure IDMS: {}", e), - ) - }); - let response = response?; - let access_token = response - .get_str("access_token") - .map_err(|e| { - Error::authentication_error( - MONGODB_OIDC_STR, - &format!("Failed to get access token from Azure IDMS: {}", e), - ) - })? - .to_string(); - let expires_in = response - .get_str("expires_in") - .map_err(|e| { - Error::authentication_error( - MONGODB_OIDC_STR, - &format!("Failed to get expires_in from Azure IDMS: {}", e), - ) - })? - .parse::() - .map_err(|e| { - Error::authentication_error( - MONGODB_OIDC_STR, - &format!( - "Failed to parse expires_in from Azure IDMS as u64: {}", - e - ), - ) - })?; - let expires = Some(Instant::now() + Duration::from_secs(expires_in)); - Ok(IdpServerResponse { - access_token, - expires, - refresh_token: None, - }) - } - .boxed() - }, - CallbackKind::Machine, - ), - cache: Cache::new(), - } + let response = crate::runtime::HttpClient::default() + .get(&url) + .headers(&[("Metadata", "true"), ("Accept", "application/json")]) + .send::() + .await + .map_err(|e| { + Error::authentication_error( + MONGODB_OIDC_STR, + &format!("Failed to get access token from Azure IDMS: {}", e), + ) + }); + let response = response?; + let access_token = response + .get_str("access_token") + .map_err(|e| { + Error::authentication_error( + MONGODB_OIDC_STR, + &format!("Failed to get access token from Azure IDMS: {}", e), + ) + })? + .to_string(); + let expires_in = response + .get_str("expires_in") + .map_err(|e| { + Error::authentication_error( + MONGODB_OIDC_STR, + &format!("Failed to get expires_in from Azure IDMS: {}", e), + ) + })? + .parse::() + .map_err(|e| { + Error::authentication_error( + MONGODB_OIDC_STR, + &format!( + "Failed to parse expires_in from Azure IDMS as u64: {}", + e + ), + ) + })?; + let expires = Some(Instant::now() + Duration::from_secs(expires_in)); + Ok(IdpServerResponse { + access_token, + expires, + refresh_token: None, + }) + } + .boxed() + }, + CallbackKind::Machine, + ) } /// Create gcp callback. #[cfg(feature = "gcp-oidc")] - fn gcp_callback(resource: &str) -> CallbackInner { + fn gcp_callback(resource: &str) -> Function { use futures_util::FutureExt; let url = format!( "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience={}", resource ); - CallbackInner { - function: Self::new_function( - move |_| { + Self::new_function( + move |_| { + let url = url.clone(); + async move { let url = url.clone(); - async move { - let url = url.clone(); - let response = crate::runtime::HttpClient::default() - .get(&url) - .headers(&[("Metadata-Flavor", "Google")]) - .send_and_get_string() - .await - .map_err(|e| { - Error::authentication_error( - MONGODB_OIDC_STR, - &format!("Failed to get access token from GCP IDMS: {}", e), - ) - }); - let access_token = response?; - Ok(IdpServerResponse { - access_token, - expires: None, - refresh_token: None, - }) - } - .boxed() - }, - CallbackKind::Machine, - ), - cache: Cache::new(), - } + let response = crate::runtime::HttpClient::default() + .get(&url) + .headers(&[("Metadata-Flavor", "Google")]) + .send_and_get_string() + .await + .map_err(|e| { + Error::authentication_error( + MONGODB_OIDC_STR, + &format!("Failed to get access token from GCP IDMS: {}", e), + ) + }); + let access_token = response?; + Ok(IdpServerResponse { + access_token, + expires: None, + refresh_token: None, + }) + } + .boxed() + }, + CallbackKind::Machine, + ) + } + + fn k8s_callback() -> Function { + Self::new_function( + move |_| { + use futures_util::FutureExt; + async move { + let path = std::env::var("AZURE_FEDERATED_TOKEN_FILE") + .or_else(|_| std::env::var("AWS_WEB_IDENTITY_TOKEN_FILE")) + .unwrap_or_else(|_| { + "/var/run/secrets/kubernetes.io/serviceaccount/token".to_string() + }); + let access_token = tokio::fs::read_to_string(path).await?; + Ok(IdpServerResponse { + access_token, + expires: None, + refresh_token: None, + }) + } + .boxed() + }, + CallbackKind::Machine, + ) } } @@ -507,7 +537,6 @@ pub(crate) async fn reauthenticate_stream( authenticate_stream(conn, credential, server_api, None).await } -#[cfg(any(feature = "azure-oidc", feature = "gcp-oidc"))] async fn setup_automatic_providers(credential: &Credential, callback: &mut Option) { // If there is already a function, there is no need to set up an automatic provider // this could happen in the case of a reauthentication, or if the user has already set up @@ -518,22 +547,24 @@ async fn setup_automatic_providers(credential: &Credential, callback: &mut Optio } if let Some(ref p) = credential.mechanism_properties { let environment = p.get_str(ENVIRONMENT_PROP_STR).unwrap_or(""); + #[cfg(any(feature = "azure-oidc", feature = "gcp-oidc"))] let resource = p.get_str(TOKEN_RESOURCE_PROP_STR).unwrap_or(""); - match environment { + let function = match environment { + #[cfg(feature = "azure-oidc")] AZURE_ENVIRONMENT_VALUE_STR => { - #[cfg(feature = "azure-oidc")] - { - let client_id = credential.username.as_deref(); - *callback = Some(Callback::azure_callback(client_id, resource)) - } - } - GCP_ENVIRONMENT_VALUE_STR => { - #[cfg(feature = "gcp-oidc")] - { - *callback = Some(Callback::gcp_callback(resource)) - } + let client_id = credential.username.as_deref(); + Some(Callback::azure_callback(client_id, resource)) } - _ => {} + #[cfg(feature = "gcp-oidc")] + GCP_ENVIRONMENT_VALUE_STR => Some(Callback::gcp_callback(resource)), + K8S_ENVIRONMENT_VALUE_STR => Some(Callback::k8s_callback()), + _ => None, + }; + if let Some(function) = function { + *callback = Some(CallbackInner { + function, + cache: Cache::new(), + }) } } } @@ -549,7 +580,6 @@ pub(crate) async fn authenticate_stream( // always matches that in the Credential Cache. let mut guard = credential.oidc_callback.inner.lock().await; - #[cfg(any(feature = "azure-oidc", feature = "gcp-oidc"))] setup_automatic_providers(credential, &mut guard).await; let CallbackInner { cache, @@ -886,3 +916,90 @@ async fn send_sasl_command( response.auth_response_body(MONGODB_OIDC_STR)?, ) } + +pub(super) fn validate_credential(credential: &Credential) -> Result<()> { + let default_document = &Document::new(); + let properties = credential + .mechanism_properties + .as_ref() + .unwrap_or(default_document); + for k in properties.keys() { + if VALID_PROPERTIES.iter().all(|p| *p != k) { + return Err(Error::invalid_argument(format!( + "'{}' is not a valid property for {} authentication", + k, MONGODB_OIDC_STR, + ))); + } + } + let environment = properties.get_str(ENVIRONMENT_PROP_STR); + if environment.is_ok() && credential.oidc_callback.is_user_provided() { + return Err(Error::invalid_argument(format!( + "OIDC callback cannot be set for {} authentication, if an `{}` is set", + MONGODB_OIDC_STR, ENVIRONMENT_PROP_STR + ))); + } + let has_token_resource = properties.contains_key(TOKEN_RESOURCE_PROP_STR); + match environment { + Ok(AZURE_ENVIRONMENT_VALUE_STR) | Ok(GCP_ENVIRONMENT_VALUE_STR) => { + if !has_token_resource { + return Err(Error::invalid_argument(format!( + "`{}` must be set for {} authentication in the `{}` or `{}` `{}`", + TOKEN_RESOURCE_PROP_STR, + MONGODB_OIDC_STR, + AZURE_ENVIRONMENT_VALUE_STR, + GCP_ENVIRONMENT_VALUE_STR, + ENVIRONMENT_PROP_STR, + ))); + } + } + _ => { + if has_token_resource { + return Err(Error::invalid_argument(format!( + "`{}` must not be set for {} authentication unless using the `{}` or `{}` `{}`", + TOKEN_RESOURCE_PROP_STR, + MONGODB_OIDC_STR, + AZURE_ENVIRONMENT_VALUE_STR, + GCP_ENVIRONMENT_VALUE_STR, + ENVIRONMENT_PROP_STR, + ))); + } + } + } + if credential + .source + .as_ref() + .map_or(false, |s| s != "$external") + { + return Err(Error::invalid_argument(format!( + "source must be $external for {} authentication, found: {:?}", + MONGODB_OIDC_STR, credential.source + ))); + } + #[cfg(test)] + if environment == Ok(TEST_ENVIRONMENT_VALUE_STR) && credential.username.is_some() { + return Err(Error::invalid_argument(format!( + "username must not be set for {} authentication in the {} {}", + MONGODB_OIDC_STR, TEST_ENVIRONMENT_VALUE_STR, ENVIRONMENT_PROP_STR, + ))); + } + if credential.password.is_some() { + return Err(Error::invalid_argument(format!( + "password must not be set for {} authentication", + MONGODB_OIDC_STR + ))); + } + if let Ok(env) = environment { + if VALID_ENVIRONMENTS.iter().all(|e| *e != env) { + return Err(Error::invalid_argument(format!( + "unsupported environment for {} authentication: {}", + MONGODB_OIDC_STR, env, + ))); + } + } + if let Some(allowed_hosts) = properties.get(ALLOWED_HOSTS_PROP_STR) { + allowed_hosts.as_array().ok_or_else(|| { + Error::invalid_argument(format!("`{}` must be an array", ALLOWED_HOSTS_PROP_STR)) + })?; + } + Ok(()) +} diff --git a/src/test/spec/auth.rs b/src/test/spec/auth.rs index e4183a5bd..35a0f8dff 100644 --- a/src/test/spec/auth.rs +++ b/src/test/spec/auth.rs @@ -65,6 +65,20 @@ async fn run_auth_test(test_file: TestFile) { { continue; } + // This one's GSSAPI but doesn't include it in the description + if test_case + .description + .contains("must raise an error when the hostname canonicalization is invalid") + { + continue; + } + // Lack of callback can't be validated from just URI parsing, as it's set in code + if test_case + .description + .contains("should throw an exception if neither environment nor callbacks specified") + { + continue; + } match ClientOptions::parse(test_case.uri.as_str()).await { Ok(options) => { diff --git a/src/test/spec/json/auth/connection-string.json b/src/test/spec/json/auth/connection-string.json index 2a37ae8df..29920de65 100644 --- a/src/test/spec/json/auth/connection-string.json +++ b/src/test/spec/json/auth/connection-string.json @@ -80,7 +80,7 @@ }, { "description": "should accept generic mechanism property (GSSAPI)", - "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com", "valid": true, "credential": { "username": "user@DOMAIN.COM", @@ -89,10 +89,46 @@ "mechanism": "GSSAPI", "mechanism_properties": { "SERVICE_NAME": "other", - "CANONICALIZE_HOST_NAME": true + "SERVICE_HOST": "example.com", + "CANONICALIZE_HOST_NAME": "forward" } } }, + { + "description": "should accept forwardAndReverse hostname canonicalization (GSSAPI)", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forwardAndReverse", + "valid": true, + "credential": { + "username": "user@DOMAIN.COM", + "password": null, + "source": "$external", + "mechanism": "GSSAPI", + "mechanism_properties": { + "SERVICE_NAME": "other", + "CANONICALIZE_HOST_NAME": "forwardAndReverse" + } + } + }, + { + "description": "should accept no hostname canonicalization (GSSAPI)", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:none", + "valid": true, + "credential": { + "username": "user@DOMAIN.COM", + "password": null, + "source": "$external", + "mechanism": "GSSAPI", + "mechanism_properties": { + "SERVICE_NAME": "other", + "CANONICALIZE_HOST_NAME": "none" + } + } + }, + { + "description": "must raise an error when the hostname canonicalization is invalid", + "uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:invalid", + "valid": false + }, { "description": "should accept the password (GSSAPI)", "uri": "mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI&authSource=$external", @@ -127,47 +163,6 @@ "uri": "mongodb://localhost/?authMechanism=GSSAPI", "valid": false }, - { - "description": "should recognize the mechanism (MONGODB-CR)", - "uri": "mongodb://user:password@localhost/?authMechanism=MONGODB-CR", - "valid": true, - "credential": { - "username": "user", - "password": "password", - "source": "admin", - "mechanism": "MONGODB-CR", - "mechanism_properties": null - } - }, - { - "description": "should use the database when no authSource is specified (MONGODB-CR)", - "uri": "mongodb://user:password@localhost/foo?authMechanism=MONGODB-CR", - "valid": true, - "credential": { - "username": "user", - "password": "password", - "source": "foo", - "mechanism": "MONGODB-CR", - "mechanism_properties": null - } - }, - { - "description": "should use the authSource when specified (MONGODB-CR)", - "uri": "mongodb://user:password@localhost/foo?authMechanism=MONGODB-CR&authSource=bar", - "valid": true, - "credential": { - "username": "user", - "password": "password", - "source": "bar", - "mechanism": "MONGODB-CR", - "mechanism_properties": null - } - }, - { - "description": "should throw an exception if no username is supplied (MONGODB-CR)", - "uri": "mongodb://localhost/?authMechanism=MONGODB-CR", - "valid": false - }, { "description": "should recognize the mechanism (MONGODB-X509)", "uri": "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509", @@ -444,6 +439,213 @@ "AWS_SESSION_TOKEN": "token!@#$%^&*()_+" } } + }, + { + "description": "should recognise the mechanism with test environment (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test", + "valid": true, + "credential": { + "username": null, + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "test" + } + } + }, + { + "description": "should recognise the mechanism when auth source is explicitly specified and with environment (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authSource=$external&authMechanismProperties=ENVIRONMENT:test", + "valid": true, + "credential": { + "username": null, + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "test" + } + } + }, + { + "description": "should throw an exception if supplied a password (MONGODB-OIDC)", + "uri": "mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test", + "valid": false, + "credential": null + }, + { + "description": "should throw an exception if username is specified for test (MONGODB-OIDC)", + "uri": "mongodb://principalName@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test", + "valid": false, + "credential": null + }, + { + "description": "should throw an exception if specified environment is not supported (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:invalid", + "valid": false, + "credential": null + }, + { + "description": "should throw an exception if neither environment nor callbacks specified (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC", + "valid": false, + "credential": null + }, + { + "description": "should throw an exception when unsupported auth property is specified (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=UnsupportedProperty:unexisted", + "valid": false, + "credential": null + }, + { + "description": "should recognise the mechanism with azure provider (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo", + "valid": true, + "credential": { + "username": null, + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "azure", + "TOKEN_RESOURCE": "foo" + } + } + }, + { + "description": "should accept a username with azure provider (MONGODB-OIDC)", + "uri": "mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo", + "valid": true, + "credential": { + "username": "user", + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "azure", + "TOKEN_RESOURCE": "foo" + } + } + }, + { + "description": "should accept a url-encoded TOKEN_RESOURCE (MONGODB-OIDC)", + "uri": "mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:mongodb%3A%2F%2Ftest-cluster", + "valid": true, + "credential": { + "username": "user", + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "azure", + "TOKEN_RESOURCE": "mongodb://test-cluster" + } + } + }, + { + "description": "should accept an un-encoded TOKEN_RESOURCE (MONGODB-OIDC)", + "uri": "mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:mongodb://test-cluster", + "valid": true, + "credential": { + "username": "user", + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "azure", + "TOKEN_RESOURCE": "mongodb://test-cluster" + } + } + }, + { + "description": "should handle a complicated url-encoded TOKEN_RESOURCE (MONGODB-OIDC)", + "uri": "mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:abcd%25ef%3Ag%26hi", + "valid": true, + "credential": { + "username": "user", + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "azure", + "TOKEN_RESOURCE": "abcd%ef:g&hi" + } + } + }, + { + "description": "should url-encode a TOKEN_RESOURCE (MONGODB-OIDC)", + "uri": "mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:a$b", + "valid": true, + "credential": { + "username": "user", + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "azure", + "TOKEN_RESOURCE": "a$b" + } + } + }, + { + "description": "should accept a username and throw an error for a password with azure provider (MONGODB-OIDC)", + "uri": "mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo", + "valid": false, + "credential": null + }, + { + "description": "should throw an exception if no token audience is given for azure provider (MONGODB-OIDC)", + "uri": "mongodb://username@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure", + "valid": false, + "credential": null + }, + { + "description": "should recognise the mechanism with gcp provider (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:foo", + "valid": true, + "credential": { + "username": null, + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "gcp", + "TOKEN_RESOURCE": "foo" + } + } + }, + { + "description": "should throw an error for a username and password with gcp provider (MONGODB-OIDC)", + "uri": "mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:foo", + "valid": false, + "credential": null + }, + { + "description": "should throw an error if not TOKEN_RESOURCE with gcp provider (MONGODB-OIDC)", + "uri": "mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp", + "valid": false, + "credential": null + }, + { + "description": "should recognise the mechanism with k8s provider (MONGODB-OIDC)", + "uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:k8s", + "valid": true, + "credential": { + "username": null, + "password": null, + "source": "$external", + "mechanism": "MONGODB-OIDC", + "mechanism_properties": { + "ENVIRONMENT": "k8s" + } + } + }, + { + "description": "should throw an error for a username and password with k8s provider (MONGODB-OIDC)", + "uri": "mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:k8s", + "valid": false, + "credential": null } ] -} +} \ No newline at end of file diff --git a/src/test/spec/json/auth/connection-string.yml b/src/test/spec/json/auth/connection-string.yml index 41dca8fab..6b82ef422 100644 --- a/src/test/spec/json/auth/connection-string.yml +++ b/src/test/spec/json/auth/connection-string.yml @@ -1,366 +1,471 @@ +--- tests: - - - description: "should use the default source and mechanism" - uri: "mongodb://user:password@localhost" - valid: true - credential: - username: "user" - password: "password" - source: "admin" - mechanism: ~ - mechanism_properties: ~ - - - description: "should use the database when no authSource is specified" - uri: "mongodb://user:password@localhost/foo" - valid: true - credential: - username: "user" - password: "password" - source: "foo" - mechanism: ~ - mechanism_properties: ~ - - - description: "should use the authSource when specified" - uri: "mongodb://user:password@localhost/foo?authSource=bar" - valid: true - credential: - username: "user" - password: "password" - source: "bar" - mechanism: ~ - mechanism_properties: ~ - - - description: "should recognise the mechanism (GSSAPI)" - uri: "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI" - valid: true - credential: - username: "user@DOMAIN.COM" - password: ~ - source: "$external" - mechanism: "GSSAPI" - mechanism_properties: - SERVICE_NAME: "mongodb" - - - description: "should ignore the database (GSSAPI)" - uri: "mongodb://user%40DOMAIN.COM@localhost/foo?authMechanism=GSSAPI" - valid: true - credential: - username: "user@DOMAIN.COM" - password: ~ - source: "$external" - mechanism: "GSSAPI" - mechanism_properties: - SERVICE_NAME: "mongodb" - - - description: "should accept valid authSource (GSSAPI)" - uri: "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authSource=$external" - valid: true - credential: - username: "user@DOMAIN.COM" - password: ~ - source: "$external" - mechanism: "GSSAPI" - mechanism_properties: - SERVICE_NAME: "mongodb" - - - description: "should accept generic mechanism property (GSSAPI)" - uri: "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true" - valid: true - credential: - username: "user@DOMAIN.COM" - password: ~ - source: "$external" - mechanism: "GSSAPI" - mechanism_properties: - SERVICE_NAME: "other" - CANONICALIZE_HOST_NAME: true - - - description: "should accept the password (GSSAPI)" - uri: "mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI&authSource=$external" - valid: true - credential: - username: "user@DOMAIN.COM" - password: "password" - source: "$external" - mechanism: "GSSAPI" - mechanism_properties: - SERVICE_NAME: "mongodb" - - - description: "must raise an error when the authSource is empty" - uri: "mongodb://user:password@localhost/foo?authSource=" - valid: false - - - description: "must raise an error when the authSource is empty without credentials" - uri: "mongodb://localhost/admin?authSource=" - valid: false - - - description: "should throw an exception if authSource is invalid (GSSAPI)" - uri: "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authSource=foo" - valid: false - - - description: "should throw an exception if no username (GSSAPI)" - uri: "mongodb://localhost/?authMechanism=GSSAPI" - valid: false - - - description: "should recognize the mechanism (MONGODB-CR)" - uri: "mongodb://user:password@localhost/?authMechanism=MONGODB-CR" - valid: true - credential: - username: "user" - password: "password" - source: "admin" - mechanism: "MONGODB-CR" - mechanism_properties: ~ - - - description: "should use the database when no authSource is specified (MONGODB-CR)" - uri: "mongodb://user:password@localhost/foo?authMechanism=MONGODB-CR" - valid: true - credential: - username: "user" - password: "password" - source: "foo" - mechanism: "MONGODB-CR" - mechanism_properties: ~ - - - description: "should use the authSource when specified (MONGODB-CR)" - uri: "mongodb://user:password@localhost/foo?authMechanism=MONGODB-CR&authSource=bar" - valid: true - credential: - username: "user" - password: "password" - source: "bar" - mechanism: "MONGODB-CR" - mechanism_properties: ~ - - - description: "should throw an exception if no username is supplied (MONGODB-CR)" - uri: "mongodb://localhost/?authMechanism=MONGODB-CR" - valid: false - - - description: "should recognize the mechanism (MONGODB-X509)" - uri: "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509" - valid: true - credential: - username: "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry" - password: ~ - source: "$external" - mechanism: "MONGODB-X509" - mechanism_properties: ~ - - - description: "should ignore the database (MONGODB-X509)" - uri: "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/foo?authMechanism=MONGODB-X509" - valid: true - credential: - username: "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry" - password: ~ - source: "$external" - mechanism: "MONGODB-X509" - mechanism_properties: ~ - - - description: "should accept valid authSource (MONGODB-X509)" - uri: "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509&authSource=$external" - valid: true - credential: - username: "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry" - password: ~ - source: "$external" - mechanism: "MONGODB-X509" - mechanism_properties: ~ - - - description: "should recognize the mechanism with no username (MONGODB-X509)" - uri: "mongodb://localhost/?authMechanism=MONGODB-X509" - valid: true - credential: - username: ~ - password: ~ - source: "$external" - mechanism: "MONGODB-X509" - mechanism_properties: ~ - - - description: "should recognize the mechanism with no username when auth source is explicitly specified (MONGODB-X509)" - uri: "mongodb://localhost/?authMechanism=MONGODB-X509&authSource=$external" - valid: true - credential: - username: ~ - password: ~ - source: "$external" - mechanism: "MONGODB-X509" - mechanism_properties: ~ - - - description: "should throw an exception if supplied a password (MONGODB-X509)" - uri: "mongodb://user:password@localhost/?authMechanism=MONGODB-X509" - valid: false - - - description: "should throw an exception if authSource is invalid (MONGODB-X509)" - uri: "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/foo?authMechanism=MONGODB-X509&authSource=bar" - valid: false - - - description: "should recognize the mechanism (PLAIN)" - uri: "mongodb://user:password@localhost/?authMechanism=PLAIN" - valid: true - credential: - username: "user" - password: "password" - source: "$external" - mechanism: "PLAIN" - mechanism_properties: ~ - - - description: "should use the database when no authSource is specified (PLAIN)" - uri: "mongodb://user:password@localhost/foo?authMechanism=PLAIN" - valid: true - credential: - username: "user" - password: "password" - source: "foo" - mechanism: "PLAIN" - mechanism_properties: ~ - - - description: "should use the authSource when specified (PLAIN)" - uri: "mongodb://user:password@localhost/foo?authMechanism=PLAIN&authSource=bar" - valid: true - credential: - username: "user" - password: "password" - source: "bar" - mechanism: "PLAIN" - mechanism_properties: ~ - - - description: "should throw an exception if no username (PLAIN)" - uri: "mongodb://localhost/?authMechanism=PLAIN" - valid: false - - - description: "should recognize the mechanism (SCRAM-SHA-1)" - uri: "mongodb://user:password@localhost/?authMechanism=SCRAM-SHA-1" - valid: true - credential: - username: "user" - password: "password" - source: "admin" - mechanism: "SCRAM-SHA-1" - mechanism_properties: ~ - - - description: "should use the database when no authSource is specified (SCRAM-SHA-1)" - uri: "mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-1" - valid: true - credential: - username: "user" - password: "password" - source: "foo" - mechanism: "SCRAM-SHA-1" - mechanism_properties: ~ - - - description: "should accept valid authSource (SCRAM-SHA-1)" - uri: "mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-1&authSource=bar" - valid: true - credential: - username: "user" - password: "password" - source: "bar" - mechanism: "SCRAM-SHA-1" - mechanism_properties: ~ - - - description: "should throw an exception if no username (SCRAM-SHA-1)" - uri: "mongodb://localhost/?authMechanism=SCRAM-SHA-1" - valid: false - - - description: "should recognize the mechanism (SCRAM-SHA-256)" - uri: "mongodb://user:password@localhost/?authMechanism=SCRAM-SHA-256" - valid: true - credential: - username: "user" - password: "password" - source: "admin" - mechanism: "SCRAM-SHA-256" - mechanism_properties: ~ - - - description: "should use the database when no authSource is specified (SCRAM-SHA-256)" - uri: "mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-256" - valid: true - credential: - username: "user" - password: "password" - source: "foo" - mechanism: "SCRAM-SHA-256" - mechanism_properties: ~ - - - description: "should accept valid authSource (SCRAM-SHA-256)" - uri: "mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-256&authSource=bar" - valid: true - credential: - username: "user" - password: "password" - source: "bar" - mechanism: "SCRAM-SHA-256" - mechanism_properties: ~ - - - description: "should throw an exception if no username (SCRAM-SHA-256)" - uri: "mongodb://localhost/?authMechanism=SCRAM-SHA-256" - valid: false - - - description: "URI with no auth-related info doesn't create credential" - uri: "mongodb://localhost/" - valid: true - credential: ~ - - - description: "database in URI path doesn't create credentials" - uri: "mongodb://localhost/foo" - valid: true - credential: ~ - - - description: "authSource without username doesn't create credential (default mechanism)" - uri: "mongodb://localhost/?authSource=foo" - valid: true - credential: ~ - - - description: "should throw an exception if no username provided (userinfo implies default mechanism)" - uri: "mongodb://@localhost.com/" - valid: false - - - description: "should throw an exception if no username/password provided (userinfo implies default mechanism)" - uri: "mongodb://:@localhost.com/" - valid: false - - - description: "should recognise the mechanism (MONGODB-AWS)" - uri: "mongodb://localhost/?authMechanism=MONGODB-AWS" - valid: true - credential: - username: ~ - password: ~ - source: "$external" - mechanism: "MONGODB-AWS" - mechanism_properties: ~ - - - description: "should recognise the mechanism when auth source is explicitly specified (MONGODB-AWS)" - uri: "mongodb://localhost/?authMechanism=MONGODB-AWS&authSource=$external" - valid: true - credential: - username: ~ - password: ~ - source: "$external" - mechanism: "MONGODB-AWS" - mechanism_properties: ~ - - - description: "should throw an exception if username and no password (MONGODB-AWS)" - uri: "mongodb://user@localhost/?authMechanism=MONGODB-AWS" - valid: false - credential: ~ - - - description: "should use username and password if specified (MONGODB-AWS)" - uri: "mongodb://user%21%40%23%24%25%5E%26%2A%28%29_%2B:pass%21%40%23%24%25%5E%26%2A%28%29_%2B@localhost/?authMechanism=MONGODB-AWS" - valid: true - credential: - username: "user!@#$%^&*()_+" - password: "pass!@#$%^&*()_+" - source: "$external" - mechanism: "MONGODB-AWS" - mechanism_properties: ~ - - - description: "should use username, password and session token if specified (MONGODB-AWS)" - uri: "mongodb://user:password@localhost/?authMechanism=MONGODB-AWS&authMechanismProperties=AWS_SESSION_TOKEN:token%21%40%23%24%25%5E%26%2A%28%29_%2B" - valid: true - credential: - username: "user" - password: "password" - source: "$external" - mechanism: "MONGODB-AWS" - mechanism_properties: - AWS_SESSION_TOKEN: "token!@#$%^&*()_+" +- description: should use the default source and mechanism + uri: mongodb://user:password@localhost + valid: true + credential: + username: user + password: password + source: admin + mechanism: + mechanism_properties: +- description: should use the database when no authSource is specified + uri: mongodb://user:password@localhost/foo + valid: true + credential: + username: user + password: password + source: foo + mechanism: + mechanism_properties: +- description: should use the authSource when specified + uri: mongodb://user:password@localhost/foo?authSource=bar + valid: true + credential: + username: user + password: password + source: bar + mechanism: + mechanism_properties: +- description: should recognise the mechanism (GSSAPI) + uri: mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI + valid: true + credential: + username: user@DOMAIN.COM + password: + source: "$external" + mechanism: GSSAPI + mechanism_properties: + SERVICE_NAME: mongodb +- description: should ignore the database (GSSAPI) + uri: mongodb://user%40DOMAIN.COM@localhost/foo?authMechanism=GSSAPI + valid: true + credential: + username: user@DOMAIN.COM + password: + source: "$external" + mechanism: GSSAPI + mechanism_properties: + SERVICE_NAME: mongodb +- description: should accept valid authSource (GSSAPI) + uri: mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authSource=$external + valid: true + credential: + username: user@DOMAIN.COM + password: + source: "$external" + mechanism: GSSAPI + mechanism_properties: + SERVICE_NAME: mongodb +- description: should accept generic mechanism property (GSSAPI) + uri: mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com + valid: true + credential: + username: user@DOMAIN.COM + password: + source: "$external" + mechanism: GSSAPI + mechanism_properties: + SERVICE_NAME: other + SERVICE_HOST: example.com + CANONICALIZE_HOST_NAME: forward +- description: should accept forwardAndReverse hostname canonicalization (GSSAPI) + uri: mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forwardAndReverse + valid: true + credential: + username: user@DOMAIN.COM + password: + source: "$external" + mechanism: GSSAPI + mechanism_properties: + SERVICE_NAME: other + CANONICALIZE_HOST_NAME: forwardAndReverse +- description: should accept no hostname canonicalization (GSSAPI) + uri: mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:none + valid: true + credential: + username: user@DOMAIN.COM + password: + source: "$external" + mechanism: GSSAPI + mechanism_properties: + SERVICE_NAME: other + CANONICALIZE_HOST_NAME: none +- description: must raise an error when the hostname canonicalization is invalid + uri: mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:invalid + valid: false +- description: should accept the password (GSSAPI) + uri: mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI&authSource=$external + valid: true + credential: + username: user@DOMAIN.COM + password: password + source: "$external" + mechanism: GSSAPI + mechanism_properties: + SERVICE_NAME: mongodb +- description: must raise an error when the authSource is empty + uri: mongodb://user:password@localhost/foo?authSource= + valid: false +- description: must raise an error when the authSource is empty without credentials + uri: mongodb://localhost/admin?authSource= + valid: false +- description: should throw an exception if authSource is invalid (GSSAPI) + uri: mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authSource=foo + valid: false +- description: should throw an exception if no username (GSSAPI) + uri: mongodb://localhost/?authMechanism=GSSAPI + valid: false +- description: should recognize the mechanism (MONGODB-X509) + uri: mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509 + valid: true + credential: + username: CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry + password: + source: "$external" + mechanism: MONGODB-X509 + mechanism_properties: +- description: should ignore the database (MONGODB-X509) + uri: mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/foo?authMechanism=MONGODB-X509 + valid: true + credential: + username: CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry + password: + source: "$external" + mechanism: MONGODB-X509 + mechanism_properties: +- description: should accept valid authSource (MONGODB-X509) + uri: mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509&authSource=$external + valid: true + credential: + username: CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry + password: + source: "$external" + mechanism: MONGODB-X509 + mechanism_properties: +- description: should recognize the mechanism with no username (MONGODB-X509) + uri: mongodb://localhost/?authMechanism=MONGODB-X509 + valid: true + credential: + username: + password: + source: "$external" + mechanism: MONGODB-X509 + mechanism_properties: +- description: should recognize the mechanism with no username when auth source is + explicitly specified (MONGODB-X509) + uri: mongodb://localhost/?authMechanism=MONGODB-X509&authSource=$external + valid: true + credential: + username: + password: + source: "$external" + mechanism: MONGODB-X509 + mechanism_properties: +- description: should throw an exception if supplied a password (MONGODB-X509) + uri: mongodb://user:password@localhost/?authMechanism=MONGODB-X509 + valid: false +- description: should throw an exception if authSource is invalid (MONGODB-X509) + uri: mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/foo?authMechanism=MONGODB-X509&authSource=bar + valid: false +- description: should recognize the mechanism (PLAIN) + uri: mongodb://user:password@localhost/?authMechanism=PLAIN + valid: true + credential: + username: user + password: password + source: "$external" + mechanism: PLAIN + mechanism_properties: +- description: should use the database when no authSource is specified (PLAIN) + uri: mongodb://user:password@localhost/foo?authMechanism=PLAIN + valid: true + credential: + username: user + password: password + source: foo + mechanism: PLAIN + mechanism_properties: +- description: should use the authSource when specified (PLAIN) + uri: mongodb://user:password@localhost/foo?authMechanism=PLAIN&authSource=bar + valid: true + credential: + username: user + password: password + source: bar + mechanism: PLAIN + mechanism_properties: +- description: should throw an exception if no username (PLAIN) + uri: mongodb://localhost/?authMechanism=PLAIN + valid: false +- description: should recognize the mechanism (SCRAM-SHA-1) + uri: mongodb://user:password@localhost/?authMechanism=SCRAM-SHA-1 + valid: true + credential: + username: user + password: password + source: admin + mechanism: SCRAM-SHA-1 + mechanism_properties: +- description: should use the database when no authSource is specified (SCRAM-SHA-1) + uri: mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-1 + valid: true + credential: + username: user + password: password + source: foo + mechanism: SCRAM-SHA-1 + mechanism_properties: +- description: should accept valid authSource (SCRAM-SHA-1) + uri: mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-1&authSource=bar + valid: true + credential: + username: user + password: password + source: bar + mechanism: SCRAM-SHA-1 + mechanism_properties: +- description: should throw an exception if no username (SCRAM-SHA-1) + uri: mongodb://localhost/?authMechanism=SCRAM-SHA-1 + valid: false +- description: should recognize the mechanism (SCRAM-SHA-256) + uri: mongodb://user:password@localhost/?authMechanism=SCRAM-SHA-256 + valid: true + credential: + username: user + password: password + source: admin + mechanism: SCRAM-SHA-256 + mechanism_properties: +- description: should use the database when no authSource is specified (SCRAM-SHA-256) + uri: mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-256 + valid: true + credential: + username: user + password: password + source: foo + mechanism: SCRAM-SHA-256 + mechanism_properties: +- description: should accept valid authSource (SCRAM-SHA-256) + uri: mongodb://user:password@localhost/foo?authMechanism=SCRAM-SHA-256&authSource=bar + valid: true + credential: + username: user + password: password + source: bar + mechanism: SCRAM-SHA-256 + mechanism_properties: +- description: should throw an exception if no username (SCRAM-SHA-256) + uri: mongodb://localhost/?authMechanism=SCRAM-SHA-256 + valid: false +- description: URI with no auth-related info doesn't create credential + uri: mongodb://localhost/ + valid: true + credential: +- description: database in URI path doesn't create credentials + uri: mongodb://localhost/foo + valid: true + credential: +- description: authSource without username doesn't create credential (default mechanism) + uri: mongodb://localhost/?authSource=foo + valid: true + credential: +- description: should throw an exception if no username provided (userinfo implies + default mechanism) + uri: mongodb://@localhost.com/ + valid: false +- description: should throw an exception if no username/password provided (userinfo + implies default mechanism) + uri: mongodb://:@localhost.com/ + valid: false +- description: should recognise the mechanism (MONGODB-AWS) + uri: mongodb://localhost/?authMechanism=MONGODB-AWS + valid: true + credential: + username: + password: + source: "$external" + mechanism: MONGODB-AWS + mechanism_properties: +- description: should recognise the mechanism when auth source is explicitly specified + (MONGODB-AWS) + uri: mongodb://localhost/?authMechanism=MONGODB-AWS&authSource=$external + valid: true + credential: + username: + password: + source: "$external" + mechanism: MONGODB-AWS + mechanism_properties: +- description: should throw an exception if username and no password (MONGODB-AWS) + uri: mongodb://user@localhost/?authMechanism=MONGODB-AWS + valid: false + credential: +- description: should use username and password if specified (MONGODB-AWS) + uri: mongodb://user%21%40%23%24%25%5E%26%2A%28%29_%2B:pass%21%40%23%24%25%5E%26%2A%28%29_%2B@localhost/?authMechanism=MONGODB-AWS + valid: true + credential: + username: user!@#$%^&*()_+ + password: pass!@#$%^&*()_+ + source: "$external" + mechanism: MONGODB-AWS + mechanism_properties: +- description: should use username, password and session token if specified (MONGODB-AWS) + uri: mongodb://user:password@localhost/?authMechanism=MONGODB-AWS&authMechanismProperties=AWS_SESSION_TOKEN:token%21%40%23%24%25%5E%26%2A%28%29_%2B + valid: true + credential: + username: user + password: password + source: "$external" + mechanism: MONGODB-AWS + mechanism_properties: + AWS_SESSION_TOKEN: token!@#$%^&*()_+ +- description: should recognise the mechanism with test environment (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test + valid: true + credential: + username: + password: + source: "$external" + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: test +- description: should recognise the mechanism when auth source is explicitly specified and with environment (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC&authSource=$external&authMechanismProperties=ENVIRONMENT:test + valid: true + credential: + username: + password: + source: "$external" + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: test +- description: should throw an exception if supplied a password (MONGODB-OIDC) + uri: mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test + valid: false + credential: +- description: should throw an exception if username is specified for test (MONGODB-OIDC) + uri: mongodb://principalName@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test + valid: false + credential: +- description: should throw an exception if specified environment is not supported (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:invalid + valid: false + credential: +- description: should throw an exception if neither environment nor callbacks specified (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC + valid: false + credential: +- description: should throw an exception when unsupported auth property is specified (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=UnsupportedProperty:unexisted + valid: false + credential: +- description: should recognise the mechanism with azure provider (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo + valid: true + credential: + username: null + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: azure + TOKEN_RESOURCE: foo +- description: should accept a username with azure provider (MONGODB-OIDC) + uri: mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo + valid: true + credential: + username: user + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: azure + TOKEN_RESOURCE: foo +- description: should accept a url-encoded TOKEN_RESOURCE (MONGODB-OIDC) + uri: mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:mongodb%3A%2F%2Ftest-cluster + valid: true + credential: + username: user + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: azure + TOKEN_RESOURCE: 'mongodb://test-cluster' +- description: should accept an un-encoded TOKEN_RESOURCE (MONGODB-OIDC) + uri: mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:mongodb://test-cluster + valid: true + credential: + username: user + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: azure + TOKEN_RESOURCE: 'mongodb://test-cluster' +- description: should handle a complicated url-encoded TOKEN_RESOURCE (MONGODB-OIDC) + uri: mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:abcd%25ef%3Ag%26hi + valid: true + credential: + username: user + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: azure + TOKEN_RESOURCE: 'abcd%ef:g&hi' +- description: should url-encode a TOKEN_RESOURCE (MONGODB-OIDC) + uri: mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:a$b + valid: true + credential: + username: user + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: azure + TOKEN_RESOURCE: a$b +- description: should accept a username and throw an error for a password with azure provider (MONGODB-OIDC) + uri: mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo + valid: false + credential: null +- description: should throw an exception if no token audience is given for azure provider (MONGODB-OIDC) + uri: mongodb://username@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure + valid: false + credential: null +- description: should recognise the mechanism with gcp provider (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:foo + valid: true + credential: + username: null + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: gcp + TOKEN_RESOURCE: foo +- description: should throw an error for a username and password with gcp provider + (MONGODB-OIDC) + uri: mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:foo + valid: false + credential: null +- description: should throw an error if not TOKEN_RESOURCE with gcp provider (MONGODB-OIDC) + uri: mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp + valid: false + credential: null +- description: should recognise the mechanism with k8s provider (MONGODB-OIDC) + uri: mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:k8s + valid: true + credential: + username: null + password: null + source: $external + mechanism: MONGODB-OIDC + mechanism_properties: + ENVIRONMENT: k8s +- description: should throw an error for a username and password with k8s provider + (MONGODB-OIDC) + uri: mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:k8s + valid: false + credential: null \ No newline at end of file diff --git a/src/test/spec/oidc.rs b/src/test/spec/oidc.rs index dd7ca8b9d..4c422805f 100644 --- a/src/test/spec/oidc.rs +++ b/src/test/spec/oidc.rs @@ -3,8 +3,7 @@ macro_rules! get_env_or_skip { match std::env::var($env_var) { Ok(val) => val, Err(_) => { - use crate::test::log_uncaptured; - log_uncaptured(&format!("Skipping test, {} not set", $env_var)); + crate::test::log_uncaptured(&format!("Skipping test, {} not set", $env_var)); return Ok(()); } } @@ -239,7 +238,7 @@ mod basic { #[tokio::test] async fn machine_2_4_invalid_client_configuration_with_callback() -> anyhow::Result<()> { get_env_or_skip!("OIDC"); - use crate::client::auth::{ENVIRONMENT_PROP_STR, TOKEN_RESOURCE_PROP_STR}; + use crate::client::auth::oidc::{ENVIRONMENT_PROP_STR, TOKEN_RESOURCE_PROP_STR}; // we need to assert the callback count let call_count = Arc::new(Mutex::new(0)); let cb_call_count = call_count.clone(); @@ -585,7 +584,7 @@ mod basic { #[tokio::test] async fn human_1_6_allowed_hosts_blocked() -> anyhow::Result<()> { get_env_or_skip!("OIDC"); - use crate::client::auth::ALLOWED_HOSTS_PROP_STR; + use crate::client::auth::oidc::ALLOWED_HOSTS_PROP_STR; { // we need to assert the callback count let call_count = Arc::new(Mutex::new(0)); @@ -1220,7 +1219,7 @@ mod azure { #[tokio::test] async fn machine_5_3_token_resource_must_be_set_for_azure() -> anyhow::Result<()> { get_env_or_skip!("OIDC"); - use crate::client::auth::{AZURE_ENVIRONMENT_VALUE_STR, ENVIRONMENT_PROP_STR}; + use crate::client::auth::oidc::{AZURE_ENVIRONMENT_VALUE_STR, ENVIRONMENT_PROP_STR}; let mut opts = ClientOptions::parse(mongodb_uri_single!()).await?; opts.credential.as_mut().unwrap().mechanism_properties = Some(doc! { @@ -1264,7 +1263,7 @@ mod gcp { #[tokio::test] async fn machine_5_5_token_resource_must_be_set_for_gcp() -> anyhow::Result<()> { get_env_or_skip!("OIDC"); - use crate::client::auth::{ENVIRONMENT_PROP_STR, GCP_ENVIRONMENT_VALUE_STR}; + use crate::client::auth::oidc::{ENVIRONMENT_PROP_STR, GCP_ENVIRONMENT_VALUE_STR}; let mut opts = ClientOptions::parse(mongodb_uri_single!()).await?; opts.credential.as_mut().unwrap().source = None; @@ -1286,3 +1285,25 @@ mod gcp { Ok(()) } } + +mod k8s { + use crate::{ + bson::{doc, Document}, + Client, + }; + + // There's no spec test for K8s, so we run this simple sanity check. + #[tokio::test] + async fn successfully_authenticates() -> anyhow::Result<()> { + get_env_or_skip!("OIDC"); + + let client = Client::with_uri_str(mongodb_uri_single!()).await?; + client + .database("test") + .collection::("test") + .find_one(doc! {}) + .await?; + + Ok(()) + } +}