Skip to content

MLE-30239 Use secure trust store#1945

Open
rjdew-progress wants to merge 1 commit into
developfrom
MLE-30239
Open

MLE-30239 Use secure trust store#1945
rjdew-progress wants to merge 1 commit into
developfrom
MLE-30239

Conversation

@rjdew-progress

Copy link
Copy Markdown

Replace trust-all TrustManager in SSL cookbook example with a trust-store-based approach

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the MarkLogic Java Client SSL examples/tests to avoid “trust-all” trust managers and instead rely on certificate validation via a configured truststore (or the JVM default trust managers where applicable).

Changes:

  • Replaces a trust-all TrustManager in the SSL cookbook example with a truststore-backed TrustManagerFactory approach and switches to STRICT hostname verification.
  • Updates functional test SSLContext creation to use a truststore (classpath resource) when configured, falling back to JVM default trust managers otherwise.
  • Adds/updates properties and a new test asserting handshake failure when the server CA is not trusted.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java Adds a test validating TLS handshake fails when using default JVM trust managers that don’t trust the test CA.
marklogic-client-api-functionaltests/src/test/resources/test.properties Documents optional truststore properties for SSL-enabled functional test runs.
marklogic-client-api-functionaltests/src/test/java/com/marklogic/client/functionaltest/ConnectedRESTQA.java Replaces trust-all trust manager with truststore/JVM-default trust managers for SSLContext initialization.
examples/src/main/resources/Example.properties Documents truststore configuration for the SSL cookbook example.
examples/src/main/java/com/marklogic/client/example/cookbook/Util.java Adds truststore fields to example configuration parsing.
examples/src/main/java/com/marklogic/client/example/cookbook/SSLClientCreator.java Loads truststore and uses a real trust manager + STRICT hostname verification for the SSL example.

Comment on lines 45 to +49
jdbcUrl = props.getProperty("example.jdbc.url");
jdbcUser = props.getProperty("example.jdbc.user");
jdbcPassword = props.getProperty("example.jdbc.password");
trustStorePath = props.getProperty("example.truststore.path");
trustStorePassword = props.getProperty("example.truststore.password");
Comment on lines +808 to +811
if (ml_truststore_file != null && !ml_truststore_file.trim().isEmpty()) {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
char[] tsPassword = ml_truststore_password != null ? ml_truststore_password.toCharArray() : new char[0];
InputStream tsInput = property.getClass().getResourceAsStream(ml_truststore_file);
Comment on lines +57 to +71
KeyStore trustStore = KeyStore.getInstance("JKS");
try (FileInputStream fis = new FileInputStream(props.trustStorePath)) {
trustStore.load(fis, props.trustStorePassword.toCharArray());
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
// Initialise a TrustManagerFactory from the truststore so that the SSLContext
// will validate the server's certificate against the trusted CAs it contains.
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

// create an SSL context
// Create an SSL context backed by the real trust manager.
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
/*
* Here, we use a naive TrustManager which would accept any certificate
* which the server produces. But in a real application, there should be a
* TrustManager which is initialized with a Keystore which would determine
* whether the remote authentication credentials should be trusted or not.
*
* If we init the sslContext with null TrustManager, it would use the
* <java-home>/lib/security/cacerts file for trusted root certificates, if
* javax.net.ssl.trustStore system property is not set and
* <java-home>/lib/security/jssecacerts is not present. See this link for
* more information on TrustManagers -
* http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/
* JSSERefGuide.html
*
* If self signed certificates, signed by CAs created internally are used,
* then the internal CA's root certificate should be added to the keystore.
* See this link -
* https://docs.oracle.com/cd/E19226-01/821-0027/geygn/index.html for adding
* a root certificate in the keystore.
*/
sslContext.init(null, naiveTrustMgr, null);
sslContext.init(null, trustManagers, null);
*/
public class SSLClientCreator {
public static void main(String[] args) throws IOException, KeyManagementException, NoSuchAlgorithmException {
public static void main(String[] args) throws IOException, KeyManagementException, NoSuchAlgorithmException,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should instead use the support in DatabaseClientFactory to configure trusted SSL via properties so that the user doesn't have to deal with all this boilerplate. Check out the public static DatabaseClient newClient(Function<String, Object> propertySource) { method. It handles all of this plumbing.

// When ml_truststore_file is configured, a TrustManagerFactory is initialised
// from that truststore (which must contain the MarkLogic server's CA certificate).
// Otherwise the JVM's default trust managers are used as a safe fallback.
final TrustManager[] trustManagers;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here - try reworking this to use the support in DatabaseClientFactory for doing all of this for the user.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants