ARTEMIS-1264 Foundation work for authentication with Kerberos using KRB_ cypher suites.
Core client with netty connector and acceptor doing kerberos jaas.doAs around sslengine init such that the SSL handshake can do kerberos ticket generaton and validation. The kerberos authenticated user is then validated with the security manager before being populated into the message userId. The feature is enabled with the kerb5Config property. When lowercase it is the principal. With a leading uppercase char it is the login.config entry to use.
This commit is contained in:
parent
faae59e6d4
commit
cda1e018e1
|
@ -27,6 +27,9 @@ import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactor
|
|||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||
import org.apache.activemq.artemis.utils.ClassloadingUtil;
|
||||
|
||||
import javax.security.auth.login.AppConfigurationEntry;
|
||||
import javax.security.auth.login.Configuration;
|
||||
|
||||
/**
|
||||
* Stores static mappings of class names to ConnectorFactory instances to act as a central repo for ConnectorFactory
|
||||
* objects.
|
||||
|
@ -95,4 +98,29 @@ public class TransportConfigurationUtil {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Configuration kerb5Config(String principal, boolean initiator) {
|
||||
final Map<String, String> krb5LoginModuleOptions = new HashMap<>();
|
||||
krb5LoginModuleOptions.put("isInitiator", String.valueOf(initiator));
|
||||
krb5LoginModuleOptions.put("principal", principal);
|
||||
krb5LoginModuleOptions.put("useKeyTab", "true");
|
||||
krb5LoginModuleOptions.put("storeKey", "true");
|
||||
krb5LoginModuleOptions.put("doNotPrompt", "true");
|
||||
krb5LoginModuleOptions.put("renewTGT", "true");
|
||||
krb5LoginModuleOptions.put("refreshKrb5Config", "true");
|
||||
krb5LoginModuleOptions.put("useTicketCache", "true");
|
||||
String ticketCache = System.getenv("KRB5CCNAME");
|
||||
if (ticketCache != null) {
|
||||
krb5LoginModuleOptions.put("ticketCache", ticketCache);
|
||||
}
|
||||
return new Configuration() {
|
||||
@Override
|
||||
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
|
||||
return new AppConfigurationEntry[]{
|
||||
new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
|
||||
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
|
||||
krb5LoginModuleOptions)};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import io.netty.buffer.ByteBuf;
|
|||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
@ -45,6 +46,8 @@ import org.apache.activemq.artemis.utils.Env;
|
|||
import org.apache.activemq.artemis.utils.IPV6Util;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
||||
public class NettyConnection implements Connection {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(NettyConnection.class);
|
||||
|
@ -487,6 +490,17 @@ public class NettyConnection implements Connection {
|
|||
//never allow this
|
||||
@Override
|
||||
public final ActiveMQPrincipal getDefaultActiveMQPrincipal() {
|
||||
ChannelHandler channelHandler = channel.pipeline().get("ssl");
|
||||
if (channelHandler != null && channelHandler instanceof SslHandler) {
|
||||
SslHandler sslHandler = (SslHandler) channelHandler;
|
||||
try {
|
||||
return new ActiveMQPrincipal(sslHandler.engine().getSession().getPeerPrincipal().getName(), "");
|
||||
} catch (SSLPeerUnverifiedException ignored) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(ignored.getMessage(), ignored);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.net.UnknownHostException;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -43,6 +44,8 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
@ -95,6 +98,7 @@ import org.apache.activemq.artemis.api.core.ActiveMQException;
|
|||
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
||||
import org.apache.activemq.artemis.core.client.ActiveMQClientMessageBundle;
|
||||
import org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQClientProtocolManager;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.TransportConfigurationUtil;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
||||
import org.apache.activemq.artemis.spi.core.remoting.AbstractConnector;
|
||||
|
@ -205,6 +209,10 @@ public class NettyConnector extends AbstractConnector {
|
|||
|
||||
private boolean verifyHost;
|
||||
|
||||
private String sniHost;
|
||||
|
||||
private String kerb5Config;
|
||||
|
||||
private boolean useDefaultSslContext;
|
||||
|
||||
private boolean tcpNoDelay;
|
||||
|
@ -328,6 +336,10 @@ public class NettyConnector extends AbstractConnector {
|
|||
|
||||
verifyHost = ConfigurationHelper.getBooleanProperty(TransportConstants.VERIFY_HOST_PROP_NAME, TransportConstants.DEFAULT_VERIFY_HOST, configuration);
|
||||
|
||||
sniHost = ConfigurationHelper.getStringProperty(TransportConstants.SNIHOST_PROP_NAME, TransportConstants.DEFAULT_SNIHOST_CONFIG, configuration);
|
||||
|
||||
kerb5Config = ConfigurationHelper.getStringProperty(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, TransportConstants.DEFAULT_SSL_KRB5_CONFIG, configuration);
|
||||
|
||||
useDefaultSslContext = ConfigurationHelper.getBooleanProperty(TransportConstants.USE_DEFAULT_SSL_CONTEXT_PROP_NAME, TransportConstants.DEFAULT_USE_DEFAULT_SSL_CONTEXT, configuration);
|
||||
} else {
|
||||
keyStoreProvider = TransportConstants.DEFAULT_KEYSTORE_PROVIDER;
|
||||
|
@ -509,13 +521,36 @@ public class NettyConnector extends AbstractConnector {
|
|||
public void initChannel(Channel channel) throws Exception {
|
||||
final ChannelPipeline pipeline = channel.pipeline();
|
||||
if (sslEnabled && !useServlet) {
|
||||
SSLEngine engine;
|
||||
if (verifyHost) {
|
||||
engine = context.createSSLEngine(host, port);
|
||||
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null && kerb5Config.length() > 0) {
|
||||
|
||||
LoginContext loginContext = null;
|
||||
if (Character.isUpperCase(kerb5Config.charAt(0))) {
|
||||
// use as login.config scope
|
||||
loginContext = new LoginContext(kerb5Config);
|
||||
} else {
|
||||
engine = context.createSSLEngine();
|
||||
// inline keytab config using kerb5Config as principal
|
||||
loginContext = new LoginContext("", null, null,
|
||||
TransportConfigurationUtil.kerb5Config(kerb5Config, true));
|
||||
}
|
||||
|
||||
loginContext.login();
|
||||
subject = loginContext.getSubject();
|
||||
verifyHost = true;
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.createSSLEngine(sniHost != null ? sniHost : host, port);
|
||||
} else {
|
||||
return context.createSSLEngine();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
engine.setUseClientMode(true);
|
||||
|
||||
engine.setWantClientAuth(true);
|
||||
|
|
|
@ -27,6 +27,8 @@ public class TransportConstants {
|
|||
|
||||
public static final String SSL_ENABLED_PROP_NAME = "sslEnabled";
|
||||
|
||||
public static final String SSL_KRB5_CONFIG_PROP_NAME = "sslKrb5Config";
|
||||
|
||||
public static final String HTTP_ENABLED_PROP_NAME = "httpEnabled";
|
||||
|
||||
public static final String HTTP_CLIENT_IDLE_PROP_NAME = "httpClientIdleTime";
|
||||
|
@ -99,6 +101,8 @@ public class TransportConstants {
|
|||
|
||||
public static final String VERIFY_HOST_PROP_NAME = "verifyHost";
|
||||
|
||||
public static final String SNIHOST_PROP_NAME = "sniHost";
|
||||
|
||||
public static final String BACKLOG_PROP_NAME = "backlog";
|
||||
|
||||
public static final String USE_DEFAULT_SSL_CONTEXT_PROP_NAME = "useDefaultSslContext";
|
||||
|
@ -145,6 +149,10 @@ public class TransportConstants {
|
|||
|
||||
public static final boolean DEFAULT_SSL_ENABLED = false;
|
||||
|
||||
public static final String DEFAULT_SSL_KRB5_CONFIG = null;
|
||||
|
||||
public static final String DEFAULT_SNIHOST_CONFIG = null;
|
||||
|
||||
public static final boolean DEFAULT_USE_GLOBAL_WORKER_POOL = true;
|
||||
|
||||
public static final boolean DEFAULT_USE_EPOLL = true;
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-integ</artifactId>
|
||||
<artifactId>apacheds-test-framework</artifactId>
|
||||
<version>${directory-version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
|
@ -105,18 +105,11 @@
|
|||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core-integ</artifactId>
|
||||
<version>${directory-version}</version>
|
||||
<groupId>org.apache.directory.jdbm</groupId>
|
||||
<artifactId>apacheds-jdbm2</artifactId>
|
||||
<version>${directory-jdbm2-version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>artemis-commons</artifactId>
|
||||
|
|
|
@ -20,10 +20,13 @@ import javax.net.ssl.SSLContext;
|
|||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -68,6 +71,7 @@ import org.apache.activemq.artemis.api.core.management.CoreNotificationType;
|
|||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl;
|
||||
import org.apache.activemq.artemis.core.protocol.ProtocolHandler;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.AbstractAcceptor;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.TransportConfigurationUtil;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.ssl.SSLSupport;
|
||||
import org.apache.activemq.artemis.core.security.ActiveMQPrincipal;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
||||
|
@ -154,6 +158,8 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
|
||||
private final boolean verifyHost;
|
||||
|
||||
private final String kerb5Config;
|
||||
|
||||
private final boolean tcpNoDelay;
|
||||
|
||||
private final int backlog;
|
||||
|
@ -217,6 +223,8 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
|
||||
sslEnabled = ConfigurationHelper.getBooleanProperty(TransportConstants.SSL_ENABLED_PROP_NAME, TransportConstants.DEFAULT_SSL_ENABLED, configuration);
|
||||
|
||||
kerb5Config = ConfigurationHelper.getStringProperty(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, TransportConstants.DEFAULT_SSL_KRB5_CONFIG, configuration);
|
||||
|
||||
remotingThreads = ConfigurationHelper.getIntProperty(TransportConstants.NIO_REMOTING_THREADS_PROPNAME, -1, configuration);
|
||||
remotingThreads = ConfigurationHelper.getIntProperty(TransportConstants.REMOTING_THREADS_PROPNAME, remotingThreads, configuration);
|
||||
|
||||
|
@ -423,7 +431,7 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
public synchronized SslHandler getSslHandler() throws Exception {
|
||||
final SSLContext context;
|
||||
try {
|
||||
if (keyStorePath == null && TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER.equals(keyStoreProvider))
|
||||
if (kerb5Config == null && keyStorePath == null && TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER.equals(keyStoreProvider))
|
||||
throw new IllegalArgumentException("If \"" + TransportConstants.SSL_ENABLED_PROP_NAME +
|
||||
"\" is true then \"" + TransportConstants.KEYSTORE_PATH_PROP_NAME + "\" must be non-null " +
|
||||
"unless an alternative \"" + TransportConstants.KEYSTORE_PROVIDER_PROP_NAME + "\" has been specified.");
|
||||
|
@ -433,12 +441,31 @@ public class NettyAcceptor extends AbstractAcceptor {
|
|||
ise.initCause(e);
|
||||
throw ise;
|
||||
}
|
||||
SSLEngine engine;
|
||||
if (verifyHost) {
|
||||
engine = context.createSSLEngine(host, port);
|
||||
Subject subject = null;
|
||||
if (kerb5Config != null && kerb5Config.length() > 0) {
|
||||
LoginContext loginContext = null;
|
||||
if (Character.isUpperCase(kerb5Config.charAt(0))) {
|
||||
// use as login.config scope
|
||||
loginContext = new LoginContext(kerb5Config);
|
||||
} else {
|
||||
engine = context.createSSLEngine();
|
||||
loginContext = new LoginContext("", null, null,
|
||||
TransportConfigurationUtil.kerb5Config(kerb5Config, false));
|
||||
}
|
||||
loginContext.login();
|
||||
|
||||
subject = loginContext.getSubject();
|
||||
}
|
||||
|
||||
SSLEngine engine = Subject.doAs(subject, new PrivilegedExceptionAction<SSLEngine>() {
|
||||
@Override
|
||||
public SSLEngine run() {
|
||||
if (verifyHost) {
|
||||
return context.createSSLEngine(host, port);
|
||||
} else {
|
||||
return context.createSSLEngine();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
engine.setUseClientMode(false);
|
||||
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -164,7 +164,9 @@
|
|||
|
||||
<javac-compiler-id>javac-with-errorprone</javac-compiler-id>
|
||||
|
||||
<directory-version>1.5.7</directory-version>
|
||||
<directory-version>2.0.0-M15</directory-version>
|
||||
<directory-jdbm2-version>2.0.0-M1</directory-jdbm2-version>
|
||||
|
||||
<cdi-api.version>1.2</cdi-api.version>
|
||||
<geronimo-annotation_1.2_spec.version>1.0</geronimo-annotation_1.2_spec.version>
|
||||
</properties>
|
||||
|
|
|
@ -249,13 +249,19 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-integ</artifactId>
|
||||
<artifactId>apacheds-test-framework</artifactId>
|
||||
<version>${directory-version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.directory.api</groupId>
|
||||
<artifactId>api-ldap-schema-data</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core-integ</artifactId>
|
||||
<artifactId>apacheds-server-annotations</artifactId>
|
||||
<version>${directory-version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
|
@ -328,6 +334,18 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.hadoop</groupId>
|
||||
<artifactId>hadoop-minikdc</artifactId>
|
||||
<version>2.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.jdbm</groupId>
|
||||
<artifactId>apacheds-jdbm2</artifactId>
|
||||
<version>${directory-jdbm2-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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.activemq.artemis.tests.integration.ssl;
|
||||
|
||||
import org.apache.activemq.artemis.api.core.RoutingType;
|
||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientMessage;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientProducer;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||
import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
||||
import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
|
||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
|
||||
import org.apache.activemq.artemis.core.security.Role;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.utils.RandomUtil;
|
||||
import org.apache.hadoop.minikdc.MiniKdc;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CoreClientOverOneWaySSLKerb5Test extends ActiveMQTestBase {
|
||||
|
||||
public static final SimpleString QUEUE = new SimpleString("QueueOverKrb5SSL");
|
||||
public static final String CLIENT_PRINCIPAL = "client";
|
||||
public static final String SNI_HOST = "sni.host";
|
||||
public static final String SERVICE_PRINCIPAL = "host/" + SNI_HOST;
|
||||
|
||||
private MiniKdc kdc;
|
||||
private ActiveMQServer server;
|
||||
|
||||
private TransportConfiguration tc;
|
||||
|
||||
@Test
|
||||
public void testOneWaySSLWithGoodClientCipherSuite() throws Exception {
|
||||
|
||||
// hard coded match, default_keytab_name in minikdc-krb5.conf template
|
||||
File userKeyTab = new File("target/test.krb5.keytab");
|
||||
kdc.createPrincipal(userKeyTab, CLIENT_PRINCIPAL, SERVICE_PRINCIPAL);
|
||||
|
||||
createCustomSslServer();
|
||||
|
||||
tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
||||
tc.getParams().put(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, getSuitableCipherSuite());
|
||||
tc.getParams().put(TransportConstants.SNIHOST_PROP_NAME, SNI_HOST); // static service name rather than dynamic machine name
|
||||
tc.getParams().put(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, "client"); // lower case used as principal with default keytab
|
||||
final ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
|
||||
|
||||
ClientSessionFactory sf = null;
|
||||
try {
|
||||
sf = createSessionFactory(locator);
|
||||
ClientSession session = sf.createSession(false, true, true);
|
||||
session.createQueue(CoreClientOverOneWaySSLKerb5Test.QUEUE, RoutingType.ANYCAST, CoreClientOverOneWaySSLKerb5Test.QUEUE);
|
||||
ClientProducer producer = session.createProducer(CoreClientOverOneWaySSLKerb5Test.QUEUE);
|
||||
|
||||
final String text = RandomUtil.randomString();
|
||||
ClientMessage message = createTextMessage(session, text);
|
||||
producer.send(message);
|
||||
|
||||
ClientConsumer consumer = session.createConsumer(CoreClientOverOneWaySSLKerb5Test.QUEUE);
|
||||
session.start();
|
||||
|
||||
ClientMessage m = consumer.receive(1000);
|
||||
Assert.assertNotNull(m);
|
||||
Assert.assertEquals(text, m.getReadOnlyBodyBuffer().readString());
|
||||
System.err.println("m:" + m + ", user:" + m.getValidatedUserID());
|
||||
Assert.assertNotNull("got validated user", m.getValidatedUserID());
|
||||
Assert.assertTrue("krb id in validated user", m.getValidatedUserID().contains(CLIENT_PRINCIPAL));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
} finally {
|
||||
if (sf != null) {
|
||||
sf.close();
|
||||
}
|
||||
locator.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getSuitableCipherSuite() throws Exception {
|
||||
return "TLS_KRB5_WITH_3DES_EDE_CBC_SHA";
|
||||
}
|
||||
|
||||
|
||||
// Package protected ---------------------------------------------
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
kdc = new MiniKdc(MiniKdc.createConf(), temporaryFolder.newFolder("kdc"));
|
||||
kdc.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
try {
|
||||
kdc.stop();
|
||||
} finally {
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
private void createCustomSslServer() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
|
||||
params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
||||
params.put(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, getSuitableCipherSuite());
|
||||
params.put(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, SERVICE_PRINCIPAL);
|
||||
|
||||
ConfigurationImpl config = createBasicConfig().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params, "nettySSL"));
|
||||
config.setPopulateValidatedUser(true); // so we can verify the kerb5 id is present
|
||||
config.setSecurityEnabled(true);
|
||||
|
||||
server = createServer(false, config);
|
||||
server.start();
|
||||
waitForServerToStart(server);
|
||||
|
||||
final String roleName = "ALLOW_ALL";
|
||||
Role role = new Role(roleName, true, true, true, true, true, true, true, true, true, true);
|
||||
Set<Role> roles = new HashSet<>();
|
||||
roles.add(role);
|
||||
HierarchicalRepository<Set<Role>> securityRepository = server.getSecurityRepository();
|
||||
securityRepository.addMatch(QUEUE.toString(), roles);
|
||||
ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager();
|
||||
|
||||
final String user = CLIENT_PRINCIPAL + "@" + kdc.getRealm();
|
||||
securityManager.getConfiguration().addUser(user, "");
|
||||
securityManager.getConfiguration().addRole(user, roleName);
|
||||
|
||||
tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# 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]
|
||||
default_realm = {0}
|
||||
udp_preference_limit = 1
|
||||
default_keytab_name = FILE:target/test.krb5.keytab
|
||||
|
||||
[realms]
|
||||
{0} = '{'
|
||||
kdc = {1}:{2}
|
||||
'}'
|
Loading…
Reference in New Issue