From 02c832d6eb861ed8cd81c20bf66698e8ae9eb52b Mon Sep 17 00:00:00 2001 From: Rob Rudin Date: Tue, 13 Jun 2023 15:56:18 -0400 Subject: [PATCH] Added test for a custom X509TrustManager --- .../client/test/CheckSSLConnectionTest.java | 22 +++++++++- .../test/junit5/RequireSSLExtension.java | 40 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/CheckSSLConnectionTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/CheckSSLConnectionTest.java index 2bcd30508..b5ec9dca8 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/CheckSSLConnectionTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/CheckSSLConnectionTest.java @@ -10,7 +10,6 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManager; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -54,6 +53,27 @@ void trustAllManager() throws Exception { assertNull(result.getErrorMessage()); } + /** + * Demonstrates using a custom X509TrustManager that only accepts the issuer of the public certificate associated + * with the certificate template created via RequireSSLExtension. + */ + @Test + void customTrustManager() { + if (Common.USE_REVERSE_PROXY_SERVER) { + return; + } + + DatabaseClient client = Common.newClientBuilder() + .withSSLProtocol("TLSv1.2") + .withTrustManager(RequireSSLExtension.newTrustManager()) + .withSSLHostnameVerifier(DatabaseClientFactory.SSLHostnameVerifier.ANY) + .build(); + + DatabaseClient.ConnectionResult result = client.checkConnection(); + assertEquals(0, result.getStatusCode()); + assertNull(result.getErrorMessage()); + } + @Test void defaultSslContext() throws Exception { DatabaseClient client = Common.newClientBuilder() diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequireSSLExtension.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequireSSLExtension.java index bec701d48..0160c3294 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequireSSLExtension.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequireSSLExtension.java @@ -5,10 +5,17 @@ import com.marklogic.mgmt.ManageClient; import com.marklogic.mgmt.resource.appservers.ServerManager; import com.marklogic.mgmt.resource.security.CertificateTemplateManager; +import com.marklogic.rest.util.Fragment; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.ExtensionContext; +import javax.net.ssl.X509TrustManager; +import java.io.ByteArrayInputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + /** * Use this on tests that require an app server to require SSL connections. The app server will be modified to require * SSL connections before any test runs and will then be restored back to normal after all tests in the test class run. @@ -52,6 +59,39 @@ public void afterAll(ExtensionContext context) { new CertificateTemplateManager(manageClient).delete(TEMPLATE); } + /** + * @return a trust manager that accepts the public certificate associated with the certificate template created + * by this class. + */ + public static X509TrustManager newTrustManager() { + return new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{getCertificate()}; + } + }; + } + + private static X509Certificate getCertificate() { + CertificateTemplateManager mgr = new CertificateTemplateManager(Common.newManageClient()); + + Fragment response = mgr.getCertificatesForTemplate(TEMPLATE_NAME); + String cert = response.getElementValue("/msec:certificate-list/msec:certificate/msec:pem"); + try { + return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(cert.getBytes())); + } catch (CertificateException e) { + throw new RuntimeException("Unable to generate X509Certificate: " + e.getMessage(), e); + } + } + private void setSslCertificateTemplate(String templateName) { new ServerManager(manageClient).save( Common.newServerPayload()