This closes #1449
This commit is contained in:
commit
d0a9d017dd
|
@ -20,6 +20,7 @@ package org.apache.activemq.artemis.core.remoting;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
import io.netty.handler.ssl.SslHandler;
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnection;
|
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnection;
|
||||||
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||||
|
|
||||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||||
|
@ -28,24 +29,30 @@ import java.security.Principal;
|
||||||
|
|
||||||
public class CertificateUtil {
|
public class CertificateUtil {
|
||||||
|
|
||||||
public static X509Certificate[] getCertsFromConnection(Connection connection) {
|
public static X509Certificate[] getCertsFromConnection(RemotingConnection remotingConnection) {
|
||||||
X509Certificate[] certificates = null;
|
X509Certificate[] certificates = null;
|
||||||
if (connection instanceof NettyConnection) {
|
if (remotingConnection != null) {
|
||||||
certificates = org.apache.activemq.artemis.utils.CertificateUtil.getCertsFromChannel(((NettyConnection) connection).getChannel());
|
Connection transportConnection = remotingConnection.getTransportConnection();
|
||||||
|
if (transportConnection instanceof NettyConnection) {
|
||||||
|
certificates = org.apache.activemq.artemis.utils.CertificateUtil.getCertsFromChannel(((NettyConnection) transportConnection).getChannel());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return certificates;
|
return certificates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Principal getPeerPrincipalFromConnection(Connection connection) {
|
public static Principal getPeerPrincipalFromConnection(RemotingConnection remotingConnection) {
|
||||||
Principal result = null;
|
Principal result = null;
|
||||||
if (connection instanceof NettyConnection) {
|
if (remotingConnection != null) {
|
||||||
NettyConnection nettyConnection = (NettyConnection) connection;
|
Connection transportConnection = remotingConnection.getTransportConnection();
|
||||||
ChannelHandler channelHandler = nettyConnection.getChannel().pipeline().get("ssl");
|
if (transportConnection instanceof NettyConnection) {
|
||||||
if (channelHandler != null && channelHandler instanceof SslHandler) {
|
NettyConnection nettyConnection = (NettyConnection) transportConnection;
|
||||||
SslHandler sslHandler = (SslHandler) channelHandler;
|
ChannelHandler channelHandler = nettyConnection.getChannel().pipeline().get("ssl");
|
||||||
try {
|
if (channelHandler != null && channelHandler instanceof SslHandler) {
|
||||||
result = sslHandler.engine().getSession().getPeerPrincipal();
|
SslHandler sslHandler = (SslHandler) channelHandler;
|
||||||
} catch (SSLPeerUnverifiedException ignored) {
|
try {
|
||||||
|
result = sslHandler.engine().getSession().getPeerPrincipal();
|
||||||
|
} catch (SSLPeerUnverifiedException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,6 @@ 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.core.remoting.impl.netty.TransportConstants;
|
||||||
import org.apache.activemq.artemis.utils.ClassloadingUtil;
|
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
|
* Stores static mappings of class names to ConnectorFactory instances to act as a central repo for ConnectorFactory
|
||||||
* objects.
|
* objects.
|
||||||
|
@ -99,28 +96,4 @@ public class TransportConfigurationUtil {
|
||||||
return false;
|
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)};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -98,7 +98,6 @@ import org.apache.activemq.artemis.api.core.ActiveMQException;
|
||||||
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
||||||
import org.apache.activemq.artemis.core.client.ActiveMQClientMessageBundle;
|
import org.apache.activemq.artemis.core.client.ActiveMQClientMessageBundle;
|
||||||
import org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQClientProtocolManager;
|
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.remoting.impl.ssl.SSLSupport;
|
||||||
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.AbstractConnector;
|
import org.apache.activemq.artemis.spi.core.remoting.AbstractConnector;
|
||||||
|
@ -523,18 +522,8 @@ public class NettyConnector extends AbstractConnector {
|
||||||
if (sslEnabled && !useServlet) {
|
if (sslEnabled && !useServlet) {
|
||||||
|
|
||||||
Subject subject = null;
|
Subject subject = null;
|
||||||
if (kerb5Config != null && kerb5Config.length() > 0) {
|
if (kerb5Config != null) {
|
||||||
|
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||||
LoginContext loginContext = null;
|
|
||||||
if (Character.isUpperCase(kerb5Config.charAt(0))) {
|
|
||||||
// use as login.config scope
|
|
||||||
loginContext = new LoginContext(kerb5Config);
|
|
||||||
} else {
|
|
||||||
// inline keytab config using kerb5Config as principal
|
|
||||||
loginContext = new LoginContext("", null, null,
|
|
||||||
TransportConfigurationUtil.kerb5Config(kerb5Config, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
loginContext.login();
|
loginContext.login();
|
||||||
subject = loginContext.getSubject();
|
subject = loginContext.getSubject();
|
||||||
verifyHost = true;
|
verifyHost = true;
|
||||||
|
|
|
@ -32,6 +32,8 @@ import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
public abstract class AbstractRemotingConnection implements RemotingConnection {
|
public abstract class AbstractRemotingConnection implements RemotingConnection {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AbstractRemotingConnection.class);
|
private static final Logger logger = Logger.getLogger(AbstractRemotingConnection.class);
|
||||||
|
@ -219,4 +221,9 @@ public abstract class AbstractRemotingConnection implements RemotingConnection {
|
||||||
public boolean isSupportsFlowControl() {
|
public boolean isSupportsFlowControl() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject getSubject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ import org.apache.activemq.artemis.spi.core.remoting.BufferHandler;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A RemotingConnection is a connection between a client and a server.
|
* A RemotingConnection is a connection between a client and a server.
|
||||||
*
|
*
|
||||||
|
@ -206,4 +208,10 @@ public interface RemotingConnection extends BufferHandler {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean isSupportsFlowControl();
|
boolean isSupportsFlowControl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the possibly null identity associated with this connection
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Subject getSubject();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.transaction.ProtonTransactionImpl;
|
import org.apache.activemq.artemis.protocol.amqp.proton.transaction.ProtonTransactionImpl;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.handler.ExtCapability;
|
import org.apache.activemq.artemis.protocol.amqp.proton.handler.ExtCapability;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.sasl.AnonymousServerSASL;
|
import org.apache.activemq.artemis.protocol.amqp.sasl.AnonymousServerSASL;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.sasl.GSSAPIServerSASL;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.sasl.PlainSASL;
|
import org.apache.activemq.artemis.protocol.amqp.sasl.PlainSASL;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.sasl.SASLResult;
|
import org.apache.activemq.artemis.protocol.amqp.sasl.SASLResult;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.sasl.ServerSASL;
|
import org.apache.activemq.artemis.protocol.amqp.sasl.ServerSASL;
|
||||||
|
@ -76,6 +77,8 @@ public class AMQPConnectionCallback implements FailureListener, CloseListener {
|
||||||
|
|
||||||
private ActiveMQServer server;
|
private ActiveMQServer server;
|
||||||
|
|
||||||
|
private final String[] saslMechanisms;
|
||||||
|
|
||||||
public AMQPConnectionCallback(ProtonProtocolManager manager,
|
public AMQPConnectionCallback(ProtonProtocolManager manager,
|
||||||
Connection connection,
|
Connection connection,
|
||||||
Executor closeExecutor,
|
Executor closeExecutor,
|
||||||
|
@ -84,25 +87,40 @@ public class AMQPConnectionCallback implements FailureListener, CloseListener {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.closeExecutor = closeExecutor;
|
this.closeExecutor = closeExecutor;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
saslMechanisms = manager.getSaslMechanisms();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerSASL[] getSASLMechnisms() {
|
public String[] getSaslMechanisms() {
|
||||||
|
return saslMechanisms;
|
||||||
|
}
|
||||||
|
|
||||||
ServerSASL[] result;
|
public ServerSASL getServerSASL(final String mechanism) {
|
||||||
|
ServerSASL result = null;
|
||||||
|
switch (mechanism) {
|
||||||
|
case PlainSASL.NAME:
|
||||||
|
result = new PlainSASL(server.getSecurityStore());
|
||||||
|
break;
|
||||||
|
|
||||||
if (isSupportsAnonymous()) {
|
case AnonymousServerSASL.NAME:
|
||||||
result = new ServerSASL[]{new PlainSASL(manager.getServer().getSecurityStore()), new AnonymousServerSASL()};
|
result = new AnonymousServerSASL();
|
||||||
} else {
|
break;
|
||||||
result = new ServerSASL[]{new PlainSASL(manager.getServer().getSecurityStore())};
|
|
||||||
|
case GSSAPIServerSASL.NAME:
|
||||||
|
GSSAPIServerSASL gssapiServerSASL = new GSSAPIServerSASL();
|
||||||
|
gssapiServerSASL.setLoginConfigScope(manager.getSaslLoginConfigScope());
|
||||||
|
result = gssapiServerSASL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSupportsAnonymous() {
|
public boolean isSupportsAnonymous() {
|
||||||
boolean supportsAnonymous = false;
|
boolean supportsAnonymous = false;
|
||||||
try {
|
try {
|
||||||
manager.getServer().getSecurityStore().authenticate(null, null, null);
|
server.getSecurityStore().authenticate(null, null, null);
|
||||||
supportsAnonymous = true;
|
supportsAnonymous = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// authentication failed so no anonymous support
|
// authentication failed so no anonymous support
|
||||||
|
|
|
@ -25,10 +25,13 @@ import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
import org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConnectionContext;
|
import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConnectionContext;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport;
|
import org.apache.activemq.artemis.protocol.amqp.proton.AmqpSupport;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.sasl.SASLResult;
|
||||||
import org.apache.activemq.artemis.spi.core.protocol.AbstractRemotingConnection;
|
import org.apache.activemq.artemis.spi.core.protocol.AbstractRemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||||
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
|
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a Server's Connection representation used by ActiveMQ Artemis.
|
* This is a Server's Connection representation used by ActiveMQ Artemis.
|
||||||
*/
|
*/
|
||||||
|
@ -148,4 +151,13 @@ public class ActiveMQProtonRemotingConnection extends AbstractRemotingConnection
|
||||||
public void killMessage(SimpleString nodeID) {
|
public void killMessage(SimpleString nodeID) {
|
||||||
//unsupported
|
//unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject getSubject() {
|
||||||
|
SASLResult saslResult = amqpConnection.getSASLResult();
|
||||||
|
if (saslResult != null) {
|
||||||
|
return saslResult.getSubject();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.apache.activemq.artemis.core.server.management.NotificationListener;
|
||||||
import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
|
import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConnectionContext;
|
import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConnectionContext;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConstants;
|
import org.apache.activemq.artemis.protocol.amqp.proton.AMQPConstants;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.sasl.MechanismFinder;
|
||||||
import org.apache.activemq.artemis.spi.core.protocol.AbstractProtocolManager;
|
import org.apache.activemq.artemis.spi.core.protocol.AbstractProtocolManager;
|
||||||
import org.apache.activemq.artemis.spi.core.protocol.ConnectionEntry;
|
import org.apache.activemq.artemis.spi.core.protocol.ConnectionEntry;
|
||||||
import org.apache.activemq.artemis.spi.core.protocol.ProtocolManagerFactory;
|
import org.apache.activemq.artemis.spi.core.protocol.ProtocolManagerFactory;
|
||||||
|
@ -63,6 +64,12 @@ public class ProtonProtocolManager extends AbstractProtocolManager<AMQPMessage,
|
||||||
|
|
||||||
private int amqpLowCredits = 30;
|
private int amqpLowCredits = 30;
|
||||||
|
|
||||||
|
private int initialRemoteMaxFrameSize = 4 * 1024;
|
||||||
|
|
||||||
|
private String[] saslMechanisms = MechanismFinder.getKnownMechanisms();
|
||||||
|
|
||||||
|
private String saslLoginConfigScope = "amqp-sasl-gssapi";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* used when you want to treat senders as a subscription on an address rather than consuming from the actual queue for
|
* used when you want to treat senders as a subscription on an address rather than consuming from the actual queue for
|
||||||
* the address. This can be changed on the acceptor.
|
* the address. This can be changed on the acceptor.
|
||||||
|
@ -197,6 +204,23 @@ public class ProtonProtocolManager extends AbstractProtocolManager<AMQPMessage,
|
||||||
this.maxFrameSize = maxFrameSize;
|
this.maxFrameSize = maxFrameSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getSaslMechanisms() {
|
||||||
|
return saslMechanisms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSaslMechanisms(String[] saslMechanisms) {
|
||||||
|
this.saslMechanisms = saslMechanisms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSaslLoginConfigScope() {
|
||||||
|
return saslLoginConfigScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSaslLoginConfigScope(String saslLoginConfigScope) {
|
||||||
|
this.saslLoginConfigScope = saslLoginConfigScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAnycastPrefix(String anycastPrefix) {
|
public void setAnycastPrefix(String anycastPrefix) {
|
||||||
for (String prefix : anycastPrefix.split(",")) {
|
for (String prefix : anycastPrefix.split(",")) {
|
||||||
|
@ -223,4 +247,13 @@ public class ProtonProtocolManager extends AbstractProtocolManager<AMQPMessage,
|
||||||
public void invokeOutgoing(AMQPMessage message, ActiveMQProtonRemotingConnection connection) {
|
public void invokeOutgoing(AMQPMessage message, ActiveMQProtonRemotingConnection connection) {
|
||||||
super.invokeInterceptors(this.outgoingInterceptors, message, connection);
|
super.invokeInterceptors(this.outgoingInterceptors, message, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getInitialRemoteMaxFrameSize() {
|
||||||
|
return initialRemoteMaxFrameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitialRemoteMaxFrameSize(int initialRemoteMaxFrameSize) {
|
||||||
|
this.initialRemoteMaxFrameSize = initialRemoteMaxFrameSize;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPExceptio
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.handler.EventHandler;
|
import org.apache.activemq.artemis.protocol.amqp.proton.handler.EventHandler;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.handler.ExtCapability;
|
import org.apache.activemq.artemis.protocol.amqp.proton.handler.ExtCapability;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.proton.handler.ProtonHandler;
|
import org.apache.activemq.artemis.protocol.amqp.proton.handler.ProtonHandler;
|
||||||
|
import org.apache.activemq.artemis.protocol.amqp.sasl.AnonymousServerSASL;
|
||||||
import org.apache.activemq.artemis.protocol.amqp.sasl.SASLResult;
|
import org.apache.activemq.artemis.protocol.amqp.sasl.SASLResult;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
||||||
import org.apache.activemq.artemis.utils.ByteUtil;
|
import org.apache.activemq.artemis.utils.ByteUtil;
|
||||||
|
@ -103,6 +104,7 @@ public class AMQPConnectionContext extends ProtonInitializable implements EventH
|
||||||
transport.setIdleTimeout(idleTimeout);
|
transport.setIdleTimeout(idleTimeout);
|
||||||
}
|
}
|
||||||
transport.setChannelMax(channelMax);
|
transport.setChannelMax(channelMax);
|
||||||
|
transport.setInitialRemoteMaxFrameSize(protocolManager.getInitialRemoteMaxFrameSize());
|
||||||
transport.setMaxFrameSize(maxFrameSize);
|
transport.setMaxFrameSize(maxFrameSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +323,12 @@ public class AMQPConnectionContext extends ProtonInitializable implements EventH
|
||||||
@Override
|
@Override
|
||||||
public void onAuthInit(ProtonHandler handler, Connection connection, boolean sasl) {
|
public void onAuthInit(ProtonHandler handler, Connection connection, boolean sasl) {
|
||||||
if (sasl) {
|
if (sasl) {
|
||||||
handler.createServerSASL(connectionCallback.getSASLMechnisms());
|
// configured mech in decreasing order of preference
|
||||||
|
String[] mechanisms = connectionCallback.getSaslMechanisms();
|
||||||
|
if (mechanisms == null || mechanisms.length == 0) {
|
||||||
|
mechanisms = AnonymousServerSASL.ANONYMOUS_MECH;
|
||||||
|
}
|
||||||
|
handler.createServerSASL(mechanisms);
|
||||||
} else {
|
} else {
|
||||||
if (!connectionCallback.isSupportsAnonymous()) {
|
if (!connectionCallback.isSupportsAnonymous()) {
|
||||||
connectionCallback.sendSASLSupported();
|
connectionCallback.sendSASLSupported();
|
||||||
|
@ -331,6 +338,11 @@ public class AMQPConnectionContext extends ProtonInitializable implements EventH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaslRemoteMechanismChosen(ProtonHandler handler, String mech) {
|
||||||
|
handler.setChosenMechanism(connectionCallback.getServerSASL(mech));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTransport(Transport transport) {
|
public void onTransport(Transport transport) {
|
||||||
handler.flushBytes();
|
handler.flushBytes();
|
||||||
|
|
|
@ -31,6 +31,8 @@ public interface EventHandler {
|
||||||
|
|
||||||
void onAuthInit(ProtonHandler handler, Connection connection, boolean sasl);
|
void onAuthInit(ProtonHandler handler, Connection connection, boolean sasl);
|
||||||
|
|
||||||
|
void onSaslRemoteMechanismChosen(ProtonHandler handler, String mech);
|
||||||
|
|
||||||
void onInit(Connection connection) throws Exception;
|
void onInit(Connection connection) throws Exception;
|
||||||
|
|
||||||
void onLocalOpen(Connection connection) throws Exception;
|
void onLocalOpen(Connection connection) throws Exception;
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.apache.activemq.artemis.protocol.amqp.proton.handler;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
@ -63,12 +62,12 @@ public class ProtonHandler extends ProtonInitializable {
|
||||||
|
|
||||||
private Sasl serverSasl;
|
private Sasl serverSasl;
|
||||||
|
|
||||||
|
private ServerSASL chosenMechanism;
|
||||||
|
|
||||||
private final ReentrantLock lock = new ReentrantLock();
|
private final ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
private final long creationTime;
|
private final long creationTime;
|
||||||
|
|
||||||
private Map<String, ServerSASL> saslHandlers;
|
|
||||||
|
|
||||||
private SASLResult saslResult;
|
private SASLResult saslResult;
|
||||||
|
|
||||||
protected volatile boolean dataReceived;
|
protected volatile boolean dataReceived;
|
||||||
|
@ -157,17 +156,10 @@ public class ProtonHandler extends ProtonInitializable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createServerSASL(ServerSASL[] handlers) {
|
public void createServerSASL(String[] mechanisms) {
|
||||||
this.serverSasl = transport.sasl();
|
this.serverSasl = transport.sasl();
|
||||||
saslHandlers = new HashMap<>();
|
|
||||||
String[] names = new String[handlers.length];
|
|
||||||
int count = 0;
|
|
||||||
for (ServerSASL handler : handlers) {
|
|
||||||
saslHandlers.put(handler.getName(), handler);
|
|
||||||
names[count++] = handler.getName();
|
|
||||||
}
|
|
||||||
this.serverSasl.server();
|
this.serverSasl.server();
|
||||||
serverSasl.setMechanisms(names);
|
serverSasl.setMechanisms(mechanisms);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushBytes() {
|
public void flushBytes() {
|
||||||
|
@ -292,9 +284,14 @@ public class ProtonHandler extends ProtonInitializable {
|
||||||
|
|
||||||
protected void checkServerSASL() {
|
protected void checkServerSASL() {
|
||||||
if (serverSasl != null && serverSasl.getRemoteMechanisms().length > 0) {
|
if (serverSasl != null && serverSasl.getRemoteMechanisms().length > 0) {
|
||||||
// TODO: should we look at the first only?
|
|
||||||
ServerSASL mechanism = saslHandlers.get(serverSasl.getRemoteMechanisms()[0]);
|
if (chosenMechanism == null) {
|
||||||
if (mechanism != null) {
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace("SASL chosenMechanism: " + serverSasl.getRemoteMechanisms()[0]);
|
||||||
|
}
|
||||||
|
dispatchRemoteMechanismChosen(serverSasl.getRemoteMechanisms()[0]);
|
||||||
|
}
|
||||||
|
if (chosenMechanism != null) {
|
||||||
|
|
||||||
byte[] dataSASL = new byte[serverSasl.pending()];
|
byte[] dataSASL = new byte[serverSasl.pending()];
|
||||||
serverSasl.recv(dataSASL, 0, dataSASL.length);
|
serverSasl.recv(dataSASL, 0, dataSASL.length);
|
||||||
|
@ -303,30 +300,46 @@ public class ProtonHandler extends ProtonInitializable {
|
||||||
log.trace("Working on sasl::" + (dataSASL != null && dataSASL.length > 0 ? ByteUtil.bytesToHex(dataSASL, 2) : "Anonymous"));
|
log.trace("Working on sasl::" + (dataSASL != null && dataSASL.length > 0 ? ByteUtil.bytesToHex(dataSASL, 2) : "Anonymous"));
|
||||||
}
|
}
|
||||||
|
|
||||||
saslResult = mechanism.processSASL(dataSASL);
|
byte[] response = chosenMechanism.processSASL(dataSASL);
|
||||||
|
if (response != null) {
|
||||||
if (saslResult != null && saslResult.isSuccess()) {
|
serverSasl.send(response, 0, response.length);
|
||||||
serverSasl.done(Sasl.SaslOutcome.PN_SASL_OK);
|
}
|
||||||
serverSasl = null;
|
saslResult = chosenMechanism.result();
|
||||||
saslHandlers.clear();
|
|
||||||
saslHandlers = null;
|
if (saslResult != null) {
|
||||||
} else {
|
if (saslResult.isSuccess()) {
|
||||||
serverSasl.done(Sasl.SaslOutcome.PN_SASL_AUTH);
|
saslComplete(Sasl.SaslOutcome.PN_SASL_OK);
|
||||||
|
} else {
|
||||||
|
saslComplete(Sasl.SaslOutcome.PN_SASL_AUTH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
serverSasl = null;
|
|
||||||
} else {
|
} else {
|
||||||
// no auth available, system error
|
// no auth available, system error
|
||||||
serverSasl.done(Sasl.SaslOutcome.PN_SASL_SYS);
|
saslComplete(Sasl.SaslOutcome.PN_SASL_SYS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saslComplete(Sasl.SaslOutcome saslOutcome) {
|
||||||
|
serverSasl.done(saslOutcome);
|
||||||
|
serverSasl = null;
|
||||||
|
if (chosenMechanism != null) {
|
||||||
|
chosenMechanism.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void dispatchAuth(boolean sasl) {
|
private void dispatchAuth(boolean sasl) {
|
||||||
for (EventHandler h : handlers) {
|
for (EventHandler h : handlers) {
|
||||||
h.onAuthInit(this, getConnection(), sasl);
|
h.onAuthInit(this, getConnection(), sasl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dispatchRemoteMechanismChosen(final String mech) {
|
||||||
|
for (EventHandler h : handlers) {
|
||||||
|
h.onSaslRemoteMechanismChosen(this, mech);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void dispatch() {
|
private void dispatch() {
|
||||||
Event ev;
|
Event ev;
|
||||||
|
|
||||||
|
@ -376,4 +389,8 @@ public class ProtonHandler extends ProtonInitializable {
|
||||||
this.connection.open();
|
this.connection.open();
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setChosenMechanism(ServerSASL chosenMechanism) {
|
||||||
|
this.chosenMechanism = chosenMechanism;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,29 @@ package org.apache.activemq.artemis.protocol.amqp.sasl;
|
||||||
|
|
||||||
public class AnonymousServerSASL implements ServerSASL {
|
public class AnonymousServerSASL implements ServerSASL {
|
||||||
|
|
||||||
|
public static final String NAME = "ANONYMOUS";
|
||||||
|
public static final String[] ANONYMOUS_MECH = new String[] {NAME};
|
||||||
|
|
||||||
public AnonymousServerSASL() {
|
public AnonymousServerSASL() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "ANONYMOUS";
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SASLResult processSASL(byte[] bytes) {
|
public byte[] processSASL(byte[] bytes) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SASLResult result() {
|
||||||
return new PlainSASLResult(true, null, null);
|
return new PlainSASLResult(true, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void done() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.sasl;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
public class GSSAPISASLResult implements SASLResult {
|
||||||
|
|
||||||
|
private final boolean success;
|
||||||
|
private final Subject identity = new Subject();
|
||||||
|
private String user;
|
||||||
|
|
||||||
|
|
||||||
|
public GSSAPISASLResult(boolean success, Principal peer) {
|
||||||
|
this.success = success;
|
||||||
|
if (success) {
|
||||||
|
this.identity.getPrivateCredentials().add(peer);
|
||||||
|
this.user = peer.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject getSubject() {
|
||||||
|
return identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* 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.protocol.amqp.sasl;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
import javax.security.auth.callback.Callback;
|
||||||
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
|
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
|
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||||
|
import javax.security.auth.login.LoginContext;
|
||||||
|
import javax.security.sasl.AuthorizeCallback;
|
||||||
|
import javax.security.sasl.Sasl;
|
||||||
|
import javax.security.sasl.SaslException;
|
||||||
|
import javax.security.sasl.SaslServer;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* delegate the the jdk GSSAPI support
|
||||||
|
*/
|
||||||
|
public class GSSAPIServerSASL implements ServerSASL {
|
||||||
|
private static final Logger log = Logger.getLogger(GSSAPIServerSASL.class);
|
||||||
|
|
||||||
|
public static final String NAME = "GSSAPI";
|
||||||
|
private String loginConfigScope;
|
||||||
|
private SaslServer saslServer;
|
||||||
|
private Subject jaasId;
|
||||||
|
private SASLResult result;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] processSASL(byte[] bytes) {
|
||||||
|
try {
|
||||||
|
if (jaasId == null) {
|
||||||
|
// populate subject with acceptor private credentials
|
||||||
|
LoginContext loginContext = new LoginContext(loginConfigScope);
|
||||||
|
loginContext.login();
|
||||||
|
jaasId = loginContext.getSubject();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saslServer == null) {
|
||||||
|
saslServer = Subject.doAs(jaasId, (PrivilegedExceptionAction<SaslServer>) () -> Sasl.createSaslServer(NAME, null, null, new HashMap<String, String>(), new CallbackHandler() {
|
||||||
|
@Override
|
||||||
|
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
||||||
|
for (Callback callback : callbacks) {
|
||||||
|
if (callback instanceof AuthorizeCallback) {
|
||||||
|
AuthorizeCallback authorizeCallback = (AuthorizeCallback) callback;
|
||||||
|
// only ok to authenticate as self
|
||||||
|
authorizeCallback.setAuthorized(authorizeCallback.getAuthenticationID().equals(authorizeCallback.getAuthorizationID()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] challenge = Subject.doAs(jaasId, (PrivilegedExceptionAction<byte[]>) () -> saslServer.evaluateResponse(bytes));
|
||||||
|
if (saslServer.isComplete()) {
|
||||||
|
result = new GSSAPISASLResult(true, new KerberosPrincipal(saslServer.getAuthorizationID()));
|
||||||
|
}
|
||||||
|
return challenge;
|
||||||
|
|
||||||
|
} catch (Exception outOfHere) {
|
||||||
|
log.info("Error on sasl input: " + outOfHere.toString(), outOfHere);
|
||||||
|
result = new GSSAPISASLResult(false, null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SASLResult result() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void done() {
|
||||||
|
if (saslServer != null) {
|
||||||
|
try {
|
||||||
|
saslServer.dispose();
|
||||||
|
} catch (SaslException error) {
|
||||||
|
log.debug("Exception on sasl dispose", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLoginConfigScope() {
|
||||||
|
return loginConfigScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoginConfigScope(String loginConfigScope) {
|
||||||
|
this.loginConfigScope = loginConfigScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.protocol.amqp.sasl;
|
||||||
|
|
||||||
|
public class MechanismFinder {
|
||||||
|
|
||||||
|
public static String[] KNOWN_MECHANISMS = new String[]{PlainSASL.NAME, AnonymousServerSASL.NAME};
|
||||||
|
|
||||||
|
public static String[] getKnownMechanisms() {
|
||||||
|
return KNOWN_MECHANISMS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.sasl;
|
package org.apache.activemq.artemis.protocol.amqp.sasl;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
public class PlainSASLResult implements SASLResult {
|
public class PlainSASLResult implements SASLResult {
|
||||||
|
|
||||||
private boolean success;
|
private boolean success;
|
||||||
|
@ -28,6 +30,11 @@ public class PlainSASLResult implements SASLResult {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject getSubject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUser() {
|
public String getUser() {
|
||||||
return user;
|
return user;
|
||||||
|
@ -41,4 +48,5 @@ public class PlainSASLResult implements SASLResult {
|
||||||
public boolean isSuccess() {
|
public boolean isSuccess() {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.protocol.amqp.sasl;
|
package org.apache.activemq.artemis.protocol.amqp.sasl;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
public interface SASLResult {
|
public interface SASLResult {
|
||||||
|
|
||||||
String getUser();
|
String getUser();
|
||||||
|
|
||||||
|
Subject getSubject();
|
||||||
|
|
||||||
boolean isSuccess();
|
boolean isSuccess();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,5 +20,9 @@ public interface ServerSASL {
|
||||||
|
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
SASLResult processSASL(byte[] bytes);
|
byte[] processSASL(byte[] bytes);
|
||||||
|
|
||||||
|
SASLResult result();
|
||||||
|
|
||||||
|
void done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.activemq.artemis.protocol.amqp.sasl;
|
||||||
public class ServerSASLPlain implements ServerSASL {
|
public class ServerSASLPlain implements ServerSASL {
|
||||||
|
|
||||||
public static final String NAME = "PLAIN";
|
public static final String NAME = "PLAIN";
|
||||||
|
private SASLResult result = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -26,7 +27,7 @@ public class ServerSASLPlain implements ServerSASL {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SASLResult processSASL(byte[] data) {
|
public byte[] processSASL(byte[] data) {
|
||||||
String username = null;
|
String username = null;
|
||||||
String password = null;
|
String password = null;
|
||||||
String bytes = new String(data);
|
String bytes = new String(data);
|
||||||
|
@ -47,7 +48,18 @@ public class ServerSASLPlain implements ServerSASL {
|
||||||
|
|
||||||
boolean success = authenticate(username, password);
|
boolean success = authenticate(username, password);
|
||||||
|
|
||||||
return new PlainSASLResult(success, username, password);
|
result = new PlainSASLResult(success, username, password);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SASLResult result() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void done() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,7 +27,8 @@ public class PlainSASLTest {
|
||||||
byte[] bytesResult = plainSASL.getBytes();
|
byte[] bytesResult = plainSASL.getBytes();
|
||||||
|
|
||||||
ServerSASLPlain serverSASLPlain = new ServerSASLPlain();
|
ServerSASLPlain serverSASLPlain = new ServerSASLPlain();
|
||||||
PlainSASLResult result = (PlainSASLResult) serverSASLPlain.processSASL(bytesResult);
|
serverSASLPlain.processSASL(bytesResult);
|
||||||
|
PlainSASLResult result = (PlainSASLResult) serverSASLPlain.result();
|
||||||
Assert.assertEquals("user-me", result.getUser());
|
Assert.assertEquals("user-me", result.getUser());
|
||||||
Assert.assertEquals("password-secret", result.getPassword());
|
Assert.assertEquals("password-secret", result.getPassword());
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
public class MQTTConnection implements RemotingConnection {
|
public class MQTTConnection implements RemotingConnection {
|
||||||
|
|
||||||
private final Connection transportConnection;
|
private final Connection transportConnection;
|
||||||
|
@ -226,4 +228,9 @@ public class MQTTConnection implements RemotingConnection {
|
||||||
public boolean isSupportsFlowControl() {
|
public boolean isSupportsFlowControl() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject getSubject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,7 +459,7 @@ public class OpenWireProtocolManager implements ProtocolManager<Interceptor>, Cl
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateUser(String login, String passcode, OpenWireConnection connection) throws Exception {
|
public void validateUser(String login, String passcode, OpenWireConnection connection) throws Exception {
|
||||||
server.getSecurityStore().authenticate(login, passcode, connection.getTransportConnection());
|
server.getSecurityStore().authenticate(login, passcode, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendBrokerInfo(OpenWireConnection connection) throws Exception {
|
public void sendBrokerInfo(OpenWireConnection connection) throws Exception {
|
||||||
|
|
|
@ -51,6 +51,8 @@ import org.apache.activemq.artemis.utils.ConfigurationHelper;
|
||||||
import org.apache.activemq.artemis.utils.ExecutorFactory;
|
import org.apache.activemq.artemis.utils.ExecutorFactory;
|
||||||
import org.apache.activemq.artemis.utils.VersionLoader;
|
import org.apache.activemq.artemis.utils.VersionLoader;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
import static org.apache.activemq.artemis.core.protocol.stomp.ActiveMQStompProtocolMessageBundle.BUNDLE;
|
import static org.apache.activemq.artemis.core.protocol.stomp.ActiveMQStompProtocolMessageBundle.BUNDLE;
|
||||||
|
|
||||||
public final class StompConnection implements RemotingConnection {
|
public final class StompConnection implements RemotingConnection {
|
||||||
|
@ -560,7 +562,7 @@ public final class StompConnection implements RemotingConnection {
|
||||||
manager.sendReply(this, frame);
|
manager.sendReply(this, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateUser(final String login, final String pass, final Connection connection) {
|
public boolean validateUser(final String login, final String pass, final RemotingConnection connection) {
|
||||||
this.valid = manager.validateUser(login, pass, connection);
|
this.valid = manager.validateUser(login, pass, connection);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.login = login;
|
this.login = login;
|
||||||
|
@ -779,4 +781,9 @@ public final class StompConnection implements RemotingConnection {
|
||||||
public boolean isSupportsFlowControl() {
|
public boolean isSupportsFlowControl() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Subject getSubject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,16 +320,16 @@ public class StompProtocolManager extends AbstractProtocolManager<StompFrame, St
|
||||||
return "activemq";
|
return "activemq";
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean validateUser(String login, String passcode, Connection connection) {
|
public boolean validateUser(String login, String passcode, RemotingConnection remotingConnection) {
|
||||||
boolean validated = true;
|
boolean validated = true;
|
||||||
|
|
||||||
ActiveMQSecurityManager sm = server.getSecurityManager();
|
ActiveMQSecurityManager sm = server.getSecurityManager();
|
||||||
|
|
||||||
if (sm != null && server.getConfiguration().isSecurityEnabled()) {
|
if (sm != null && server.getConfiguration().isSecurityEnabled()) {
|
||||||
if (sm instanceof ActiveMQSecurityManager3) {
|
if (sm instanceof ActiveMQSecurityManager3) {
|
||||||
validated = ((ActiveMQSecurityManager3) sm).validateUser(login, passcode, connection) != null;
|
validated = ((ActiveMQSecurityManager3) sm).validateUser(login, passcode, remotingConnection) != null;
|
||||||
} else if (sm instanceof ActiveMQSecurityManager2) {
|
} else if (sm instanceof ActiveMQSecurityManager2) {
|
||||||
validated = ((ActiveMQSecurityManager2) sm).validateUser(login, passcode, CertificateUtil.getCertsFromConnection(connection));
|
validated = ((ActiveMQSecurityManager2) sm).validateUser(login, passcode, CertificateUtil.getCertsFromConnection(remotingConnection));
|
||||||
} else {
|
} else {
|
||||||
validated = sm.validateUser(login, passcode);
|
validated = sm.validateUser(login, passcode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class StompFrameHandlerV10 extends VersionedStompFrameHandler implements
|
||||||
String clientID = headers.get(Stomp.Headers.Connect.CLIENT_ID);
|
String clientID = headers.get(Stomp.Headers.Connect.CLIENT_ID);
|
||||||
String requestID = headers.get(Stomp.Headers.Connect.REQUEST_ID);
|
String requestID = headers.get(Stomp.Headers.Connect.REQUEST_ID);
|
||||||
|
|
||||||
if (connection.validateUser(login, passcode, connection.getTransportConnection())) {
|
if (connection.validateUser(login, passcode, connection)) {
|
||||||
connection.setClientID(clientID);
|
connection.setClientID(clientID);
|
||||||
connection.setValid(true);
|
connection.setValid(true);
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class StompFrameHandlerV11 extends VersionedStompFrameHandler implements
|
||||||
String requestID = headers.get(Stomp.Headers.Connect.REQUEST_ID);
|
String requestID = headers.get(Stomp.Headers.Connect.REQUEST_ID);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (connection.validateUser(login, passcode, connection.getTransportConnection())) {
|
if (connection.validateUser(login, passcode, connection)) {
|
||||||
connection.setClientID(clientID);
|
connection.setClientID(clientID);
|
||||||
connection.setValid(true);
|
connection.setValid(true);
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,6 @@ import org.apache.activemq.artemis.api.core.management.CoreNotificationType;
|
||||||
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl;
|
import org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl;
|
||||||
import org.apache.activemq.artemis.core.protocol.ProtocolHandler;
|
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.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.remoting.impl.ssl.SSLSupport;
|
||||||
import org.apache.activemq.artemis.core.security.ActiveMQPrincipal;
|
import org.apache.activemq.artemis.core.security.ActiveMQPrincipal;
|
||||||
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
import org.apache.activemq.artemis.core.server.ActiveMQComponent;
|
||||||
|
@ -442,17 +441,9 @@ public class NettyAcceptor extends AbstractAcceptor {
|
||||||
throw ise;
|
throw ise;
|
||||||
}
|
}
|
||||||
Subject subject = null;
|
Subject subject = null;
|
||||||
if (kerb5Config != null && kerb5Config.length() > 0) {
|
if (kerb5Config != null) {
|
||||||
LoginContext loginContext = null;
|
LoginContext loginContext = new LoginContext(kerb5Config);
|
||||||
if (Character.isUpperCase(kerb5Config.charAt(0))) {
|
|
||||||
// use as login.config scope
|
|
||||||
loginContext = new LoginContext(kerb5Config);
|
|
||||||
} else {
|
|
||||||
loginContext = new LoginContext("", null, null,
|
|
||||||
TransportConfigurationUtil.kerb5Config(kerb5Config, false));
|
|
||||||
}
|
|
||||||
loginContext.login();
|
loginContext.login();
|
||||||
|
|
||||||
subject = loginContext.getSubject();
|
subject = loginContext.getSubject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
package org.apache.activemq.artemis.core.security;
|
package org.apache.activemq.artemis.core.security;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.api.core.SimpleString;
|
import org.apache.activemq.artemis.api.core.SimpleString;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
|
|
||||||
public interface SecurityStore {
|
public interface SecurityStore {
|
||||||
|
|
||||||
String authenticate(String user, String password, Connection transportConnection) throws Exception;
|
String authenticate(String user, String password, RemotingConnection remotingConnection) throws Exception;
|
||||||
|
|
||||||
void check(SimpleString address, CheckType checkType, SecurityAuth session) throws Exception;
|
void check(SimpleString address, CheckType checkType, SecurityAuth session) throws Exception;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ import org.apache.activemq.artemis.core.server.management.Notification;
|
||||||
import org.apache.activemq.artemis.core.server.management.NotificationService;
|
import org.apache.activemq.artemis.core.server.management.NotificationService;
|
||||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
|
import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3;
|
||||||
|
@ -104,7 +104,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
||||||
@Override
|
@Override
|
||||||
public String authenticate(final String user,
|
public String authenticate(final String user,
|
||||||
final String password,
|
final String password,
|
||||||
Connection connection) throws Exception {
|
RemotingConnection connection) throws Exception {
|
||||||
if (securityEnabled) {
|
if (securityEnabled) {
|
||||||
|
|
||||||
if (managementClusterUser.equals(user)) {
|
if (managementClusterUser.equals(user)) {
|
||||||
|
@ -185,7 +185,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
||||||
final boolean validated;
|
final boolean validated;
|
||||||
if (securityManager instanceof ActiveMQSecurityManager3) {
|
if (securityManager instanceof ActiveMQSecurityManager3) {
|
||||||
final ActiveMQSecurityManager3 securityManager3 = (ActiveMQSecurityManager3) securityManager;
|
final ActiveMQSecurityManager3 securityManager3 = (ActiveMQSecurityManager3) securityManager;
|
||||||
validated = securityManager3.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection().getTransportConnection()) != null;
|
validated = securityManager3.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection()) != null;
|
||||||
} else if (securityManager instanceof ActiveMQSecurityManager2) {
|
} else if (securityManager instanceof ActiveMQSecurityManager2) {
|
||||||
final ActiveMQSecurityManager2 securityManager2 = (ActiveMQSecurityManager2) securityManager;
|
final ActiveMQSecurityManager2 securityManager2 = (ActiveMQSecurityManager2) securityManager;
|
||||||
validated = securityManager2.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection());
|
validated = securityManager2.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection());
|
||||||
|
|
|
@ -1394,7 +1394,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
||||||
String validatedUser = "";
|
String validatedUser = "";
|
||||||
|
|
||||||
if (securityStore != null) {
|
if (securityStore != null) {
|
||||||
validatedUser = securityStore.authenticate(username, password, connection.getTransportConnection());
|
validatedUser = securityStore.authenticate(username, password, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkSessionLimit(validatedUser);
|
checkSessionLimit(validatedUser);
|
||||||
|
|
|
@ -29,7 +29,7 @@ import java.util.Set;
|
||||||
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
|
import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration;
|
||||||
import org.apache.activemq.artemis.core.security.CheckType;
|
import org.apache.activemq.artemis.core.security.CheckType;
|
||||||
import org.apache.activemq.artemis.core.security.Role;
|
import org.apache.activemq.artemis.core.security.Role;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler;
|
import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler;
|
||||||
import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal;
|
import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal;
|
||||||
import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal;
|
import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal;
|
||||||
|
@ -88,9 +88,9 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String validateUser(final String user, final String password, Connection connection) {
|
public String validateUser(final String user, final String password, RemotingConnection remotingConnection) {
|
||||||
try {
|
try {
|
||||||
return getUserFromSubject(getAuthenticatedSubject(user, password, connection));
|
return getUserFromSubject(getAuthenticatedSubject(user, password, remotingConnection));
|
||||||
} catch (LoginException e) {
|
} catch (LoginException e) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Couldn't validate user", e);
|
logger.debug("Couldn't validate user", e);
|
||||||
|
@ -121,10 +121,10 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 {
|
||||||
final Set<Role> roles,
|
final Set<Role> roles,
|
||||||
final CheckType checkType,
|
final CheckType checkType,
|
||||||
final String address,
|
final String address,
|
||||||
final Connection connection) {
|
final RemotingConnection remotingConnection) {
|
||||||
Subject localSubject;
|
Subject localSubject;
|
||||||
try {
|
try {
|
||||||
localSubject = getAuthenticatedSubject(user, password, connection);
|
localSubject = getAuthenticatedSubject(user, password, remotingConnection);
|
||||||
} catch (LoginException e) {
|
} catch (LoginException e) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Couldn't validate user", e);
|
logger.debug("Couldn't validate user", e);
|
||||||
|
@ -170,7 +170,7 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 {
|
||||||
|
|
||||||
private Subject getAuthenticatedSubject(final String user,
|
private Subject getAuthenticatedSubject(final String user,
|
||||||
final String password,
|
final String password,
|
||||||
final Connection connection) throws LoginException {
|
final RemotingConnection remotingConnection) throws LoginException {
|
||||||
LoginContext lc;
|
LoginContext lc;
|
||||||
ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
|
||||||
ClassLoader thisLoader = this.getClass().getClassLoader();
|
ClassLoader thisLoader = this.getClass().getClassLoader();
|
||||||
|
@ -178,10 +178,10 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 {
|
||||||
if (thisLoader != currentLoader) {
|
if (thisLoader != currentLoader) {
|
||||||
Thread.currentThread().setContextClassLoader(thisLoader);
|
Thread.currentThread().setContextClassLoader(thisLoader);
|
||||||
}
|
}
|
||||||
if (certificateConfigurationName != null && certificateConfigurationName.length() > 0 && getCertsFromConnection(connection) != null) {
|
if (certificateConfigurationName != null && certificateConfigurationName.length() > 0 && getCertsFromConnection(remotingConnection) != null) {
|
||||||
lc = new LoginContext(certificateConfigurationName, null, new JaasCallbackHandler(user, password, connection), certificateConfiguration);
|
lc = new LoginContext(certificateConfigurationName, null, new JaasCallbackHandler(user, password, remotingConnection), certificateConfiguration);
|
||||||
} else {
|
} else {
|
||||||
lc = new LoginContext(configurationName, null, new JaasCallbackHandler(user, password, connection), configuration);
|
lc = new LoginContext(configurationName, null, new JaasCallbackHandler(user, password, remotingConnection), configuration);
|
||||||
}
|
}
|
||||||
lc.login();
|
lc.login();
|
||||||
return lc.getSubject();
|
return lc.getSubject();
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.core.security.CheckType;
|
import org.apache.activemq.artemis.core.security.CheckType;
|
||||||
import org.apache.activemq.artemis.core.security.Role;
|
import org.apache.activemq.artemis.core.security.Role;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to validate whether a user is authorized to connect to the
|
* Used to validate whether a user is authorized to connect to the
|
||||||
|
@ -40,9 +40,10 @@ public interface ActiveMQSecurityManager3 extends ActiveMQSecurityManager {
|
||||||
*
|
*
|
||||||
* @param user the user
|
* @param user the user
|
||||||
* @param password the users password
|
* @param password the users password
|
||||||
|
* @param remotingConnection
|
||||||
* @return the name of the validated user or null if the user isn't validated
|
* @return the name of the validated user or null if the user isn't validated
|
||||||
*/
|
*/
|
||||||
String validateUser(String user, String password, Connection connection);
|
String validateUser(String user, String password, RemotingConnection remotingConnection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the given user is valid and whether they have
|
* Determine whether the given user is valid and whether they have
|
||||||
|
@ -56,7 +57,7 @@ public interface ActiveMQSecurityManager3 extends ActiveMQSecurityManager {
|
||||||
* @param roles the user's roles
|
* @param roles the user's roles
|
||||||
* @param checkType which permission to validate
|
* @param checkType which permission to validate
|
||||||
* @param address the address for which to perform authorization
|
* @param address the address for which to perform authorization
|
||||||
* @param connection the user's connection
|
* @param remotingConnection the user's connection
|
||||||
* @return the name of the validated user or null if the user isn't validated
|
* @return the name of the validated user or null if the user isn't validated
|
||||||
*/
|
*/
|
||||||
String validateUserAndRole(String user,
|
String validateUserAndRole(String user,
|
||||||
|
@ -64,5 +65,5 @@ public interface ActiveMQSecurityManager3 extends ActiveMQSecurityManager {
|
||||||
Set<Role> roles,
|
Set<Role> roles,
|
||||||
CheckType checkType,
|
CheckType checkType,
|
||||||
String address,
|
String address,
|
||||||
Connection connection);
|
RemotingConnection remotingConnection);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,17 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.activemq.artemis.spi.core.security.jaas;
|
package org.apache.activemq.artemis.spi.core.security.jaas;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
|
|
||||||
|
import javax.security.auth.Subject;
|
||||||
import javax.security.auth.callback.Callback;
|
import javax.security.auth.callback.Callback;
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
import javax.security.auth.callback.NameCallback;
|
import javax.security.auth.callback.NameCallback;
|
||||||
import javax.security.auth.callback.PasswordCallback;
|
import javax.security.auth.callback.PasswordCallback;
|
||||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||||
|
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
import static org.apache.activemq.artemis.core.remoting.CertificateUtil.getCertsFromConnection;
|
import static org.apache.activemq.artemis.core.remoting.CertificateUtil.getCertsFromConnection;
|
||||||
import static org.apache.activemq.artemis.core.remoting.CertificateUtil.getPeerPrincipalFromConnection;
|
import static org.apache.activemq.artemis.core.remoting.CertificateUtil.getPeerPrincipalFromConnection;
|
||||||
|
@ -35,12 +38,12 @@ public class JaasCallbackHandler implements CallbackHandler {
|
||||||
|
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String password;
|
private final String password;
|
||||||
final Connection connection;
|
final RemotingConnection remotingConnection;
|
||||||
|
|
||||||
public JaasCallbackHandler(String username, String password, Connection connection) {
|
public JaasCallbackHandler(String username, String password, RemotingConnection remotingConnection) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.connection = connection;
|
this.remotingConnection = remotingConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,11 +66,19 @@ public class JaasCallbackHandler implements CallbackHandler {
|
||||||
} else if (callback instanceof CertificateCallback) {
|
} else if (callback instanceof CertificateCallback) {
|
||||||
CertificateCallback certCallback = (CertificateCallback) callback;
|
CertificateCallback certCallback = (CertificateCallback) callback;
|
||||||
|
|
||||||
certCallback.setCertificates(getCertsFromConnection(connection));
|
certCallback.setCertificates(getCertsFromConnection(remotingConnection));
|
||||||
} else if (callback instanceof Krb5SslCallback) {
|
} else if (callback instanceof Krb5Callback) {
|
||||||
Krb5SslCallback krb5SslCallback = (Krb5SslCallback) callback;
|
Krb5Callback krb5Callback = (Krb5Callback) callback;
|
||||||
|
|
||||||
krb5SslCallback.setPeerPrincipal(getPeerPrincipalFromConnection(connection));
|
Subject peerSubject = remotingConnection.getSubject();
|
||||||
|
if (peerSubject != null) {
|
||||||
|
for (Principal principal : peerSubject.getPrivateCredentials(KerberosPrincipal.class)) {
|
||||||
|
krb5Callback.setPeerPrincipal(principal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5Callback.setPeerPrincipal(getPeerPrincipalFromConnection(remotingConnection));
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedCallbackException(callback);
|
throw new UnsupportedCallbackException(callback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ import javax.security.auth.callback.Callback;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Callback for SSL kerberos peer principal.
|
* A Callback for kerberos peer principal.
|
||||||
*/
|
*/
|
||||||
public class Krb5SslCallback implements Callback {
|
public class Krb5Callback implements Callback {
|
||||||
|
|
||||||
Principal peerPrincipal;
|
Principal peerPrincipal;
|
||||||
|
|
|
@ -31,11 +31,11 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* populate a subject with kerberos and UserPrincipal from SSLContext peerPrincipal
|
* populate a subject with kerberos credential from the handler
|
||||||
*/
|
*/
|
||||||
public class Krb5SslLoginModule implements LoginModule {
|
public class Krb5LoginModule implements LoginModule {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(Krb5SslLoginModule.class);
|
private static final Logger logger = Logger.getLogger(Krb5LoginModule.class);
|
||||||
|
|
||||||
private Subject subject;
|
private Subject subject;
|
||||||
private final List<Principal> principals = new LinkedList<>();
|
private final List<Principal> principals = new LinkedList<>();
|
||||||
|
@ -55,7 +55,7 @@ public class Krb5SslLoginModule implements LoginModule {
|
||||||
public boolean login() throws LoginException {
|
public boolean login() throws LoginException {
|
||||||
Callback[] callbacks = new Callback[1];
|
Callback[] callbacks = new Callback[1];
|
||||||
|
|
||||||
callbacks[0] = new Krb5SslCallback();
|
callbacks[0] = new Krb5Callback();
|
||||||
try {
|
try {
|
||||||
callbackHandler.handle(callbacks);
|
callbackHandler.handle(callbacks);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
|
@ -63,7 +63,7 @@ public class Krb5SslLoginModule implements LoginModule {
|
||||||
} catch (UnsupportedCallbackException uce) {
|
} catch (UnsupportedCallbackException uce) {
|
||||||
throw new LoginException(uce.getMessage() + " not available to obtain information from user");
|
throw new LoginException(uce.getMessage() + " not available to obtain information from user");
|
||||||
}
|
}
|
||||||
principals.add(((Krb5SslCallback)callbacks[0]).getPeerPrincipal());
|
principals.add(((Krb5Callback)callbacks[0]).getPeerPrincipal());
|
||||||
if (!principals.isEmpty()) {
|
if (!principals.isEmpty()) {
|
||||||
loginSucceeded = true;
|
loginSucceeded = true;
|
||||||
}
|
}
|
|
@ -649,6 +649,31 @@ like the following:
|
||||||
The simplest way to make the login configuration available to JAAS is to add the directory containing the file,
|
The simplest way to make the login configuration available to JAAS is to add the directory containing the file,
|
||||||
`login.config`, to your CLASSPATH.
|
`login.config`, to your CLASSPATH.
|
||||||
|
|
||||||
|
### Kerberos Authentication
|
||||||
|
|
||||||
|
The [Krb5LoginModule](https://docs.oracle.com/javase/7/docs/jre/api/security/jaas/spec/com/sun/security/auth/module/Krb5LoginModule.html)
|
||||||
|
can be used with JAAS to authenticate using the Kerberos protocol.
|
||||||
|
|
||||||
|
Using SASL over [AMQP](using-AMQP.md), Kerberos authentication is supported using the `GSSAPI` SASL mechanism. With SASL doing Kerberos
|
||||||
|
authentication, TLS can be used to provide integrity and confidentially to the communications channel in the normal way.
|
||||||
|
The `GSSAPI` SASL mechanism must be enabled on the amqp acceptor by adding it to the `saslMechanisms` list url parameter:
|
||||||
|
`saslMechanisms="GSSAPI<,PLAIN, etc>`.
|
||||||
|
|
||||||
|
By default the server will use a JAAS login configuration scope named `amqp-sasl-gssapi` to obtain acceptor Kerberos
|
||||||
|
credentials. An alternative configuration scope can be specified on the amqp acceptor url using the parameter: `saslLoginConfigScope=<some other scope>`.
|
||||||
|
|
||||||
|
On the server, the Kerberos authenticated Peer Principal can be associated with a JAAS Subject as an Apache ActiveMQ Artemis UserPrincipal
|
||||||
|
using the Apache ActiveMQ Artemis Krb5LoginModule login module. The [PropertiesLoginModule](#propertiesloginmodule) can be used to map
|
||||||
|
the peer principal to a role.
|
||||||
|
Note: the Kerberos Peer Principal does not exist as an Apache ActiveMQ Artemis user.
|
||||||
|
|
||||||
|
org.apache.activemq.artemis.spi.core.security.jaas.Krb5LoginModule optional;
|
||||||
|
|
||||||
|
The legacy [rfc2712](http://www.ietf.org/rfc/rfc2712.txt) defines TLS Kerberos cipher suites that can be used by TLS to negotiate
|
||||||
|
Kerberos authentication. The cypher suites offered by rfc2712 are dated and insecure and rfc2712 has been superseded by
|
||||||
|
SASL GSSAPI. However, for clients that don't support SASL (core client), using TLS can provide Kerberos authentication
|
||||||
|
over an *unsecure* channel.
|
||||||
|
|
||||||
|
|
||||||
## Changing the username/password for clustering
|
## Changing the username/password for clustering
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,11 @@ public class JMSConnectionWithSecurityTest extends JMSClientTestSupport {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getJmsConnectionURIOptions() {
|
||||||
|
return "amqp.saslMechanisms=PLAIN";
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout = 10000)
|
@Test(timeout = 10000)
|
||||||
public void testNoUserOrPassword() throws Exception {
|
public void testNoUserOrPassword() throws Exception {
|
||||||
Connection connection = null;
|
Connection connection = null;
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* 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.amqp;
|
||||||
|
|
||||||
|
import javax.jms.Connection;
|
||||||
|
import javax.jms.MessageConsumer;
|
||||||
|
import javax.jms.MessageProducer;
|
||||||
|
import javax.jms.Session;
|
||||||
|
import javax.jms.TextMessage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.activemq.artemis.core.security.Role;
|
||||||
|
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||||
|
import org.apache.activemq.artemis.utils.RandomUtil;
|
||||||
|
import org.apache.hadoop.minikdc.MiniKdc;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class JMSSaslGssapiTest extends JMSClientTestSupport {
|
||||||
|
|
||||||
|
static {
|
||||||
|
String path = System.getProperty("java.security.auth.login.config");
|
||||||
|
if (path == null) {
|
||||||
|
URL resource = JMSSaslGssapiTest.class.getClassLoader().getResource("login.config");
|
||||||
|
if (resource != null) {
|
||||||
|
path = resource.getFile();
|
||||||
|
System.setProperty("java.security.auth.login.config", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MiniKdc kdc = null;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUpKerberos() throws Exception {
|
||||||
|
kdc = new MiniKdc(MiniKdc.createConf(), temporaryFolder.newFolder("kdc"));
|
||||||
|
kdc.start();
|
||||||
|
|
||||||
|
// hard coded match, default_keytab_name in minikdc-krb5.conf template
|
||||||
|
File userKeyTab = new File("target/test.krb5.keytab");
|
||||||
|
kdc.createPrincipal(userKeyTab, "client", "amqp/localhost");
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void stopKerberos() throws Exception {
|
||||||
|
if (kdc != null) {
|
||||||
|
kdc.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isSecurityEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureBrokerSecurity(ActiveMQServer server) {
|
||||||
|
server.getConfiguration().setSecurityEnabled(isSecurityEnabled());
|
||||||
|
ActiveMQJAASSecurityManager securityManager = (ActiveMQJAASSecurityManager) server.getSecurityManager();
|
||||||
|
securityManager.setConfigurationName("Krb5Plus");
|
||||||
|
securityManager.setConfiguration(null);
|
||||||
|
|
||||||
|
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);
|
||||||
|
server.getSecurityRepository().addMatch(getQueueName().toString(), roles);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getJmsConnectionURIOptions() {
|
||||||
|
return "amqp.saslMechanisms=GSSAPI";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URI getBrokerQpidJMSConnectionURI() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
int port = AMQP_PORT;
|
||||||
|
|
||||||
|
// match the sasl.service <the host name>
|
||||||
|
String uri = "amqp://localhost:" + port;
|
||||||
|
|
||||||
|
if (!getJmsConnectionURIOptions().isEmpty()) {
|
||||||
|
uri = uri + "?" + getJmsConnectionURIOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new URI(uri);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureAMQPAcceptorParameters(Map<String, Object> params) {
|
||||||
|
params.put("saslMechanisms", "GSSAPI");
|
||||||
|
params.put("saslLoginConfigScope", "amqp-sasl-gssapi");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 600000)
|
||||||
|
public void testConnection() throws Exception {
|
||||||
|
Connection connection = createConnection("client", null);
|
||||||
|
connection.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||||
|
javax.jms.Queue queue = session.createQueue(getQueueName());
|
||||||
|
MessageConsumer consumer = session.createConsumer(queue);
|
||||||
|
MessageProducer producer = session.createProducer(queue);
|
||||||
|
|
||||||
|
final String text = RandomUtil.randomString();
|
||||||
|
producer.send(session.createTextMessage(text));
|
||||||
|
|
||||||
|
TextMessage m = (TextMessage) consumer.receive(1000);
|
||||||
|
assertNotNull(m);
|
||||||
|
assertEquals(text, m.getText());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,7 +54,6 @@ import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
|
||||||
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
|
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
|
||||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||||
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
|
||||||
import org.apache.activemq.artemis.spi.core.remoting.Connection;
|
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
||||||
|
@ -1936,7 +1935,7 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
@Override
|
@Override
|
||||||
public String validateUser(final String username,
|
public String validateUser(final String username,
|
||||||
final String password,
|
final String password,
|
||||||
final Connection connection) {
|
final RemotingConnection remotingConnection) {
|
||||||
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) && password.equals("frobnicate")) {
|
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) && password.equals("frobnicate")) {
|
||||||
return username;
|
return username;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1960,9 +1959,9 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
final Set<Role> requiredRoles,
|
final Set<Role> requiredRoles,
|
||||||
final CheckType checkType,
|
final CheckType checkType,
|
||||||
final String address,
|
final String address,
|
||||||
final Connection connection) {
|
final RemotingConnection connection) {
|
||||||
|
|
||||||
if (!(connection instanceof InVMConnection)) {
|
if (!(connection.getTransportConnection() instanceof InVMConnection)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class CoreClientOverOneWaySSLKerb5Test extends ActiveMQTestBase {
|
||||||
tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
||||||
tc.getParams().put(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, getSuitableCipherSuite());
|
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.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
|
tc.getParams().put(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, "core-tls-krb5-client");
|
||||||
final ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
|
final ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
|
||||||
|
|
||||||
ClientSessionFactory sf = null;
|
ClientSessionFactory sf = null;
|
||||||
|
@ -171,7 +171,7 @@ public class CoreClientOverOneWaySSLKerb5Test extends ActiveMQTestBase {
|
||||||
|
|
||||||
params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
|
||||||
params.put(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, getSuitableCipherSuite());
|
params.put(TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME, getSuitableCipherSuite());
|
||||||
params.put(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, SERVICE_PRINCIPAL);
|
params.put(TransportConstants.SSL_KRB5_CONFIG_PROP_NAME, "core-tls-krb5-server");
|
||||||
|
|
||||||
ConfigurationImpl config = createBasicConfig().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params, "nettySSL"));
|
ConfigurationImpl config = createBasicConfig().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params, "nettySSL"));
|
||||||
config.setPopulateValidatedUser(true); // so we can verify the kerb5 id is present
|
config.setPopulateValidatedUser(true); // so we can verify the kerb5 id is present
|
||||||
|
@ -179,7 +179,7 @@ public class CoreClientOverOneWaySSLKerb5Test extends ActiveMQTestBase {
|
||||||
|
|
||||||
config.addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY));
|
config.addAcceptorConfiguration(new TransportConfiguration(INVM_ACCEPTOR_FACTORY));
|
||||||
|
|
||||||
ActiveMQSecurityManager securityManager = new ActiveMQJAASSecurityManager("Krb5SslPlus");
|
ActiveMQSecurityManager securityManager = new ActiveMQJAASSecurityManager("Krb5Plus");
|
||||||
server = addServer(ActiveMQServers.newActiveMQServer(config, ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
server = addServer(ActiveMQServers.newActiveMQServer(config, ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
||||||
HierarchicalRepository<Set<Role>> securityRepository = server.getSecurityRepository();
|
HierarchicalRepository<Set<Role>> securityRepository = server.getSecurityRepository();
|
||||||
|
|
||||||
|
|
|
@ -138,9 +138,9 @@ DualAuthenticationPropertiesLogin {
|
||||||
org.apache.activemq.jaas.properties.role="dual-authentication-roles.properties";
|
org.apache.activemq.jaas.properties.role="dual-authentication-roles.properties";
|
||||||
};
|
};
|
||||||
|
|
||||||
Krb5SslPlus {
|
Krb5Plus {
|
||||||
|
|
||||||
org.apache.activemq.artemis.spi.core.security.jaas.Krb5SslLoginModule optional
|
org.apache.activemq.artemis.spi.core.security.jaas.Krb5LoginModule optional
|
||||||
debug=true;
|
debug=true;
|
||||||
|
|
||||||
org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule optional
|
org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule optional
|
||||||
|
@ -148,3 +148,32 @@ Krb5SslPlus {
|
||||||
org.apache.activemq.jaas.properties.user="dual-authentication-users.properties"
|
org.apache.activemq.jaas.properties.user="dual-authentication-users.properties"
|
||||||
org.apache.activemq.jaas.properties.role="dual-authentication-roles.properties";
|
org.apache.activemq.jaas.properties.role="dual-authentication-roles.properties";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
core-tls-krb5-server {
|
||||||
|
com.sun.security.auth.module.Krb5LoginModule required
|
||||||
|
isInitiator=false
|
||||||
|
storeKey=true
|
||||||
|
useKeyTab=true
|
||||||
|
principal="host/sni.host"
|
||||||
|
debug=true;
|
||||||
|
};
|
||||||
|
|
||||||
|
core-tls-krb5-client {
|
||||||
|
com.sun.security.auth.module.Krb5LoginModule required
|
||||||
|
principal="client"
|
||||||
|
useKeyTab=true;
|
||||||
|
};
|
||||||
|
|
||||||
|
amqp-sasl-gssapi {
|
||||||
|
com.sun.security.auth.module.Krb5LoginModule required
|
||||||
|
isInitiator=false
|
||||||
|
storeKey=true
|
||||||
|
useKeyTab=true
|
||||||
|
principal="amqp/localhost"
|
||||||
|
debug=true;
|
||||||
|
};
|
||||||
|
|
||||||
|
amqp-jms-client {
|
||||||
|
com.sun.security.auth.module.Krb5LoginModule required
|
||||||
|
useKeyTab=true;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue