From d9fee99b07ed2d8fd9f0acff07a21ee7ffce660a Mon Sep 17 00:00:00 2001 From: David Engel Date: Thu, 3 Jun 2021 13:59:37 -0700 Subject: [PATCH 1/2] Fix multiple, successive connections using AKV provider --- .../sqlserver/jdbc/SQLServerConnection.java | 44 ++++++++----------- .../sqlserver/jdbc/SQLServerResource.java | 2 + .../jdbc/connection/ConnectionTest.java | 38 ++++++++++++++++ 3 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionTest.java diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index e58ac4a2f..2d932a787 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1576,8 +1576,11 @@ private void registerKeyStoreProviderOnConnection(String keyStoreAuth, String ke // need a secret to use the secret method if (null == keyStoreSecret) { throw new SQLServerException(SQLServerException.getErrString("R_keyStoreSecretNotSet"), null); + } else { + SQLServerColumnEncryptionAzureKeyVaultProvider provider = new SQLServerColumnEncryptionAzureKeyVaultProvider( + keyStorePrincipalId, keyStoreSecret); + systemColumnEncryptionKeyStoreProvider.put(provider.getName(), provider); } - registerKeyVaultProvider(keyStorePrincipalId, keyStoreSecret); break; case KeyVaultManagedIdentity: SQLServerColumnEncryptionAzureKeyVaultProvider provider; @@ -1586,9 +1589,7 @@ private void registerKeyStoreProviderOnConnection(String keyStoreAuth, String ke } else { provider = new SQLServerColumnEncryptionAzureKeyVaultProvider(); } - Map keyStoreMap = new HashMap<>(); - keyStoreMap.put(provider.getName(), provider); - registerColumnEncryptionKeyStoreProviders(keyStoreMap); + systemColumnEncryptionKeyStoreProvider.put(provider.getName(), provider); break; default: // valueOfString would throw an exception if the keyStoreAuthentication is not valid. @@ -1597,15 +1598,6 @@ private void registerKeyStoreProviderOnConnection(String keyStoreAuth, String ke } } - private void registerKeyVaultProvider(String clientId, String clientKey) throws SQLServerException { - // need a secret to use the secret method - SQLServerColumnEncryptionAzureKeyVaultProvider provider = new SQLServerColumnEncryptionAzureKeyVaultProvider( - clientId, clientKey); - Map keyStoreMap = new HashMap<>(); - keyStoreMap.put(provider.getName(), provider); - registerColumnEncryptionKeyStoreProviders(keyStoreMap); - } - // Helper to check if timeout value is valid int validateTimeout(SQLServerDriverIntProperty property) throws SQLServerException { int timeout = property.getDefaultValue(); @@ -1843,20 +1835,22 @@ Connection connectInternal(Properties propsIn, registerKeyStoreProviderOnConnection(keyStoreAuthentication, keyStoreSecret, keyStoreLocation); - if (null == globalCustomColumnEncryptionKeyStoreProviders) { - sPropKey = SQLServerDriverStringProperty.KEY_VAULT_PROVIDER_CLIENT_ID.toString(); + sPropKey = SQLServerDriverStringProperty.KEY_VAULT_PROVIDER_CLIENT_ID.toString(); + sPropValue = activeConnectionProperties.getProperty(sPropKey); + if (null != sPropValue) { + if (null != keyStoreAuthentication) { + throw new SQLServerException(SQLServerException.getErrString("R_keyVaultProviderNotSupportedWithKeyStoreAuthentication"), null); + } + String keyVaultColumnEncryptionProviderClientId = sPropValue; + sPropKey = SQLServerDriverStringProperty.KEY_VAULT_PROVIDER_CLIENT_KEY.toString(); sPropValue = activeConnectionProperties.getProperty(sPropKey); - if (null != sPropValue) { - String keyVaultColumnEncryptionProviderClientId = sPropValue; - sPropKey = SQLServerDriverStringProperty.KEY_VAULT_PROVIDER_CLIENT_KEY.toString(); - sPropValue = activeConnectionProperties.getProperty(sPropKey); - if (null != sPropValue) { - String keyVaultColumnEncryptionProviderClientKey = sPropValue; - - registerKeyVaultProvider(keyVaultColumnEncryptionProviderClientId, - keyVaultColumnEncryptionProviderClientKey); - } + if (null == sPropValue) { + throw new SQLServerException(SQLServerException.getErrString("R_keyVaultProviderNotSupportedWithKeyStoreAuthentication"), null); } + String keyVaultColumnEncryptionProviderClientKey = sPropValue; + SQLServerColumnEncryptionAzureKeyVaultProvider provider = new SQLServerColumnEncryptionAzureKeyVaultProvider( + keyVaultColumnEncryptionProviderClientId, keyVaultColumnEncryptionProviderClientKey); + systemColumnEncryptionKeyStoreProvider.put(provider.getName(), provider); } sPropKey = SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.toString(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index 327277e27..a08fda13b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -550,6 +550,8 @@ protected Object[][] getContents() { "Both \"keyStoreSecret\" and \"keyStoreLocation\" must be set, if \"keyStoreAuthentication=JavaKeyStorePassword\" has been specified in the connection string."}, {"R_keyStoreSecretNotSet", "\"keyStoreSecret\" must be set, if \"keyStoreAuthentication=KeyVaultClientSecret\" has been specified in the connection string."}, + {"R_keyVaultProviderNotSupportedWithKeyStoreAuthentication", + "\"keyStoreAuthentication\" cannot be used with \"keyVaultProviderClientId\" or \"keyVaultProviderClientKey\" in the connection string."}, {"R_certificateStoreInvalidKeyword", "Cannot set \"keyStoreSecret\", if \"keyStoreAuthentication=CertificateStore\" has been specified in the connection string."}, {"R_certificateStoreLocationNotSet", diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionTest.java new file mode 100644 index 000000000..50b13cf21 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionTest.java @@ -0,0 +1,38 @@ +/* + * 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.connection; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; +import com.microsoft.sqlserver.testframework.AbstractTest; + +/* + * This test is for testing various connection options + */ +@RunWith(JUnitPlatform.class) +public class ConnectionTest extends AbstractTest { + + @Test + public void testConnections() throws SQLException { + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setURL(connectionString); + ds.setKeyStoreAuthentication("KeyVaultClientSecret"); + ds.setKeyStorePrincipalId("placeholder"); + ds.setKeyStoreSecret("placeholder"); + + // Multiple, successive connections should not fail + try (Connection con = ds.getConnection()) { + } + + try (Connection con = ds.getConnection()) { + } + } +} From d0aa0d0f90b15294b77f77418f027ca640be098b Mon Sep 17 00:00:00 2001 From: David Engel Date: Mon, 7 Jun 2021 11:14:03 -0700 Subject: [PATCH 2/2] Throw correct error message when keyVaultProviderClientKey is not specified --- .../java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java | 2 +- .../java/com/microsoft/sqlserver/jdbc/SQLServerResource.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 2d932a787..5eb76e8ef 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1845,7 +1845,7 @@ Connection connectInternal(Properties propsIn, sPropKey = SQLServerDriverStringProperty.KEY_VAULT_PROVIDER_CLIENT_KEY.toString(); sPropValue = activeConnectionProperties.getProperty(sPropKey); if (null == sPropValue) { - throw new SQLServerException(SQLServerException.getErrString("R_keyVaultProviderNotSupportedWithKeyStoreAuthentication"), null); + throw new SQLServerException(SQLServerException.getErrString("R_keyVaultProviderClientKeyNotSet"), null); } String keyVaultColumnEncryptionProviderClientKey = sPropValue; SQLServerColumnEncryptionAzureKeyVaultProvider provider = new SQLServerColumnEncryptionAzureKeyVaultProvider( diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index a08fda13b..53bbec290 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -550,6 +550,8 @@ protected Object[][] getContents() { "Both \"keyStoreSecret\" and \"keyStoreLocation\" must be set, if \"keyStoreAuthentication=JavaKeyStorePassword\" has been specified in the connection string."}, {"R_keyStoreSecretNotSet", "\"keyStoreSecret\" must be set, if \"keyStoreAuthentication=KeyVaultClientSecret\" has been specified in the connection string."}, + {"R_keyVaultProviderClientKeyNotSet", + "\"keyVaultProviderClientKey\" must be set, if \"keyVaultProviderClientId\" has been specified in the connection string."}, {"R_keyVaultProviderNotSupportedWithKeyStoreAuthentication", "\"keyStoreAuthentication\" cannot be used with \"keyVaultProviderClientId\" or \"keyVaultProviderClientKey\" in the connection string."}, {"R_certificateStoreInvalidKeyword",