|
@@ -19,27 +19,45 @@
|
|
|
package org.apache.zookeeper.server.admin;
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
+import java.io.File;
|
|
|
import java.io.IOException;
|
|
|
import java.io.InputStreamReader;
|
|
|
import java.net.MalformedURLException;
|
|
|
import java.net.URL;
|
|
|
+import javax.net.ssl.HostnameVerifier;
|
|
|
+import javax.net.ssl.HttpsURLConnection;
|
|
|
+import javax.net.ssl.SSLSession;
|
|
|
|
|
|
+import org.apache.zookeeper.common.KeyStoreFileType;
|
|
|
+import org.apache.zookeeper.common.X509Exception.SSLContextException;
|
|
|
import org.apache.zookeeper.PortAssignment;
|
|
|
import org.apache.zookeeper.ZKTestCase;
|
|
|
+import org.apache.zookeeper.common.X509KeyType;
|
|
|
+import org.apache.zookeeper.common.X509TestContext;
|
|
|
import org.apache.zookeeper.server.ZooKeeperServerMainTest;
|
|
|
import org.apache.zookeeper.server.admin.AdminServer.AdminServerException;
|
|
|
import org.apache.zookeeper.server.quorum.QuorumPeerTestBase;
|
|
|
import org.apache.zookeeper.test.ClientBase;
|
|
|
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
|
+import org.junit.After;
|
|
|
import org.junit.Assert;
|
|
|
import org.junit.Before;
|
|
|
import org.junit.Test;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
+import javax.net.ssl.SSLContext;
|
|
|
+import javax.net.ssl.TrustManager;
|
|
|
+import javax.net.ssl.X509TrustManager;
|
|
|
+import java.security.Security;
|
|
|
+import java.security.cert.X509Certificate;
|
|
|
+import java.security.GeneralSecurityException;
|
|
|
+
|
|
|
public class JettyAdminServerTest extends ZKTestCase{
|
|
|
protected static final Logger LOG = LoggerFactory.getLogger(JettyAdminServerTest.class);
|
|
|
|
|
|
private static final String URL_FORMAT = "http://localhost:%d/commands";
|
|
|
+ private static final String HTTPS_URL_FORMAT = "https://localhost:%d/commands";
|
|
|
private static final int jettyAdminPort = PortAssignment.unique();
|
|
|
|
|
|
@Before
|
|
@@ -49,11 +67,79 @@ public class JettyAdminServerTest extends ZKTestCase{
|
|
|
System.setProperty("zookeeper.admin.serverPort", "" + jettyAdminPort);
|
|
|
}
|
|
|
|
|
|
+ @Before
|
|
|
+ public void setupEncryption() {
|
|
|
+ Security.addProvider(new BouncyCastleProvider());
|
|
|
+ File tmpDir = null;
|
|
|
+ X509TestContext x509TestContext = null;
|
|
|
+ try {
|
|
|
+ tmpDir = ClientBase.createEmptyTestDir();
|
|
|
+ x509TestContext = X509TestContext.newBuilder()
|
|
|
+ .setTempDir(tmpDir)
|
|
|
+ .setKeyStorePassword("")
|
|
|
+ .setKeyStoreKeyType(X509KeyType.EC)
|
|
|
+ .setTrustStorePassword("")
|
|
|
+ .setTrustStoreKeyType(X509KeyType.EC)
|
|
|
+ .build();
|
|
|
+ System.setProperty("zookeeper.ssl.quorum.keyStore.location",
|
|
|
+ x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath());
|
|
|
+ System.setProperty("zookeeper.ssl.quorum.trustStore.location",
|
|
|
+ x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath());
|
|
|
+ } catch (Exception e) {
|
|
|
+ LOG.info("Problems encountered while setting up encryption for Jetty admin server test: " + e);
|
|
|
+ }
|
|
|
+ System.setProperty("zookeeper.ssl.quorum.keyStore.password", "");
|
|
|
+ System.setProperty("zookeeper.ssl.quorum.keyStore.type", "PEM");
|
|
|
+ System.setProperty("zookeeper.ssl.quorum.trustStore.password", "");
|
|
|
+ System.setProperty("zookeeper.ssl.quorum.trustStore.type", "PEM");
|
|
|
+ System.setProperty("zookeeper.admin.portUnification", "true");
|
|
|
+
|
|
|
+ // Create a trust manager that does not validate certificate chains
|
|
|
+ TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
|
|
|
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
|
|
|
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
|
|
|
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
|
|
|
+ }};
|
|
|
+
|
|
|
+ // Create all-trusting trust manager
|
|
|
+ SSLContext sc = null;
|
|
|
+ try {
|
|
|
+ sc = SSLContext.getInstance("SSL");
|
|
|
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
|
|
+ } catch (Exception e) { LOG.error("Failed to customize encryption for HTTPS: e"); }
|
|
|
+
|
|
|
+ // Create all-trusting hostname verifier
|
|
|
+ HostnameVerifier allValid = new HostnameVerifier() {
|
|
|
+ public boolean verify(String hostname, SSLSession session) { return true; }
|
|
|
+ };
|
|
|
+
|
|
|
+ // This is a temporary fix while we do not yet have certificates set up to make
|
|
|
+ // HTTPS requests correctly. This is equivalent to the "-k" option in curl.
|
|
|
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
|
|
|
+ HttpsURLConnection.setDefaultHostnameVerifier(allValid);
|
|
|
+ }
|
|
|
+
|
|
|
+ @After
|
|
|
+ public void cleanUp() {
|
|
|
+ Security.removeProvider("BC");
|
|
|
+
|
|
|
+ System.clearProperty("zookeeper.admin.enableServer");
|
|
|
+ System.clearProperty("zookeeper.admin.serverPort");
|
|
|
+
|
|
|
+ System.clearProperty("zookeeper.ssl.quorum.keyStore.location");
|
|
|
+ System.clearProperty("zookeeper.ssl.quorum.keyStore.password");
|
|
|
+ System.clearProperty("zookeeper.ssl.quorum.keyStore.type");
|
|
|
+ System.clearProperty("zookeeper.ssl.quorum.trustStore.location");
|
|
|
+ System.clearProperty("zookeeper.ssl.quorum.trustStore.password");
|
|
|
+ System.clearProperty("zookeeper.ssl.quorum.trustStore.type");
|
|
|
+ System.clearProperty("zookeeper.admin.portUnification");
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Tests that we can start and query a JettyAdminServer.
|
|
|
*/
|
|
|
@Test
|
|
|
- public void testJettyAdminServer() throws AdminServerException, IOException {
|
|
|
+ public void testJettyAdminServer() throws AdminServerException, IOException, SSLContextException, GeneralSecurityException {
|
|
|
JettyAdminServer server = new JettyAdminServer();;
|
|
|
try {
|
|
|
server.start();
|
|
@@ -146,16 +232,23 @@ public class JettyAdminServerTest extends ZKTestCase{
|
|
|
* Check that we can load the commands page of an AdminServer running at
|
|
|
* localhost:port. (Note that this should work even if no zk server is set.)
|
|
|
*/
|
|
|
- private void queryAdminServer(int port) throws MalformedURLException, IOException {
|
|
|
- queryAdminServer(String.format(URL_FORMAT, port));
|
|
|
+ private void queryAdminServer(int port) throws MalformedURLException, IOException, SSLContextException {
|
|
|
+ queryAdminServer(String.format(URL_FORMAT, port), false);
|
|
|
+ queryAdminServer(String.format(HTTPS_URL_FORMAT, port), true);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check that loading urlStr results in a non-zero length response.
|
|
|
*/
|
|
|
- private void queryAdminServer(String urlStr) throws MalformedURLException, IOException {
|
|
|
+ private void queryAdminServer(String urlStr, boolean encrypted) throws MalformedURLException, IOException, SSLContextException {
|
|
|
URL url = new URL(urlStr);
|
|
|
- BufferedReader dis = new BufferedReader(new InputStreamReader((url.openStream())));
|
|
|
+ BufferedReader dis;
|
|
|
+ if (!encrypted) {
|
|
|
+ dis = new BufferedReader(new InputStreamReader((url.openStream())));
|
|
|
+ } else {
|
|
|
+ HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
|
|
|
+ dis = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
|
|
+ }
|
|
|
String line = dis.readLine();
|
|
|
Assert.assertTrue(line.length() > 0);
|
|
|
}
|