Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit 5860a89

Browse files
committed
#128 Can now construct SSLContext using default keystore
1 parent 3756cde commit 5860a89

File tree

6 files changed

+219
-33
lines changed

6 files changed

+219
-33
lines changed

src/main/java/com/marklogic/client/ext/DatabaseClientConfig.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@ public class DatabaseClientConfig {
1717
private String username;
1818
private String password;
1919
private String database;
20+
2021
private SSLContext sslContext;
22+
private String sslProtocol;
23+
private String trustManagementAlgorithm;
2124
private SSLHostnameVerifier sslHostnameVerifier;
25+
2226
private String certFile;
2327
private String certPassword;
2428
private String externalName;
2529
private X509TrustManager trustManager;
2630
private DatabaseClient.ConnectionType connectionType;
2731

32+
2833
public DatabaseClientConfig() {
2934
}
3035

@@ -148,4 +153,20 @@ public DatabaseClient.ConnectionType getConnectionType() {
148153
public void setConnectionType(DatabaseClient.ConnectionType connectionType) {
149154
this.connectionType = connectionType;
150155
}
156+
157+
public String getSslProtocol() {
158+
return sslProtocol;
159+
}
160+
161+
public void setSslProtocol(String sslProtocol) {
162+
this.sslProtocol = sslProtocol;
163+
}
164+
165+
public String getTrustManagementAlgorithm() {
166+
return trustManagementAlgorithm;
167+
}
168+
169+
public void setTrustManagementAlgorithm(String trustManagementAlgorithm) {
170+
this.trustManagementAlgorithm = trustManagementAlgorithm;
171+
}
151172
}

src/main/java/com/marklogic/client/ext/DefaultConfiguredDatabaseClientFactory.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import com.marklogic.client.DatabaseClient;
44
import com.marklogic.client.DatabaseClientFactory;
5-
import com.marklogic.client.ext.ConfiguredDatabaseClientFactory;
6-
import com.marklogic.client.ext.DatabaseClientConfig;
5+
import com.marklogic.client.ext.ssl.SslConfig;
6+
import com.marklogic.client.ext.ssl.SslUtil;
77

88
import javax.net.ssl.SSLContext;
99
import javax.net.ssl.X509TrustManager;
@@ -31,17 +31,17 @@ public DatabaseClient newDatabaseClient(DatabaseClientConfig config) {
3131
securityContext = new DatabaseClientFactory.KerberosAuthContext(config.getExternalName());
3232
} else if (SecurityContextType.NONE.equals(securityContextType)) {
3333
securityContext = null;
34-
}
35-
else {
34+
} else {
3635
throw new IllegalArgumentException("Unsupported SecurityContextType: " + securityContextType);
3736
}
3837

3938
if (securityContext != null) {
40-
SSLContext sslContext = config.getSslContext();
41-
DatabaseClientFactory.SSLHostnameVerifier verifier = config.getSslHostnameVerifier();
42-
if (sslContext != null) {
43-
securityContext = securityContext.withSSLContext(sslContext, config.getTrustManager());
39+
final SslConfig sslConfig = determineSslConfig(config);
40+
if (sslConfig != null) {
41+
securityContext = securityContext.withSSLContext(sslConfig.getSslContext(), sslConfig.getTrustManager());
4442
}
43+
44+
DatabaseClientFactory.SSLHostnameVerifier verifier = config.getSslHostnameVerifier();
4545
if (verifier != null) {
4646
securityContext = securityContext.withSSLHostnameVerifier(verifier);
4747
}
@@ -62,8 +62,7 @@ public DatabaseClient newDatabaseClient(DatabaseClientConfig config) {
6262
return DatabaseClientFactory.newClient(host, port, securityContext);
6363
}
6464
return DatabaseClientFactory.newClient(host, port, database, securityContext);
65-
}
66-
else {
65+
} else {
6766
if (securityContext == null) {
6867
if (database == null) {
6968
return DatabaseClientFactory.newClient(host, port, null, connectionType);
@@ -77,7 +76,6 @@ public DatabaseClient newDatabaseClient(DatabaseClientConfig config) {
7776
}
7877
}
7978

80-
8179
protected DatabaseClientFactory.SecurityContext buildCertificateAuthContent(DatabaseClientConfig config) {
8280
X509TrustManager trustManager = config.getTrustManager();
8381

@@ -93,12 +91,23 @@ protected DatabaseClientFactory.SecurityContext buildCertificateAuthContent(Data
9391
}
9492
}
9593

94+
SslConfig sslConfig = determineSslConfig(config);
9695
DatabaseClientFactory.SSLHostnameVerifier verifier = config.getSslHostnameVerifier();
96+
return verifier != null ?
97+
new DatabaseClientFactory.CertificateAuthContext(sslConfig.getSslContext(), verifier, sslConfig.getTrustManager()) :
98+
new DatabaseClientFactory.CertificateAuthContext(sslConfig.getSslContext(), sslConfig.getTrustManager());
99+
}
97100

98-
if (verifier != null) {
99-
return new DatabaseClientFactory.CertificateAuthContext(config.getSslContext(), verifier, trustManager);
101+
protected SslConfig determineSslConfig(DatabaseClientConfig config) {
102+
SSLContext sslContext = config.getSslContext();
103+
X509TrustManager trustManager = config.getTrustManager();
104+
if (sslContext != null && trustManager != null) {
105+
return new SslConfig(sslContext, trustManager);
100106
}
101107

102-
return new DatabaseClientFactory.CertificateAuthContext(config.getSslContext(), trustManager);
108+
final String protocol = config.getSslProtocol();
109+
return protocol != null && protocol.trim().length() > 0 ?
110+
SslUtil.configureUsingTrustManagerFactory(protocol, config.getTrustManagementAlgorithm()) :
111+
null;
103112
}
104113
}
Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.marklogic.client.ext.modulesloader.ssl;
22

3+
import com.marklogic.client.ext.ssl.SslUtil;
4+
35
import javax.net.ssl.SSLContext;
46
import javax.net.ssl.TrustManager;
57
import javax.net.ssl.X509TrustManager;
@@ -11,36 +13,36 @@
1113
*/
1214
public class SimpleX509TrustManager implements X509TrustManager {
1315

14-
/**
15-
* Factory method for creating a simple SSLContext that uses this class as its TrustManager.
16-
*
17-
* @return
18-
*/
19-
public static SSLContext newSSLContext() {
20-
return newSSLContext("TLSv1.2");
21-
}
16+
/**
17+
* Factory method for creating a simple SSLContext that uses this class as its TrustManager.
18+
*
19+
* @return
20+
*/
21+
public static SSLContext newSSLContext() {
22+
return newSSLContext(SslUtil.DEFAULT_SSL_PROTOCOL);
23+
}
2224

2325
public static SSLContext newSSLContext(String protocol) {
2426
try {
2527
SSLContext sslContext = SSLContext.getInstance(protocol);
26-
sslContext.init(null, new TrustManager[] { new SimpleX509TrustManager() }, null);
28+
sslContext.init(null, new TrustManager[]{new SimpleX509TrustManager()}, null);
2729
return sslContext;
2830
} catch (Exception e) {
2931
throw new RuntimeException(e);
3032
}
3133
}
3234

33-
@Override
34-
public void checkClientTrusted(X509Certificate[] chain, String authType) {
35-
}
35+
@Override
36+
public void checkClientTrusted(X509Certificate[] chain, String authType) {
37+
}
3638

37-
@Override
38-
public void checkServerTrusted(X509Certificate[] chain, String authType) {
39-
}
39+
@Override
40+
public void checkServerTrusted(X509Certificate[] chain, String authType) {
41+
}
4042

41-
@Override
42-
public X509Certificate[] getAcceptedIssuers() {
43-
return new X509Certificate[0];
44-
}
43+
@Override
44+
public X509Certificate[] getAcceptedIssuers() {
45+
return new X509Certificate[0];
46+
}
4547

4648
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.marklogic.client.ext.ssl;
2+
3+
import javax.net.ssl.SSLContext;
4+
import javax.net.ssl.X509TrustManager;
5+
6+
/**
7+
* Captures the output of functions in SslUtil so that they can be easily used when constructing a DatabaseClient,
8+
* which requires the X509TrustManager to be an input separate from the SSLContext.
9+
*/
10+
public class SslConfig {
11+
12+
private SSLContext sslContext;
13+
private X509TrustManager trustManager;
14+
15+
public SslConfig(SSLContext sslContext, X509TrustManager trustManager) {
16+
this.sslContext = sslContext;
17+
this.trustManager = trustManager;
18+
}
19+
20+
public SSLContext getSslContext() {
21+
return sslContext;
22+
}
23+
24+
public X509TrustManager getTrustManager() {
25+
return trustManager;
26+
}
27+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.marklogic.client.ext.ssl;
2+
3+
import javax.net.ssl.SSLContext;
4+
import javax.net.ssl.TrustManager;
5+
import javax.net.ssl.TrustManagerFactory;
6+
import javax.net.ssl.X509TrustManager;
7+
import java.security.KeyManagementException;
8+
import java.security.KeyStore;
9+
import java.security.KeyStoreException;
10+
import java.security.NoSuchAlgorithmException;
11+
12+
public abstract class SslUtil {
13+
14+
public final static String DEFAULT_SSL_PROTOCOL = "TLSv1.2";
15+
16+
/**
17+
* Configure an SSLContext and X509TrustManager with TLSv1.2 as the default protocol and the default algorithm of
18+
* TrustManagerFactory.
19+
*
20+
* @return
21+
*/
22+
public static SslConfig configureUsingTrustManagerFactory() {
23+
return configureUsingTrustManagerFactory(DEFAULT_SSL_PROTOCOL, null);
24+
}
25+
26+
/**
27+
* Configure an SSLContext and X509TrustManager with the given inputs.
28+
*
29+
* @param protocol the protocol to use when getting an instance of an SSLContext
30+
* @param algorithm an optional algorithm to use for getting an instance of TrustManagerFactory; if not specified,
31+
* the default algorithm of TrustManagerFactory is used
32+
* @return
33+
*/
34+
public static SslConfig configureUsingTrustManagerFactory(String protocol, String algorithm) {
35+
SSLContext sslContext;
36+
try {
37+
sslContext = SSLContext.getInstance(protocol);
38+
} catch (NoSuchAlgorithmException e) {
39+
throw new RuntimeException("Unable to instantiate SSLContext with protocol: " + protocol + "; cause: " + e.getMessage(), e);
40+
}
41+
42+
if (algorithm == null || algorithm.trim().length() < 1) {
43+
algorithm = TrustManagerFactory.getDefaultAlgorithm();
44+
}
45+
TrustManagerFactory trustManagerFactory;
46+
try {
47+
trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
48+
} catch (NoSuchAlgorithmException e) {
49+
throw new RuntimeException("Unable to instantiate TrustManagerFactory, cause: " + e.getMessage(), e);
50+
}
51+
52+
try {
53+
trustManagerFactory.init((KeyStore) null);
54+
} catch (KeyStoreException e) {
55+
throw new RuntimeException("Unable to initialize TrustManagerFactory, cause: " + e.getMessage(), e);
56+
}
57+
58+
X509TrustManager x509TrustManager = null;
59+
for (TrustManager tm : trustManagerFactory.getTrustManagers()) {
60+
if (tm instanceof X509TrustManager) {
61+
x509TrustManager = (X509TrustManager) tm;
62+
break;
63+
}
64+
}
65+
if (x509TrustManager == null) {
66+
throw new RuntimeException("Could not initialize an SSLContext; unable to find an X509TrustManager in the " +
67+
"TrustManagerFactory instantiated with algorithm: " + algorithm);
68+
}
69+
70+
try {
71+
sslContext.init(null, new TrustManager[]{x509TrustManager}, null);
72+
} catch (KeyManagementException e) {
73+
throw new RuntimeException("Unable to initialize SSLContext, cause: " + e.getMessage(), e);
74+
}
75+
76+
return new SslConfig(sslContext, x509TrustManager);
77+
}
78+
79+
}
80+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.marklogic.client.ext.ssl;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
import javax.net.ssl.SSLContext;
7+
import java.security.cert.X509Certificate;
8+
9+
public class SslUtilTest extends Assert {
10+
11+
@Test
12+
public void configureWithDefaults() {
13+
SslConfig config = SslUtil.configureUsingTrustManagerFactory();
14+
X509Certificate[] certs = config.getTrustManager().getAcceptedIssuers();
15+
assertTrue(certs.length > 0);
16+
17+
SSLContext context = config.getSslContext();
18+
assertEquals("TLSv1.2", context.getProtocol());
19+
}
20+
21+
@Test
22+
public void configureWithCustomProtocol() {
23+
SslConfig config = SslUtil.configureUsingTrustManagerFactory("SSLv3", null);
24+
assertEquals("SSLv3", config.getSslContext().getProtocol());
25+
}
26+
27+
@Test
28+
public void invalidProtocol() {
29+
try {
30+
SslUtil.configureUsingTrustManagerFactory("invalid", null);
31+
fail("An exception should have been thrown due to an invalid SSL protocol being passed in");
32+
} catch (Exception ex) {
33+
System.out.println("Caught expected exception: " + ex.getMessage());
34+
}
35+
}
36+
37+
@Test
38+
public void invalidAlgorithm() {
39+
try {
40+
SslUtil.configureUsingTrustManagerFactory("TLSv1.2", "invalid");
41+
fail("An exception should have been thrown due to an invalid algorithm being passed in");
42+
} catch (Exception ex) {
43+
System.out.println("Caught expected exception: " + ex.getMessage());
44+
}
45+
}
46+
47+
}

0 commit comments

Comments
 (0)