diff --git a/pom.xml b/pom.xml index 7c7a9aae26..55bf706af3 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,7 @@ 4.3.0 4.9.1 2.7 - 3.0 + 3.12.0 5.16.0 10.11.1.1 1.9.4 @@ -199,7 +199,7 @@ true true - 2.0.0-M15 + 2.0.0.AM26 2.0.0-M1 linux-x86_64 @@ -280,7 +280,7 @@ - + org.eclipse.paho org.eclipse.paho.client.mqttv3 ${paho.client.mqttv3.version} diff --git a/tests/integration-tests/pom.xml b/tests/integration-tests/pom.xml index 65140fa567..02ef8ade63 100644 --- a/tests/integration-tests/pom.xml +++ b/tests/integration-tests/pom.xml @@ -335,6 +335,11 @@ + + org.apache.commons + commons-lang3 + test + @@ -390,7 +395,13 @@ org.apache.hadoop hadoop-minikdc - 2.8.1 + 3.3.0 + test + + + org.apache.directory.server + apacheds-interceptor-kerberos + ${directory-version} test @@ -554,10 +565,6 @@ maven-surefire-plugin - - **/JMSSaslGssapiTest.java - **/SaslKrb5LDAPSecurityTest.java - **/CoreClientOverOneWaySSLKerb5Test.java diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java index 7b6e220a66..99c4ae8d59 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSSaslGssapiTest.java @@ -16,24 +16,37 @@ */ package org.apache.activemq.artemis.tests.integration.amqp; -import javax.jms.Connection; -import javax.jms.JMSSecurityException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; +import java.io.OutputStream; import java.net.URI; import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; +import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import javax.jms.Connection; +import javax.jms.JMSSecurityException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnector; import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants; import org.apache.activemq.artemis.core.security.Role; @@ -47,21 +60,25 @@ import org.apache.activemq.artemis.protocol.amqp.proton.handler.ProtonHandler; import org.apache.activemq.artemis.protocol.amqp.sasl.ClientSASL; import org.apache.activemq.artemis.protocol.amqp.sasl.ClientSASLFactory; import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; -import org.apache.activemq.artemis.tests.util.JavaVersionUtil; import org.apache.activemq.artemis.tests.util.Wait; import org.apache.activemq.artemis.utils.RandomUtil; import org.apache.hadoop.minikdc.MiniKdc; +import org.apache.kerby.kerberos.kerb.keytab.Keytab; +import org.apache.kerby.kerberos.kerb.keytab.KeytabEntry; +import org.apache.kerby.kerberos.kerb.type.base.PrincipalName; import org.apache.qpid.jms.JmsConnectionFactory; import org.apache.qpid.jms.sasl.GssapiMechanism; import org.apache.qpid.proton.amqp.Symbol; -import org.junit.After; -import org.junit.Assume; -import org.junit.Before; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class JMSSaslGssapiTest extends JMSClientTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(JMSSaslGssapiTest.class); + static { String path = System.getProperty("java.security.auth.login.config"); if (path == null) { @@ -72,25 +89,48 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { } } } - MiniKdc kdc = null; - private final boolean debug = false; + + private static final String KRB5_TCP_PORT_TEMPLATE = "MINI_KDC_PORT"; + private static final String KRB5_CONFIG_TEMPLATE = "minikdc-krb5-template.conf"; + private static final String KRB5_DEFAULT_KEYTAB = "target/test.krb5.keytab"; + + private static MiniKdc kdc; + private static final boolean debug = false; @BeforeClass - public static void checkAssumptions() throws Exception { - Assume.assumeTrue("Test only runs on JDK 8", JavaVersionUtil.isJava8()); - } + public static void setUpKerberos() throws Exception { + Properties kdcConf = MiniKdc.createConf(); + kdcConf.setProperty("debug", Boolean.toString(debug)); - @Before - public void setUpKerberos() throws Exception { - kdc = new MiniKdc(MiniKdc.createConf(), temporaryFolder.newFolder("kdc")); + // Creates a single server for the tests as there were failures when spawning and killing one per unit test. + kdc = new MiniKdc(kdcConf, new File("target/")); kdc.start(); // hard coded match, default_keytab_name in minikdc-krb5.conf template - File userKeyTab = new File("target/test.krb5.keytab"); + File userKeyTab = new File(KRB5_DEFAULT_KEYTAB); kdc.createPrincipal(userKeyTab, "client", "amqp/localhost"); + // We need to hard code the default keyTab into the Krb5 configuration file which is not possible + // with this version of MiniKDC so we use a template file and replace the port with the value from + // the MiniKDC instance we just started. + rewriteKrbConfFile(kdc); + if (debug) { - for (java.util.logging.Logger logger : new java.util.logging.Logger[] {java.util.logging.Logger.getLogger("javax.security.sasl"), java.util.logging.Logger.getLogger("org.apache.qpid.proton")}) { + LOG.debug("java.security.krb5.conf='{}'", System.getProperty("java.security.krb5.conf")); + try (BufferedReader br = new BufferedReader(new FileReader(System.getProperty("java.security.krb5.conf")))) { + br.lines().forEach(line -> LOG.debug(line)); + } + + Keytab kt = Keytab.loadKeytab(userKeyTab); + for (PrincipalName name : kt.getPrincipals()) { + for (KeytabEntry entry : kt.getKeytabEntries(name)) { + LOG.info("KeyTab Entry: PrincipalName:" + entry.getPrincipal() + " ; KeyInfo:" + entry.getKey().getKeyType()); + } + } + + for (java.util.logging.Logger logger : new java.util.logging.Logger[] {java.util.logging.Logger.getLogger("logincontext"), + java.util.logging.Logger.getLogger("javax.security.sasl"), + java.util.logging.Logger.getLogger("org.apache.qpid.proton")}) { logger.setLevel(java.util.logging.Level.FINEST); logger.addHandler(new java.util.logging.ConsoleHandler()); for (java.util.logging.Handler handler : logger.getHandlers()) { @@ -100,8 +140,8 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { } } - @After - public void stopKerberos() throws Exception { + @AfterClass + public static void stopKerberos() throws Exception { if (kdc != null) { kdc.stop(); } @@ -125,6 +165,10 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { roles.add(role); server.getSecurityRepository().addMatch(getQueueName().toString(), roles); + if (debug) { + // The default produces so much log spam that debugging the exchanges becomes impossible. + server.getConfiguration().setMessageExpiryScanPeriod(30_000); + } } @Override @@ -134,7 +178,6 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { @Override protected URI getBrokerQpidJMSConnectionURI() { - try { int port = AMQP_PORT; @@ -164,7 +207,7 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { try { Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - javax.jms.Queue queue = session.createQueue(getQueueName()); + Queue queue = session.createQueue(getQueueName()); MessageConsumer consumer = session.createConsumer(queue); MessageProducer producer = session.createProducer(queue); @@ -174,7 +217,6 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { TextMessage m = (TextMessage) consumer.receive(1000); assertNotNull(m); assertEquals(text, m.getText()); - } finally { connection.close(); } @@ -182,7 +224,6 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { @Test(timeout = 600000) public void testSaslPlainConnectionDenied() throws Exception { - JmsConnectionFactory factory = new JmsConnectionFactory(new URI("amqp://localhost:" + AMQP_PORT + "?amqp.saslMechanisms=PLAIN")); try { factory.createConnection("plain", "secret"); @@ -192,7 +233,7 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { } } - @Test + @Test(timeout = 900000) public void testOutboundWithSlowMech() throws Exception { final Map config = new LinkedHashMap<>(); config.put(TransportConstants.HOST_PROP_NAME, "localhost"); config.put(TransportConstants.PORT_PROP_NAME, String.valueOf(AMQP_PORT)); @@ -270,4 +311,19 @@ public class JMSSaslGssapiTest extends JMSClientTestSupport { lifeCycleListener.stop(); } } + + private static void rewriteKrbConfFile(MiniKdc server) throws Exception { + final Path template = Paths.get(JMSSaslGssapiTest.class.getClassLoader().getResource(KRB5_CONFIG_TEMPLATE).toURI()); + final String krb5confTemplate = new String(Files.readAllBytes(template), StandardCharsets.UTF_8); + final String replacementPort = Integer.toString(server.getPort()); + + // Replace the port template with the current actual port of the MiniKDC Server instance. + final String krb5confUpdated = krb5confTemplate.replaceAll(KRB5_TCP_PORT_TEMPLATE, replacementPort); + + try (OutputStream outputStream = Files.newOutputStream(server.getKrb5conf().toPath()); + WritableByteChannel channel = Channels.newChannel(outputStream)) { + + channel.write(ByteBuffer.wrap(krb5confUpdated.getBytes(StandardCharsets.UTF_8))); + } + } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/SaslKrb5LDAPSecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/SaslKrb5LDAPSecurityTest.java index 3b7dcd8635..4f610163f1 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/SaslKrb5LDAPSecurityTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/SaslKrb5LDAPSecurityTest.java @@ -30,6 +30,7 @@ import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; @@ -58,10 +59,8 @@ import org.apache.activemq.artemis.core.server.ActiveMQServer; import org.apache.activemq.artemis.core.server.ActiveMQServers; import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager; import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; -import org.apache.activemq.artemis.tests.util.JavaVersionUtil; import org.apache.activemq.artemis.utils.RandomUtil; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms; import org.apache.directory.api.ldap.model.entry.DefaultEntry; import org.apache.directory.api.ldap.model.entry.Entry; @@ -95,9 +94,7 @@ import org.apache.directory.shared.kerberos.components.EncryptionKey; import org.apache.qpid.jms.JmsConnectionFactory; import org.junit.After; import org.junit.Assert; -import org.junit.Assume; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -122,9 +119,8 @@ import static org.apache.activemq.artemis.tests.util.ActiveMQTestBase.NETTY_ACCE @CreateKdcServer(transports = {@CreateTransport(protocol = "TCP", port = 0)}) @ApplyLdifFiles("SaslKrb5LDAPSecurityTest.ldif") public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { - private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(SaslKrb5LDAPSecurityTest.class); - protected static final Logger LOG = LoggerFactory.getLogger(SaslKrb5LDAPSecurityTest.class); + public static final String QUEUE_NAME = "some_queue"; static { @@ -155,14 +151,8 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { public TemporaryFolder temporaryFolder; private String testDir; - @BeforeClass - public static void checkAssumptions() throws Exception { - Assume.assumeTrue("Test only runs on JDK 8", JavaVersionUtil.isJava8()); - } - @Before public void setUp() throws Exception { - if (debug) { initLogging(); } @@ -196,27 +186,24 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { private void rewriteKerb5Conf() throws Exception { StringBuilder sb = new StringBuilder(); - InputStream is2 = this.getClass().getClassLoader().getResourceAsStream("minikdc-krb5.conf"); - BufferedReader r = null; - try { - r = new BufferedReader(new InputStreamReader(is2, StandardCharsets.UTF_8)); - String line = r.readLine(); + try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("minikdc-krb5.conf"); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + + String line = reader.readLine(); while (line != null) { sb.append(line).append("{3}"); - line = r.readLine(); + line = reader.readLine(); } - } finally { - IOUtils.closeQuietly(r); - IOUtils.closeQuietly(is2); } InetSocketAddress addr = (InetSocketAddress)kdcServer.getTransports()[0].getAcceptor().getLocalAddress(); int port = addr.getPort(); File krb5conf = new File(testDir, "krb5.conf").getAbsoluteFile(); - FileUtils.writeStringToFile(krb5conf, MessageFormat.format(sb.toString(), getRealm(), "localhost", Integer.toString(port), System.getProperty("line.separator"))); + String krb5confBody = MessageFormat.format(sb.toString(), getRealm(), "localhost", Integer.toString(port), System.getProperty("line.separator")); + FileUtils.writeStringToFile(krb5conf, krb5confBody, StandardCharsets.UTF_8); System.setProperty("java.security.krb5.conf", krb5conf.getAbsolutePath()); System.setProperty("sun.security.krb5.debug", "true"); @@ -232,10 +219,16 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { refreshMethod.invoke(classRef, new Object[0]); LOG.debug("krb5.conf to: {}", krb5conf.getAbsolutePath()); + if (debug) { + LOG.debug("java.security.krb5.conf='{}'", System.getProperty("java.security.krb5.conf")); + try (BufferedReader br = new BufferedReader(new FileReader(System.getProperty("java.security.krb5.conf")))) { + br.lines().forEach(line -> LOG.debug(line)); + } + } } private void dumpLdapContents() throws Exception { - EntryFilteringCursor cursor = getService().getAdminSession().search(new Dn("ou=system"), SearchScope.SUBTREE, new PresenceNode("ObjectClass"), AliasDerefMode.DEREF_ALWAYS); + EntryFilteringCursor cursor = (EntryFilteringCursor) getService().getAdminSession().search(new Dn("ou=system"), SearchScope.SUBTREE, new PresenceNode("ObjectClass"), AliasDerefMode.DEREF_ALWAYS); String st = ""; while (cursor.next()) { @@ -243,9 +236,9 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { String ss = LdifUtils.convertToLdif(entry); st += ss + "\n"; } - log.debug(st); + LOG.debug(st); - cursor = getService().getAdminSession().search(new Dn("dc=example,dc=com"), SearchScope.SUBTREE, new PresenceNode("ObjectClass"), AliasDerefMode.DEREF_ALWAYS); + cursor = (EntryFilteringCursor) getService().getAdminSession().search(new Dn("dc=example,dc=com"), SearchScope.SUBTREE, new PresenceNode("ObjectClass"), AliasDerefMode.DEREF_ALWAYS); st = ""; while (cursor.next()) { @@ -253,15 +246,18 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { String ss = LdifUtils.convertToLdif(entry); st += ss + "\n"; } - log.debug(st); + LOG.debug(st); } private void initLogging() { - java.util.logging.Logger logger = java.util.logging.Logger.getLogger("javax.security.sasl"); - logger.setLevel(java.util.logging.Level.FINEST); - logger.addHandler(new java.util.logging.ConsoleHandler()); - for (java.util.logging.Handler handler: logger.getHandlers()) { - handler.setLevel(java.util.logging.Level.FINEST); + for (java.util.logging.Logger logger : new java.util.logging.Logger[] {java.util.logging.Logger.getLogger("logincontext"), + java.util.logging.Logger.getLogger("javax.security.sasl"), + java.util.logging.Logger.getLogger("org.apache.qpid.proton")}) { + logger.setLevel(java.util.logging.Level.FINEST); + logger.addHandler(new java.util.logging.ConsoleHandler()); + for (java.util.logging.Handler handler : logger.getHandlers()) { + handler.setLevel(java.util.logging.Level.FINEST); + } } } @@ -276,8 +272,10 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { + "krb5PrincipalName: " + principal + "@" + getRealm() + "\n" + "krb5KeyVersionNumber: 0"; - for (LdifEntry ldifEntry : new LdifReader(new StringReader(content))) { - service.getAdminSession().add(new DefaultEntry(service.getSchemaManager(), ldifEntry.getEntry())); + try (LdifReader ldifReader = new LdifReader(new StringReader(content))) { + for (LdifEntry ldifEntry : ldifReader) { + service.getAdminSession().add(new DefaultEntry(service.getSchemaManager(), ldifEntry.getEntry())); + } } } @@ -292,7 +290,7 @@ public class SaslKrb5LDAPSecurityTest extends AbstractLdapTestUnit { for (Map.Entry entry : KerberosKeyFactory.getKerberosKeys(principal, generatedPassword).entrySet()) { EncryptionKey ekey = entry.getValue(); byte keyVersion = (byte) ekey.getKeyVersion(); - entries.add(new KeytabEntry(principal, 1L, timestamp, keyVersion, ekey)); + entries.add(new KeytabEntry(principal, 1, timestamp, keyVersion, ekey)); } } keytab.setEntries(entries); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/metrics/JournalPendingMessageTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/metrics/JournalPendingMessageTest.java index db9be9e3ac..3ef0cc30e3 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/metrics/JournalPendingMessageTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/persistence/metrics/JournalPendingMessageTest.java @@ -42,7 +42,7 @@ import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory; import org.apache.activemq.artemis.jms.client.ActiveMQTextMessage; import org.apache.activemq.artemis.utils.Wait; import org.apache.activemq.artemis.utils.Wait.Condition; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompWebSocketMaxFrameTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompWebSocketMaxFrameTest.java index bc580cc149..f56a96cd1a 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompWebSocketMaxFrameTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/StompWebSocketMaxFrameTest.java @@ -24,7 +24,7 @@ import org.apache.activemq.artemis.tests.util.Wait; import org.apache.activemq.artemis.tests.integration.stomp.util.ClientStompFrame; import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnection; import org.apache.activemq.artemis.tests.integration.stomp.util.StompClientConnectionFactory; -import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; diff --git a/tests/integration-tests/src/test/resources/minikdc-krb5-template.conf b/tests/integration-tests/src/test/resources/minikdc-krb5-template.conf new file mode 100644 index 0000000000..1d08811ce8 --- /dev/null +++ b/tests/integration-tests/src/test/resources/minikdc-krb5-template.conf @@ -0,0 +1,30 @@ +# +# 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. +# + +[libdefaults] + kdc_realm = EXAMPLE.COM + default_realm = EXAMPLE.COM + udp_preference_limit = 1 + kdc_tcp_port = MINI_KDC_PORT + default_keytab_name = FILE:target/test.krb5.keytab + +[realms] + EXAMPLE.COM = { + kdc = localhost:MINI_KDC_PORT + } +