blob: c808b45d09188f1c91ae24bd668afb955247f170 [file] [log] [blame]
/*
*
* 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.systests.jms_1_1.extensions.sasl;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeThat;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TemporaryQueue;
import javax.naming.NamingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.qpid.server.security.FileTrustStoreTest;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.model.User;
import org.apache.qpid.server.security.FileKeyStore;
import org.apache.qpid.server.security.FileTrustStore;
import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManager;
import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManagerImpl;
import org.apache.qpid.server.security.auth.manager.ScramSHA1AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.ScramSHA256AuthenticationManager;
import org.apache.qpid.server.security.auth.sasl.crammd5.CramMd5HashedNegotiator;
import org.apache.qpid.systests.AmqpManagementFacade;
import org.apache.qpid.systests.JmsTestBase;
import org.apache.qpid.test.utils.TestSSLConstants;
public class AuthenticationTest extends JmsTestBase
{
private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationTest.class);
private static final String USER = "user";
private static final String USER_PASSWORD = "user";
// see how port is specified when certificates are generated in script
// test-profiles/test_resources/ssl/generate_certificates.sh
private static final int CRL_HTTP_PORT = 8186;
private static final Server CRL_SERVER = new Server();
private static final HandlerCollection HANDLERS = new HandlerCollection();
@BeforeClass
public static void setUp() throws Exception
{
System.setProperty("javax.net.debug", "ssl");
// workaround for QPID-8069
if (getProtocol() != Protocol.AMQP_1_0 && getProtocol() != Protocol.AMQP_0_10)
{
System.setProperty("amqj.MaximumStateWait", "4000");
}
// legacy client keystore/truststore types can only be configured with JVM settings
if (getProtocol() != Protocol.AMQP_1_0)
{
System.setProperty("javax.net.ssl.trustStoreType", TestSSLConstants.JAVA_KEYSTORE_TYPE);
System.setProperty("javax.net.ssl.keyStoreType", TestSSLConstants.JAVA_KEYSTORE_TYPE);
}
final ServerConnector connector = new ServerConnector(CRL_SERVER);
connector.setPort(CRL_HTTP_PORT);
connector.setHost("localhost");
CRL_SERVER.addConnector(connector);
createContext(Paths.get(TestSSLConstants.CA_CRL));
createContext(Paths.get(TestSSLConstants.CA_CRL_EMPTY));
createContext(Paths.get(TestSSLConstants.INTERMEDIATE_CA_CRL));
CRL_SERVER.setHandler(HANDLERS);
CRL_SERVER.start();
}
@AfterClass
public static void tearDown() throws Exception
{
System.clearProperty("javax.net.debug");
if (getProtocol() != Protocol.AMQP_1_0)
{
System.clearProperty("amqj.MaximumStateWait");
}
if (getProtocol() != Protocol.AMQP_1_0)
{
System.clearProperty("javax.net.ssl.trustStoreType");
System.clearProperty("javax.net.ssl.keyStoreType");
}
CRL_SERVER.stop();
}
@Test
public void md5() throws Exception
{
assumeThat("Qpid JMS Client does not support MD5 mechanisms",
getProtocol(),
is(not(equalTo(Protocol.AMQP_1_0))));
final int port = createAuthenticationProviderAndUserAndPort(getTestName(), "MD5", USER, USER_PASSWORD);
assertPlainConnectivity(port, USER, USER_PASSWORD, CramMd5HashedNegotiator.MECHANISM);
}
@Test
public void sha256() throws Exception
{
final int port = createAuthenticationProviderAndUserAndPort(getTestName(),
ScramSHA256AuthenticationManager.PROVIDER_TYPE,
USER,
USER_PASSWORD);
assertPlainConnectivity(port, USER, USER_PASSWORD, ScramSHA256AuthenticationManager.MECHANISM);
}
@Test
public void sha1() throws Exception
{
final int port = createAuthenticationProviderAndUserAndPort(getTestName(),
ScramSHA1AuthenticationManager.PROVIDER_TYPE,
USER,
USER_PASSWORD);
assertPlainConnectivity(port, USER, USER_PASSWORD, ScramSHA1AuthenticationManager.MECHANISM);
}
@Test
public void external() throws Exception
{
final int port = createExternalProviderAndTlsPort();
Connection connection = getConnectionBuilder().setPort(port)
.setTls(true)
.setSaslMechanisms(ExternalAuthenticationManagerImpl.MECHANISM_NAME)
.setKeyStoreLocation(TestSSLConstants.CLIENT_KEYSTORE)
.setKeyStorePassword(TestSSLConstants.PASSWORD)
.setTrustStoreLocation(TestSSLConstants.CLIENT_TRUSTSTORE)
.setTrustStorePassword(TestSSLConstants.PASSWORD)
.build();
try
{
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
assertNotNull("Temporary queue was not created", session.createTemporaryQueue());
}
finally
{
connection.close();
}
}
public void externalWithRevocationWithDataUrlCrlFileAndAllowedCertificate() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_LIST_URL,
FileTrustStoreTest.createDataUrlForFile(TestSSLConstants.CA_CRL));
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED);
}
@Test
public void externalWithRevocationWithDataUrlCrlFileAndRevokedCertificate() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_LIST_URL,
FileTrustStoreTest.createDataUrlForFile(TestSSLConstants.CA_CRL));
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_REVOKED);
}
@Test
public void externalWithRevocationWithCrlFileAndAllowedCertificate() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_LIST_URL, TestSSLConstants.CA_CRL);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED);
}
@Test
public void externalWithRevocationWithCrlFileAndAllowedCertificateWithoutPreferCrls() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_LIST_URL, TestSSLConstants.CA_CRL);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_WITH_PREFERRING_CERTIFICATE_REVOCATION_LIST, false);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED);
}
@Test
public void externalWithRevocationWithCrlFileAndRevokedCertificate() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_LIST_URL, TestSSLConstants.CA_CRL);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_REVOKED);
}
@Test
public void externalWithRevocationWithEmptyCrlFileAndRevokedCertificate() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_LIST_URL, TestSSLConstants.CA_CRL_EMPTY);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED);
}
@Test
public void externalWithRevocationAndAllowedCertificateWithCrlUrl() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED);
}
@Test
public void externalWithRevocationAndRevokedCertificateWithCrlUrl() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_REVOKED);
}
@Test
public void externalWithRevocationAndRevokedCertificateWithCrlUrlWithEmptyCrl() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_REVOKED_EMPTY_CRL);
}
@Test
public void externalWithRevocationDisabledWithCrlFileAndRevokedCertificate() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, false);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_LIST_URL, TestSSLConstants.CA_CRL);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_REVOKED);
}
@Test
public void externalWithRevocationDisabledWithCrlUrlInRevokedCertificate() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, false);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_REVOKED);
}
@Test
public void externalWithRevocationAndRevokedCertificateWithCrlUrlWithSoftFail() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_WITH_IGNORING_SOFT_FAILURES, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_REVOKED_INVALID_CRL_PATH);
}
@Test
public void externalWithRevocationAndRevokedCertificateWithCrlUrlWithoutPreferCrls() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_WITH_PREFERRING_CERTIFICATE_REVOCATION_LIST, false);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED);
}
@Test
public void externalWithRevocationAndRevokedCertificateWithCrlUrlWithoutPreferCrlsWithFallback() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_WITH_PREFERRING_CERTIFICATE_REVOCATION_LIST, false);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_WITH_NO_FALLBACK, false);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED);
}
@Test
public void externalWithRevocationAndRevokedIntermediateCertificateWithCrlUrl() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_OF_ONLY_END_ENTITY_CERTIFICATES, false);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_WITH_IGNORING_SOFT_FAILURES, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED_WITH_INTERMEDIATE);
}
@Test
public void externalWithRevocationAndRevokedIntermediateCertificateWithCrlUrlOnlyEndEntity() throws Exception
{
assumeThat("HTTP server failed to bind to port '" + CRL_HTTP_PORT + "'",
CRL_SERVER, is(not(equalTo(null))));
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_ENABLED, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_OF_ONLY_END_ENTITY_CERTIFICATES, true);
trustStoreAttributes.put(FileTrustStore.CERTIFICATE_REVOCATION_CHECK_WITH_IGNORING_SOFT_FAILURES, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_ALLOWED_WITH_INTERMEDIATE);
}
@Test
public void externalDeniesUntrustedClientCert() throws Exception
{
assumeThat("QPID-8069", getProtocol(), is(anyOf(equalTo(Protocol.AMQP_1_0), equalTo(Protocol.AMQP_0_10))));
final int port = createExternalProviderAndTlsPort();
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_UNTRUSTED_CLIENT);
}
@Test
public void externalDeniesExpiredClientCert() throws Exception
{
assumeThat("QPID-8069", getProtocol(), is(anyOf(equalTo(Protocol.AMQP_1_0), equalTo(Protocol.AMQP_0_10))));
final Map<String, Object> trustStoreAttributes = new HashMap<>();
trustStoreAttributes.put(FileTrustStore.STORE_URL, TestSSLConstants.BROKER_PEERSTORE);
trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.PASSWORD);
trustStoreAttributes.put(FileTrustStore.TRUST_ANCHOR_VALIDITY_ENFORCED, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
try
{
getConnectionBuilder().setPort(port)
.setTls(true)
.setSaslMechanisms(ExternalAuthenticationManagerImpl.MECHANISM_NAME)
.setKeyStoreLocation(TestSSLConstants.CLIENT_EXPIRED_KEYSTORE)
.setKeyStorePassword(TestSSLConstants.PASSWORD)
.setTrustStoreLocation(TestSSLConstants.CLIENT_TRUSTSTORE)
.setTrustStorePassword(TestSSLConstants.PASSWORD)
.build();
fail("Connection should not succeed");
}
catch (JMSException e)
{
e.printStackTrace();
}
}
@Test
public void externalWithPeersOnlyTrustStore() throws Exception
{
final Map<String, Object> trustStoreAttributes = new HashMap<>();
trustStoreAttributes.put(FileTrustStore.STORE_URL, TestSSLConstants.BROKER_PEERSTORE);
trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.PASSWORD);
trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_APP1);
assumeThat("QPID-8069", getProtocol(), is(anyOf(equalTo(Protocol.AMQP_1_0), equalTo(Protocol.AMQP_0_10))));
assertNoTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_APP2);
}
@Test
public void externalWithRegularAndPeersOnlyTrustStores() throws Exception
{
final String trustStoreName = getTestName() + "RegularTrustStore";
final Connection brokerConnection = getConnectionBuilder().setVirtualHost("$management").build();
try
{
brokerConnection.start();
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
trustStoreAttributes.put(FileTrustStore.TRUST_STORE_TYPE, TestSSLConstants.JAVA_KEYSTORE_TYPE);
createEntity(trustStoreName,
FileTrustStore.class.getName(),
trustStoreAttributes,
brokerConnection);
}
finally
{
brokerConnection.close();
}
final Map<String, Object> trustStoreAttributes = new HashMap<>();
trustStoreAttributes.put(FileTrustStore.STORE_URL, TestSSLConstants.BROKER_PEERSTORE);
trustStoreAttributes.put(FileTrustStore.PASSWORD,TestSSLConstants.PASSWORD);
trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, true);
final int port = createExternalProviderAndTlsPort(trustStoreAttributes, trustStoreName, false);
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_APP1);
//use the app2 cert, which is NOT in the peerstore (but is signed by the same CA as app1)
assertTlsConnectivity(port, TestSSLConstants.CERT_ALIAS_APP2);
}
@Test
public void externalUsernameAsDN() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
final String clientId = getTestName();
final int port = createExternalProviderAndTlsPort(trustStoreAttributes, null, true);
final Connection connection = getConnectionBuilder().setPort(port)
.setTls(true)
.setSaslMechanisms(ExternalAuthenticationManagerImpl.MECHANISM_NAME)
.setKeyStoreLocation(TestSSLConstants.CLIENT_KEYSTORE)
.setKeyStorePassword(TestSSLConstants.PASSWORD)
.setTrustStoreLocation(TestSSLConstants.CLIENT_TRUSTSTORE)
.setTrustStorePassword(TestSSLConstants.PASSWORD)
.setKeyAlias(TestSSLConstants.CERT_ALIAS_APP2)
.setClientId(clientId)
.build();
try
{
assertConnectionPrincipal( clientId, "CN=app2@acme.org,OU=art,O=acme,L=Toronto,ST=ON,C=CA");
}
catch (JMSException e)
{
fail("Should be able to create a connection to the SSL port: " + e.getMessage());
}
finally
{
connection.close();
}
}
@Test
public void externalUsernameAsCN() throws Exception
{
final Map<String, Object> trustStoreAttributes = getBrokerTrustStoreAttributes();
final String clientId = getTestName();
final int port = createExternalProviderAndTlsPort(trustStoreAttributes, null, false);
final Connection connection = getConnectionBuilder().setPort(port)
.setTls(true)
.setSaslMechanisms(ExternalAuthenticationManagerImpl.MECHANISM_NAME)
.setKeyStoreLocation(TestSSLConstants.CLIENT_KEYSTORE)
.setKeyStorePassword(TestSSLConstants.PASSWORD)
.setTrustStoreLocation(TestSSLConstants.CLIENT_TRUSTSTORE)
.setTrustStorePassword(TestSSLConstants.PASSWORD)
.setKeyAlias(TestSSLConstants.CERT_ALIAS_APP2)
.setClientId(clientId)
.build();
try
{
assertConnectionPrincipal( clientId, "app2@acme.org");
}
catch (JMSException e)
{
fail("Should be able to create a connection to the SSL port: " + e.getMessage());
}
finally
{
connection.close();
}
}
private void assertConnectionPrincipal(final String clientId, final String expectedPrincipal) throws Exception
{
final Connection brokerConnection = getConnectionBuilder().setVirtualHost("$management").build();
try
{
brokerConnection.start();
String principal = null;
final List<Map<String, Object>> connections = queryEntitiesUsingAmqpManagement("org.apache.qpid.Connection", brokerConnection);
for (final Map<String, Object> connection : connections)
{
final String name = String.valueOf(connection.get(ConfiguredObject.NAME));
final Map<String, Object> attributes;
try
{
attributes = readEntityUsingAmqpManagement(
getPortName() + "/" + name,
"org.apache.qpid.Connection",
false,
brokerConnection);
}
catch (AmqpManagementFacade.OperationUnsuccessfulException e)
{
LOGGER.error("Read operation failed for an existing object '{}' having attributes '{}': {}",
getPortName() + "/" + name,
connection,
e.getMessage(),
e);
throw e;
}
if (attributes.get(org.apache.qpid.server.model.Connection.CLIENT_ID).equals(clientId))
{
principal = String.valueOf(attributes.get(org.apache.qpid.server.model.Connection.PRINCIPAL));
break;
}
}
assertEquals("Unexpected principal", expectedPrincipal, principal);
}
finally
{
brokerConnection.close();
}
}
private Map<String, Object> getBrokerTrustStoreAttributes()
{
final Map<String, Object> trustStoreAttributes = new HashMap<>();
trustStoreAttributes.put(FileTrustStore.STORE_URL, TestSSLConstants.BROKER_TRUSTSTORE);
trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.PASSWORD);
return trustStoreAttributes;
}
private int createExternalProviderAndTlsPort() throws Exception
{
return createExternalProviderAndTlsPort(getBrokerTrustStoreAttributes());
}
private int createExternalProviderAndTlsPort(final Map<String, Object> trustStoreAttributes) throws Exception
{
return createExternalProviderAndTlsPort(trustStoreAttributes, null, false);
}
private int createExternalProviderAndTlsPort(final Map<String, Object> trustStoreAttributes,
final String additionalTrustStore,
final boolean useFullDN) throws Exception
{
final String providerName = getTestName();
final Connection connection = getConnectionBuilder().setVirtualHost("$management").build();
try
{
connection.start();
final Map<String, Object> providerAttributes = new HashMap<>();
providerAttributes.put("qpid-type", ExternalAuthenticationManager.PROVIDER_TYPE);
providerAttributes.put(ExternalAuthenticationManager.ATTRIBUTE_USE_FULL_DN, useFullDN);
createEntity(providerName,
AuthenticationProvider.class.getName(),
providerAttributes,
connection);
final Map<String, Object> keyStoreAttributes = new HashMap<>();
keyStoreAttributes.put("storeUrl", TestSSLConstants.BROKER_KEYSTORE);
keyStoreAttributes.put("password", TestSSLConstants.PASSWORD);
keyStoreAttributes.put("keyStoreType", TestSSLConstants.JAVA_KEYSTORE_TYPE);
final String keyStoreName = providerName + "KeyStore";
createEntity(keyStoreName,
FileKeyStore.class.getName(),
keyStoreAttributes,
connection);
final Map<String, Object> trustStoreSettings = new HashMap<>(trustStoreAttributes);
trustStoreSettings.put("trustStoreType", TestSSLConstants.JAVA_KEYSTORE_TYPE);
final String trustStoreName = providerName + "TrustStore";
createEntity(trustStoreName,
FileTrustStore.class.getName(),
trustStoreSettings,
connection);
final String portName = getPortName();
final Map<String, Object> sslPortAttributes = new HashMap<>();
sslPortAttributes.put(Port.TRANSPORTS, "[\"SSL\"]");
sslPortAttributes.put(Port.PORT, 0);
sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, providerName);
sslPortAttributes.put(Port.NEED_CLIENT_AUTH, true);
sslPortAttributes.put(Port.WANT_CLIENT_AUTH, false);
sslPortAttributes.put(Port.NAME, portName);
sslPortAttributes.put(Port.KEY_STORE, keyStoreName);
final String trustStores = additionalTrustStore == null
? "[\"" + trustStoreName + "\"]"
: "[\"" + trustStoreName + "\",\"" + additionalTrustStore + "\"]";
sslPortAttributes.put(Port.TRUST_STORES, trustStores);
createEntity(portName,
"org.apache.qpid.AmqpPort",
sslPortAttributes,
connection);
final Map<String, Object> portEffectiveAttributes =
readEntityUsingAmqpManagement(portName, "org.apache.qpid.AmqpPort", false, connection);
if (portEffectiveAttributes.containsKey("boundPort"))
{
return (int) portEffectiveAttributes.get("boundPort");
}
throw new RuntimeException("Bound port is not found");
}
finally
{
connection.close();
}
}
private String getPortName()
{
return getTestName() + "TlsPort";
}
private int createAuthenticationProviderAndUserAndPort(final String providerName,
final String providerType,
final String userName,
final String userPassword) throws Exception
{
final Connection connection = getConnectionBuilder().setVirtualHost("$management").build();
try
{
connection.start();
createEntity(providerName,
AuthenticationProvider.class.getName(),
Collections.singletonMap("qpid-type", providerType),
connection);
final Map<String, Object> userAttributes = new HashMap<>();
userAttributes.put("qpid-type", "managed");
userAttributes.put(User.PASSWORD, userPassword);
userAttributes.put("object-path", providerName);
createEntity(userName, User.class.getName(), userAttributes, connection);
final String portName = providerName + "Port";
final Map<String, Object> portAttributes = new HashMap<>();
portAttributes.put(Port.AUTHENTICATION_PROVIDER, providerName);
portAttributes.put(Port.PORT, 0);
createEntity(portName, "org.apache.qpid.AmqpPort", portAttributes, connection);
final Map<String, Object> portEffectiveAttributes =
readEntityUsingAmqpManagement(portName, "org.apache.qpid.AmqpPort", false, connection);
if (portEffectiveAttributes.containsKey("boundPort"))
{
return (int) portEffectiveAttributes.get("boundPort");
}
throw new RuntimeException("Bound port is not found");
}
finally
{
connection.close();
}
}
private Connection getConnection(int port, String certificateAlias) throws NamingException, JMSException
{
return getConnectionBuilder().setPort(port)
.setTls(true)
.setSaslMechanisms(ExternalAuthenticationManagerImpl.MECHANISM_NAME)
.setKeyStoreLocation(TestSSLConstants.CLIENT_KEYSTORE)
.setKeyStorePassword(TestSSLConstants.PASSWORD)
.setKeyAlias(certificateAlias)
.setTrustStoreLocation(TestSSLConstants.CLIENT_TRUSTSTORE)
.setTrustStorePassword(TestSSLConstants.PASSWORD)
.build();
}
private void assertTlsConnectivity(int port, String certificateAlias) throws NamingException, JMSException
{
final Connection connection = getConnection(port, certificateAlias);
try
{
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
assertNotNull("Temporary queue was not created", session.createTemporaryQueue());
}
finally
{
connection.close();
}
}
private void assertNoTlsConnectivity(int port, String certificateAlias) throws NamingException
{
try
{
getConnection(port, certificateAlias);
fail("Connection should not succeed");
}
catch (JMSException e)
{
// pass
}
}
private void assertPlainConnectivity(final int port,
final String userName,
final String userPassword,
final String mechanism) throws Exception
{
final Connection connection = getConnectionBuilder().setPort(port)
.setUsername(userName)
.setPassword(userPassword)
.setSaslMechanisms(mechanism)
.build();
try
{
final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final TemporaryQueue queue = session.createTemporaryQueue();
assertNotNull("Temporary queue was not created", queue);
}
finally
{
connection.close();
}
try
{
getConnectionBuilder().setPort(port)
.setUsername(userName)
.setPassword("invalid" + userPassword)
.setSaslMechanisms(mechanism)
.build();
fail("Connection is established for invalid password");
}
catch (JMSException e)
{
// pass
}
try
{
getConnectionBuilder().setPort(port)
.setUsername("invalid" + userName)
.setPassword(userPassword)
.setSaslMechanisms(mechanism)
.build();
fail("Connection is established for invalid user name");
}
catch (JMSException e)
{
// pass
}
}
private static void createContext(Path crlPath)
{
final ContextHandler contextHandler = new ContextHandler();
contextHandler.setContextPath("/" + crlPath.getFileName());
contextHandler.setHandler(new CrlServerHandler(crlPath));
HANDLERS.addHandler(contextHandler);
}
private static class CrlServerHandler extends AbstractHandler
{
final Path crlPath;
public CrlServerHandler(Path crlPath)
{
this.crlPath = crlPath;
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException
{
final byte[] crlBytes = Files.readAllBytes(crlPath);
response.setStatus(HttpServletResponse.SC_OK);
final OutputStream responseBody = response.getOutputStream();
responseBody.write(crlBytes);
responseBody.close();
}
}
}