Skip to content

Commit

Permalink
Allow using multiple JAAS configurations and override the configurati…
Browse files Browse the repository at this point in the history
…on per connection properties.

We also set a different default LoginConfig for IBM JVM, so it should work well with user-provided
passwords and username for Kerberos.

Should solve microsoft#66 for IBM JVM.
  • Loading branch information
pierresouchay committed Apr 18, 2017
1 parent c1f88c5 commit 02f1372
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 77 deletions.
68 changes: 68 additions & 0 deletions src/main/java/com/microsoft/sqlserver/jdbc/JaasConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Microsoft JDBC Driver for SQL Server
*
* Copyright(c) Microsoft Corporation All rights reserved.
*
* This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information.
*/
package com.microsoft.sqlserver.jdbc;

import java.util.HashMap;
import java.util.Map;

import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;

/**
* This class overrides JAAS Configuration and always provide a configuration is not defined for default configuration.
*/
public class JaasConfiguration extends Configuration {

private final Configuration delegate;
private AppConfigurationEntry[] defaultValue;

private static AppConfigurationEntry[] generateDefaultConfiguration() {
if (Util.isIBM()) {
Map<String, String> confDetailsWithoutPassword = new HashMap<String, String>();
confDetailsWithoutPassword.put("useDefaultCcache", "true");
confDetailsWithoutPassword.put("moduleBanner", "false");
Map<String, String> confDetailsWithPassword = new HashMap<String, String>();
confDetailsWithPassword.putAll(confDetailsWithPassword);
confDetailsWithPassword.put("useDefaultCcache", "false");
// We generated a two configurations fallback that is suitable for password and password-less authentication
return new AppConfigurationEntry[] {
new AppConfigurationEntry("com.ibm.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT,
confDetailsWithoutPassword),
new AppConfigurationEntry("com.ibm.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT,
confDetailsWithPassword)};
}
else {
Map<String, String> confDetails = new HashMap<String, String>();
confDetails.put("useTicketCache", "true");
return new AppConfigurationEntry[] {new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, confDetails)};
}
}

/**
* Package protected constructor.
*
* @param delegate
* a possibly null delegate
*/
JaasConfiguration(Configuration delegate) {
this.delegate = delegate;
this.defaultValue = generateDefaultConfiguration();
}

@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
AppConfigurationEntry[] conf = delegate == null ? null : delegate.getAppConfigurationEntry(name);
// We return our configuration only if user requested default one
// In case where user did request another JAAS Configuration name, we expect he knows what he is doing.
if (conf == null && name.equals(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue())) {
return defaultValue;
}
return conf;
}
}
83 changes: 6 additions & 77 deletions src/main/java/com/microsoft/sqlserver/jdbc/KerbAuthentication.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,13 @@
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
Expand All @@ -44,7 +41,6 @@
* KerbAuthentication for int auth.
*/
final class KerbAuthentication extends SSPIAuthentication {
private final static String CONFIGNAME = "SQLJDBCDriver";
private final static java.util.logging.Logger authLogger = java.util.logging.Logger
.getLogger("com.microsoft.sqlserver.jdbc.internals.KerbAuthentication");

Expand All @@ -57,78 +53,9 @@ final class KerbAuthentication extends SSPIAuthentication {
private GSSContext peerContext = null;

static {
// The driver on load will look to see if there is a configuration set for the SQLJDBCDriver, if not it will install its
// own configuration. Note it is possible that there is a configuration exists but it does not contain a configuration entry
// for the driver in that case, we will override the configuration but will flow the configuration requests to existing
// config for anything other than SQLJDBCDriver
//
class SQLJDBCDriverConfig extends Configuration {
Configuration current = null;
AppConfigurationEntry[] driverConf;

SQLJDBCDriverConfig() {
try {
current = Configuration.getConfiguration();
}
catch (SecurityException e) {
// if we cant get the configuration, it is likely that no configuration has been specified. So go ahead and set the config
authLogger.finer(toString() + " No configurations provided, setting driver default");
}
AppConfigurationEntry[] config = null;

if (null != current) {
config = current.getAppConfigurationEntry(CONFIGNAME);
}
// If there is user provided configuration we leave use that and not install our configuration
if (null == config) {
if (authLogger.isLoggable(Level.FINER))
authLogger.finer(toString() + " SQLJDBCDriver configuration entry is not provided, setting driver default");

AppConfigurationEntry appConf;
if (Util.isIBM()) {
Map<String, String> confDetails = new HashMap<String, String>();
confDetails.put("useDefaultCcache", "true");
confDetails.put("moduleBanner", "false");
appConf = new AppConfigurationEntry("com.ibm.security.auth.module.Krb5LoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, confDetails);
if (authLogger.isLoggable(Level.FINER))
authLogger.finer(toString() + " Setting IBM Krb5LoginModule");
}
else {
Map<String, String> confDetails = new HashMap<String, String>();
confDetails.put("useTicketCache", "true");
appConf = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, confDetails);
if (authLogger.isLoggable(Level.FINER))
authLogger.finer(toString() + " Setting Sun Krb5LoginModule");
}
driverConf = new AppConfigurationEntry[1];
driverConf[0] = appConf;
Configuration.setConfiguration(this);
}

}

public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
// we should only handle anything that is related to our part, everything else is handled by the configuration
// already existing configuration if there is one.
if (name.equals(CONFIGNAME)) {
return driverConf;
}
else {
if (null != current)
return current.getAppConfigurationEntry(name);
else
return null;
}
}

public void refresh() {
if (null != current)
current.refresh();
}
}
SQLJDBCDriverConfig driverconfig = new SQLJDBCDriverConfig();
// Overrides the default JAAS configuration loader.
// This one will forward to the default one in all cases but the default configuration is empty.
Configuration.setConfiguration(new JaasConfiguration(Configuration.getConfiguration()));
}

private void intAuthInit() throws SQLServerException {
Expand All @@ -148,13 +75,15 @@ private void intAuthInit() throws SQLServerException {
peerContext.requestInteg(true);
}
else {
String configName = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(),
SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue());
Subject currentSubject = null;
KerbCallback callback = new KerbCallback(con);
try {
AccessControlContext context = AccessController.getContext();
currentSubject = Subject.getSubject(context);
if (null == currentSubject) {
lc = new LoginContext(CONFIGNAME, callback);
lc = new LoginContext(configName, callback);
lc.login();
// per documentation LoginContext will instantiate a new subject.
currentSubject = lc.getSubject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ public String toString() {
}
}



enum SQLServerDriverStringProperty
{
APPLICATION_INTENT ("applicationIntent", ApplicationIntent.READ_WRITE.toString()),
Expand All @@ -226,6 +228,7 @@ enum SQLServerDriverStringProperty
FAILOVER_PARTNER ("failoverPartner", ""),
HOSTNAME_IN_CERTIFICATE ("hostNameInCertificate", ""),
INSTANCE_NAME ("instanceName", ""),
JAAS_CONFIG_NAME ("jaasConfigurationName", "SQLJDBCDriver"),
PASSWORD ("password", ""),
RESPONSE_BUFFERING ("responseBuffering", "adaptive"),
SELECT_METHOD ("selectMethod", "direct"),
Expand Down

0 comments on commit 02f1372

Please sign in to comment.