question

SubinSankaran-5415 avatar image
0 Votes"
SubinSankaran-5415 asked Cathyji-msft commented

Key store providers cannot be set more than once(Always Encrypted with JDBC and Java 8)

We are trying to use SQL Always Encrypted feature in our Java Web Application.

Java 8 is the JRE and uses mssql-jdbc-9.2.1.jre8.jar as the jdbc driver.

Azure-Key-vault as the column master key store provider


Our application uses below code to obtain a DB connection whenever needed(No Connection Pooling).


   String  conStr="jdbc:sqlserver://x.x.x.x:x;DatabaseName=MYDB;User=x;Password=x;columnEncryptionSetting=Enabled;keyStoreAuthentication=KeyVaultClientSecret;keyStorePrincipalId=x-x-x-x-x;keyStoreSecret=x"
     DriverManager.getConnection(conStr);

When we run the application , DB connection is successful on the first connection. From second connection attempt onwards ,we are getting the below exception.

 com.microsoft.sqlserver.jdbc.SQLServerException: Key store providers cannot be set more than once.
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.registerColumnEncryptionKeyStoreProviders(SQLServerConnection.java:753)
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.registerKeyVaultProvider(SQLServerConnection.java:1414)
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.registerKeyStoreProviderOnConnection(SQLServerConnection.java:1388)
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1642)
  at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1291)
  at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:881)
  at java.sql.DriverManager.getConnection(DriverManager.java:664)
  at java.sql.DriverManager.getConnection(DriverManager.java:270)

When I checked code , could find the code which is causing the exception.


 public static synchronized void registerColumnEncryptionKeyStoreProviders(
             Map<String, SQLServerColumnEncryptionKeyStoreProvider> clientKeyStoreProviders) throws SQLServerException {
         loggerExternal.entering(loggingClassName, "registerColumnEncryptionKeyStoreProviders",
                 "Registering Column Encryption Key Store Providers");
    
         if (null == clientKeyStoreProviders) {
             throw new SQLServerException(null, SQLServerException.getErrString("R_CustomKeyStoreProviderMapNull"), null,
                     0, false);
         }
    
         if (null != globalCustomColumnEncryptionKeyStoreProviders
                 && !globalCustomColumnEncryptionKeyStoreProviders.isEmpty()) {
             throw new SQLServerException(null, SQLServerException.getErrString("R_CustomKeyStoreProviderSetOnce"), null,
                     0, false);
         }
    
 //continue......
 }

Root cause is , globalCustomColumnEncryptionKeyStoreProviders is a static HashMap variable and is populated with the KeyStoreProvider instance on the first connection attempt itself. So from second connection attempt onwards , the exception is thrown since globalCustomColumnEncryptionKeyStoreProviders is not empty.

Can I resolve the issue without changing DriverManager.getConnection() ? Am I missing something here ?

There is public static synchronized void unregisterColumnEncryptionKeyStoreProviders() method in com.microsoft.sqlserver.jdbc.SQLServerConnection class which will clear the globalCustomColumnEncryptionKeyStoreProviders map.
But calling that before DriverManage.getConnection() doesn't seem to solve the issue when there are multiple connection attempts happening in parallel.








sql-server-general
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @SubinSankaran-5415,

Welcome to Q&A forum.

I not familiar with Java. I search this issue over google. Suggest you reading the document Using Always Encrypted with the JDBC driver to find if you missed something.


0 Votes 0 ·

0 Answers