Skip to content
Merged
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
1 change: 1 addition & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Added
- Added DCO (Developer Certificate of Origin) check workflow for pull requests to ensure all commits are properly signed-off
- Added support for SSL client certificate authentication via parameter: SSLTrustStoreProvider

### Updated
-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,11 @@ public String getSSLTrustStoreType() {
return getParameter(DatabricksJdbcUrlParams.SSL_TRUST_STORE_TYPE);
}

@Override
public String getSSLTrustStoreProvider() {
return getParameter(DatabricksJdbcUrlParams.SSL_TRUST_STORE_PROVIDER);
}

@Override
public String getSSLKeyStore() {
return getParameter(DatabricksJdbcUrlParams.SSL_KEY_STORE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ public interface IDatabricksConnectionContext {
/** Returns the SSL key store provider for the key store. */
String getSSLKeyStoreProvider();

/** Returns the SSL trust store provider for the trust store. */
String getSSLTrustStoreProvider();

/** Returns the maximum number of commands that can be executed in a single batch. */
int getMaxBatchSize();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public enum DatabricksJdbcUrlParams {
SSL_KEY_STORE_PASSWORD("SSLKeyStorePwd", "SSL key store password"),
SSL_KEY_STORE_TYPE("SSLKeyStoreType", "SSL key store type", "JKS"),
SSL_KEY_STORE_PROVIDER("SSLKeyStoreProvider", "SSL key store provider"),
SSL_TRUST_STORE_PROVIDER("SSLTrustStoreProvider", "SSL trust store provider"),
USE_SYSTEM_TRUST_STORE("UseSystemTrustStore", "Use system trust store for SSL", "0"),
CHECK_CERTIFICATE_REVOCATION("CheckCertRevocation", "Check certificate revocation", "1"),
ACCEPT_UNDETERMINED_CERTIFICATE_REVOCATION(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,24 +470,36 @@ public static KeyStore loadTruststoreOrNull(IDatabricksConnectionContext connect
}

String trustStoreType = connectionContext.getSSLTrustStoreType();
String trustStoreProvider = connectionContext.getSSLTrustStoreProvider();

try (FileInputStream trustStoreStream = new FileInputStream(trustStorePath)) {
LOGGER.info("Loading trust store as type: " + trustStoreType);
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
KeyStore trustStore;
if (trustStoreProvider != null && !trustStoreProvider.isEmpty()) {
LOGGER.info("Using trust store provider: " + trustStoreProvider);
trustStore = KeyStore.getInstance(trustStoreType, trustStoreProvider);
} else {
trustStore = KeyStore.getInstance(trustStoreType);
}
trustStore.load(trustStoreStream, password);
LOGGER.info("Successfully loaded trust store: " + trustStorePath);
return trustStore;
} catch (Exception e) {
String errorMessage =
"Failed to load trust store: "
+ trustStorePath
+ " with type "
+ trustStoreType
+ ": "
+ e.getMessage();
LOGGER.error(errorMessage);
String errorMessage;
if (trustStoreProvider != null && !trustStoreProvider.isEmpty()) {
errorMessage =
String.format(
"Failed to load trust store: %s with type %s and provider %s: %s",
trustStorePath, trustStoreType, trustStoreProvider, e.getMessage());
} else {
errorMessage =
String.format(
"Failed to load trust store: %s with type %s: %s",
trustStorePath, trustStoreType, e.getMessage());
}
LOGGER.error(errorMessage.toString());
throw new DatabricksSSLException(
errorMessage, e, DatabricksDriverErrorCode.SSL_HANDSHAKE_ERROR);
errorMessage.toString(), e, DatabricksDriverErrorCode.SSL_HANDSHAKE_ERROR);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -592,4 +592,22 @@ public void testSSLKeystoreParameters() throws DatabricksSQLException {
assertEquals("PKCS12", connectionContext.getSSLKeyStoreType());
assertEquals("SunJSSE", connectionContext.getSSLKeyStoreProvider());
}

@Test
public void testSSLTrustStoreParameters() throws DatabricksSQLException {
// Test case 1: Default settings (all null)
String validJdbcUrl = TestConstants.VALID_URL_1;
Properties properties = new Properties();
DatabricksConnectionContext connectionContext =
(DatabricksConnectionContext) DatabricksConnectionContext.parse(validJdbcUrl, properties);
assertNull(connectionContext.getSSLTrustStore());

// Test case 2: With truststore parameters
properties.put("SSLTrustStore", "/path/to/truststore.jks");
properties.put("SSLTrustStorePwd", "truststorepassword");
properties.put("SSLTrustStoreType", "PKCS12");
properties.put("SSLTrustStoreProvider", "SunJSSE");
connectionContext =
(DatabricksConnectionContext) DatabricksConnectionContext.parse(validJdbcUrl, properties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -577,4 +577,26 @@ void testMissingKeyStorePassword() {
() -> ConfiguratorUtils.loadKeystoreOrNull(mockContext),
"Should throw an exception when key store password is missing");
}

@Test
void testLoadTrustStoreWithProvider() throws Exception {
String providerName = "TestProvider";
when(mockContext.getSSLTrustStore()).thenReturn(DUMMY_TRUST_STORE_PATH);
when(mockContext.getSSLTrustStorePassword()).thenReturn(TRUST_STORE_PASSWORD);
when(mockContext.getSSLTrustStoreType()).thenReturn(TRUST_STORE_TYPE);
when(mockContext.getSSLTrustStoreProvider()).thenReturn(providerName);

try (MockedStatic<KeyStore> keyStoreStatic = mockStatic(KeyStore.class)) {
KeyStore mockKeyStore = mock(KeyStore.class);
keyStoreStatic
.when(() -> KeyStore.getInstance(TRUST_STORE_TYPE, providerName))
.thenReturn(mockKeyStore);

// Call the method under test
ConfiguratorUtils.loadTruststoreOrNull(mockContext);

keyStoreStatic.verify(() -> KeyStore.getInstance(TRUST_STORE_TYPE, providerName));
verify(mockKeyStore).load(any(), eq(TRUST_STORE_PASSWORD.toCharArray()));
}
}
}
Loading