Skip to content

Commit

Permalink
Merge pull request #254 from pierresouchay/multiple_jaas_config_names
Browse files Browse the repository at this point in the history
Allow using multiple JAAS configurations and override the configuration per connection properties
  • Loading branch information
Suraiya Hameed authored Apr 26, 2017
2 parents 18a9265 + dfc1567 commit 148b21d
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 77 deletions.
65 changes: 65 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,65 @@
/*
* 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");
Map<String, String> confDetailsWithPassword = new HashMap<String, String>();
// We generated a two configurations fallback that is suitable for password and password-less authentication
// See https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/jgssDocs/jaas_login_user.html
final String ibmLoginModule = "com.ibm.security.auth.module.Krb5LoginModule";
return new AppConfigurationEntry[] {
new AppConfigurationEntry(ibmLoginModule, AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, confDetailsWithoutPassword),
new AppConfigurationEntry(ibmLoginModule, 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 @@ -722,6 +722,27 @@ public int getSocketTimeout() {
return getIntProperty(connectionProps, SQLServerDriverIntProperty.SOCKET_TIMEOUT.toString(), defaultTimeOut);
}

/**
* Sets the login configuration file for Kerberos authentication. This
* overrides the default configuration <i> SQLJDBCDriver </i>
*
* @param configurationName
*/
public void setJASSConfigurationName(String configurationName) {
setStringProperty(connectionProps, SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(),
configurationName);
}

/**
* Retrieves the login configuration file for Kerberos authentication.
*
* @return
*/
public String getJASSConfigurationName() {
return getStringProperty(connectionProps, SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(),
SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue());
}

// responseBuffering controls the driver's buffering of responses from SQL Server.
// Possible values are:
//
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 Expand Up @@ -377,6 +380,7 @@ public final class SQLServerDriver implements java.sql.Driver {
new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.FIPS.toString(), Boolean.toString(SQLServerDriverBooleanProperty.FIPS.getDefaultValue()), false, TRUE_FALSE),
new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), Boolean.toString(SQLServerConnection.getDefaultEnablePrepareOnFirstPreparedStatementCall()), false, TRUE_FALSE),
new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), Integer.toString(SQLServerConnection.getDefaultServerPreparedStatementDiscardThreshold()), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue(), false, null),
};

// Properties that can only be set by using Properties.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,5 +381,6 @@ protected Object[][] getContents() {
{"R_serverPreparedStatementDiscardThreshold", "The serverPreparedStatementDiscardThreshold {0} is not valid."},
{"R_kerberosLoginFailedForUsername", "Cannot login with Kerberos principal {0}, check your credentials. {1}"},
{"R_kerberosLoginFailed", "Kerberos Login failed: {0} due to {1} ({2})"},
{"R_jaasConfigurationNamePropertyDescription", "Login configuration file for Kerberos authentication."},
};
}

0 comments on commit 148b21d

Please sign in to comment.