Skip to content
Closed
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
31 changes: 23 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,51 +70,57 @@
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-console</artifactId>
<version>1.0.0-M3</version>
<version>1.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>1.0.0-M3</version>
<version>1.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
<version>1.0.0-M3</version>
<version>1.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.0.0-M3</version>
<version>1.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.0.0-M3</version>
<version>1.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.0.0-M3</version>
<version>1.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.0.0-M3</version>
<version>5.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.0-M3</version>
<version>5.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.0.0-M4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
Expand Down Expand Up @@ -283,4 +289,13 @@
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.20</version>
</plugin>
</plugins>
</reporting>
</project>
18 changes: 13 additions & 5 deletions src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,7 @@ void enableSSL(String host,
boolean isFips = false;
String trustStoreType = null;
String fipsProvider = null;
String sslProtocol = null;

// If anything in here fails, terminate the connection and throw an exception
try {
Expand All @@ -1595,7 +1596,10 @@ void enableSSL(String host,
}

fipsProvider = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.FIPS_PROVIDER.toString());
isFips = Boolean.valueOf(con.activeConnectionProperties.getProperty(SQLServerDriverBooleanProperty.FIPS.toString()));
isFips = Boolean.valueOf(con.activeConnectionProperties.getProperty(SQLServerDriverBooleanProperty.FIPS.toString()));

sslProtocol = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.SSL_PROTOCOL.toString(),
SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue());

if (isFips) {
validateFips(fipsProvider, trustStoreType, trustStoreFileName);
Expand Down Expand Up @@ -1644,7 +1648,7 @@ void enableSSL(String host,
if (logger.isLoggable(Level.FINEST))
logger.finest(toString() + " Finding key store interface");

if (isFips) {
if (isFips && !StringUtils.isEmpty(fipsProvider)) {
ks = KeyStore.getInstance(trustStoreType, fipsProvider);
}
else {
Expand Down Expand Up @@ -1723,9 +1727,9 @@ void enableSSL(String host,
SSLContext sslContext = null;

if (logger.isLoggable(Level.FINEST))
logger.finest(toString() + " Getting TLS or better SSL context");
logger.finest(toString() + " Getting TLS or better SSL context with " + sslProtocol );

sslContext = SSLContext.getInstance("TLS");
sslContext = SSLContext.getInstance(sslProtocol);
sslContextProvider = sslContext.getProvider();

if (logger.isLoggable(Level.FINEST))
Expand Down Expand Up @@ -1826,6 +1830,8 @@ void enableSSL(String host,
* <LI>trustServerCertificate should be false
* <LI>if certificate is not installed FIPSProvider & TrustStoreType should be present.
*
* @since 6.2.x It will not generate any error. We found out for some FIPS implementation like IBM one should not pass FIPSProvider.
*
* @param fipsProvider
* FIPS Provider
* @param trustStoreType
Expand Down Expand Up @@ -1877,7 +1883,9 @@ private void validateFips(final String fipsProvider,
}

if (!isValid) {
throw new SQLServerException(strError, null, 0, null);
// In some FIPS implementations e.g. BouncyCastle we need to pass FIPSProvider for getting appropriate KeyStore.
// While IBM FIPS implementation, one should not pass FIPSProvider, instead rely on security configuration file.
logger.warning(strError);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;

import javax.sql.XAConnection;
Expand Down Expand Up @@ -1466,6 +1466,16 @@ else if (0 == requestedPacketSize)
if (null != sPropValue) {
setEnablePrepareOnFirstPreparedStatementCall(booleanPropertyOn(sPropKey, sPropValue));
}

sPropKey = SQLServerDriverStringProperty.SSL_PROTOCOL.toString();
sPropValue = activeConnectionProperties.getProperty(sPropKey, SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue());
if ("TLS".equalsIgnoreCase(sPropValue) || "TLSv1.1".equalsIgnoreCase(sPropValue) || "TLSv1.2".equalsIgnoreCase(sPropValue)) {
activeConnectionProperties.setProperty(sPropKey, sPropValue);
}else {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidSSLProtocol"));
Object[] msgArgs = {sPropValue};
SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false);
}

FailoverInfo fo = null;
String databaseNameProperty = SQLServerDriverStringProperty.DATABASE_NAME.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,14 @@ public void setFIPSProvider(String fipsProvider) {
public String getFIPSProvider() {
return getStringProperty(connectionProps, SQLServerDriverStringProperty.FIPS_PROVIDER.toString(), null);
}

public void setSSLProtocol(String sslProtocol) {
setStringProperty(connectionProps, SQLServerDriverStringProperty.SSL_PROTOCOL.toString(), sslProtocol);
}

public String getSSLProtocol() {
return getStringProperty(connectionProps, SQLServerDriverStringProperty.SSL_PROTOCOL.toString(), SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue());
}

// The URL property is exposed for backwards compatibility reasons. Also, several
// Java Application servers expect a setURL function on the DataSource and set it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ enum SQLServerDriverStringProperty
KEY_STORE_SECRET ("keyStoreSecret", ""),
KEY_STORE_LOCATION ("keyStoreLocation", ""),
FIPS_PROVIDER ("fipsProvider", ""),
;
SSL_PROTOCOL ("sslProtocol", "TLS") ;

private String name;
private String defaultValue;
Expand Down Expand Up @@ -381,6 +381,8 @@ public final class SQLServerDriver implements java.sql.Driver {
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),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SELECT_METHOD.toString(), SQLServerDriverStringProperty.SELECT_METHOD.getDefaultValue(), false, new String[] {"direct", "cursor"}),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SSL_PROTOCOL.toString(), SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue(), false, new String[] {"TLS", "TLSv1.1", "TLSv1.2"}),
};

// Properties that can only be set by using Properties.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,13 @@ protected Object[][] getContents() {
{"R_fipsPropertyDescription", "Determines if enable FIPS compilant SSL connection between the client and the server."},
{"R_invalidFipsConfig", "Could not enable FIPS."},
{"R_invalidFipsEncryptConfig", "Could not enable FIPS due to either encrypt is not true or using trusted certificate settings."},
{"R_invalidFipsProviderConfig", "Could not enable FIPS due to invalid FIPSProvider or TrustStoreType."},
{"R_invalidFipsProviderConfig", "FIPS may not enable due to invalid FIPSProvider or TrustStoreType."},
{"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_StoredProcedureNotFound", "Could not find stored procedure ''{0}''."},
{"R_jaasConfigurationNamePropertyDescription", "Login configuration file for Kerberos authentication."},
{"R_sslProtocolPropertyDescription", "Able to set SSL protocol from TLS, TLSv1.1 & TLSv1.2. Default is TLS"},
{"R_invalidSSLProtocol", "SSL Protocol {0} is not valid. Supporting only TLS, TLSv1.1 & TLSv1.2."}
};
}
10 changes: 9 additions & 1 deletion src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -39,10 +40,11 @@ public static void init() {

/**
* Test after setting TrustServerCertificate as true.
*
* This is disable due to IBM FIPS environment behavior. We should not mandate FIPS Provider & other parameters.
* @throws Exception
*/
@Test
@Disabled
public void fipsTrustServerCertificateTest() throws Exception {
try {
Properties props = buildConnectionProperties();
Expand All @@ -62,6 +64,7 @@ public void fipsTrustServerCertificateTest() throws Exception {
*
* @throws Exception
*/
@Disabled
@Test
public void fipsEncryptTest() throws Exception {
try {
Expand All @@ -82,6 +85,7 @@ public void fipsEncryptTest() throws Exception {
*
* @throws Exception
*/
@Disabled
@Test
public void fipsProviderTest() throws Exception {
try {
Expand Down Expand Up @@ -120,6 +124,7 @@ public void fipsPropertyTest() throws Exception {
* @throws Exception
*/
@Test
@Disabled
public void fipsDataSourcePropertyTest() throws Exception {
SQLServerDataSource ds = new SQLServerDataSource();
setDataSourceProperties(ds);
Expand All @@ -137,6 +142,7 @@ public void fipsDataSourcePropertyTest() throws Exception {
* Test after removing encrypt in FIPS Data Source.
*/
@Test
@Disabled
public void fipsDatSourceEncrypt() {
try {
SQLServerDataSource ds = new SQLServerDataSource();
Expand All @@ -159,6 +165,7 @@ public void fipsDatSourceEncrypt() {
* @throws Exception
*/
@Test
@Disabled
public void fipsDataSourceProviderTest() throws Exception {
try {
SQLServerDataSource ds = new SQLServerDataSource();
Expand All @@ -180,6 +187,7 @@ public void fipsDataSourceProviderTest() throws Exception {
* @throws Exception
*/
@Test
@Disabled
public void fipsDataSourceTrustServerCertificateTest() throws Exception {
try {
SQLServerDataSource ds = new SQLServerDataSource();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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.unit;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.Statement;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;

import com.microsoft.sqlserver.jdbc.SQLServerException;
import com.microsoft.sqlserver.jdbc.StringUtils;
import com.microsoft.sqlserver.testframework.AbstractTest;

/**
* This unit test case targeted to test new functionality of configuring SSLProtocol for connecting to SQL Server.
*/
@RunWith(JUnitPlatform.class)
public class TestSSLProtocol extends AbstractTest {

Connection con = null;
Statement stmt = null;

/**
*
* @param sslProtocol
* @throws Exception
*/
@DisplayName("TestForSupportedProtocols")
@ParameterizedTest
@ValueSource(strings={"TLS","TLSv1.1","TLSv1.2"})
public void testSuportedProtocols(String sslProtocol) throws Exception {
String url = connectionString + ";sslProtocol=" + sslProtocol;
con = DriverManager.getConnection(url);
DatabaseMetaData dbmd = con.getMetaData();
assertNotNull(dbmd);
assertTrue(!StringUtils.isEmpty(dbmd.getDatabaseProductName()));
}

/**
* Connect with valid but not supported protocols
* @param sslProtocol
* @throws Exception
*/
@DisplayName("TestForNotSupportedProtocols")
@ParameterizedTest
@ValueSource(strings={"SSLv1","SSLv2","SSLv3", "SSLv2Hello","SSL"})
public void testWithUnSupportedProtocols(String sslProtocol) throws Exception {
try {
String url = connectionString + ";sslProtocol=" + sslProtocol;
con = DriverManager.getConnection(url);
assertFalse(true, "Any protocol other than TLS, TLSv1.1 & TLSv1.2 should throw Exception");
}catch(SQLServerException e) {
assertTrue(true,"Should throw exception");
String errMsg = "SSL Protocol "+ sslProtocol +" is not valid. Supporting only TLS, TLSv1.1 & TLSv1.2.";

assertTrue(errMsg.equals(e.getMessage()),"Message should be from SQL Server resources : " + e.getMessage());
}
}

/**
* Test with wrong values.
* @param sslProtocol
* @throws Exception
*/
@DisplayName("TestForWrongValues")
@ParameterizedTest
@ValueSource(strings={"SSLv1111","SSLv2222","SSLv3111", "SSLv2Hello1111","TLSv1.11","TLSv2.4","HTTPS"})
public void testConnectWithWrongProtocol(String sslProtocol) throws Exception {
testWithUnSupportedProtocols(sslProtocol);
}
}