You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kw...@apache.org on 2018/02/23 17:18:58 UTC
qpid-broker-j git commit: QPID-8083: [System Tests] [REST/HTTP] Add
TlsClientAuthenticationTest
Repository: qpid-broker-j
Updated Branches:
refs/heads/master b720d7d1e -> 20f47fec8
QPID-8083: [System Tests] [REST/HTTP] Add TlsClientAuthenticationTest
Project: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/commit/20f47fec
Tree: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/tree/20f47fec
Diff: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/diff/20f47fec
Branch: refs/heads/master
Commit: 20f47fec86440686e7d345c6718618abfc8a09cf
Parents: b720d7d
Author: Keith Wall <kw...@apache.org>
Authored: Fri Feb 23 17:15:51 2018 +0000
Committer: Keith Wall <kw...@apache.org>
Committed: Fri Feb 23 17:18:36 2018 +0000
----------------------------------------------------------------------
.../ManagedPeerCertificateTrustStore.java | 1 +
.../apache/qpid/tests/http/HttpTestHelper.java | 87 +++++---
.../TlsClientAuthenticationTest.java | 210 +++++++++++++++++++
.../rest/BrokerRestHttpsClientCertAuthTest.java | 87 --------
4 files changed, 272 insertions(+), 113 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/20f47fec/broker-core/src/main/java/org/apache/qpid/server/security/ManagedPeerCertificateTrustStore.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/ManagedPeerCertificateTrustStore.java b/broker-core/src/main/java/org/apache/qpid/server/security/ManagedPeerCertificateTrustStore.java
index 580696a..1010611 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/ManagedPeerCertificateTrustStore.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/ManagedPeerCertificateTrustStore.java
@@ -37,6 +37,7 @@ public interface ManagedPeerCertificateTrustStore<X extends ManagedPeerCertifica
{
String TYPE_NAME = "ManagedCertificateStore";
+ String STORED_CERTIFICATES = "storedCertificates";
@Override
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/20f47fec/systests/qpid-systests-http-management/src/main/java/org/apache/qpid/tests/http/HttpTestHelper.java
----------------------------------------------------------------------
diff --git a/systests/qpid-systests-http-management/src/main/java/org/apache/qpid/tests/http/HttpTestHelper.java b/systests/qpid-systests-http-management/src/main/java/org/apache/qpid/tests/http/HttpTestHelper.java
index 6561504..a2bb3b8 100644
--- a/systests/qpid-systests-http-management/src/main/java/org/apache/qpid/tests/http/HttpTestHelper.java
+++ b/systests/qpid-systests-http-management/src/main/java/org/apache/qpid/tests/http/HttpTestHelper.java
@@ -33,17 +33,20 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.bind.DatatypeConverter;
@@ -54,6 +57,7 @@ import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
import org.apache.qpid.tests.utils.BrokerAdmin;
public class HttpTestHelper
@@ -74,12 +78,14 @@ public class HttpTestHelper
private final String _username;
private final String _password;
private final String _requestHostName;
-
private final int _connectTimeout = Integer.getInteger("qpid.resttest_connection_timeout", 30000);
private String _acceptEncoding;
private boolean _tls = false;
+ private KeyStore _keyStore;
+ private String _keyStorePassword;
+
public HttpTestHelper(final BrokerAdmin admin)
{
this(admin, null);
@@ -138,32 +144,21 @@ public class HttpTestHelper
try
{
SSLContext sslContext = SSLContext.getInstance("TLS");
- TrustManager[] trustAllCerts = new TrustManager[] {
- new X509TrustManager()
- {
- public X509Certificate[] getAcceptedIssuers()
- {
- X509Certificate[] issuers = new X509Certificate[0];
- return issuers;
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] certs, String authType)
- {
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] certs, String authType)
- {
- }
- }
- };
-
- sslContext.init(null, trustAllCerts, null);
+ TrustManager[] trustAllCerts = new TrustManager[] {new TrustAllTrustManager()};
+
+ KeyManager[] keyManagers = null;
+ if (_keyStore != null)
+ {
+ char[] keyStoreCharPassword = _keyStorePassword == null ? null : _keyStorePassword.toCharArray();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(_keyStore, keyStoreCharPassword);
+ keyManagers = kmf.getKeyManagers();
+ }
+ sslContext.init(keyManagers, trustAllCerts, null);
httpsCon.setSSLSocketFactory(sslContext.getSocketFactory());
httpsCon.setHostnameVerifier((s, sslSession) -> true);
}
- catch (KeyManagementException | NoSuchAlgorithmException e)
+ catch (KeyStoreException | UnrecoverableKeyException | KeyManagementException | NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
@@ -439,4 +434,44 @@ public class HttpTestHelper
_acceptEncoding = acceptEncoding;
}
+ public void setKeyStore(final String keystore, final String password) throws Exception
+ {
+ _keyStorePassword = password;
+
+ if (keystore != null)
+ {
+ try
+ {
+ URL ks = new URL(keystore);
+ _keyStore = SSLUtil.getInitializedKeyStore(ks, password, KeyStore.getDefaultType());
+ }
+ catch (MalformedURLException e)
+ {
+ _keyStore = SSLUtil.getInitializedKeyStore(keystore, password, KeyStore.getDefaultType());
+ }
+ }
+ else
+ {
+ _keyStore = null;
+ }
+ }
+
+ private static class TrustAllTrustManager implements X509TrustManager
+ {
+ public X509Certificate[] getAcceptedIssuers()
+ {
+ X509Certificate[] issuers = new X509Certificate[0];
+ return issuers;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType)
+ {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType)
+ {
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/20f47fec/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/TlsClientAuthenticationTest.java
----------------------------------------------------------------------
diff --git a/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/TlsClientAuthenticationTest.java b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/TlsClientAuthenticationTest.java
new file mode 100644
index 0000000..7d14ff8
--- /dev/null
+++ b/systests/qpid-systests-http-management/src/test/java/org/apache/qpid/tests/http/authentication/TlsClientAuthenticationTest.java
@@ -0,0 +1,210 @@
+/*
+ *
+ * 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.qpid.tests.http.authentication;
+
+import static javax.servlet.http.HttpServletResponse.SC_CREATED;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static org.apache.qpid.server.transport.network.security.ssl.SSLUtil.generateSelfSignedCertificate;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayDeque;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.junit.After;
+import org.junit.Test;
+
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.security.FileKeyStore;
+import org.apache.qpid.server.security.ManagedPeerCertificateTrustStore;
+import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManager;
+import org.apache.qpid.server.transport.network.security.ssl.SSLUtil.KeyCertPair;
+import org.apache.qpid.server.util.BaseAction;
+import org.apache.qpid.server.util.DataUrlUtils;
+import org.apache.qpid.tests.http.HttpTestBase;
+import org.apache.qpid.tests.http.HttpTestHelper;
+
+public class TlsClientAuthenticationTest extends HttpTestBase
+{
+
+ private Deque<BaseAction<Void, Exception>> _tearDownActions;
+ private int _clientAuthPort;
+ private String _keyStore;
+
+ @After
+ public void tearDown() throws Exception
+ {
+ if (_tearDownActions != null)
+ {
+ Exception exception = null;
+ while(!_tearDownActions.isEmpty())
+ {
+ try
+ {
+ _tearDownActions.removeLast().performAction(null);
+ }
+ catch (Exception e)
+ {
+ exception = e;
+ }
+ }
+
+ if (exception != null)
+ {
+ throw exception;
+ }
+ }
+ }
+
+ @Test
+ public void clientAuthenticationSuccess() throws Exception
+ {
+ configPortAndAuthProvider("CN=foo");
+
+ HttpTestHelper helper = new HttpTestHelper(getBrokerAdmin(), null, _clientAuthPort);
+ helper.setTls(true);
+ helper.setKeyStore(_keyStore, "password");
+
+ String userId = helper.getJson("broker/getUser", new TypeReference<String>() {}, SC_OK);
+ assertThat(userId, startsWith("foo@"));
+ }
+
+ @Test
+ public void unrecognisedCertification() throws Exception
+ {
+ configPortAndAuthProvider("CN=foo");
+
+ String keyStore = createKeyStoreDataUrl(getKeyCertPair("CN=bar"), "password");
+
+ HttpTestHelper helper = new HttpTestHelper(getBrokerAdmin(), null, _clientAuthPort);
+ helper.setTls(true);
+ helper.setKeyStore(keyStore, "password");
+
+ try
+ {
+ helper.getJson("broker/getUser", new TypeReference<String>() {}, SC_OK);
+ fail("Exception not thrown");
+ }
+ catch (SSLHandshakeException e)
+ {
+ // PASS
+ }
+ }
+
+ private void configPortAndAuthProvider(final String x500Name) throws Exception
+ {
+
+ final KeyCertPair keyCertPair = getKeyCertPair(x500Name);
+ final byte[] cert = keyCertPair.getCertificate().getEncoded();
+
+ _keyStore = createKeyStoreDataUrl(keyCertPair, "password");
+
+
+ final Deque<BaseAction<Void,Exception>> deleteActions = new ArrayDeque<>();
+
+ final Map<String, Object> authAttr = new HashMap<>();
+ authAttr.put(ExternalAuthenticationManager.TYPE, "External");
+ authAttr.put(ExternalAuthenticationManager.ATTRIBUTE_USE_FULL_DN, false);
+
+ getHelper().submitRequest("authenticationprovider/myexternal","PUT", authAttr, SC_CREATED);
+
+ deleteActions.add(object -> getHelper().submitRequest("authenticationprovider/myexternal", "DELETE", SC_OK));
+
+ final Map<String, Object> keystoreAttr = new HashMap<>();
+ keystoreAttr.put(FileKeyStore.TYPE, "FileKeyStore");
+ keystoreAttr.put(FileKeyStore.STORE_URL, "classpath:java_broker_keystore.jks");
+ keystoreAttr.put(FileKeyStore.PASSWORD, "password");
+
+ getHelper().submitRequest("keystore/mykeystore","PUT", keystoreAttr, SC_CREATED);
+ deleteActions.add(object -> getHelper().submitRequest("keystore/mykeystore", "DELETE", SC_OK));
+
+ final Map<String, Object> truststoreAttr = new HashMap<>();
+ truststoreAttr.put(ManagedPeerCertificateTrustStore.TYPE, ManagedPeerCertificateTrustStore.TYPE_NAME);
+ truststoreAttr.put(ManagedPeerCertificateTrustStore.STORED_CERTIFICATES, Collections.singletonList(Base64.getEncoder().encodeToString(cert)));
+
+ getHelper().submitRequest("truststore/mytruststore","PUT", truststoreAttr, SC_CREATED);
+ deleteActions.add(object -> getHelper().submitRequest("truststore/mytruststore", "DELETE", SC_OK));
+
+ final Map<String, Object> portAttr = new HashMap<>();
+ portAttr.put(Port.TYPE, "HTTP");
+ portAttr.put(Port.PORT, 0);
+ portAttr.put(Port.AUTHENTICATION_PROVIDER, "myexternal");
+ portAttr.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP));
+ portAttr.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ portAttr.put(Port.NEED_CLIENT_AUTH, true);
+ portAttr.put(Port.KEY_STORE, "mykeystore");
+ portAttr.put(Port.TRUST_STORES, Collections.singletonList("mytruststore"));
+
+ getHelper().submitRequest("port/myport","PUT", portAttr, SC_CREATED);
+ deleteActions.add(object -> getHelper().submitRequest("port/myport", "DELETE", SC_OK));
+
+ Map<String, Object> clientAuthPort = getHelper().getJsonAsMap("port/myport");
+ int boundPort = Integer.parseInt(String.valueOf(clientAuthPort.get("boundPort")));
+
+ assertThat(boundPort, is(greaterThan(0)));
+
+ _tearDownActions = deleteActions;
+ _clientAuthPort = boundPort;
+ }
+
+ private String createKeyStoreDataUrl(final KeyCertPair keyCertPair, final String password) throws Exception
+ {
+ final KeyStore keyStore = KeyStore.getInstance("JKS");
+ keyStore.load(null, null);
+ Certificate[] certChain = new Certificate[] {keyCertPair.getCertificate()};
+ keyStore.setKeyEntry("key1", keyCertPair.getPrivateKey(), password.toCharArray(), certChain);
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream())
+ {
+ keyStore.store(bos, password.toCharArray());
+ bos.toByteArray();
+ return DataUrlUtils.getDataUrlForBytes(bos.toByteArray());
+ }
+ }
+
+ private KeyCertPair getKeyCertPair(final String x500Name) throws Exception
+ {
+ return generateSelfSignedCertificate("RSA", "SHA256WithRSA",
+ 2048, Instant.now().toEpochMilli(),
+ Duration.of(365, ChronoUnit.DAYS).getSeconds(),
+ x500Name,
+ Collections.emptySet(),
+ Collections.emptySet());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/20f47fec/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java
----------------------------------------------------------------------
diff --git a/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java b/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java
deleted file mode 100644
index 2df866a..0000000
--- a/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *
- * 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.qpid.systest.rest;
-
-import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE;
-import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD;
-import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
-import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
-import static org.apache.qpid.test.utils.TestSSLConstants.CERT_ALIAS_APP1;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.qpid.server.model.AuthenticationProvider;
-import org.apache.qpid.server.model.Port;
-import org.apache.qpid.server.model.Protocol;
-import org.apache.qpid.server.model.Transport;
-import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManager;
-import org.apache.qpid.test.utils.TestBrokerConfiguration;
-
-public class BrokerRestHttpsClientCertAuthTest extends QpidRestTestCase
-{
-
- @Override
- public void setUp() throws Exception
- {
- setSystemProperty("javax.net.debug", "ssl");
- super.setUp();
- }
-
- @Override
- protected void customizeConfiguration() throws Exception
- {
- super.customizeConfiguration();
-
- Map<String, Object> newAttributes = new HashMap<String, Object>();
- newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP));
- newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
- newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
- newAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
- newAttributes.put(Port.NEED_CLIENT_AUTH,"true");
-
-
- Map<String, Object> externalProviderAttributes = new HashMap<String, Object>();
- externalProviderAttributes.put(AuthenticationProvider.TYPE, ExternalAuthenticationManager.PROVIDER_TYPE);
- externalProviderAttributes.put(AuthenticationProvider.NAME, EXTERNAL_AUTHENTICATION_PROVIDER);
- getDefaultBrokerConfiguration().addObjectConfiguration(AuthenticationProvider.class, externalProviderAttributes);
-
- // set password authentication provider on http port for the tests
- getDefaultBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER,
- EXTERNAL_AUTHENTICATION_PROVIDER);
-
- getDefaultBrokerConfiguration().setObjectAttributes(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, newAttributes);
- }
-
- public void testGetWithHttps() throws Exception
- {
- _restTestHelper = new RestTestHelper(getDefaultBroker().getHttpsPort());
- _restTestHelper.setUseSslAuth(true);
- _restTestHelper.setTruststore(TRUSTSTORE, TRUSTSTORE_PASSWORD);
- _restTestHelper.setKeystore(KEYSTORE, KEYSTORE_PASSWORD);
- _restTestHelper.setClientAuthAlias(CERT_ALIAS_APP1);
-
- Map<String, Object> saslData = getRestTestHelper().getJsonAsMap("broker");
-
- Asserts.assertAttributesPresent(saslData, "modelVersion");
- }
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org