diff options
-rw-r--r-- | qpid/java/common/src/test/java/org/apache/qpid/ssl/TrustManagerTest.java | 262 | ||||
-rw-r--r-- | qpid/java/systests/etc/config-systests.json | 2 | ||||
-rw-r--r-- | qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java | 60 | ||||
-rw-r--r-- | qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java | 1 | ||||
-rw-r--r-- | qpid/java/test-profiles/test_resources/ssl/java_broker_peerstore.jks | bin | 1246 -> 639 bytes | |||
-rw-r--r-- | qpid/java/test-profiles/test_resources/ssl/java_broker_truststore.jks | bin | 0 -> 591 bytes | |||
-rw-r--r-- | qpid/java/test-profiles/test_resources/ssl/java_client_untrusted_keystore.jks | bin | 0 -> 2056 bytes |
7 files changed, 284 insertions, 41 deletions
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/ssl/TrustManagerTest.java b/qpid/java/common/src/test/java/org/apache/qpid/ssl/TrustManagerTest.java index 34ca4e0e03..3b76d81e42 100644 --- a/qpid/java/common/src/test/java/org/apache/qpid/ssl/TrustManagerTest.java +++ b/qpid/java/common/src/test/java/org/apache/qpid/ssl/TrustManagerTest.java @@ -37,126 +37,308 @@ import org.apache.qpid.transport.network.security.ssl.SSLUtil; public class TrustManagerTest extends QpidTestCase { - private static final String BROKER_KEYSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_broker_keystore.jks"; + private static final String BROKER_TRUSTSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_broker_truststore.jks"; private static final String BROKER_PEERSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_broker_peerstore.jks"; private static final String CLIENT_KEYSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_client_keystore.jks"; + private static final String CLIENT_UNTRUSTED_KEYSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_client_untrusted_keystore.jks"; private static final String STORE_PASSWORD = "password"; private static final String STORE_TYPE = "JKS"; private static final String DEFAULT_TRUST_MANAGER_ALGORITHM = TrustManagerFactory.getDefaultAlgorithm(); private static final String CERT_ALIAS_APP1 = "app1"; private static final String CERT_ALIAS_APP2 = "app2"; + private static final String CERT_ALIAS_UNTRUSTED_CLIENT = "untrusted_client"; // retrieves the client certificate's chain from store and returns it as an array - private X509Certificate[] getClientChain() throws Exception + private X509Certificate[] getClientChain(final String storePath, final String alias) throws Exception { - final KeyStore ks = SSLUtil.getInitializedKeyStore(CLIENT_KEYSTORE_PATH, STORE_PASSWORD, STORE_TYPE); - final Certificate[] chain = ks.getCertificateChain(CERT_ALIAS_APP1); + final KeyStore ks = SSLUtil.getInitializedKeyStore(storePath, STORE_PASSWORD, STORE_TYPE); + final Certificate[] chain = ks.getCertificateChain(alias); return Arrays.copyOf(chain, chain.length, X509Certificate[].class); } - // verifies that peer store is loaded only with client's (peer's) certificates (no CA) + // verifies that peer store is loaded only with client's (peer's) app1 certificate (no CA) private void noCAinPeerStore(final KeyStore ps) throws KeyStoreException { final Enumeration<String> aliases = ps.aliases(); while (aliases.hasMoreElements()) { final String alias = aliases.nextElement(); - if (!alias.equalsIgnoreCase(CERT_ALIAS_APP1) && !alias.equalsIgnoreCase(CERT_ALIAS_APP2)) + if (!alias.equalsIgnoreCase(CERT_ALIAS_APP1)) { - fail("Broker's peer store contains other certificate than client's public keys"); + fail("Broker's peer store contains other certificate than client's app1 public key"); } } } - public void testPeerStoreClientAuthentication() throws Exception + /** + * Tests that the QpidPeersOnlyTrustManager gives the expected behaviour when loaded separately + * with the broker peerstore and truststore. + */ + public void testQpidPeersOnlyTrustManager() throws Exception { - // first let's check that peer manager loaded with proper store succeeds + // first let's check that peer manager loaded with the PEERstore succeeds final KeyStore ps = SSLUtil.getInitializedKeyStore(BROKER_PEERSTORE_PATH, STORE_PASSWORD, STORE_TYPE); this.noCAinPeerStore(ps); final TrustManagerFactory pmf = TrustManagerFactory.getInstance(DEFAULT_TRUST_MANAGER_ALGORITHM); pmf.init(ps); final TrustManager[] delegatePeerManagers = pmf.getTrustManagers(); - boolean peerManagerTested = false; + + X509TrustManager peerManager = null; for (final TrustManager tm : delegatePeerManagers) { if (tm instanceof X509TrustManager) { - peerManagerTested = true; // peer manager is supposed to trust only clients which peers certificates // are directly in the store. CA signing will not be considered. - X509TrustManager peerManager = new QpidPeersOnlyTrustManager(ps, (X509TrustManager) tm); - // since broker's peerstore contains the client's certificate, the check should succeed - try - { - peerManager.checkClientTrusted(this.getClientChain(), "RSA"); - } - catch (CertificateException e) - { - fail("Client's validation against the broker's peer store manager failed."); - } + peerManager = new QpidPeersOnlyTrustManager(ps, (X509TrustManager) tm); } } - assertEquals("No QpidPeersOnlyTrustManager(s) were created from the peer store.", true, peerManagerTested); - // now let's check that peer manager loaded with improper store fails - final KeyStore ts = SSLUtil.getInitializedKeyStore(BROKER_KEYSTORE_PATH, STORE_PASSWORD, STORE_TYPE); + + try + { + // since broker's peerstore contains the client's app1 certificate, the check should succeed + peerManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP1), "RSA"); + } + catch (CertificateException e) + { + fail("Trusted client's validation against the broker's peer store manager failed."); + } + + try + { + // since broker's peerstore does not contain the client's app2 certificate, the check should fail + peerManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP2), "RSA"); + fail("Untrusted client's validation against the broker's peer store manager succeeded."); + } + catch (CertificateException e) + { + //expected + } + + // now let's check that peer manager loaded with the brokers TRUSTstore fails because + // it does not have the clients certificate in it (though it does have a CA-cert that + // would otherwise trust the client cert when using the regular trust manager). + final KeyStore ts = SSLUtil.getInitializedKeyStore(BROKER_TRUSTSTORE_PATH, STORE_PASSWORD, STORE_TYPE); final TrustManagerFactory tmf = TrustManagerFactory.getInstance(DEFAULT_TRUST_MANAGER_ALGORITHM); tmf.init(ts); final TrustManager[] delegateTrustManagers = tmf.getTrustManagers(); + + peerManager = null; for (final TrustManager tm : delegateTrustManagers) { if (tm instanceof X509TrustManager) { // peer manager is supposed to trust only clients which peers certificates // are directly in the store. CA signing will not be considered. - X509TrustManager peerManager = new QpidPeersOnlyTrustManager(ts, (X509TrustManager) tm); - // since broker's truststore doesn't contain the client's certificate, the check should fail - try - { - peerManager.checkClientTrusted(this.getClientChain(), "RSA"); - fail("Client's validation against the broker's peer store manager didn't fail."); - } - catch (CertificateException e) - { - // expected - } + peerManager = new QpidPeersOnlyTrustManager(ts, (X509TrustManager) tm); } } + + try + { + // since broker's truststore doesn't contain the client's app1 certificate, the check should fail + // despite the fact that the truststore does have a CA that would otherwise trust the cert + peerManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP1), "RSA"); + fail("Client's validation against the broker's peer store manager didn't fail."); + } + catch (CertificateException e) + { + // expected + } + + try + { + // since broker's truststore doesn't contain the client's app2 certificate, the check should fail + // despite the fact that the truststore does have a CA that would otherwise trust the cert + peerManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP2), "RSA"); + fail("Client's validation against the broker's peer store manager didn't fail."); + } + catch (CertificateException e) + { + // expected + } } - - public void testMultipleStoreClientAuthentication() throws Exception + + /** + * Tests that the QpidMultipleTrustManager gives the expected behaviour when wrapping a + * regular TrustManager against the broker truststore. + */ + public void testQpidMultipleTrustManagerWithRegularTrustStore() throws Exception + { + final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager(); + final KeyStore ts = SSLUtil.getInitializedKeyStore(BROKER_TRUSTSTORE_PATH, STORE_PASSWORD, STORE_TYPE); + final TrustManagerFactory tmf = TrustManagerFactory.getInstance(DEFAULT_TRUST_MANAGER_ALGORITHM); + tmf.init(ts); + final TrustManager[] delegateTrustManagers = tmf.getTrustManagers(); + boolean trustManagerAdded = false; + for (final TrustManager tm : delegateTrustManagers) + { + if (tm instanceof X509TrustManager) + { + // add broker's trust manager + mulTrustManager.addTrustManager((X509TrustManager) tm); + trustManagerAdded = true; + } + } + assertTrue("The regular trust manager for the trust store was not added", trustManagerAdded); + + try + { + // verify the CA-trusted app1 cert (should succeed) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP1), "RSA"); + } + catch (CertificateException ex) + { + fail("Trusted client's validation against the broker's multi store manager failed."); + } + + try + { + // verify the CA-trusted app2 cert (should succeed) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP2), "RSA"); + } + catch (CertificateException ex) + { + fail("Trusted client's validation against the broker's multi store manager failed."); + } + + try + { + // verify the untrusted cert (should fail) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_UNTRUSTED_KEYSTORE_PATH, CERT_ALIAS_UNTRUSTED_CLIENT), "RSA"); + fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed."); + } + catch (CertificateException ex) + { + // expected + } + } + + /** + * Tests that the QpidMultipleTrustManager gives the expected behaviour when wrapping a + * QpidPeersOnlyTrustManager against the broker peerstore. + */ + public void testQpidMultipleTrustManagerWithPeerStore() throws Exception { final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager(); - final KeyStore ts = SSLUtil.getInitializedKeyStore(BROKER_KEYSTORE_PATH, STORE_PASSWORD, STORE_TYPE); + final KeyStore ps = SSLUtil.getInitializedKeyStore(BROKER_PEERSTORE_PATH, STORE_PASSWORD, STORE_TYPE); + final TrustManagerFactory pmf = TrustManagerFactory.getInstance(DEFAULT_TRUST_MANAGER_ALGORITHM); + pmf.init(ps); + final TrustManager[] delegatePeerManagers = pmf.getTrustManagers(); + boolean peerManagerAdded = false; + for (final TrustManager tm : delegatePeerManagers) + { + if (tm instanceof X509TrustManager) + { + // add broker's peer manager + mulTrustManager.addTrustManager(new QpidPeersOnlyTrustManager(ps, (X509TrustManager) tm)); + peerManagerAdded = true; + } + } + assertTrue("The QpidPeersOnlyTrustManager for the peerstore was not added", peerManagerAdded); + + try + { + // verify the trusted app1 cert (should succeed as the key is in the peerstore) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP1), "RSA"); + } + catch (CertificateException ex) + { + fail("Trusted client's validation against the broker's multi store manager failed."); + } + + try + { + // verify the untrusted app2 cert (should fail as the key is not in the peerstore) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP2), "RSA"); + fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed."); + } + catch (CertificateException ex) + { + // expected + } + + try + { + // verify the untrusted cert (should fail as the key is not in the peerstore) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_UNTRUSTED_KEYSTORE_PATH, CERT_ALIAS_UNTRUSTED_CLIENT), "RSA"); + fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed."); + } + catch (CertificateException ex) + { + // expected + } + } + + /** + * Tests that the QpidMultipleTrustManager gives the expected behaviour when wrapping a + * QpidPeersOnlyTrustManager against the broker peerstore, a regular TrustManager + * against the broker truststore. + */ + public void testQpidMultipleTrustManagerWithTrustAndPeerStores() throws Exception + { + final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager(); + final KeyStore ts = SSLUtil.getInitializedKeyStore(BROKER_TRUSTSTORE_PATH, STORE_PASSWORD, STORE_TYPE); final TrustManagerFactory tmf = TrustManagerFactory.getInstance(DEFAULT_TRUST_MANAGER_ALGORITHM); tmf.init(ts); final TrustManager[] delegateTrustManagers = tmf.getTrustManagers(); + boolean trustManagerAdded = false; for (final TrustManager tm : delegateTrustManagers) { if (tm instanceof X509TrustManager) { // add broker's trust manager mulTrustManager.addTrustManager((X509TrustManager) tm); + trustManagerAdded = true; } } + assertTrue("The regular trust manager for the trust store was not added", trustManagerAdded); + final KeyStore ps = SSLUtil.getInitializedKeyStore(BROKER_PEERSTORE_PATH, STORE_PASSWORD, STORE_TYPE); final TrustManagerFactory pmf = TrustManagerFactory.getInstance(DEFAULT_TRUST_MANAGER_ALGORITHM); pmf.init(ps); final TrustManager[] delegatePeerManagers = pmf.getTrustManagers(); + boolean peerManagerAdded = false; for (final TrustManager tm : delegatePeerManagers) { if (tm instanceof X509TrustManager) { // add broker's peer manager mulTrustManager.addTrustManager(new QpidPeersOnlyTrustManager(ps, (X509TrustManager) tm)); + peerManagerAdded = true; } } + assertTrue("The QpidPeersOnlyTrustManager for the peerstore was not added", peerManagerAdded); + + try + { + // verify the CA-trusted app1 cert (should succeed) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP1), "RSA"); + } + catch (CertificateException ex) + { + fail("Trusted client's validation against the broker's multi store manager failed."); + } + + try + { + // verify the CA-trusted app2 cert (should succeed) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_KEYSTORE_PATH, CERT_ALIAS_APP2), "RSA"); + } + catch (CertificateException ex) + { + fail("Trusted client's validation against the broker's multi store manager failed."); + } + try { - mulTrustManager.checkClientTrusted(this.getClientChain(), "RSA"); + // verify the untrusted cert (should fail) + mulTrustManager.checkClientTrusted(this.getClientChain(CLIENT_UNTRUSTED_KEYSTORE_PATH, CERT_ALIAS_UNTRUSTED_CLIENT), "RSA"); + fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed."); } catch (CertificateException ex) { - fail("Client's validation against the broker's multi store manager failed."); + // expected } } } diff --git a/qpid/java/systests/etc/config-systests.json b/qpid/java/systests/etc/config-systests.json index 36e6f61d43..b06b469891 100644 --- a/qpid/java/systests/etc/config-systests.json +++ b/qpid/java/systests/etc/config-systests.json @@ -24,7 +24,7 @@ "defaultVirtualHost" : "test", "keyStorePath": "${QPID_HOME}/../test-profiles/test_resources/ssl/java_broker_keystore.jks", "keyStorePassword": "password", - "trustStorePath": "${QPID_HOME}/../test-profiles/test_resources/ssl/java_client_truststore.jks", + "trustStorePath": "${QPID_HOME}/../test-profiles/test_resources/ssl/java_broker_truststore.jks", "trustStorePassword": "password", "authenticationproviders" : [ { "name" : "plain", diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java index b90f56daf6..e9e6f93ab6 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.security.auth.manager; import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.UNTRUSTED_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; @@ -139,6 +140,59 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase } } + /** + * Tests that when using the EXTERNAL authentication provider and needing client auth, clients with + * untrusted certificates are unable to connect to the SSL port. + */ + public void testExternalAuthenticationDeniesUntrustedClientCert() throws Exception + { + setCommonBrokerSSLProperties(true); + getBrokerConfiguration().setBrokerAttribute(Broker.DEFAULT_AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); + super.setUp(); + + setUntrustedClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false); + fail("Connection should not succeed"); + } + catch (JMSException e) + { + // pass + } + } + + /** + * Tests that when using the EXTERNAL auth provide and the broker 'peerstore' is configured to contain a certificate that is + * otherwise untrusted by the broker [truststore], clients using that certificate will then be able to connect. + */ + public void testExternalAuthenticationWithPeerStoreAllowsOtherwiseUntrustedClientCert() throws Exception + { + setCommonBrokerSSLProperties(true); + getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_SSL_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); + + //Use the untrusted client keystore as the brokers peerstore to make the broker trust the cert. + getBrokerConfiguration().setBrokerAttribute(Broker.PEER_STORE_PATH, UNTRUSTED_KEYSTORE); + getBrokerConfiguration().setBrokerAttribute(Broker.PEER_STORE_PASSWORD, KEYSTORE_PASSWORD); + + super.setUp(); + + setUntrustedClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false); + fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed."); + } + catch (JMSException e) + { + // expected + } + } + private Connection getExternalSSLConnection(boolean includeUserNameAndPassword) throws Exception { String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL''"; @@ -169,6 +223,12 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase config.addAuthenticationProviderConfiguration(externalAuthProviderAttributes); } + private void setUntrustedClientKeystoreProperties() + { + setSystemProperty("javax.net.ssl.keyStore", UNTRUSTED_KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + } + private void setClientKeystoreProperties() { setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java index 9d5be775dc..5664e94bd9 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java @@ -21,6 +21,7 @@ package org.apache.qpid.test.utils; public interface TestSSLConstants { String KEYSTORE = "test-profiles/test_resources/ssl/java_client_keystore.jks"; + String UNTRUSTED_KEYSTORE = "test-profiles/test_resources/ssl/java_client_untrusted_keystore.jks"; String KEYSTORE_PASSWORD = "password"; String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks"; String TRUSTSTORE_PASSWORD = "password"; diff --git a/qpid/java/test-profiles/test_resources/ssl/java_broker_peerstore.jks b/qpid/java/test-profiles/test_resources/ssl/java_broker_peerstore.jks Binary files differindex 52027cae06..a716581a7e 100644 --- a/qpid/java/test-profiles/test_resources/ssl/java_broker_peerstore.jks +++ b/qpid/java/test-profiles/test_resources/ssl/java_broker_peerstore.jks diff --git a/qpid/java/test-profiles/test_resources/ssl/java_broker_truststore.jks b/qpid/java/test-profiles/test_resources/ssl/java_broker_truststore.jks Binary files differnew file mode 100644 index 0000000000..2af95f21f8 --- /dev/null +++ b/qpid/java/test-profiles/test_resources/ssl/java_broker_truststore.jks diff --git a/qpid/java/test-profiles/test_resources/ssl/java_client_untrusted_keystore.jks b/qpid/java/test-profiles/test_resources/ssl/java_client_untrusted_keystore.jks Binary files differnew file mode 100644 index 0000000000..45a0c10667 --- /dev/null +++ b/qpid/java/test-profiles/test_resources/ssl/java_client_untrusted_keystore.jks |