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