@@ -64,20 +64,24 @@ static void setup() throws Exception {
6464
6565 private static void createEmptyTrustStore ()
6666 throws KeyStoreException , CertificateException , IOException , NoSuchAlgorithmException {
67+ String password = TRUST_STORE_PASSWORD ;
6768 // Create an empty JKS keystore
6869 KeyStore keyStore = KeyStore .getInstance (TRUST_STORE_TYPE );
69- keyStore .load (null , TRUST_STORE_PASSWORD .toCharArray ());
70+ keyStore .load (null , password .toCharArray ());
7071
7172 // Save the empty keystore to a file
7273 try (FileOutputStream fos = new FileOutputStream (EMPTY_TRUST_STORE_PATH )) {
73- keyStore .store (fos , TRUST_STORE_PASSWORD .toCharArray ());
74+ keyStore .store (fos , password .toCharArray ());
7475 }
7576 }
7677
7778 private static void createDummyTrustStore () throws Exception {
79+ String trustStorePassword = TRUST_STORE_PASSWORD ; // Password for the trust store
80+ String alias = "dummy-cert" ; // Alias for the dummy certificate
81+
7882 // Create an empty JKS keystore
7983 KeyStore keyStore = KeyStore .getInstance (TRUST_STORE_TYPE );
80- keyStore .load (null , TRUST_STORE_PASSWORD .toCharArray ());
84+ keyStore .load (null , trustStorePassword .toCharArray ());
8185
8286 // Generate a key pair (public and private keys)
8387 KeyPairGenerator keyPairGen = KeyPairGenerator .getInstance ("RSA" );
@@ -86,9 +90,13 @@ private static void createDummyTrustStore() throws Exception {
8690
8791 // Create a self-signed certificate
8892 X509Certificate certificate = generateBarebonesCertificate (keyPair );
89- keyStore .setCertificateEntry ("dummy-cert" , certificate );
93+
94+ // Add the certificate to the keystore
95+ keyStore .setCertificateEntry (alias , certificate );
96+
97+ // Save the keystore to a file
9098 try (FileOutputStream fos = new FileOutputStream (DUMMY_TRUST_STORE_PATH )) {
91- keyStore .store (fos , TRUST_STORE_PASSWORD .toCharArray ());
99+ keyStore .store (fos , trustStorePassword .toCharArray ());
92100 }
93101 }
94102
@@ -129,13 +137,46 @@ static void cleanup() {
129137 }
130138 }
131139
140+ @ Test
141+ void testGetConnectionSocketFactoryRegistry () throws DatabricksHttpException {
142+ when (mockContext .getSSLTrustStorePassword ()).thenReturn (TRUST_STORE_PASSWORD );
143+ when (mockContext .getSSLTrustStoreType ()).thenReturn (TRUST_STORE_TYPE );
144+ when (mockContext .getSSLTrustStore ()).thenReturn (EMPTY_TRUST_STORE_PATH );
145+ assertThrows (
146+ DatabricksHttpException .class ,
147+ () -> ConfiguratorUtils .createConnectionSocketFactoryRegistry (mockContext ),
148+ "the trustAnchors parameter must be non-empty" );
149+
150+ when (mockContext .getSSLTrustStore ()).thenReturn (DUMMY_TRUST_STORE_PATH );
151+ Registry <ConnectionSocketFactory > registry =
152+ ConfiguratorUtils .createConnectionSocketFactoryRegistry (mockContext );
153+ assertInstanceOf (
154+ SSLConnectionSocketFactory .class , registry .lookup (DatabricksJdbcConstants .HTTPS ));
155+ assertInstanceOf (
156+ PlainConnectionSocketFactory .class , registry .lookup (DatabricksJdbcConstants .HTTP ));
157+ }
158+
159+ @ Test
160+ void testGetTrustAnchorsFromTrustStore () throws DatabricksHttpException {
161+ when (mockContext .getSSLTrustStorePassword ()).thenReturn (TRUST_STORE_PASSWORD );
162+ when (mockContext .getSSLTrustStoreType ()).thenReturn (TRUST_STORE_TYPE );
163+ when (mockContext .getSSLTrustStore ()).thenReturn (DUMMY_TRUST_STORE_PATH );
164+ KeyStore trustStore = ConfiguratorUtils .loadTruststoreOrNull (mockContext );
165+ Set <TrustAnchor > trustAnchors = ConfiguratorUtils .getTrustAnchorsFromTrustStore (trustStore );
166+ assertTrue (
167+ trustAnchors .stream ()
168+ .anyMatch (ta -> ta .getTrustedCert ().getIssuerDN ().toString ().contains (CERTIFICATE_CN )));
169+ }
170+
132171 @ Test
133172 void testGetBaseConnectionManager_NoSSLTrustStoreAndRevocationCheckEnabled ()
134173 throws DatabricksHttpException {
135174 // Define behavior for mock context
175+ when (mockContext .getSSLTrustStore ()).thenReturn (null );
136176 when (mockContext .checkCertificateRevocation ()).thenReturn (true );
137177 when (mockContext .acceptUndeterminedCertificateRevocation ()).thenReturn (false );
138178 when (mockContext .useSystemTrustStore ()).thenReturn (false );
179+ when (mockContext .allowSelfSignedCerts ()).thenReturn (false );
139180
140181 try (MockedStatic <ConfiguratorUtils > configuratorUtils =
141182 mockStatic (ConfiguratorUtils .class , withSettings ().defaultAnswer (CALLS_REAL_METHODS ))) {
@@ -179,20 +220,43 @@ void testUseSystemTrustStoreFalse_NoCustomTrustStore() throws DatabricksHttpExce
179220 // Scenario: useSystemTrustStore=false and no custom trust store provided
180221 // Should use JDK default trust store and ignore system property
181222
223+ when (mockContext .getSSLTrustStore ()).thenReturn (null );
182224 when (mockContext .useSystemTrustStore ()).thenReturn (false );
183225 when (mockContext .checkCertificateRevocation ()).thenReturn (false );
184226
185- Registry <ConnectionSocketFactory > registry =
186- ConfiguratorUtils .createConnectionSocketFactoryRegistry (mockContext );
187- assertNotNull (registry );
188- assertInstanceOf (
189- SSLConnectionSocketFactory .class , registry .lookup (DatabricksJdbcConstants .HTTPS ));
227+ try {
228+ Registry <ConnectionSocketFactory > registry =
229+ ConfiguratorUtils .createConnectionSocketFactoryRegistry (mockContext );
230+ assertNotNull (registry );
231+ assertInstanceOf (
232+ SSLConnectionSocketFactory .class , registry .lookup (DatabricksJdbcConstants .HTTPS ));
233+ } catch (Exception e ) {
234+ fail (
235+ "Should not throw exception when useSystemTrustStore=false and no custom trust store: "
236+ + e .getMessage ());
237+ }
238+ }
239+
240+ @ Test
241+ void testAllowSelfSignedCerts () throws DatabricksHttpException {
242+ // Scenario: allowSelfSignedCerts=true
243+ // Should use trust-all socket factory
244+
245+ when (mockContext .allowSelfSignedCerts ()).thenReturn (true );
246+
247+ PoolingHttpClientConnectionManager connManager =
248+ ConfiguratorUtils .getBaseConnectionManager (mockContext );
249+
250+ assertNotNull (connManager );
190251 }
191252
192253 @ Test
193254 void testCustomTrustStore_WithRevocationChecking () throws DatabricksHttpException {
194255 // Scenario: Custom trust store with certificate revocation checking
195256
257+ when (mockContext .getSSLTrustStore ()).thenReturn (DUMMY_TRUST_STORE_PATH );
258+ when (mockContext .getSSLTrustStorePassword ()).thenReturn (TRUST_STORE_PASSWORD );
259+ when (mockContext .getSSLTrustStoreType ()).thenReturn (TRUST_STORE_TYPE );
196260 when (mockContext .checkCertificateRevocation ()).thenReturn (true );
197261 when (mockContext .acceptUndeterminedCertificateRevocation ()).thenReturn (true );
198262
@@ -204,6 +268,41 @@ void testCustomTrustStore_WithRevocationChecking() throws DatabricksHttpExceptio
204268 SSLConnectionSocketFactory .class , registry .lookup (DatabricksJdbcConstants .HTTPS ));
205269 }
206270
271+ @ Test
272+ void testLoadTruststoreWithAutoDetection ()
273+ throws DatabricksHttpException ,
274+ IOException ,
275+ KeyStoreException ,
276+ CertificateException ,
277+ NoSuchAlgorithmException {
278+ // Scenario: Trust store type auto-detection
279+ // Create a trust store with default type but try to load with different types
280+
281+ String tempTrustStorePath = BASE_TRUST_STORE_PATH + "auto-detect-truststore.jks" ;
282+
283+ try {
284+ // Create a trust store with password but without specifying type
285+ KeyStore keyStore = KeyStore .getInstance ("JKS" );
286+ keyStore .load (null , TRUST_STORE_PASSWORD .toCharArray ());
287+ try (FileOutputStream fos = new FileOutputStream (tempTrustStorePath )) {
288+ keyStore .store (fos , TRUST_STORE_PASSWORD .toCharArray ());
289+ }
290+
291+ when (mockContext .getSSLTrustStore ()).thenReturn (tempTrustStorePath );
292+ when (mockContext .getSSLTrustStorePassword ()).thenReturn (TRUST_STORE_PASSWORD );
293+ when (mockContext .getSSLTrustStoreType ()).thenReturn (null ); // No type specified
294+
295+ KeyStore loadedStore = ConfiguratorUtils .loadTruststoreOrNull (mockContext );
296+ assertNotNull (loadedStore , "Trust store should be auto-detected and loaded" );
297+ } finally {
298+ try {
299+ Files .delete (Path .of (tempTrustStorePath ));
300+ } catch (IOException e ) {
301+ LOGGER .info ("Failed to delete temp trust store file: " + e .getMessage ());
302+ }
303+ }
304+ }
305+
207306 @ Test
208307 void testCreateRegistryWithSystemPropertyTrustStore () throws DatabricksHttpException {
209308 // Save original system properties to restore later
@@ -216,6 +315,8 @@ void testCreateRegistryWithSystemPropertyTrustStore() throws DatabricksHttpExcep
216315 System .setProperty ("javax.net.ssl.trustStore" , DUMMY_TRUST_STORE_PATH );
217316 System .setProperty ("javax.net.ssl.trustStorePassword" , TRUST_STORE_PASSWORD );
218317 System .setProperty ("javax.net.ssl.trustStoreType" , TRUST_STORE_TYPE );
318+
319+ when (mockContext .getSSLTrustStore ()).thenReturn (null );
219320 when (mockContext .useSystemTrustStore ()).thenReturn (true );
220321 when (mockContext .checkCertificateRevocation ()).thenReturn (false );
221322
@@ -261,6 +362,7 @@ void testCreateRegistryWithSystemPropertyTrustStore_WithRevocationChecking()
261362 System .setProperty ("javax.net.ssl.trustStorePassword" , TRUST_STORE_PASSWORD );
262363 System .setProperty ("javax.net.ssl.trustStoreType" , TRUST_STORE_TYPE );
263364
365+ when (mockContext .getSSLTrustStore ()).thenReturn (null );
264366 when (mockContext .useSystemTrustStore ()).thenReturn (true );
265367 when (mockContext .checkCertificateRevocation ()).thenReturn (true );
266368 when (mockContext .acceptUndeterminedCertificateRevocation ()).thenReturn (true );
@@ -293,9 +395,35 @@ void testCreateRegistryWithSystemPropertyTrustStore_WithRevocationChecking()
293395 }
294396 }
295397
398+ @ Test
399+ void testNonExistentTrustStore () {
400+ // Create a mock with lenient verification since this test only expects an exception
401+ IDatabricksConnectionContext mockContextLocal = mock (IDatabricksConnectionContext .class );
402+
403+ String nonExistentPath = "/path/to/nonexistent/truststore.jks" ;
404+ when (mockContextLocal .getSSLTrustStore ()).thenReturn (nonExistentPath );
405+
406+ DatabricksHttpException exception =
407+ assertThrows (
408+ DatabricksHttpException .class ,
409+ () -> ConfiguratorUtils .loadTruststoreOrNull (mockContextLocal ));
410+
411+ assertTrue (
412+ exception .getMessage ().contains ("does not exist" ),
413+ "Exception should mention that the trust store does not exist" );
414+ }
415+
296416 @ Test
297417 void testCreateTrustManagers_WithAndWithoutRevocationChecking () throws Exception {
298418 // Load a real trust store to test with
419+ when (mockContext .getSSLTrustStore ()).thenReturn (DUMMY_TRUST_STORE_PATH );
420+ when (mockContext .getSSLTrustStorePassword ()).thenReturn (TRUST_STORE_PASSWORD );
421+ when (mockContext .getSSLTrustStoreType ()).thenReturn (TRUST_STORE_TYPE );
422+
423+ KeyStore trustStore = ConfiguratorUtils .loadTruststoreOrNull (mockContext );
424+ Set <TrustAnchor > trustAnchors = ConfiguratorUtils .getTrustAnchorsFromTrustStore (trustStore );
425+
426+ // We're testing a private method, so we'll verify the public method behavior that uses it
299427 when (mockContext .checkCertificateRevocation ()).thenReturn (true );
300428 when (mockContext .acceptUndeterminedCertificateRevocation ()).thenReturn (false );
301429 Registry <ConnectionSocketFactory > revocationCheckingRegistry =
@@ -311,6 +439,8 @@ void testCreateTrustManagers_WithAndWithoutRevocationChecking() throws Exception
311439
312440 @ Test
313441 void testFindX509TrustManager () throws Exception {
442+ // Test instance method rather than using reflection on the private static method
443+ // First test that we can create a trust manager factory
314444 TrustManagerFactory tmf =
315445 TrustManagerFactory .getInstance (TrustManagerFactory .getDefaultAlgorithm ());
316446 tmf .init ((KeyStore ) null );
@@ -354,6 +484,7 @@ void testCreateSocketFactoryRegistry() throws Exception {
354484 tmf .init ((KeyStore ) null );
355485
356486 // Create a registry with the system default trust managers
487+ when (mockContext .getSSLTrustStore ()).thenReturn (null );
357488 when (mockContext .checkCertificateRevocation ()).thenReturn (false );
358489 when (mockContext .useSystemTrustStore ()).thenReturn (false );
359490
0 commit comments