diff --git a/.evergreen/.evg.yml b/.evergreen/.evg.yml index d35c01fd89f..886282b77c4 100644 --- a/.evergreen/.evg.yml +++ b/.evergreen/.evg.yml @@ -12,9 +12,8 @@ stepback: true # Actual testing tasks are marked with `type: test` command_type: system -# Protect ourself against rogue test case, or curl gone wild, that runs forever -# 12 minutes is the longest we'll ever run -exec_timeout_secs: 3600 # 12 minutes is the longest we'll ever run +# Protect ourselves against rogue test case, or curl gone wild, that runs forever +exec_timeout_secs: 3600 # What to do when evergreen hits the timeout (`post:` tasks are run automatically) timeout: @@ -968,6 +967,60 @@ tasks: - func: "run load-balancer" - func: "run load-balancer tests" + - name: "oidc-auth-test" + commands: + - command: subprocess.exec + type: test + params: + working_dir: "src" + binary: bash + include_expansions_in_env: ["DRIVERS_TOOLS", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"] + env: + OIDC_ENV: "test" + args: + - .evergreen/run-mongodb-oidc-test.sh + + - name: "oidc-auth-test-azure" + commands: + - command: shell.exec + params: + shell: bash + env: + JAVA_HOME: ${JAVA_HOME} + script: |- + set -o errexit + ${PREPARE_SHELL} + cd src + git add . + git commit -m "add files" + # uncompressed tar used to allow appending .git folder + export AZUREOIDC_DRIVERS_TAR_FILE=/tmp/mongo-java-driver.tar + git archive -o $AZUREOIDC_DRIVERS_TAR_FILE HEAD + tar -rf $AZUREOIDC_DRIVERS_TAR_FILE .git + export AZUREOIDC_TEST_CMD="OIDC_ENV=azure ./.evergreen/run-mongodb-oidc-test.sh" + bash $DRIVERS_TOOLS/.evergreen/auth_oidc/azure/run-driver-test.sh + + - name: "oidc-auth-test-gcp" + commands: + - command: shell.exec + params: + shell: bash + script: |- + set -o errexit + ${PREPARE_SHELL} + cd src + git add . + git commit -m "add files" + # uncompressed tar used to allow appending .git folder + export GCPOIDC_DRIVERS_TAR_FILE=/tmp/mongo-java-driver.tar + git archive -o $GCPOIDC_DRIVERS_TAR_FILE HEAD + tar -rf $GCPOIDC_DRIVERS_TAR_FILE .git + # Define the command to run on the 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="OIDC_ENV=gcp ./.evergreen/run-mongodb-oidc-test.sh" + bash $DRIVERS_TOOLS/.evergreen/auth_oidc/gcp/run-driver-test.sh + - name: serverless-test commands: - func: "run serverless" @@ -2065,6 +2118,78 @@ task_groups: tasks: - test-aws-lambda-deployed + - name: testoidc_task_group + setup_group: + - func: fetch source + - func: prepare resources + - func: fix absolute paths + - command: ec2.assume_role + params: + role_arn: ${aws_test_secrets_role} + - command: subprocess.exec + params: + binary: bash + include_expansions_in_env: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"] + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/setup.sh + teardown_task: + - command: subprocess.exec + params: + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/teardown.sh + setup_group_can_fail_task: true + setup_group_timeout_secs: 1800 + tasks: + - oidc-auth-test + + - name: testazureoidc_task_group + setup_group: + - func: fetch source + - func: prepare resources + - func: fix absolute paths + - command: subprocess.exec + params: + binary: bash + env: + AZUREOIDC_VMNAME_PREFIX: "JAVA_DRIVER" + args: + - ${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 + + - name: testgcpoidc_task_group + setup_group: + - func: fetch source + - func: prepare resources + - func: fix absolute paths + - command: subprocess.exec + params: + binary: bash + env: + GCPOIDC_VMNAME_PREFIX: "JAVA_DRIVER" + GCPKMS_MACHINETYPE: "e2-medium" # comparable elapsed time to Azure; default was starved, caused timeouts + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/gcp/setup.sh + teardown_task: + - command: subprocess.exec + params: + binary: bash + args: + - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/gcp/teardown.sh + setup_group_can_fail_task: true + setup_group_timeout_secs: 1800 + tasks: + - oidc-auth-test-gcp + buildvariants: # Test packaging and other release related routines @@ -2216,6 +2341,27 @@ buildvariants: tasks: - name: "test_atlas_task_group_search_indexes" +- name: "oidc-auth-test" + display_name: "OIDC Auth" + run_on: ubuntu2204-small + tasks: + - name: testoidc_task_group + batchtime: 20160 # 14 days + +- name: testazureoidc-variant + display_name: "OIDC Auth Azure" + run_on: ubuntu2204-small + tasks: + - name: testazureoidc_task_group + batchtime: 20160 # 14 days + +- name: testgcpoidc-variant + display_name: "OIDC Auth GCP" + run_on: ubuntu2204-small + tasks: + - name: testgcpoidc_task_group + batchtime: 20160 # 14 days + - matrix_name: "aws-auth-test" matrix_spec: { ssl: "nossl", jdk: ["jdk8", "jdk17", "jdk21"], version: ["4.4", "5.0", "6.0", "7.0", "latest"], os: "ubuntu", aws-credential-provider: "*" } diff --git a/.evergreen/prepare-oidc-get-tokens-docker.sh b/.evergreen/prepare-oidc-get-tokens-docker.sh new file mode 100755 index 00000000000..e904d5d2b89 --- /dev/null +++ b/.evergreen/prepare-oidc-get-tokens-docker.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +set -o xtrace +set -o errexit # Exit the script with error if any of the commands fail + +############################################ +# Main Program # +############################################ + +# Supported/used environment variables: +# DRIVERS_TOOLS The path to evergreeen tools +# OIDC_AWS_* Required OIDC_AWS_* env variables must be configured +# +# Environment variables used as output: +# OIDC_TESTS_ENABLED Allows running OIDC tests +# OIDC_TOKEN_DIR The path to generated OIDC AWS tokens +# AWS_WEB_IDENTITY_TOKEN_FILE The path to AWS token for device workflow + +if [ -z ${DRIVERS_TOOLS+x} ]; then + echo "DRIVERS_TOOLS. is not set"; + exit 1 +fi + +if [ -z ${OIDC_AWS_ROLE_ARN+x} ]; then + echo "OIDC_AWS_ROLE_ARN. is not set"; + exit 1 +fi + +if [ -z ${OIDC_AWS_SECRET_ACCESS_KEY+x} ]; then + echo "OIDC_AWS_SECRET_ACCESS_KEY. is not set"; + exit 1 +fi + +if [ -z ${OIDC_AWS_ACCESS_KEY_ID+x} ]; then + echo "OIDC_AWS_ACCESS_KEY_ID. is not set"; + exit 1 +fi + +export AWS_ROLE_ARN=${OIDC_AWS_ROLE_ARN} +export AWS_SECRET_ACCESS_KEY=${OIDC_AWS_SECRET_ACCESS_KEY} +export AWS_ACCESS_KEY_ID=${OIDC_AWS_ACCESS_KEY_ID} +export OIDC_FOLDER=${DRIVERS_TOOLS}/.evergreen/auth_oidc +export OIDC_TOKEN_DIR=${OIDC_FOLDER}/test_tokens +export AWS_WEB_IDENTITY_TOKEN_FILE=${OIDC_TOKEN_DIR}/test1 +export OIDC_TESTS_ENABLED=true + +echo "Configuring OIDC server for local authentication tests" + +cd ${OIDC_FOLDER} +DRIVERS_TOOLS=${DRIVERS_TOOLS} ./oidc_get_tokens.sh \ No newline at end of file diff --git a/.evergreen/prepare-oidc-server-docker.sh b/.evergreen/prepare-oidc-server-docker.sh new file mode 100755 index 00000000000..0fcd1ed4194 --- /dev/null +++ b/.evergreen/prepare-oidc-server-docker.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +set -o xtrace +set -o errexit # Exit the script with error if any of the commands fail + +############################################ +# Main Program # +############################################ + +# Supported/used environment variables: +# DRIVERS_TOOLS The path to evergreeen tools +# OIDC_AWS_* OIDC_AWS_* env variables must be configured +# +# Environment variables used as output: +# OIDC_TESTS_ENABLED Allows running OIDC tests +# OIDC_TOKEN_DIR The path to generated tokens +# AWS_WEB_IDENTITY_TOKEN_FILE The path to AWS token for device workflow + +if [ -z ${DRIVERS_TOOLS+x} ]; then + echo "DRIVERS_TOOLS. is not set"; + exit 1 +fi + +if [ -z ${OIDC_AWS_ROLE_ARN+x} ]; then + echo "OIDC_AWS_ROLE_ARN. is not set"; + exit 1 +fi + +if [ -z ${OIDC_AWS_SECRET_ACCESS_KEY+x} ]; then + echo "OIDC_AWS_SECRET_ACCESS_KEY. is not set"; + exit 1 +fi + +if [ -z ${OIDC_AWS_ACCESS_KEY_ID+x} ]; then + echo "OIDC_AWS_ACCESS_KEY_ID. is not set"; + exit 1 +fi + +export AWS_ROLE_ARN=${OIDC_AWS_ROLE_ARN} +export AWS_SECRET_ACCESS_KEY=${OIDC_AWS_SECRET_ACCESS_KEY} +export AWS_ACCESS_KEY_ID=${OIDC_AWS_ACCESS_KEY_ID} +export OIDC_FOLDER=${DRIVERS_TOOLS}/.evergreen/auth_oidc +export OIDC_TOKEN_DIR=${OIDC_FOLDER}/test_tokens +export AWS_WEB_IDENTITY_TOKEN_FILE=${OIDC_TOKEN_DIR}/test1 +export OIDC_TESTS_ENABLED=true + +echo "Configuring OIDC server for local authentication tests" + +cd ${OIDC_FOLDER} +DRIVERS_TOOLS=${DRIVERS_TOOLS} ./start_local_server.sh \ No newline at end of file diff --git a/.evergreen/run-mongodb-oidc-test.sh b/.evergreen/run-mongodb-oidc-test.sh new file mode 100755 index 00000000000..1f5c1b310cc --- /dev/null +++ b/.evergreen/run-mongodb-oidc-test.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set +x # Disable debug trace +set -eu + +echo "Running MONGODB-OIDC authentication tests" +echo "OIDC_ENV $OIDC_ENV" + +if [ $OIDC_ENV == "test" ]; then + if [ -z "$DRIVERS_TOOLS" ]; then + echo "Must specify DRIVERS_TOOLS" + exit 1 + fi + source ${DRIVERS_TOOLS}/.evergreen/auth_oidc/secrets-export.sh + # java will not need to be installed, but we need to config + RELATIVE_DIR_PATH="$(dirname "${BASH_SOURCE:-$0}")" + source "${RELATIVE_DIR_PATH}/javaConfig.bash" +elif [ $OIDC_ENV == "azure" ]; then + source ./env.sh +elif [ $OIDC_ENV == "gcp" ]; then + source ./secrets-export.sh +else + echo "Unrecognized OIDC_ENV $OIDC_ENV" + exit 1 +fi + + +if ! which java ; then + echo "Installing java..." + sudo apt install openjdk-17-jdk -y + echo "Installed java." +fi + +which java +export OIDC_TESTS_ENABLED=true + +./gradlew -Dorg.mongodb.test.uri="$MONGODB_URI" \ + --stacktrace --debug --info --no-build-cache driver-core:cleanTest \ + driver-sync:test --tests OidcAuthenticationProseTests --tests UnifiedAuthTest \ + driver-reactive-streams:test --tests OidcAuthenticationAsyncProseTests \ diff --git a/bson/src/test/unit/util/ThreadTestHelpers.java b/bson/src/test/unit/util/ThreadTestHelpers.java index a4767c503f9..e2115da079f 100644 --- a/bson/src/test/unit/util/ThreadTestHelpers.java +++ b/bson/src/test/unit/util/ThreadTestHelpers.java @@ -31,15 +31,19 @@ private ThreadTestHelpers() { } public static void executeAll(final int nThreads, final Runnable c) { + executeAll(Collections.nCopies(nThreads, c).toArray(new Runnable[0])); + } + + public static void executeAll(final Runnable... runnables) { ExecutorService service = null; try { - service = Executors.newFixedThreadPool(nThreads); - CountDownLatch latch = new CountDownLatch(nThreads); + service = Executors.newFixedThreadPool(runnables.length); + CountDownLatch latch = new CountDownLatch(runnables.length); List failures = Collections.synchronizedList(new ArrayList<>()); - for (int i = 0; i < nThreads; i++) { + for (final Runnable runnable : runnables) { service.submit(() -> { try { - c.run(); + runnable.run(); } catch (Throwable e) { failures.add(e); } finally { diff --git a/driver-core/src/main/com/mongodb/AuthenticationMechanism.java b/driver-core/src/main/com/mongodb/AuthenticationMechanism.java index db8a909b79d..7a7b7415ef6 100644 --- a/driver-core/src/main/com/mongodb/AuthenticationMechanism.java +++ b/driver-core/src/main/com/mongodb/AuthenticationMechanism.java @@ -37,6 +37,13 @@ public enum AuthenticationMechanism { */ MONGODB_AWS("MONGODB-AWS"), + /** + * The MONGODB-OIDC mechanism. + * @since 4.10 + * @mongodb.server.release 7.0 + */ + MONGODB_OIDC("MONGODB-OIDC"), + /** * The MongoDB X.509 mechanism. This mechanism is available only with client certificates over SSL. */ diff --git a/driver-core/src/main/com/mongodb/ConnectionString.java b/driver-core/src/main/com/mongodb/ConnectionString.java index e715b8983f6..34378d4069f 100644 --- a/driver-core/src/main/com/mongodb/ConnectionString.java +++ b/driver-core/src/main/com/mongodb/ConnectionString.java @@ -38,6 +38,7 @@ import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -47,7 +48,11 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import static com.mongodb.MongoCredential.ALLOWED_HOSTS_KEY; +import static com.mongodb.internal.connection.OidcAuthenticator.OidcValidator.validateCreateOidcCredential; import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -225,9 +230,9 @@ * *

Authentication configuration:

*