Skip to content
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

add useDefaultGSSCredential property #2177

Merged
merged 8 commits into from
Oct 16, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -594,17 +594,32 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
*/
String getServerSpn();

/**
* Sets the value to indicate whether useDefaultGSSCredential is enabled.
*
* @param enable
* true if useDefaultGSSCredential is enabled. Otherwise, false.
*/
void setUseDefaultGSSCredential(boolean enable);

/**
* Returns the useDefaultGSSCredential.
*
* @return if enabled, return true. Otherwise, false.
*/
boolean getUseDefaultGSSCredential();

/**
* Sets the GSSCredential.
*
*
* @param userCredential
* the credential
*/
void setGSSCredentials(GSSCredential userCredential);

/**
* Returns the GSSCredential.
*
*
* @return GSSCredential
*/
GSSCredential getGSSCredentials();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ final class KerbAuthentication extends SSPIAuthentication {
private LoginContext lc = null;
private boolean isUserCreatedCredential = false;
private GSSCredential peerCredentials = null;
private boolean useDefaultNativeGSSCredential = false;
private GSSContext peerContext = null;

static {
Expand All @@ -63,6 +64,10 @@ private void initAuthInit() throws SQLServerException {
// as it is.
GSSName remotePeerName = manager.createName(spn, null);

if (useDefaultNativeGSSCredential) {
peerCredentials = manager.createCredential(null, GSSCredential.DEFAULT_LIFETIME, kerberos, GSSCredential.INITIATE_ONLY);
}

if (null != peerCredentials) {
peerContext = manager.createContext(remotePeerName, kerberos, peerCredentials,
GSSContext.DEFAULT_LIFETIME);
Expand Down Expand Up @@ -220,10 +225,11 @@ private byte[] initAuthHandShake(byte[] pin, boolean[] done) throws SQLServerExc
* @param impersonatedUserCred
*/
KerbAuthentication(SQLServerConnection con, String address, int port, GSSCredential impersonatedUserCred,
boolean isUserCreated) {
boolean isUserCreated, boolean useDefaultNativeGSSCredential) {
this(con, address, port);
this.peerCredentials = impersonatedUserCred;
this.isUserCreatedCredential = isUserCreated;
this.useDefaultNativeGSSCredential = useDefaultNativeGSSCredential;
}

byte[] generateClientContext(byte[] pin, boolean[] done) throws SQLServerException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -982,9 +982,11 @@ IdleConnectionResiliency getSessionRecovery() {

/** global system ColumnEncryptionKeyStoreProviders */
static Map<String, SQLServerColumnEncryptionKeyStoreProvider> globalSystemColumnEncryptionKeyStoreProviders = new HashMap<>();
static boolean isWindows;
tkyc marked this conversation as resolved.
Show resolved Hide resolved

static {
if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows")) {
isWindows = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows");
tkyc marked this conversation as resolved.
Show resolved Hide resolved
if (isWindows) {
SQLServerColumnEncryptionCertificateStoreProvider provider = new SQLServerColumnEncryptionCertificateStoreProvider();
globalSystemColumnEncryptionKeyStoreProviders.put(provider.getName(), provider);
}
Expand Down Expand Up @@ -1426,6 +1428,9 @@ public static void clearUserTokenCache() {
/** integrated authentication scheme */
private AuthenticationScheme intAuthScheme = AuthenticationScheme.NATIVE_AUTHENTICATION;

/** use default native GSS-API Credential flag */
private boolean useDefaultGSSCredential = SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.getDefaultValue();

/** impersonated user credential */
private transient GSSCredential impersonatedUserCred;

Expand Down Expand Up @@ -2480,6 +2485,11 @@ Connection connectInternal(Properties propsIn,
impersonatedUserCred = (GSSCredential) activeConnectionProperties.get(sPropKey);
isUserCreatedCredential = true;
}
sPropKey = SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.toString();
sPropValue = activeConnectionProperties.getProperty(sPropKey);
if(null != sPropValue && isWindows) {
useDefaultGSSCredential = isBooleanPropertyOn(sPropKey, sPropValue);
}
} else if (intAuthScheme == AuthenticationScheme.NTLM) {
String sPropKeyDomain = SQLServerDriverStringProperty.DOMAIN.toString();
String sPropValueDomain = activeConnectionProperties.getProperty(sPropKeyDomain);
Expand Down Expand Up @@ -5097,9 +5107,9 @@ private void logon(LogonCommand command) throws SQLServerException {
authentication = new AuthenticationJNI(this, currentConnectPlaceHolder.getServerName(),
currentConnectPlaceHolder.getPortNumber());
} else if (AuthenticationScheme.JAVA_KERBEROS == intAuthScheme) {
if (null != impersonatedUserCred) {
if (null != impersonatedUserCred || useDefaultGSSCredential) {
authentication = new KerbAuthentication(this, currentConnectPlaceHolder.getServerName(),
currentConnectPlaceHolder.getPortNumber(), impersonatedUserCred, isUserCreatedCredential);
currentConnectPlaceHolder.getPortNumber(), impersonatedUserCred, isUserCreatedCredential, useDefaultGSSCredential);
} else {
authentication = new KerbAuthentication(this, currentConnectPlaceHolder.getServerName(),
currentConnectPlaceHolder.getPortNumber());
Expand Down Expand Up @@ -5800,8 +5810,7 @@ private SqlAuthenticationToken getFedAuthToken(SqlFedAuthInfo fedAuthInfo) throw
} else if (authenticationString
.equalsIgnoreCase(SqlAuthentication.ACTIVE_DIRECTORY_INTEGRATED.toString())) {
// If operating system is windows and mssql-jdbc_auth is loaded then choose the DLL authentication.
if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows")
&& AuthenticationJNI.isDllLoaded()) {
if (isWindows && AuthenticationJNI.isDllLoaded()) {
try {
FedAuthDllInfo dllInfo = AuthenticationJNI.getAccessTokenForWindowsIntegrated(
fedAuthInfo.stsurl, fedAuthInfo.spn, clientConnectionId.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,17 @@ public GSSCredential getGSSCredentials() {
SQLServerDriverObjectProperty.GSS_CREDENTIAL.getDefaultValue());
}

@Override
public void setUseDefaultGSSCredential(boolean enable) {
setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.toString(), enable);
}

@Override
public boolean getUseDefaultGSSCredential() {
return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.toString(),
SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.getDefaultValue());
}

@Override
public void setAccessToken(String accessToken) {
setStringProperty(connectionProps, SQLServerDriverStringProperty.ACCESS_TOKEN.toString(), accessToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,8 @@ enum SQLServerDriverBooleanProperty {
USE_FMT_ONLY("useFmtOnly", false),
SEND_TEMPORAL_DATATYPES_AS_STRING_FOR_BULK_COPY("sendTemporalDataTypesAsStringForBulkCopy", true),
DELAY_LOADING_LOBS("delayLoadingLobs", true),
USE_DEFAULT_JAAS_CONFIG("useDefaultJaasConfig", false);
USE_DEFAULT_JAAS_CONFIG("useDefaultJaasConfig", false),
USE_DEFAULT_GSS_CREDENTIAL("useDefaultGSSCredential", false);

private final String name;
private final boolean defaultValue;
Expand Down Expand Up @@ -748,7 +749,7 @@ public final class SQLServerDriver implements java.sql.Driver {
SQLServerDriverStringProperty.DATABASE_NAME.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(),
Boolean.toString(SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.getDefaultValue()), false,
new String[] {"true", "false"}),
TRUE_FALSE),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.ENCRYPT.toString(),
SQLServerDriverStringProperty.ENCRYPT.getDefaultValue(), false,
new String[] {EncryptOption.FALSE.toString(), EncryptOption.NO.toString(),
Expand All @@ -768,6 +769,9 @@ public final class SQLServerDriver implements java.sql.Driver {
new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.toString(),
Boolean.toString(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.getDefaultValue()), false,
TRUE_FALSE),
new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.toString(),
Boolean.toString(SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.getDefaultValue()), false,
TRUE_FALSE),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(),
SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.getDefaultValue(), false,
new String[] {KeyStoreAuthentication.JAVA_KEYSTORE_PASSWORD.toString()}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ protected Object[][] getContents() {
{"R_lastUpdateCountPropertyDescription", "Ensures that only the last update count is returned from an SQL statement passed to the server."},
{"R_disableStatementPoolingPropertyDescription", "Disables the statement pooling feature."},
{"R_integratedSecurityPropertyDescription", "Indicates whether Windows authentication will be used to connect to SQL Server."},
{"R_useDefaultGSSCredentialPropertyDescription", "Indicates whether GSSCredential will be created using native GSS-API."},
{"R_authenticationSchemePropertyDescription", "The authentication scheme to be used for integrated authentication."},
{"R_lockTimeoutPropertyDescription", "The number of milliseconds to wait before the database reports a lock time-out."},
{"R_connectRetryCountPropertyDescription", "The number of reconnection attempts if there is a connection failure."},
Expand Down
31 changes: 28 additions & 3 deletions src/test/java/com/microsoft/sqlserver/jdbc/KerberosTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
public class KerberosTest extends AbstractTest {

private static String kerberosAuth = "KERBEROS";
private static String authSchemeQuery = "select auth_scheme from sys.dm_exec_connections where session_id=@@spid";

@BeforeAll
public static void setupTests() throws Exception {
Expand All @@ -33,7 +34,7 @@ public void testUseDefaultJaasConfigConnectionStringPropertyTrue() throws Except

// Initial connection should succeed with default JAAS config
try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionStringUseDefaultJaasConfig)) {
ResultSet rs = conn.createStatement().executeQuery("select auth_scheme from sys.dm_exec_connections where session_id=@@spid");
ResultSet rs = conn.createStatement().executeQuery(authSchemeQuery);
rs.next();
Assertions.assertEquals(kerberosAuth, rs.getString(1));
tkyc marked this conversation as resolved.
Show resolved Hide resolved
}
Expand All @@ -44,7 +45,7 @@ public void testUseDefaultJaasConfigConnectionStringPropertyTrue() throws Except

// New connection should successfully connect and continue to use the default JAAS config.
try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionStringUseDefaultJaasConfig)) {
ResultSet rs = conn.createStatement().executeQuery("select auth_scheme from sys.dm_exec_connections where session_id=@@spid");
ResultSet rs = conn.createStatement().executeQuery(authSchemeQuery);
rs.next();
Assertions.assertEquals(kerberosAuth, rs.getString(1));
}
Expand All @@ -57,7 +58,7 @@ public void testUseDefaultJaasConfigConnectionStringPropertyFalse() throws Excep
// useDefaultJaasConfig=false by default
// Initial connection should succeed with default JAAS config
try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionStringKerberos)) {
ResultSet rs = conn.createStatement().executeQuery("select auth_scheme from sys.dm_exec_connections where session_id=@@spid");
ResultSet rs = conn.createStatement().executeQuery(authSchemeQuery);
rs.next();
Assertions.assertEquals(kerberosAuth, rs.getString(1));
}
Expand All @@ -75,6 +76,30 @@ public void testUseDefaultJaasConfigConnectionStringPropertyFalse() throws Excep
}
}

@Tag(Constants.Kerberos)
Jeffery-Wasty marked this conversation as resolved.
Show resolved Hide resolved
@Test
public void testUseDefaultNativeGSSCredential() throws Exception {
// This is a negative test. This test should fail as expected as the JVM arg "-Dsun.security.jgss.native=true"
// isn't provided.
String connectionString = connectionStringKerberos + ";useDefaultGSSCredential=true;";

try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionString)) {
Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown"));
} catch (SQLServerException e) {
Assertions.assertEquals(e.getCause().getMessage(), TestResource.getResource("R_kerberosNativeGSSFailure"));
}
}

@Tag(Constants.Kerberos)
@Test
public void testBasicKerberosAuth() throws Exception {
try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionStringKerberos)) {
ResultSet rs = conn.createStatement().executeQuery(authSchemeQuery);
rs.next();
Assertions.assertEquals(kerberosAuth, rs.getString(1));
}
}

/**
* Overwrites the default JAAS config. Call before making a connection.
*/
tkyc marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ public void testDataSource() throws SQLServerException {
assertEquals(Boolean.toString(booleanPropValue), ds.getEncrypt(),
TestResource.getResource("R_valuesAreDifferent"));

ds.setUseDefaultGSSCredential(booleanPropValue);
assertEquals(booleanPropValue, ds.getUseDefaultGSSCredential(),
TestResource.getResource("R_valuesAreDifferent"));

ds.setServerCertificate(stringPropValue);
assertEquals(stringPropValue, ds.getServerCertificate(), TestResource.getResource("R_valuesAreDifferent"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ protected Object[][] getContents() {
{"R_lengthTruncated", " The inserted length is truncated or not correct!"},
{"R_timeValueTruncated", " The time value is truncated or not correct!"},
{"R_invalidErrorMessage", "Invalid Error Message: "},
{"R_kerberosNativeGSSFailure", "No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)"},
tkyc marked this conversation as resolved.
Show resolved Hide resolved
{"R_expectedFailPassed", "Expected failure did not fail"}, {"R_dataTypeNotFound", "Cannot find data type"},
{"R_illegalCharWktPosition", "Illegal character in Well-Known text at position {0}."},
{"R_illegalCharWkt", "Illegal Well-Known text. Please make sure Well-Known text is valid."},
Expand Down
Loading