Skip to content

Conversation

@kevinAlbs
Copy link
Collaborator

Summary

Support ENVIRONMENT:azure for MONGODB-OIDC.

  • Extend mcd-azure.h to support Azure IMDS requests for OIDC. This internal header previously only supported Azure IMDS requests to Azure Key Vault for In-Use Encryption.
  • Add a percent encoding utility to encode the token resource string.

Patch build: https://spruce.mongodb.com/version/6904afbc379d3a0007e1ac83

Testing

Evergreen testing is described in the drivers-evergreen-tools README.md. Testing follows a similar pattern to the testazurekms-task: build test-libmongoc on an Evergreen host, create a remote Azure VM with a matching OS, copy the binary, run the test.

oidc-compile-azure.sh includes a temporary workaround to install UV (as was done in #2163).

@kevinAlbs kevinAlbs marked this pull request as ready for review October 31, 2025 17:27
@kevinAlbs kevinAlbs requested a review from a team as a code owner October 31, 2025 17:27
@kevinAlbs kevinAlbs requested review from connorsmacd and removed request for mdb-ad November 10, 2025 14:30
Comment on lines +31 to +40
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
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.

-DENABLE_EXAMPLES=OFF \
-DENABLE_SRV=OFF \
-S. -Bcmake-build
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.

# 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',
),

Comment on lines +48 to +52
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
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.

# 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.

const char *const opt_imds_host,
int opt_port,
const char *opt_extra_headers,
int opt_timeout_ms,
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 opt_timeout_ms,
int32_t opt_timeout_ms,

We really need to address CDRIVER-1329 and CDRIVER-4589 sometime soon so that new API does not continue to be burdened by int32_t compatibility issues. 🫠

Comment on lines +59 to +70
if (timeout_us) {
int64_t remaining_ms = (*timeout_us - bson_get_monotonic_time()) / 1000;
if (remaining_ms <= 0) {
// No time remaining. Immediately fail.
mongoc_oidc_callback_params_cancel_with_timeout(params);
goto fail;
}
if (mlib_narrow(&max_duration_ms, remaining_ms)) {
// Requested timeout too large to fit. Cap at INT_MAX.
max_duration_ms = mlib_maxof(int);
}
}
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
if (timeout_us) {
int64_t remaining_ms = (*timeout_us - bson_get_monotonic_time()) / 1000;
if (remaining_ms <= 0) {
// No time remaining. Immediately fail.
mongoc_oidc_callback_params_cancel_with_timeout(params);
goto fail;
}
if (mlib_narrow(&max_duration_ms, remaining_ms)) {
// Requested timeout too large to fit. Cap at INT_MAX.
max_duration_ms = mlib_maxof(int);
}
}
if (timeout_us) {
const mlib_timer timer = {.expires_at = mlib_duration(*timeout_us, us)};
if (mlib_timer_is_expired(timer, NULL)) {
// No time remaining. Immediately fail.
mongoc_oidc_callback_params_cancel_with_timeout(params);
goto fail;
}
if (mlib_narrow(&max_duration_ms, mlib_milliseconds_count(mlib_timer_remaining(timer)))) {
// Requested timeout too large to fit. Cap at INT_MAX.
max_duration_ms = mlib_maxof(int);
}
}

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

Comment on lines +214 to +217
int timeout_ms = 3 * 1000; // Default 3 second timeout
if (opt_timeout_ms > 0) {
timeout_ms = opt_timeout_ms;
}
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.


ret = mongoc_oidc_credential_new_with_expires_in(token.access_token, mcd_get_microseconds(token.expires_in));
if (!ret) {
MONGOC_ERROR("Failed to process Azure OIDC access token");
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest providing more descriptive error messages for users when able, e.g.:

if (!ret) {
  MONGOC_ERROR("Failed to process Azure OIDC access token");

  if (!token.access_token) {
    MONGOC_ERROR("missing Azure OIDC access token string");
  }

  if (token.expires_in < 0) {
    MONGOC_ERROR("Azure OIDC access token expiration must not be a negative value");
  }

  goto fail;
}

Comment on lines +256 to +259
if (mongoc_oidc_callback_params_get_cancelled_with_timeout(params)) {
SET_ERROR("MONGODB-OIDC callback was cancelled due to timeout");
goto unlock_and_return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Confirming: this will surface timeouts as an authentication error via mongoc_cluster_run_command_monitored or _mongoc_cluster_auth_node. Is this correct?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants