Skip to content
Merged
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
3 changes: 0 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Copy link
Member Author

Choose a reason for hiding this comment

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

This is related to the human flow. I was testing it manually to verify all is well and I get an error ☹️. So this must have been broken since the shadow change went in:

Caused by: java.lang.NoClassDefFoundError: shadow/net/minidev/json/JSONAware

relocate 'ognl', 'shadow.ognl'
relocate('org', 'shadow.org') {
exclude 'org.ow2.asm:.*'
exclude 'net.minidev:.*'
exclude 'org.javassist:.*'
}

Expand All @@ -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:.*'))
}

Expand Down
28 changes: 20 additions & 8 deletions src/main/java/com/mongodb/jdbc/MongoConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
82 changes: 82 additions & 0 deletions src/test/java/com/mongodb/jdbc/MongoConnectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}