diff --git a/build.gradle b/build.gradle index 578f52c4..e7926cf1 100644 --- a/build.gradle +++ b/build.gradle @@ -185,11 +185,9 @@ shadowJar { relocate 'com.google', 'shadow.com.google' relocate 'com.nimbusds', 'shadow.com.nimbusds' relocate 'net.jcip', 'shadow.net.jcip' - relocate 'net.minidev', 'shadow.net.minidev' relocate 'ognl', 'shadow.ognl' relocate('org', 'shadow.org') { exclude 'org.ow2.asm:.*' - exclude 'net.minidev:.*' exclude 'org.javassist:.*' } @@ -200,7 +198,6 @@ shadowJar { // Exclude specific dependencies that contain Java 21 bytecode dependencies { exclude(dependency('org.ow2.asm:.*')) - exclude(dependency('net.minidev:.*')) exclude(dependency('org.javassist:.*')) } diff --git a/src/main/java/com/mongodb/jdbc/MongoConnection.java b/src/main/java/com/mongodb/jdbc/MongoConnection.java index 601f9147..f9cd8de4 100644 --- a/src/main/java/com/mongodb/jdbc/MongoConnection.java +++ b/src/main/java/com/mongodb/jdbc/MongoConnection.java @@ -82,6 +82,7 @@ public class MongoConnection implements Connection { public static final String MONGODB_JDBC_X509_CLIENT_CERT_PATH = "MONGODB_JDBC_X509_CLIENT_CERT_PATH"; + public static final String K8S_ENVIRONMENT = "k8s"; public int getServerMajorVersion() { return serverMajorVersion; @@ -191,14 +192,25 @@ private MongoClientSettings createMongoClientSettings( if (authMechanism != null) { if (authMechanism.equals(MONGODB_OIDC)) { // Handle OIDC authentication - OidcCallback oidcCallback = new JdbcOidcCallback(this.logger); - credential = - MongoCredential.createOidcCredential( - connectionProperties - .getConnectionString() - .getUsername()) - .withMechanismProperty( - MongoCredential.OIDC_HUMAN_CALLBACK_KEY, oidcCallback); + String environment = + credential.getMechanismProperty(MongoCredential.ENVIRONMENT_KEY, null); + String tokenResource = + credential.getMechanismProperty( + MongoCredential.TOKEN_RESOURCE_KEY, null); + + boolean isK8s = K8S_ENVIRONMENT.equalsIgnoreCase(environment); + if (!isK8s && (environment == null && tokenResource == null)) { + // No machine flow properties, specify human flow OIDC Callback + OidcCallback oidcCallback = new JdbcOidcCallback(this.logger); + credential = + MongoCredential.createOidcCredential( + connectionProperties + .getConnectionString() + .getUsername()) + .withMechanismProperty( + MongoCredential.OIDC_HUMAN_CALLBACK_KEY, + oidcCallback); + } settingsBuilder.credential(credential); } else if (authMechanism.equals(GSSAPI)) { String jaasPath = connectionProperties.getJaasConfigPath(); diff --git a/src/test/java/com/mongodb/jdbc/MongoConnectionTest.java b/src/test/java/com/mongodb/jdbc/MongoConnectionTest.java index 4757e806..2f4fb786 100644 --- a/src/test/java/com/mongodb/jdbc/MongoConnectionTest.java +++ b/src/test/java/com/mongodb/jdbc/MongoConnectionTest.java @@ -21,7 +21,10 @@ import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; +import com.mongodb.MongoCredential; import com.mongodb.client.internal.MongoClientImpl; +import com.mongodb.jdbc.oidc.JdbcOidcCallback; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.SQLException; import java.sql.Savepoint; @@ -227,4 +230,83 @@ void testRollbackJ3() { Savepoint sp = mock(Savepoint.class); testNoop(() -> mongoConnection.rollback(sp)); } + + // Helper method to create a connection with OIDC auth and test the credential properties + private void testOidcConnection( + String connectionString, + boolean shouldHaveHumanCallback, + String expectedEnvironment, + String expectedTokenResource) + throws Exception { + + ConnectionString cs = new ConnectionString(connectionString); + when(mockConnectionProperties.getConnectionString()).thenReturn(cs); + + MongoConnection conn = new MongoConnection(null, mockConnectionProperties); + + // Use reflection to access the private mongoClientSettings field + Field settingsField = MongoConnection.class.getDeclaredField("mongoClientSettings"); + settingsField.setAccessible(true); + MongoClientSettings settings = (MongoClientSettings) settingsField.get(conn); + + MongoCredential credential = settings.getCredential(); + + if (expectedEnvironment != null) { + assertEquals( + expectedEnvironment, + credential.getMechanismProperty(MongoCredential.ENVIRONMENT_KEY, null), + "ENVIRONMENT value should match"); + } + + if (expectedTokenResource != null) { + assertEquals( + expectedTokenResource, + credential.getMechanismProperty(MongoCredential.TOKEN_RESOURCE_KEY, null), + "TOKEN_RESOURCE value should match"); + } + + Object callback = + credential.getMechanismProperty(MongoCredential.OIDC_HUMAN_CALLBACK_KEY, null); + if (shouldHaveHumanCallback) { + assertNotNull(callback, "Human flow callback should be set"); + assertTrue(callback instanceof JdbcOidcCallback, "Callback should be JdbcOidcCallback"); + } else { + assertNull(callback, "Human flow callback should NOT be set for machine flow"); + } + } + + @Test + void testOidcHumanFlowWhenMachinePropertiesNotPresent() throws Exception { + // No auth mechanism properties - should use human flow + testOidcConnection(localhost + "?authMechanism=MONGODB-OIDC", true, null, null); + } + + @Test + void testOidcGcpMachineFlow() throws Exception { + testOidcConnection( + localhost + + "?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:gcp,TOKEN_RESOURCE:audience", + false, + "gcp", + "audience"); + } + + @Test + void testOidcAzureMachineFlow() throws Exception { + testOidcConnection( + localhost + + "?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:audience", + false, + "azure", + "audience"); + } + + @Test + void testOidcKubernetesMachineFlow() throws Exception { + testOidcConnection( + localhost + "?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:k8s", + false, + "k8s", + null); + } }