From c5dc369bcf2cb81c92406f57eebc8417e3cb9529 Mon Sep 17 00:00:00 2001 From: v-nish Date: Wed, 10 May 2017 18:58:45 -0700 Subject: [PATCH 1/4] Initial Checkin Initial check in for configurable SSLProtocols --- .../microsoft/sqlserver/jdbc/IOBuffer.java | 10 ++- .../sqlserver/jdbc/SQLServerConnection.java | 12 ++- .../sqlserver/jdbc/SQLServerDataSource.java | 8 ++ .../sqlserver/jdbc/SQLServerDriver.java | 4 +- .../sqlserver/jdbc/SQLServerResource.java | 2 + .../sqlserver/jdbc/unit/TestSSLProtocol.java | 86 +++++++++++++++++++ 6 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index 891b5355f..ed57437da 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -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 { @@ -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); @@ -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)) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index caee05b97..811ec145e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -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; @@ -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(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java index 891fe3b90..0fcb8c7bf 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java @@ -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 diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 646af582b..e9cfc8095 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -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; @@ -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. diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index 79ed19168..433ce5971 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -383,5 +383,7 @@ protected Object[][] getContents() { {"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."} }; } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java new file mode 100644 index 000000000..d303c793a --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java @@ -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.Test; +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; + +/** + * + */ +@RunWith(JUnitPlatform.class) +public class TestSSLProtocol extends AbstractTest { + + Connection con = null; + Statement stmt = null; + + /** + * TODO: add @ParameterizedTest() with @ValueSource(strings={"TLS", "TLSv1.1"}) + * + * @throws Exception + */ + @Test + public void testConnectWithTLS1_2() throws Exception { + String url = connectionString + ";sslProtocol=TLSv1.2"; + con = DriverManager.getConnection(url); + DatabaseMetaData dbmd = con.getMetaData(); + assertNotNull(dbmd); + assertTrue(!StringUtils.isEmpty(dbmd.getDatabaseProductName())); + } + + @Test + public void testConnectWithTLS1_1() throws Exception { + String url = connectionString + ";sslProtocol=TLSv1.1"; + con = DriverManager.getConnection(url); + DatabaseMetaData dbmd = con.getMetaData(); + assertNotNull(dbmd); + assertTrue(!StringUtils.isEmpty(dbmd.getDatabaseProductName())); + } + + @Test + public void testConnectWithSSL() throws Exception { + try { + String url = connectionString + ";sslProtocol=SSLv3"; + con = DriverManager.getConnection(url); + assertFalse(true, "With Garbage Protocol you should not see this"); + }catch(Exception e) { + assertTrue(true,"Should throw exception"); + } + } + + /** + * Wrong version number used. + * @throws Exception + */ + @Test + public void testConnectWithWrongProtocol() throws Exception { + try { + String url = connectionString + ";sslProtocol=TLSv1.11"; + con = DriverManager.getConnection(url); + assertFalse(true, "With Garbage Protocol you should not see this"); + } + catch (SQLServerException e) { + assertTrue("SSL Protocol TLSv1.11 is not valid. Supporting only TLS, TLSv1.1 & TLSv1.2.".equals(e.getMessage()),"Message should be from SQL Server resources"); + } + } + +} From f9ea4ac4ffb0672e8a8ed107f7d869000ffb3a1d Mon Sep 17 00:00:00 2001 From: v-nish Date: Thu, 11 May 2017 16:43:11 -0700 Subject: [PATCH 2/4] Added parametrized test cases Added parametrized test cases --- pom.xml | 31 ++++++--- .../sqlserver/jdbc/unit/TestSSLProtocol.java | 64 +++++++++---------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/pom.xml b/pom.xml index c5d123987..4aaae90e9 100644 --- a/pom.xml +++ b/pom.xml @@ -70,51 +70,57 @@ org.junit.platform junit-platform-console - 1.0.0-M3 + 1.0.0-M4 test org.junit.platform junit-platform-commons - 1.0.0-M3 + 1.0.0-M4 test org.junit.platform junit-platform-engine - 1.0.0-M3 + 1.0.0-M4 test org.junit.platform junit-platform-launcher - 1.0.0-M3 + 1.0.0-M4 test org.junit.platform junit-platform-runner - 1.0.0-M3 + 1.0.0-M4 test org.junit.platform junit-platform-surefire-provider - 1.0.0-M3 + 1.0.0-M4 test org.junit.jupiter junit-jupiter-api - 5.0.0-M3 + 5.0.0-M4 test org.junit.jupiter junit-jupiter-engine - 5.0.0-M3 + 5.0.0-M4 test + + org.junit.jupiter + junit-jupiter-params + 5.0.0-M4 + test + com.zaxxer HikariCP @@ -283,4 +289,13 @@ + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.20 + + + diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java index d303c793a..cfbfe6953 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSSLProtocol.java @@ -16,7 +16,9 @@ import java.sql.DriverManager; import java.sql.Statement; -import org.junit.jupiter.api.Test; +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; @@ -25,7 +27,7 @@ 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 { @@ -34,53 +36,51 @@ public class TestSSLProtocol extends AbstractTest { Statement stmt = null; /** - * TODO: add @ParameterizedTest() with @ValueSource(strings={"TLS", "TLSv1.1"}) * + * @param sslProtocol * @throws Exception */ - @Test - public void testConnectWithTLS1_2() throws Exception { - String url = connectionString + ";sslProtocol=TLSv1.2"; - con = DriverManager.getConnection(url); - DatabaseMetaData dbmd = con.getMetaData(); - assertNotNull(dbmd); - assertTrue(!StringUtils.isEmpty(dbmd.getDatabaseProductName())); - } - - @Test - public void testConnectWithTLS1_1() throws Exception { - String url = connectionString + ";sslProtocol=TLSv1.1"; + @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())); } - @Test - public void testConnectWithSSL() throws Exception { + /** + * 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=SSLv3"; + String url = connectionString + ";sslProtocol=" + sslProtocol; con = DriverManager.getConnection(url); - assertFalse(true, "With Garbage Protocol you should not see this"); - }catch(Exception e) { + 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()); } } /** - * Wrong version number used. + * Test with wrong values. + * @param sslProtocol * @throws Exception */ - @Test - public void testConnectWithWrongProtocol() throws Exception { - try { - String url = connectionString + ";sslProtocol=TLSv1.11"; - con = DriverManager.getConnection(url); - assertFalse(true, "With Garbage Protocol you should not see this"); - } - catch (SQLServerException e) { - assertTrue("SSL Protocol TLSv1.11 is not valid. Supporting only TLS, TLSv1.1 & TLSv1.2.".equals(e.getMessage()),"Message should be from SQL Server resources"); - } + @DisplayName("TestForWrongValues") + @ParameterizedTest + @ValueSource(strings={"SSLv1111","SSLv2222","SSLv3111", "SSLv2Hello1111","TLSv1.11","TLSv2.4","HTTPS"}) + public void testConnectWithWrongProtocol(String sslProtocol) throws Exception { + testWithUnSupportedProtocols(sslProtocol); } - } From d6d7f0ed92914b435874e60ca8fe894aa3f432ba Mon Sep 17 00:00:00 2001 From: v-nish Date: Tue, 30 May 2017 14:02:52 -0700 Subject: [PATCH 3/4] For IBM FIPS In IBM FIPS environment IBM JRE expects FIPSProvider should be read from JVM config files. --- src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java | 8 ++++++-- .../com/microsoft/sqlserver/jdbc/SQLServerResource.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index ed57437da..442c3c508 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -1648,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 { @@ -1830,6 +1830,8 @@ void enableSSL(String host, *
  • trustServerCertificate should be false *
  • 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 @@ -1881,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); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index 433ce5971..f5b615d32 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -377,7 +377,7 @@ 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})"}, From 11ea2c70d18d0f89fc021713a4c393fdf322bf32 Mon Sep 17 00:00:00 2001 From: v-nish Date: Tue, 30 May 2017 19:26:32 -0700 Subject: [PATCH 4/4] Disable Some tests Disabled some test for FIPS env. due to change in logic. Need to write tests for FIPS --- .../com/microsoft/sqlserver/jdbc/fips/FipsTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java index 83f8a9f71..dbd3e0c4b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java @@ -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; @@ -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(); @@ -62,6 +64,7 @@ public void fipsTrustServerCertificateTest() throws Exception { * * @throws Exception */ + @Disabled @Test public void fipsEncryptTest() throws Exception { try { @@ -82,6 +85,7 @@ public void fipsEncryptTest() throws Exception { * * @throws Exception */ + @Disabled @Test public void fipsProviderTest() throws Exception { try { @@ -120,6 +124,7 @@ public void fipsPropertyTest() throws Exception { * @throws Exception */ @Test + @Disabled public void fipsDataSourcePropertyTest() throws Exception { SQLServerDataSource ds = new SQLServerDataSource(); setDataSourceProperties(ds); @@ -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(); @@ -159,6 +165,7 @@ public void fipsDatSourceEncrypt() { * @throws Exception */ @Test + @Disabled public void fipsDataSourceProviderTest() throws Exception { try { SQLServerDataSource ds = new SQLServerDataSource(); @@ -180,6 +187,7 @@ public void fipsDataSourceProviderTest() throws Exception { * @throws Exception */ @Test + @Disabled public void fipsDataSourceTrustServerCertificateTest() throws Exception { try { SQLServerDataSource ds = new SQLServerDataSource();