Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions .evergreen/config_generator/components/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,30 @@ def task_groups():
script='./drivers-evergreen-tools/.evergreen/auth_oidc/teardown.sh',
)
],
),
EvgTaskGroup(
name='test-oidc-azure-task-group',
tasks=['oidc-azure-auth-test-task'],
setup_group_can_fail_task=True,
setup_group_timeout_secs=60 * 60, # 1 hour
teardown_group_can_fail_task=True,
teardown_group_timeout_secs=180, # 3 minutes
Comment on lines +42 to +45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
setup_group_can_fail_task=True,
setup_group_timeout_secs=60 * 60, # 1 hour
teardown_group_can_fail_task=True,
teardown_group_timeout_secs=180, # 3 minutes
setup_group_can_fail_task=True,
teardown_group_can_fail_task=True,
teardown_group_timeout_secs=180, # 3 minutes

The project-level default timeout is already set to 1 hour and applies to both pre and task setup commands (but not task teardown or post commands).

setup_group=[
FetchDET.call(),
ec2_assume_role(role_arn='${aws_test_secrets_role}'),
bash_exec(
command_type=EvgCommandType.SETUP,
include_expansions_in_env=['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_SESSION_TOKEN'],
env={"AZUREOIDC_VMNAME_PREFIX": "CDRIVER"},
script='./drivers-evergreen-tools/.evergreen/auth_oidc/azure/create-and-setup-vm.sh',
),
],
teardown_group=[
bash_exec(
command_type=EvgCommandType.SETUP,
script='./drivers-evergreen-tools/.evergreen/auth_oidc/azure/delete-vm.sh',
)
],
)
]

Expand All @@ -59,6 +83,29 @@ def tasks():
),
RunTests.call(),
],
),
EvgTask(
name='oidc-azure-auth-test-task',
run_on=['debian11-small'], # TODO: switch to 'debian11-latest' after DEVPROD-23011 fixed.
commands=[
FetchSource.call(),
bash_exec(
working_dir="mongoc",
add_expansions_to_env=True,
command_type=EvgCommandType.TEST,
script='.evergreen/scripts/oidc-azure-compile.sh',
),
expansions_update(file="mongoc/oidc-remote-test-expansion.yml"),
bash_exec(
add_expansions_to_env=True,
command_type=EvgCommandType.TEST,
env={
"AZUREOIDC_DRIVERS_TAR_FILE": "${OIDC_TEST_TARBALL}",
"AZUREOIDC_TEST_CMD": "source ./env.sh && ./.evergreen/scripts/oidc-azure-test.sh"
},
script='./drivers-evergreen-tools/.evergreen/auth_oidc/azure/run-driver-test.sh',
),
],
)
]

Expand All @@ -68,7 +115,6 @@ def variants():
BuildVariant(
name='oidc',
display_name='OIDC',
run_on=[find_small_distro('ubuntu2404').name],
tasks=[EvgTaskRef(name='test-oidc-task-group')],
tasks=[EvgTaskRef(name='test-oidc-task-group'), EvgTaskRef(name='test-oidc-azure-task-group')],
),
]
32 changes: 32 additions & 0 deletions .evergreen/generated_configs/task_groups.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,36 @@
task_groups:
- name: test-oidc-azure-task-group
setup_group:
- func: fetch-det
- command: ec2.assume_role
params:
role_arn: ${aws_test_secrets_role}
- command: subprocess.exec
type: setup
params:
binary: bash
env:
AZUREOIDC_VMNAME_PREFIX: CDRIVER
include_expansions_in_env:
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_SESSION_TOKEN
args:
- -c
- ./drivers-evergreen-tools/.evergreen/auth_oidc/azure/create-and-setup-vm.sh
setup_group_can_fail_task: true
setup_group_timeout_secs: 3600
tasks:
- oidc-azure-auth-test-task
teardown_group:
- command: subprocess.exec
type: setup
params:
binary: bash
args:
- -c
- ./drivers-evergreen-tools/.evergreen/auth_oidc/azure/delete-vm.sh
teardown_group_timeout_secs: 180
- name: test-oidc-task-group
setup_group:
- func: fetch-det
Expand Down
28 changes: 28 additions & 0 deletions .evergreen/generated_configs/tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4221,6 +4221,34 @@ tasks:
- { key: MONGODB_VERSION, value: latest }
- { key: TOPOLOGY, value: replica_set }
- func: run-tests
- name: oidc-azure-auth-test-task
run_on:
- debian11-small
commands:
- func: fetch-source
- command: subprocess.exec
type: test
params:
binary: bash
working_dir: mongoc
add_expansions_to_env: true
args:
- -c
- .evergreen/scripts/oidc-azure-compile.sh
- command: expansions.update
params:
file: mongoc/oidc-remote-test-expansion.yml
- command: subprocess.exec
type: test
params:
binary: bash
add_expansions_to_env: true
env:
AZUREOIDC_DRIVERS_TAR_FILE: ${OIDC_TEST_TARBALL}
AZUREOIDC_TEST_CMD: source ./env.sh && ./.evergreen/scripts/oidc-azure-test.sh
args:
- -c
- ./drivers-evergreen-tools/.evergreen/auth_oidc/azure/run-driver-test.sh
- name: openssl-compat-1.0.2-shared-ubuntu2404-gcc
run_on: ubuntu2404-large
tags: [openssl-compat, openssl-1.0.2, openssl-shared, ubuntu2404, gcc]
Expand Down
3 changes: 1 addition & 2 deletions .evergreen/generated_configs/variants.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,9 @@ buildvariants:
- name: mock-server-test
- name: oidc
display_name: OIDC
run_on:
- ubuntu2404-small
tasks:
- name: test-oidc-task-group
- name: test-oidc-azure-task-group
- name: openssl-compat-matrix
display_name: OpenSSL Compatibility Matrix
tasks:
Expand Down
57 changes: 57 additions & 0 deletions .evergreen/scripts/oidc-azure-compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset

# shellcheck source=.evergreen/scripts/use-tools.sh
. "$(dirname "${BASH_SOURCE[0]}")/use-tools.sh" paths # Sets MONGOC_DIR

cd "$MONGOC_DIR"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working directory is already set to mongoc via the EVG task definition:

bash_exec(
    working_dir="mongoc",
    add_expansions_to_env=True,
    command_type=EvgCommandType.TEST,
    script='.evergreen/scripts/oidc-azure-compile.sh',
),


if [[ "${distro_id:?}" == "debian11-small" ]]; then
# Temporary workaround for lack of uv on `debian11`. TODO: remove after DEVPROD-23011 is resolved.
uv_dir="$(mktemp -d)"
python3 -m virtualenv "${uv_dir:?}"
# shellcheck source=/dev/null
(. "${uv_dir:?}/bin/activate" && python -m pip install uv)
PATH="${uv_dir:?}/bin:${PATH:-}"
command -V uv >/dev/null
fi

. .evergreen/scripts/install-build-tools.sh
install_build_tools
export CMAKE_GENERATOR="Ninja"

# Use ccache if able.
. .evergreen/scripts/find-ccache.sh
find_ccache_and_export_vars "$(pwd)" || true

echo "Compile test-libmongoc ... begin"
# Disable unnecessary dependencies. test-libmongoc is copied to a remote host for testing, which may not have all dependent libraries.
cmake \
-DENABLE_SASL=OFF \
-DENABLE_SNAPPY=OFF \
-DENABLE_ZSTD=OFF \
-DENABLE_ZLIB=OFF \
-DENABLE_SRV=OFF \
-DENABLE_CLIENT_SIDE_ENCRYPTION=OFF \
-DENABLE_EXAMPLES=OFF \
-DENABLE_SRV=OFF \
-S. -Bcmake-build
Comment on lines +31 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cmake \
-DENABLE_SASL=OFF \
-DENABLE_SNAPPY=OFF \
-DENABLE_ZSTD=OFF \
-DENABLE_ZLIB=OFF \
-DENABLE_SRV=OFF \
-DENABLE_CLIENT_SIDE_ENCRYPTION=OFF \
-DENABLE_EXAMPLES=OFF \
-DENABLE_SRV=OFF \
-S. -Bcmake-build
cmake_flags=(
-DENABLE_SASL=OFF
-DENABLE_SNAPPY=OFF
-DENABLE_ZSTD=OFF
-DENABLE_ZLIB=OFF
-DENABLE_SRV=OFF
-DENABLE_CLIENT_SIDE_ENCRYPTION=OFF
-DENABLE_EXAMPLES=OFF
-DENABLE_SRV=OFF
)
cmake "${cmake_flags[@]}" -Bcmake-build

Avoid awkward backslashes + redundant -S for current working directory as source.

cmake --build cmake-build --target test-libmongoc --parallel
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cmake --build cmake-build --target test-libmongoc --parallel
cmake --build cmake-build --target test-libmongoc

Ninja generator already uses max parallelism by default.

echo "Compile test-libmongoc ... end"

# Create tarball for remote testing.
echo "Creating test-libmongoc tarball ... begin"

# Copy test binary and JSON test files. All JSON test files are needed to start test-libmongoc.
tar -czf test-libmongoc.tar.gz \
.evergreen/scripts/oidc-azure-test.sh \
./cmake-build/src/libmongoc/test-libmongoc \
src/libmongoc/tests/json \
src/libbson/tests/json
Comment on lines +48 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
tar -czf test-libmongoc.tar.gz \
.evergreen/scripts/oidc-azure-test.sh \
./cmake-build/src/libmongoc/test-libmongoc \
src/libmongoc/tests/json \
src/libbson/tests/json
files=(
.evergreen/scripts/oidc-azure-test.sh
cmake-build/src/libmongoc/test-libmongoc
src/libmongoc/tests/json
src/libbson/tests/json
)
tar -czf test-libmongoc.tar.gz "${files[@]}"

Avoid awkward backslashes.

echo "Creating test-libmongoc tarball ... end"

cat <<EOT > oidc-remote-test-expansion.yml
OIDC_TEST_TARBALL: ${MONGOC_DIR}/test-libmongoc.tar.gz
EOT
14 changes: 14 additions & 0 deletions .evergreen/scripts/oidc-azure-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset

export MONGOC_TEST_OIDC="ON"
export MONGOC_TEST_USER="$OIDC_ADMIN_USER"
export MONGOC_TEST_PASSWORD="$OIDC_ADMIN_PWD"
export MONGOC_AZURE_RESOURCE="$AZUREOIDC_RESOURCE"

# Install required OpenSSL runtime library.
sudo apt install -y libssl-dev

./cmake-build/src/libmongoc/test-libmongoc -d --match '/auth/unified/*' --match '/oidc/*'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this include -f/--no-fork?

Aside: I think most scripts use the shorter -l instead of --match.

1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ To run test cases with large allocations, set:
* `MONGOC_TEST_LARGE_ALLOCATIONS=on` This may result in sudden test suite termination due to allocation failure. Use with caution.

* `MONGOC_TEST_OIDC=on` to test OIDC using a test environment described [here](https://github.com/mongodb-labs/drivers-evergreen-tools/tree/d7a7337b384392a09fbe7fc80a7244e6f1226c18/.evergreen/auth_oidc).
* `MONGOC_AZURE_RESOURCE=<resource>` to test OIDC using an Azure test environment described [here](https://github.com/mongodb-labs/drivers-evergreen-tools/blob/d7a7337b384392a09fbe7fc80a7244e6f1226c18/.evergreen/auth_oidc/azure/README.md).

All tests should pass before submitting a patch.

Expand Down
62 changes: 52 additions & 10 deletions src/libmongoc/src/mongoc/mcd-azure.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,23 @@

#define AZURE_API_VERSION "2018-02-01"

static const char *const DEFAULT_METADATA_PATH =
"/metadata/identity/oauth2/"
"token?api-version=" AZURE_API_VERSION "&resource=https%3A%2F%2Fvault.azure.net";
static const char *const DEFAULT_METADATA_PATH = "/metadata/identity/oauth2/token?api-version=" AZURE_API_VERSION;

void
bool
mcd_azure_imds_request_init(mcd_azure_imds_request *req,
const char *token_resource,
const char *const opt_imds_host,
int opt_port,
const char *const opt_extra_headers)
const char *const opt_extra_headers,
const char *const opt_client_id)
{
BSON_ASSERT_PARAM(req);
BSON_ASSERT_PARAM(token_resource);

bool ok = false;
char *encoded_token_resource = NULL;
mcommon_string_append_t path = {0};

_mongoc_http_request_init(&req->req);
// The HTTP host of the IMDS server
req->req.host = req->_owned_host = bson_strdup(opt_imds_host ? opt_imds_host : "169.254.169.254");
Expand All @@ -50,9 +56,33 @@ mcd_azure_imds_request_init(mcd_azure_imds_request *req,
req->req.extra_headers = req->_owned_headers = bson_strdup_printf("Metadata: true\r\n"
"Accept: application/json\r\n%s",
opt_extra_headers ? opt_extra_headers : "");
// The default path is suitable. In the future, we may want to add query
// parameters to disambiguate a managed identity.
req->req.path = req->_owned_path = bson_strdup(DEFAULT_METADATA_PATH);
// Build the path with query parameters.
encoded_token_resource = mongoc_percent_encode(token_resource);
if (!encoded_token_resource) {
goto fail;
}

mcommon_string_new_as_append(&path);

if (!mcommon_string_append(&path, DEFAULT_METADATA_PATH) ||
!mcommon_string_append_printf(&path, "&resource=%s", encoded_token_resource)) {
goto fail;
}

if (opt_client_id) {
if (!mcommon_string_append_printf(&path, "&client_id=%s", opt_client_id)) {
goto fail;
}
}

req->req.path = req->_owned_path = mcommon_string_from_append_destroy_with_steal(&path);
path = (mcommon_string_append_t){0};

ok = true;
fail:
bson_free(encoded_token_resource);
mcommon_string_from_append_destroy(&path);
return ok;
}

void
Expand Down Expand Up @@ -156,11 +186,15 @@ mcd_azure_access_token_destroy(mcd_azure_access_token *c)

bool
mcd_azure_access_token_from_imds(mcd_azure_access_token *const out,
const char *token_resource,
const char *const opt_imds_host,
int opt_port,
const char *opt_extra_headers,
int opt_timeout_ms,
const char *opt_client_id,
bson_error_t *error)
{
BSON_ASSERT_PARAM(token_resource);
BSON_ASSERT_PARAM(out);

bool okay = false;
Expand All @@ -172,9 +206,17 @@ mcd_azure_access_token_from_imds(mcd_azure_access_token *const out,
_mongoc_http_response_init(&resp);

mcd_azure_imds_request req = MCD_AZURE_IMDS_REQUEST_INIT;
mcd_azure_imds_request_init(&req, opt_imds_host, opt_port, opt_extra_headers);
if (!mcd_azure_imds_request_init(&req, token_resource, opt_imds_host, opt_port, opt_extra_headers, opt_client_id)) {
_mongoc_set_error(error, MONGOC_ERROR_AZURE, MONGOC_ERROR_KMS_SERVER_HTTP, "Failed to initialize request");
goto fail;
}

int timeout_ms = 3 * 1000; // Default 3 second timeout
if (opt_timeout_ms > 0) {
timeout_ms = opt_timeout_ms;
}
Comment on lines +214 to +217
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int timeout_ms = 3 * 1000; // Default 3 second timeout
if (opt_timeout_ms > 0) {
timeout_ms = opt_timeout_ms;
}
const mlib_time_point now = mlib_now();
mlib_timer timer = mlib_expires_at(mlib_time_add(now, (3, s))); // Default 3 second timeout.
if (opt_timeout_ms > 0) {
timer = mlib_expires_at(mlib_time_add(now, (opt_timeout_ms, ms)));
}

Suggest implementing new timer/expiry/duration code in terms of mlib utilities when able.


if (!_mongoc_http_send(&req.req, 3 * 1000, false, NULL, &resp, error)) {
if (!_mongoc_http_send(&req.req, timeout_ms, false, NULL, &resp, error)) {
goto fail;
}

Expand Down
Loading