Skip to content

Commit

Permalink
RUST-1562: Automatic token acquisition for Azure Identity Provider (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
pmeredit authored Apr 26, 2024
1 parent 24570ed commit b06660c
Show file tree
Hide file tree
Showing 8 changed files with 1,474 additions and 1,169 deletions.
49 changes: 49 additions & 0 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ buildvariants:
SSL: ssl
tasks:
- testoidc_task_group
- testazureoidc_task_group

- name: oidc-macos
display_name: "OIDC Macos"
Expand All @@ -315,6 +316,7 @@ buildvariants:
- testoidc_task_group

- name: oidc-windows
disable: true
display_name: "OIDC Windows"
patchable: true
run_on:
Expand All @@ -324,6 +326,7 @@ buildvariants:
SSL: ssl
tasks:
- testoidc_task_group
- testazureoidc_task_group

- name: in-use-encryption
display_name: "In-Use Encryption"
Expand Down Expand Up @@ -639,6 +642,33 @@ task_groups:
tasks:
- oidc-auth-test-latest

- name: testazureoidc_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
- command: shell.exec
params:
shell: bash
env:
AZUREOIDC_VMNAME_PREFIX: "RUST_DRIVER"
script: |
${PREPARE_SHELL}
${DRIVERS_TOOLS}/.evergreen/auth_oidc/azure/create-and-setup-vm.sh
teardown_task:
- command: subprocess.exec
params:
binary: bash
args:
- ${DRIVERS_TOOLS}/.evergreen/auth_oidc/azure/delete-vm.sh
setup_group_can_fail_task: true
setup_group_timeout_secs: 1800
tasks:
- oidc-auth-test-azure-latest

#########
# Tasks #
#########
Expand Down Expand Up @@ -1276,6 +1306,24 @@ tasks:
commands:
- func: "run oidc auth test with test credentials"

- name: "oidc-auth-test-azure-latest"
commands:
- command: shell.exec
params:
working_dir: src
shell: bash
script: |-
set -o errexit
${PREPARE_SHELL}
git add .
git commit -m "add files"
export AZUREOIDC_DRIVERS_TAR_FILE=/tmp/mongo-rust-driver.tgz
git archive -o $AZUREOIDC_DRIVERS_TAR_FILE HEAD
export AZUREOIDC_TEST_CMD="PROJECT_DIRECTORY='.' ./.evergreen/install-dependencies.sh rust\
&& PROJECT_DIRECTORY='.' .evergreen/install-dependencies.sh junit-dependencies\
&& PROJECT_DIRECTORY='.' OIDC_ENV=azure OIDC=oidc ./.evergreen/run-mongodb-oidc-test.sh"
bash $DRIVERS_TOOLS/.evergreen/auth_oidc/azure/run-driver-test.sh
#############
# Functions #
#############
Expand Down Expand Up @@ -1730,6 +1778,7 @@ functions:
include_expansions_in_env: ["DRIVERS_TOOLS", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"]
script: |
${PREPARE_SHELL}
export OIDC="oidc"
.evergreen/run-mongodb-oidc-test.sh
"compile only":
Expand Down
15 changes: 8 additions & 7 deletions .evergreen/run-mongodb-oidc-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ echo "Running MONGODB-OIDC authentication tests"

OIDC_ENV=${OIDC_ENV:-"test"}

export TEST_AUTH_OIDC=1
export COVERAGE=1
export AUTH="auth"

if [ $OIDC_ENV == "test" ]; then
# Make sure DRIVERS_TOOLS is set.
if [ -z "$DRIVERS_TOOLS" ]; then
Expand All @@ -18,20 +22,17 @@ if [ $OIDC_ENV == "test" ]; then
fi
source ${DRIVERS_TOOLS}/.evergreen/auth_oidc/secrets-export.sh

cargo nextest run test::spec::oidc::basic --no-capture --profile ci
RESULT=$?
elif [ $OIDC_ENV == "azure" ]; then
source ./env.sh

cargo nextest run test::spec::oidc::azure --no-capture --profile ci --features=azure-oidc
RESULT=$?
else
echo "Unrecognized OIDC_ENV $OIDC_ENV"
exit 1
fi

export TEST_AUTH_OIDC=1
export COVERAGE=1
export AUTH="auth"
export OIDC="oidc"

cargo nextest run test::spec::oidc --profile ci
RESULT=$?
cp target/nextest/ci/junit.xml results.xml
exit $RESULT
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ aws-auth = ["dep:reqwest"]
# This can only be used with the tokio-runtime feature flag.
azure-kms = ["dep:reqwest"]

# Enable support for azure OIDC authentication.
azure-oidc = ["dep:reqwest"]

# Enable support for on-demand GCP KMS credentials.
# This can only be used with the tokio-runtime feature flag.
gcp-kms = ["dep:reqwest"]
Expand Down
71 changes: 51 additions & 20 deletions src/client/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ 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.
///
Expand Down Expand Up @@ -184,40 +189,65 @@ impl AuthMechanism {
Ok(())
}
AuthMechanism::MongoDbOidc => {
let is_automatic = credential
let default_document = &Document::new();
let environment = credential
.mechanism_properties
.as_ref()
.map_or(false, |p| p.contains_key("PROVIDER_NAME"));
if credential.username.is_some() && is_automatic {
return Err(Error::invalid_argument(
"username and PROVIDER_NAME cannot both be specified for MONGODB-OIDC \
authentication",
));
.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
)));
}
match environment {
Ok(AZURE_ENVIRONMENT_VALUE_STR) | Ok(GCP_ENVIRONMENT_VALUE_STR) => {
if !credential
.mechanism_properties
.as_ref()
.unwrap_or(default_document)
.contains_key(TOKEN_RESOURCE_PROP_STR)
{
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,
)));
}
}
_ => (),
}
// TODO RUST-1660: Handle specific provider validation, perhaps also do Azure as
// part of this ticket. Specific providers will add predefined oidc_callback here
if credential
.source
.as_ref()
.map_or(false, |s| s != "$external")
{
return Err(Error::invalid_argument(
"source must be $external for MONGODB-OIDC authentication",
));
return Err(Error::invalid_argument(format!(
"source must be $external for {} authentication",
MONGODB_OIDC_STR
)));
}
if credential.password.is_some() {
return Err(Error::invalid_argument(
"password must not be set for MONGODB-OIDC authentication",
));
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"))
.and_then(|p| p.get(ALLOWED_HOSTS_PROP_STR))
{
allowed_hosts
.as_array()
.ok_or_else(|| Error::invalid_argument("ALLOWED_HOSTS must be an array"))?;
allowed_hosts.as_array().ok_or_else(|| {
Error::invalid_argument(format!(
"`{}` must be an array",
ALLOWED_HOSTS_PROP_STR
))
})?;
}
Ok(())
}
Expand Down Expand Up @@ -447,7 +477,8 @@ pub struct Credential {
// to how a user would interact with it.
#[serde(skip)]
#[derivative(Debug = "ignore", PartialEq = "ignore")]
pub(crate) oidc_callback: Option<oidc::State>,
#[builder(default)]
pub(crate) oidc_callback: oidc::State,
}

impl Credential {
Expand Down
Loading

0 comments on commit b06660c

Please sign in to comment.