Skip to content

Commit b06660c

Browse files
authored
RUST-1562: Automatic token acquisition for Azure Identity Provider (#1087)
1 parent 24570ed commit b06660c

File tree

8 files changed

+1474
-1169
lines changed

8 files changed

+1474
-1169
lines changed

.evergreen/config.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ buildvariants:
302302
SSL: ssl
303303
tasks:
304304
- testoidc_task_group
305+
- testazureoidc_task_group
305306

306307
- name: oidc-macos
307308
display_name: "OIDC Macos"
@@ -315,6 +316,7 @@ buildvariants:
315316
- testoidc_task_group
316317

317318
- name: oidc-windows
319+
disable: true
318320
display_name: "OIDC Windows"
319321
patchable: true
320322
run_on:
@@ -324,6 +326,7 @@ buildvariants:
324326
SSL: ssl
325327
tasks:
326328
- testoidc_task_group
329+
- testazureoidc_task_group
327330

328331
- name: in-use-encryption
329332
display_name: "In-Use Encryption"
@@ -639,6 +642,33 @@ task_groups:
639642
tasks:
640643
- oidc-auth-test-latest
641644

645+
- name: testazureoidc_task_group
646+
setup_group:
647+
- func: fetch source
648+
- func: create expansions
649+
- func: prepare resources
650+
- func: fix absolute paths
651+
- func: init test-results
652+
- func: make files executable
653+
- command: shell.exec
654+
params:
655+
shell: bash
656+
env:
657+
AZUREOIDC_VMNAME_PREFIX: "RUST_DRIVER"
658+
script: |
659+
${PREPARE_SHELL}
660+
${DRIVERS_TOOLS}/.evergreen/auth_oidc/azure/create-and-setup-vm.sh
661+
teardown_task:
662+
- command: subprocess.exec
663+
params:
664+
binary: bash
665+
args:
666+
- ${DRIVERS_TOOLS}/.evergreen/auth_oidc/azure/delete-vm.sh
667+
setup_group_can_fail_task: true
668+
setup_group_timeout_secs: 1800
669+
tasks:
670+
- oidc-auth-test-azure-latest
671+
642672
#########
643673
# Tasks #
644674
#########
@@ -1276,6 +1306,24 @@ tasks:
12761306
commands:
12771307
- func: "run oidc auth test with test credentials"
12781308

1309+
- name: "oidc-auth-test-azure-latest"
1310+
commands:
1311+
- command: shell.exec
1312+
params:
1313+
working_dir: src
1314+
shell: bash
1315+
script: |-
1316+
set -o errexit
1317+
${PREPARE_SHELL}
1318+
git add .
1319+
git commit -m "add files"
1320+
export AZUREOIDC_DRIVERS_TAR_FILE=/tmp/mongo-rust-driver.tgz
1321+
git archive -o $AZUREOIDC_DRIVERS_TAR_FILE HEAD
1322+
export AZUREOIDC_TEST_CMD="PROJECT_DIRECTORY='.' ./.evergreen/install-dependencies.sh rust\
1323+
&& PROJECT_DIRECTORY='.' .evergreen/install-dependencies.sh junit-dependencies\
1324+
&& PROJECT_DIRECTORY='.' OIDC_ENV=azure OIDC=oidc ./.evergreen/run-mongodb-oidc-test.sh"
1325+
bash $DRIVERS_TOOLS/.evergreen/auth_oidc/azure/run-driver-test.sh
1326+
12791327
#############
12801328
# Functions #
12811329
#############
@@ -1730,6 +1778,7 @@ functions:
17301778
include_expansions_in_env: ["DRIVERS_TOOLS", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"]
17311779
script: |
17321780
${PREPARE_SHELL}
1781+
export OIDC="oidc"
17331782
.evergreen/run-mongodb-oidc-test.sh
17341783
17351784
"compile only":

.evergreen/run-mongodb-oidc-test.sh

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ echo "Running MONGODB-OIDC authentication tests"
1010

1111
OIDC_ENV=${OIDC_ENV:-"test"}
1212

13+
export TEST_AUTH_OIDC=1
14+
export COVERAGE=1
15+
export AUTH="auth"
16+
1317
if [ $OIDC_ENV == "test" ]; then
1418
# Make sure DRIVERS_TOOLS is set.
1519
if [ -z "$DRIVERS_TOOLS" ]; then
@@ -18,20 +22,17 @@ if [ $OIDC_ENV == "test" ]; then
1822
fi
1923
source ${DRIVERS_TOOLS}/.evergreen/auth_oidc/secrets-export.sh
2024

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

30+
cargo nextest run test::spec::oidc::azure --no-capture --profile ci --features=azure-oidc
31+
RESULT=$?
2432
else
2533
echo "Unrecognized OIDC_ENV $OIDC_ENV"
2634
exit 1
2735
fi
2836

29-
export TEST_AUTH_OIDC=1
30-
export COVERAGE=1
31-
export AUTH="auth"
32-
export OIDC="oidc"
33-
34-
cargo nextest run test::spec::oidc --profile ci
35-
RESULT=$?
3637
cp target/nextest/ci/junit.xml results.xml
3738
exit $RESULT

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ aws-auth = ["dep:reqwest"]
4242
# This can only be used with the tokio-runtime feature flag.
4343
azure-kms = ["dep:reqwest"]
4444

45+
# Enable support for azure OIDC authentication.
46+
azure-oidc = ["dep:reqwest"]
47+
4548
# Enable support for on-demand GCP KMS credentials.
4649
# This can only be used with the tokio-runtime feature flag.
4750
gcp-kms = ["dep:reqwest"]

src/client/auth.rs

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ const MONGODB_AWS_STR: &str = "MONGODB-AWS";
3535
const MONGODB_X509_STR: &str = "MONGODB-X509";
3636
const PLAIN_STR: &str = "PLAIN";
3737
const MONGODB_OIDC_STR: &str = "MONGODB-OIDC";
38+
pub(crate) const TOKEN_RESOURCE_PROP_STR: &str = "TOKEN_RESOURCE";
39+
pub(crate) const ENVIRONMENT_PROP_STR: &str = "ENVIRONMENT";
40+
pub(crate) const ALLOWED_HOSTS_PROP_STR: &str = "ALLOWED_HOSTS";
41+
pub(crate) const AZURE_ENVIRONMENT_VALUE_STR: &str = "azure";
42+
pub(crate) const GCP_ENVIRONMENT_VALUE_STR: &str = "gcp";
3843

3944
/// The authentication mechanisms supported by MongoDB.
4045
///
@@ -184,40 +189,65 @@ impl AuthMechanism {
184189
Ok(())
185190
}
186191
AuthMechanism::MongoDbOidc => {
187-
let is_automatic = credential
192+
let default_document = &Document::new();
193+
let environment = credential
188194
.mechanism_properties
189195
.as_ref()
190-
.map_or(false, |p| p.contains_key("PROVIDER_NAME"));
191-
if credential.username.is_some() && is_automatic {
192-
return Err(Error::invalid_argument(
193-
"username and PROVIDER_NAME cannot both be specified for MONGODB-OIDC \
194-
authentication",
195-
));
196+
.unwrap_or(default_document)
197+
.get_str(ENVIRONMENT_PROP_STR);
198+
if environment.is_ok() && credential.oidc_callback.is_user_provided() {
199+
return Err(Error::invalid_argument(format!(
200+
"OIDC callback cannot be set for {} authentication, if an `{}` is set",
201+
MONGODB_OIDC_STR, ENVIRONMENT_PROP_STR
202+
)));
203+
}
204+
match environment {
205+
Ok(AZURE_ENVIRONMENT_VALUE_STR) | Ok(GCP_ENVIRONMENT_VALUE_STR) => {
206+
if !credential
207+
.mechanism_properties
208+
.as_ref()
209+
.unwrap_or(default_document)
210+
.contains_key(TOKEN_RESOURCE_PROP_STR)
211+
{
212+
return Err(Error::invalid_argument(format!(
213+
"`{}` must be set for {} authentication in the `{}` or `{}` `{}`",
214+
TOKEN_RESOURCE_PROP_STR,
215+
MONGODB_OIDC_STR,
216+
AZURE_ENVIRONMENT_VALUE_STR,
217+
GCP_ENVIRONMENT_VALUE_STR,
218+
ENVIRONMENT_PROP_STR,
219+
)));
220+
}
221+
}
222+
_ => (),
196223
}
197-
// TODO RUST-1660: Handle specific provider validation, perhaps also do Azure as
198-
// part of this ticket. Specific providers will add predefined oidc_callback here
199224
if credential
200225
.source
201226
.as_ref()
202227
.map_or(false, |s| s != "$external")
203228
{
204-
return Err(Error::invalid_argument(
205-
"source must be $external for MONGODB-OIDC authentication",
206-
));
229+
return Err(Error::invalid_argument(format!(
230+
"source must be $external for {} authentication",
231+
MONGODB_OIDC_STR
232+
)));
207233
}
208234
if credential.password.is_some() {
209-
return Err(Error::invalid_argument(
210-
"password must not be set for MONGODB-OIDC authentication",
211-
));
235+
return Err(Error::invalid_argument(format!(
236+
"password must not be set for {} authentication",
237+
MONGODB_OIDC_STR
238+
)));
212239
}
213240
if let Some(allowed_hosts) = credential
214241
.mechanism_properties
215242
.as_ref()
216-
.and_then(|p| p.get("ALLOWED_HOSTS"))
243+
.and_then(|p| p.get(ALLOWED_HOSTS_PROP_STR))
217244
{
218-
allowed_hosts
219-
.as_array()
220-
.ok_or_else(|| Error::invalid_argument("ALLOWED_HOSTS must be an array"))?;
245+
allowed_hosts.as_array().ok_or_else(|| {
246+
Error::invalid_argument(format!(
247+
"`{}` must be an array",
248+
ALLOWED_HOSTS_PROP_STR
249+
))
250+
})?;
221251
}
222252
Ok(())
223253
}
@@ -447,7 +477,8 @@ pub struct Credential {
447477
// to how a user would interact with it.
448478
#[serde(skip)]
449479
#[derivative(Debug = "ignore", PartialEq = "ignore")]
450-
pub(crate) oidc_callback: Option<oidc::State>,
480+
#[builder(default)]
481+
pub(crate) oidc_callback: oidc::State,
451482
}
452483

453484
impl Credential {

0 commit comments

Comments
 (0)