diff --git a/gateway-discovery-cm/pom.xml b/gateway-discovery-cm/pom.xml
index 8a484cb8ce..86332b9d5d 100644
--- a/gateway-discovery-cm/pom.xml
+++ b/gateway-discovery-cm/pom.xml
@@ -63,6 +63,10 @@
org.apache.knox
gateway-util-configinjector
+
+ org.apache.knox
+ gateway-util-common
+
com.cloudera.api.swagger
cloudera-manager-api-swagger
diff --git a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactory.java b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactory.java
index 6ba9f90068..ce1babeb3d 100644
--- a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactory.java
+++ b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactory.java
@@ -21,28 +21,26 @@
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
+import org.apache.knox.gateway.util.TruststorePasswordSetter;
import java.security.KeyStore;
public class ApiClientFactory {
private static final ClouderaManagerServiceDiscoveryMessages LOG = MessagesFactory.get(ClouderaManagerServiceDiscoveryMessages.class);
- static final String TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY = "javax.net.ssl.trustStorePassword";
- public static final String TRUSTSTORE_PASSWORD_ALIAS = "cm.discovery.trustStorePassword";
public static DiscoveryApiClient getApiClient(final GatewayConfig gatewayConfig, final ServiceDiscoveryConfig discoveryConfig,
final AliasService aliasService, final KeyStore truststore) {
+ final char[] trustStorePassword;
try {
- final char[] trustStorePassword = aliasService.getPasswordFromAliasForGateway(TRUSTSTORE_PASSWORD_ALIAS);
- if (trustStorePassword != null && trustStorePassword.length > 0) {
- System.setProperty(TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, new String(trustStorePassword));
- }
- return new DiscoveryApiClient(gatewayConfig, discoveryConfig, aliasService, truststore);
+ trustStorePassword = aliasService.getPasswordFromAliasForGateway(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_ALIAS);
} catch (AliasServiceException e) {
LOG.clouderaManagerApiClientBuildError(e);
throw new ServiceDiscoveryException("Unable to retrieve CM service discovery truststore password", e);
- } finally {
- System.clearProperty(TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY);
+ }
+
+ try (TruststorePasswordSetter ignored = new TruststorePasswordSetter(trustStorePassword)) {
+ return new DiscoveryApiClient(gatewayConfig, discoveryConfig, aliasService, truststore);
}
}
}
diff --git a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactoryTest.java b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactoryTest.java
index 322166fda2..6125f47c5b 100644
--- a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactoryTest.java
+++ b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ApiClientFactoryTest.java
@@ -21,6 +21,7 @@
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
+import org.apache.knox.gateway.util.TruststorePasswordSetter;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Assert;
@@ -77,9 +78,9 @@ private void testGetApiClient(final boolean shouldSetSystemProperty, String trus
EasyMock.expect(serviceDiscoveryConfig.getPasswordAlias()).andReturn("myCmPasswordAlias").anyTimes();
final AliasService aliasService = EasyMock.createMock(AliasService.class);
if (shouldSetSystemProperty) {
- EasyMock.expect(aliasService.getPasswordFromAliasForGateway(ApiClientFactory.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(trustStorePassword.toCharArray()).anyTimes();
+ EasyMock.expect(aliasService.getPasswordFromAliasForGateway(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(trustStorePassword.toCharArray()).anyTimes();
} else {
- EasyMock.expect(aliasService.getPasswordFromAliasForGateway(ApiClientFactory.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(null).anyTimes();
+ EasyMock.expect(aliasService.getPasswordFromAliasForGateway(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(null).anyTimes();
}
EasyMock.expect(aliasService.getPasswordFromAliasForGateway("myCmPasswordAlias")).andReturn("myCmPassword".toCharArray()).anyTimes();
final KeyStore trustStore = EasyMock.createMock(KeyStore.class);
@@ -88,13 +89,13 @@ private void testGetApiClient(final boolean shouldSetSystemProperty, String trus
ApiClientFactory.getApiClient(gatewayConfig, serviceDiscoveryConfig, aliasService, trustStore);
if (shouldSetSystemProperty && StringUtils.isNotBlank(trustStorePassword)) {
- Assert.assertEquals(ApiClientFactory.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, testProps.lastSetKey);
+ Assert.assertEquals(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, testProps.lastSetKey);
Assert.assertEquals(trustStorePassword, testProps.lastSetValue);
- Assert.assertEquals(ApiClientFactory.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, testProps.lastRemovedKey);
+ Assert.assertEquals(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, testProps.lastRemovedKey);
} else {
Assert.assertNull(testProps.lastSetKey);
Assert.assertNull(testProps.lastSetValue);
- Assert.assertEquals(ApiClientFactory.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, testProps.lastRemovedKey);
+ Assert.assertEquals(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, testProps.lastRemovedKey);
}
}
diff --git a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java
index 5d734027b9..9d6dbd95bd 100644
--- a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java
+++ b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java
@@ -32,9 +32,9 @@
import org.apache.knox.gateway.services.topology.impl.GatewayStatusService;
import org.apache.knox.gateway.topology.ClusterConfigurationMonitorService;
import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
-import org.apache.knox.gateway.topology.discovery.cm.ApiClientFactory;
import org.apache.knox.gateway.topology.discovery.cm.model.hdfs.NameNodeServiceModelGenerator;
import org.apache.knox.gateway.topology.discovery.cm.model.hive.HiveOnTezServiceModelGenerator;
+import org.apache.knox.gateway.util.TruststorePasswordSetter;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Test;
@@ -363,7 +363,7 @@ public void testClusterConfigMonitorTerminationForNoLongerReferencedClusters() t
EasyMock.replay(ts, ccms, gatewayStatusService, gws);
AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
- EasyMock.expect(aliasService.getPasswordFromAliasForGateway(ApiClientFactory.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(null).anyTimes();
+ EasyMock.expect(aliasService.getPasswordFromAliasForGateway(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(null).anyTimes();
EasyMock.replay(aliasService);
try {
@@ -540,7 +540,7 @@ private TestablePollingConfigAnalyzer buildPollingConfigAnalyzer(final String ad
EasyMock.replay(configCache);
AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
- EasyMock.expect(aliasService.getPasswordFromAliasForGateway(ApiClientFactory.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(null).anyTimes();
+ EasyMock.expect(aliasService.getPasswordFromAliasForGateway(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_ALIAS)).andReturn(null).anyTimes();
EasyMock.replay(aliasService);
if (isKnoxGatewayReady) {
diff --git a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
index a01d5a554c..75eb88baa4 100644
--- a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
+++ b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
@@ -69,6 +69,7 @@
import org.apache.knox.gateway.topology.Service;
import org.apache.knox.gateway.topology.Topology;
import org.apache.knox.gateway.util.JsonUtils;
+import org.apache.knox.gateway.util.TruststorePasswordSetter;
import org.apache.knox.gateway.util.X509CertificateUtil;
import com.kstruct.gethostname4j.Hostname;
@@ -173,11 +174,16 @@ private Response generateFailureFileDownloadResponse(Status status, String error
private Certificate[] getPublicCertificates() {
try {
- return X509CertificateUtil.fetchPublicCertsFromServer(request.getRequestURL().toString(), true, null);
+ final GatewayServices gatewayServices = (GatewayServices) request.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+ if (gatewayServices != null) {
+ final AliasService aliasService = gatewayServices.getService(ServiceType.ALIAS_SERVICE);
+ char[] trustStorePassword = aliasService.getPasswordFromAliasForGateway(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_ALIAS);
+ return X509CertificateUtil.fetchPublicCertsFromServer(request.getRequestURL().toString(), trustStorePassword, true, null);
+ }
} catch (Exception e) {
LOG.failedToFetchPublicCert(e.getMessage(), e);
- return null;
}
+ return null;
}
private void generateCertificatePem(Certificate[] certificateChain, GatewayConfig gatewayConfig) {
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSh.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSh.java
index ec169b51d7..a9bce5f9db 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSh.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSh.java
@@ -181,7 +181,8 @@ class KnoxBuildTrustStore extends Command {
public void execute() throws Exception {
String result = GATEWAY_CERT_NOT_EXPORTED;
try {
- final X509Certificate[] gatewayServerPublicCerts = X509CertificateUtil.fetchPublicCertsFromServer(gateway, false, out);
+ final X509Certificate[] gatewayServerPublicCerts = X509CertificateUtil.fetchPublicCertsFromServer(
+ gateway, ClientTrustStoreHelper.getClientTrustStoreFilePassword().toCharArray(), false, out);
if (gatewayServerPublicCerts != null) {
final File trustStoreFile = ClientTrustStoreHelper.getClientTrustStoreFile();
final String trustStorePassword = ClientTrustStoreHelper.getClientTrustStoreFilePassword();
diff --git a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/TruststorePasswordSetter.java b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/TruststorePasswordSetter.java
new file mode 100644
index 0000000000..9de37e6179
--- /dev/null
+++ b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/TruststorePasswordSetter.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+/**
+ * A utility class that sets and clears the javax.net.ssl.trustStorePassword system property.
+ */
+public class TruststorePasswordSetter implements AutoCloseable {
+ public static final String TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY = "javax.net.ssl.trustStorePassword";
+ public static final String TRUSTSTORE_PASSWORD_ALIAS = "cm.discovery.trustStorePassword";
+
+ public TruststorePasswordSetter(char[] password) {
+ if (password != null && password.length > 0) {
+ System.setProperty(TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, new String(password));
+ }
+ }
+
+ @Override
+ public void close() {
+ System.clearProperty(TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY);
+ }
+}
diff --git a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java
index 93cfb0d3ae..8d0574d209 100644
--- a/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java
+++ b/gateway-util-common/src/main/java/org/apache/knox/gateway/util/X509CertificateUtil.java
@@ -232,11 +232,14 @@ public static boolean isSelfSignedCertificate(Certificate certificate) {
}
}
- public static X509Certificate[] fetchPublicCertsFromServer(String serverUrl, boolean forceReturnCert, PrintStream out) throws Exception {
- final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- trustManagerFactory.init((KeyStore) null);
- final X509TrustManager defaultTrustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
- final CertificateChainAwareTrustManager trustManagerWithCertificateChain = new CertificateChainAwareTrustManager(defaultTrustManager);
+ public static X509Certificate[] fetchPublicCertsFromServer(String serverUrl, char[] trustStorePassword, boolean forceReturnCert, PrintStream out) throws Exception {
+ CertificateChainAwareTrustManager trustManagerWithCertificateChain;
+ try (TruststorePasswordSetter ignored = new TruststorePasswordSetter(trustStorePassword)) {
+ final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init((KeyStore) null);
+ final X509TrustManager defaultTrustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
+ trustManagerWithCertificateChain = new CertificateChainAwareTrustManager(defaultTrustManager);
+ }
final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { trustManagerWithCertificateChain }, null);
diff --git a/gateway-util-common/src/test/java/org/apache/knox/gateway/util/TruststorePasswordSetterTest.java b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/TruststorePasswordSetterTest.java
new file mode 100644
index 0000000000..3a43b6ec93
--- /dev/null
+++ b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/TruststorePasswordSetterTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TruststorePasswordSetterTest {
+ private String originalPassword;
+
+ @Before
+ public void setUp() {
+ originalPassword = System.getProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY);
+ System.clearProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY);
+ }
+
+ @After
+ public void tearDown() {
+ if (originalPassword != null) {
+ System.setProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY, originalPassword);
+ } else {
+ System.clearProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY);
+ }
+ }
+
+ @Test
+ public void testSetPassword() {
+ final String password = "test-password";
+ try (TruststorePasswordSetter setter = new TruststorePasswordSetter(password.toCharArray())) {
+ Assert.assertEquals("The system property should be set to the provided password.",
+ password, System.getProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY));
+ }
+ Assert.assertNull("The system property should be cleared after closing the setter.",
+ System.getProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY));
+ }
+
+ @Test
+ public void testNullPassword() {
+ try (TruststorePasswordSetter setter = new TruststorePasswordSetter(null)) {
+ Assert.assertNull("The system property should not be set if the password is null.",
+ System.getProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY));
+ }
+ Assert.assertNull(System.getProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY));
+ }
+
+ @Test
+ public void testEmptyPassword() {
+ try (TruststorePasswordSetter setter = new TruststorePasswordSetter(new char[0])) {
+ Assert.assertNull("The system property should not be set if the password array is empty.",
+ System.getProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY));
+ }
+ Assert.assertNull(System.getProperty(TruststorePasswordSetter.TRUSTSTORE_PASSWORD_SYSTEM_PROPERTY));
+ }
+}
diff --git a/gateway-util-common/src/test/java/org/apache/knox/gateway/util/X509CertificateUtilTest.java b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/X509CertificateUtilTest.java
new file mode 100644
index 0000000000..06365f575e
--- /dev/null
+++ b/gateway-util-common/src/test/java/org/apache/knox/gateway/util/X509CertificateUtilTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class X509CertificateUtilTest {
+
+ @Test
+ public void testFetchPublicCertsFromServer() throws Exception {
+ // 1. Generate a self-signed certificate
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ X509Certificate cert = X509CertificateUtil.generateCertificate("CN=localhost", keyPair, 30, "SHA256withRSA");
+
+ // 2. Set up a KeyStore with the certificate
+ KeyStore keyStore = KeyStore.getInstance("JKS");
+ keyStore.load(null, null);
+ keyStore.setKeyEntry("alias", keyPair.getPrivate(), "password".toCharArray(), new java.security.cert.Certificate[]{cert});
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(keyStore, "password".toCharArray());
+
+ SSLContext serverSslContext = SSLContext.getInstance("TLS");
+ serverSslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
+
+ SSLServerSocketFactory ssf = serverSslContext.getServerSocketFactory();
+ try (SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket(0)) {
+ int port = serverSocket.getLocalPort();
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future serverFuture = executor.submit(new Callable() {
+ @Override
+ public Void call() throws Exception {
+ try (SSLSocket clientSocket = (SSLSocket) serverSocket.accept()) {
+ clientSocket.startHandshake();
+ } catch (IOException e) {
+ // Expected if client closes connection early
+ }
+ return null;
+ }
+ });
+
+ // 3. Fetch the certificate from the server
+ try {
+ String serverUrl = "https://localhost:" + port;
+ X509Certificate[] certs = X509CertificateUtil.fetchPublicCertsFromServer(serverUrl, null, true, null);
+
+ // 4. Verify
+ Assert.assertNotNull(certs);
+ Assert.assertTrue(certs.length > 0);
+ Assert.assertEquals(cert.getSubjectX500Principal(), certs[0].getSubjectX500Principal());
+ Assert.assertEquals(cert.getPublicKey(), certs[0].getPublicKey());
+ } finally {
+ serverFuture.get(5, TimeUnit.SECONDS);
+ executor.shutdown();
+ }
+ }
+ }
+}