-
Notifications
You must be signed in to change notification settings - Fork 42
SQL-2920: Add configuration properties to support GSSAPI #367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good start, but if we are able to set the config only for the driver that would be much better.
If not, we want to discuss that with Alexi, and maybe the people at Tableau.
Could we add an integration test too?
MongoCredential.OIDC_HUMAN_CALLBACK_KEY, oidcCallback); | ||
settingsBuilder.credential(credential); | ||
} else if (authMechanism.equals(GSSAPI)) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
String jaasPath = connectionProperties.getJaasConfigPath(); | ||
if (jaasPath != null && !jaasPath.isEmpty()) { | ||
System.setProperty("java.security.auth.login.config", jaasPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conf changes will affect more than our driver. It will affect everything currently running JVM.
This is a problem, especially with tools like Tableau. We need to talk about it a bit more.
Here is a starting point from Gemini on how we could use a local conf (possibly, we want to try it out to make sure this is true):
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import java.util.Collections;
import java.util.Map;
import java.util.logging.Logger;
public class MongoJaasProgrammatic {
private static final Logger LOGGER = Logger.getLogger(MongoJaasProgrammatic.class.getName());
public static void main(String[] args) {
// Step 1: Set the custom JAAS Configuration programmatically
// MyJaasConfig.loadConfiguration(); // Reuse the class from the previous answer
Subject authenticatedSubject = null;
try {
LoginContext loginContext = new LoginContext("MyApplication");
loginContext.login();
authenticatedSubject = loginContext.getSubject();
} catch (Exception e) {
LOGGER.severe("JAAS login failed: " + e.getMessage());
return;
}
if (authenticatedSubject == null) {
LOGGER.severe("Authenticated subject is null. Exiting.");
return;
}
// Step 2: Create a MongoCredential with the authenticated subject
Map<String, String> properties = Collections.singletonMap(MongoCredential.JAVA_SUBJECT_KEY, authenticatedSubject.toString());
MongoCredential credential = MongoCredential.createGSSAPICredential(properties);
// Step 3: Build MongoClientSettings with the credential
MongoClientSettings settings = MongoClientSettings.builder()
.credential(credential)
.build();
// Step 4: Create MongoClient using the custom settings
try (MongoClient mongoClient = MongoClients.create(settings)) {
// Your database operations here
System.out.println("Successfully connected to MongoDB using programmatic JAAS config.");
} catch (Exception e) {
LOGGER.severe("MongoDB connection failed: " + e.getMessage());
}
}
}
|
||
String gssNative = connectionProperties.getGssNativeMode(); | ||
if (gssNative != null && !gssNative.isEmpty()) { | ||
System.setProperty("sun.security.jgss.native", gssNative); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, we want to look at using a local conf to make sure we don't impact other drivers when using Tableau for example.
Here is another Gemini quickstart:
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import javax.security.auth.Subject;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
public class GssapiMongoNoSystemProp {
private static final Logger LOGGER = Logger.getLogger(GssapiMongoNoSystemProp.class.getName());
public static void main(String[] args) {
// Step 1: Create a custom JAAS Configuration in memory.
Configuration jaasConfig = new Configuration() {
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
if ("MongoConnection".equals(name)) {
Map<String, String> options = new HashMap<>();
options.put("useKeyTab", "true");
options.put("keyTab", "/path/to/your/keytab/file.keytab");
options.put("principal", "[email protected]");
options.put("storeKey", "true");
options.put("doNotPrompt", "true");
return new AppConfigurationEntry[]{
new AppConfigurationEntry(
"com.sun.security.auth.module.Krb5LoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
options
)
};
}
return null;
}
};
Subject authenticatedSubject = null;
try {
// Step 2: Use the custom Configuration to perform the login.
// No need for a separate krb5.conf file if your
// principal and keytab are correct. Kerberos will
// try to auto-discover the KDC.
LoginContext loginContext = new LoginContext("MongoConnection", authenticatedSubject, null, jaasConfig);
loginContext.login();
authenticatedSubject = loginContext.getSubject();
LOGGER.info("Kerberos login successful using in-memory config.");
} catch (Exception e) {
LOGGER.severe("Kerberos login failed: " + e.getMessage());
return;
}
if (authenticatedSubject == null) {
LOGGER.severe("Authenticated subject is null. Cannot proceed.");
return;
}
// Step 3: Create a MongoCredential with the authenticated subject.
Map<String, Object> properties = Collections.singletonMap(
MongoCredential.JAVA_SUBJECT_KEY, authenticatedSubject
);
MongoCredential credential = MongoCredential.createGSSAPICredential(
// The principal must match the one used in the login module options.
"[email protected]"
).withMechanismProperties(properties);
// Build MongoClientSettings
MongoClientSettings settings = MongoClientSettings.builder()
.credential(credential)
.build();
// Create MongoClient using the custom settings.
try (MongoClient mongoClient = MongoClients.create(settings)) {
System.out.println("Successfully connected to MongoDB with GSSAPI using programmatic configs.");
mongoClient.listDatabaseNames().forEach(System.out::println);
} catch (Exception e) {
LOGGER.severe("MongoDB connection failed: " + e.getMessage());
}
}
}
String gssNativeModeVal = info.getProperty(GSS_NATIVE_MODE.getPropertyName()); | ||
if (gssNativeModeVal != null) { | ||
gssNativeModeVal = gssNativeModeVal.trim().toLowerCase(); | ||
if (!"true".equals(gssNativeModeVal) && !"false".equals(gssNativeModeVal)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to be less restrictive.
if (!"true".equals(gssNativeModeVal) && !"false".equals(gssNativeModeVal)) { | |
if (!"true".equalsIgnoreCase(gssNativeModeVal) && !"false".equalsIgnoreCase(gssNativeModeVal)) { |
Adding properties:
jaasconfigpath
: Set a custom jaas.config file path if the default doesn't work or can't be modified. This was used since the default jaas.conf that was getting picked up by Tableau was in thejdbcserver.jar
needed to be changed to get a working connection.gssnativemode
: Used on Windows to allow the use of MIT Kerberos vs the native Windows Kerberos. Set this tofalse
to use MIT Kerberos.Tested on Mac with a locally setup KDC using Docker containers.
Tested on Windows against ldaptest.10gen.cc using MIT Kerberos.