[ARTEMIS-1310] add amqp sasl gssapi mechanism support delegate to the jdk saslServer. Allow acceptor configuration of supported mechanismis; saslMechanisms=<a,b> and allow login config scope for krb5 to be configured via saslLoginConfigScope=x
Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/ca7197b5 Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/ca7197b5 Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/ca7197b5 Branch: refs/heads/master Commit: ca7197b5c3b1a1d945ee8c00967f33cf37d0cfbe Parents: 766f412 Author: gtully <gary.tu...@gmail.com> Authored: Fri Jul 28 16:02:32 2017 +0100 Committer: Clebert Suconic <clebertsuco...@apache.org> Committed: Tue Aug 8 13:28:50 2017 -0400 ---------------------------------------------------------------------- .../artemis/core/remoting/CertificateUtil.java | 31 ++-- .../protocol/AbstractRemotingConnection.java | 7 + .../spi/core/protocol/RemotingConnection.java | 8 + .../amqp/broker/AMQPConnectionCallback.java | 36 +++-- .../ActiveMQProtonRemotingConnection.java | 12 ++ .../amqp/broker/ProtonProtocolManager.java | 33 ++++ .../amqp/proton/AMQPConnectionContext.java | 14 +- .../amqp/proton/handler/EventHandler.java | 2 + .../amqp/proton/handler/ProtonHandler.java | 67 +++++--- .../protocol/amqp/sasl/AnonymousServerSASL.java | 16 +- .../protocol/amqp/sasl/GSSAPISASLResult.java | 51 +++++++ .../protocol/amqp/sasl/GSSAPIServerSASL.java | 114 ++++++++++++++ .../protocol/amqp/sasl/MechanismFinder.java | 27 ++++ .../protocol/amqp/sasl/PlainSASLResult.java | 8 + .../artemis/protocol/amqp/sasl/SASLResult.java | 4 + .../artemis/protocol/amqp/sasl/ServerSASL.java | 6 +- .../protocol/amqp/sasl/ServerSASLPlain.java | 16 +- .../protocol/amqp/sasl/PlainSASLTest.java | 3 +- .../core/protocol/mqtt/MQTTConnection.java | 7 + .../openwire/OpenWireProtocolManager.java | 2 +- .../core/protocol/stomp/StompConnection.java | 9 +- .../protocol/stomp/StompProtocolManager.java | 6 +- .../stomp/v10/StompFrameHandlerV10.java | 2 +- .../stomp/v11/StompFrameHandlerV11.java | 2 +- .../artemis/core/security/SecurityStore.java | 4 +- .../core/security/impl/SecurityStoreImpl.java | 6 +- .../core/server/impl/ActiveMQServerImpl.java | 2 +- .../security/ActiveMQJAASSecurityManager.java | 18 +-- .../core/security/ActiveMQSecurityManager3.java | 9 +- .../core/security/jaas/JaasCallbackHandler.java | 27 +++- .../spi/core/security/jaas/Krb5Callback.java | 46 ++++++ .../spi/core/security/jaas/Krb5LoginModule.java | 112 ++++++++++++++ .../spi/core/security/jaas/Krb5SslCallback.java | 46 ------ .../core/security/jaas/Krb5SslLoginModule.java | 112 -------------- docs/user-manual/en/security.md | 19 +++ .../amqp/JMSConnectionWithSecurityTest.java | 5 + .../integration/amqp/JMSSaslGssapiTest.java | 151 +++++++++++++++++++ .../integration/security/SecurityTest.java | 7 +- .../src/test/resources/login.config | 16 +- 39 files changed, 813 insertions(+), 250 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/CertificateUtil.java ---------------------------------------------------------------------- diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/CertificateUtil.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/CertificateUtil.java index 598fcf3..57c2309 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/CertificateUtil.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/core/remoting/CertificateUtil.java @@ -20,6 +20,7 @@ package org.apache.activemq.artemis.core.remoting; import io.netty.channel.ChannelHandler; import io.netty.handler.ssl.SslHandler; 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 javax.net.ssl.SSLPeerUnverifiedException; @@ -28,24 +29,30 @@ import java.security.Principal; public class CertificateUtil { - public static X509Certificate[] getCertsFromConnection(Connection connection) { + public static X509Certificate[] getCertsFromConnection(RemotingConnection remotingConnection) { X509Certificate[] certificates = null; - if (connection instanceof NettyConnection) { - certificates = org.apache.activemq.artemis.utils.CertificateUtil.getCertsFromChannel(((NettyConnection) connection).getChannel()); + if (remotingConnection != null) { + Connection transportConnection = remotingConnection.getTransportConnection(); + if (transportConnection instanceof NettyConnection) { + certificates = org.apache.activemq.artemis.utils.CertificateUtil.getCertsFromChannel(((NettyConnection) transportConnection).getChannel()); + } } return certificates; } - public static Principal getPeerPrincipalFromConnection(Connection connection) { + public static Principal getPeerPrincipalFromConnection(RemotingConnection remotingConnection) { Principal result = null; - if (connection instanceof NettyConnection) { - NettyConnection nettyConnection = (NettyConnection) connection; - ChannelHandler channelHandler = nettyConnection.getChannel().pipeline().get("ssl"); - if (channelHandler != null && channelHandler instanceof SslHandler) { - SslHandler sslHandler = (SslHandler) channelHandler; - try { - result = sslHandler.engine().getSession().getPeerPrincipal(); - } catch (SSLPeerUnverifiedException ignored) { + if (remotingConnection != null) { + Connection transportConnection = remotingConnection.getTransportConnection(); + if (transportConnection instanceof NettyConnection) { + NettyConnection nettyConnection = (NettyConnection) transportConnection; + ChannelHandler channelHandler = nettyConnection.getChannel().pipeline().get("ssl"); + if (channelHandler != null && channelHandler instanceof SslHandler) { + SslHandler sslHandler = (SslHandler) channelHandler; + try { + result = sslHandler.engine().getSession().getPeerPrincipal(); + } catch (SSLPeerUnverifiedException ignored) { + } } } } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/AbstractRemotingConnection.java ---------------------------------------------------------------------- diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/AbstractRemotingConnection.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/AbstractRemotingConnection.java index a9e12aa..3893902 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/AbstractRemotingConnection.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/AbstractRemotingConnection.java @@ -32,6 +32,8 @@ import org.apache.activemq.artemis.spi.core.remoting.Connection; import org.apache.activemq.artemis.spi.core.remoting.ReadyListener; import org.jboss.logging.Logger; +import javax.security.auth.Subject; + public abstract class AbstractRemotingConnection implements RemotingConnection { private static final Logger logger = Logger.getLogger(AbstractRemotingConnection.class); @@ -219,4 +221,9 @@ public abstract class AbstractRemotingConnection implements RemotingConnection { public boolean isSupportsFlowControl() { return true; } + + @Override + public Subject getSubject() { + return null; + } } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/RemotingConnection.java ---------------------------------------------------------------------- diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/RemotingConnection.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/RemotingConnection.java index 39ecdf6..4cda8c0 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/RemotingConnection.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/spi/core/protocol/RemotingConnection.java @@ -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.ReadyListener; +import javax.security.auth.Subject; + /** * A RemotingConnection is a connection between a client and a server. * @@ -206,4 +208,10 @@ public interface RemotingConnection extends BufferHandler { * @return */ boolean isSupportsFlowControl(); + + /** + * the possibly null identity associated with this connection + * @return + */ + Subject getSubject(); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPConnectionCallback.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPConnectionCallback.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPConnectionCallback.java index a5ed973..47b5f69 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPConnectionCallback.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/AMQPConnectionCallback.java @@ -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.handler.ExtCapability; 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.SASLResult; import org.apache.activemq.artemis.protocol.amqp.sasl.ServerSASL; @@ -76,6 +77,8 @@ public class AMQPConnectionCallback implements FailureListener, CloseListener { private ActiveMQServer server; + private final String[] saslMechanisms; + public AMQPConnectionCallback(ProtonProtocolManager manager, Connection connection, Executor closeExecutor, @@ -84,25 +87,40 @@ public class AMQPConnectionCallback implements FailureListener, CloseListener { this.connection = connection; this.closeExecutor = closeExecutor; this.server = server; + saslMechanisms = manager.getSaslMechanisms(); } - public ServerSASL[] getSASLMechnisms() { - - ServerSASL[] result; + public String[] getSaslMechanisms() { + return saslMechanisms; + } - if (isSupportsAnonymous()) { - result = new ServerSASL[]{new PlainSASL(manager.getServer().getSecurityStore()), new AnonymousServerSASL()}; - } else { - result = new ServerSASL[]{new PlainSASL(manager.getServer().getSecurityStore())}; + public ServerSASL getServerSASL(final String mechanism) { + ServerSASL result = null; + switch (mechanism) { + case PlainSASL.NAME: + result = new PlainSASL(server.getSecurityStore()); + break; + + case AnonymousServerSASL.NAME: + result = new AnonymousServerSASL(); + break; + + case GSSAPIServerSASL.NAME: + GSSAPIServerSASL gssapiServerSASL = new GSSAPIServerSASL(); + gssapiServerSASL.setLoginConfigScope(manager.getSaslLoginConfigScope()); + result = gssapiServerSASL; + break; + + default: + break; } - return result; } public boolean isSupportsAnonymous() { boolean supportsAnonymous = false; try { - manager.getServer().getSecurityStore().authenticate(null, null, null); + server.getSecurityStore().authenticate(null, null, null); supportsAnonymous = true; } catch (Exception e) { // authentication failed so no anonymous support http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ActiveMQProtonRemotingConnection.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ActiveMQProtonRemotingConnection.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ActiveMQProtonRemotingConnection.java index 4a1fe80..1441b96 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ActiveMQProtonRemotingConnection.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ActiveMQProtonRemotingConnection.java @@ -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.protocol.amqp.proton.AMQPConnectionContext; 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.remoting.Connection; import org.apache.qpid.proton.amqp.transport.ErrorCondition; +import javax.security.auth.Subject; + /** * 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) { //unsupported } + + @Override + public Subject getSubject() { + SASLResult saslResult = amqpConnection.getSASLResult(); + if (saslResult != null) { + return saslResult.getSubject(); + } + return null; + } } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonProtocolManager.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonProtocolManager.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonProtocolManager.java index d36f18e..8f88d8f 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonProtocolManager.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/broker/ProtonProtocolManager.java @@ -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.protocol.amqp.proton.AMQPConnectionContext; 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.ConnectionEntry; 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 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 * the address. This can be changed on the acceptor. @@ -197,6 +204,23 @@ public class ProtonProtocolManager extends AbstractProtocolManager<AMQPMessage, 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 public void setAnycastPrefix(String anycastPrefix) { for (String prefix : anycastPrefix.split(",")) { @@ -223,4 +247,13 @@ public class ProtonProtocolManager extends AbstractProtocolManager<AMQPMessage, public void invokeOutgoing(AMQPMessage message, ActiveMQProtonRemotingConnection connection) { super.invokeInterceptors(this.outgoingInterceptors, message, connection); } + + public int getInitialRemoteMaxFrameSize() { + return initialRemoteMaxFrameSize; + } + + public void setInitialRemoteMaxFrameSize(int initialRemoteMaxFrameSize) { + this.initialRemoteMaxFrameSize = initialRemoteMaxFrameSize; + } + } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java index 0ab4171..47cb11d 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/AMQPConnectionContext.java @@ -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.ExtCapability; 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.spi.core.remoting.ReadyListener; import org.apache.activemq.artemis.utils.ByteUtil; @@ -103,6 +104,7 @@ public class AMQPConnectionContext extends ProtonInitializable implements EventH transport.setIdleTimeout(idleTimeout); } transport.setChannelMax(channelMax); + transport.setInitialRemoteMaxFrameSize(protocolManager.getInitialRemoteMaxFrameSize()); transport.setMaxFrameSize(maxFrameSize); } @@ -321,7 +323,12 @@ public class AMQPConnectionContext extends ProtonInitializable implements EventH @Override public void onAuthInit(ProtonHandler handler, Connection connection, boolean 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 { if (!connectionCallback.isSupportsAnonymous()) { connectionCallback.sendSASLSupported(); @@ -332,6 +339,11 @@ public class AMQPConnectionContext extends ProtonInitializable implements EventH } @Override + public void onSaslRemoteMechanismChosen(ProtonHandler handler, String mech) { + handler.setChosenMechanism(connectionCallback.getServerSASL(mech)); + } + + @Override public void onTransport(Transport transport) { handler.flushBytes(); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/EventHandler.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/EventHandler.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/EventHandler.java index c8ba136..8b99284 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/EventHandler.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/EventHandler.java @@ -31,6 +31,8 @@ public interface EventHandler { void onAuthInit(ProtonHandler handler, Connection connection, boolean sasl); + void onSaslRemoteMechanismChosen(ProtonHandler handler, String mech); + void onInit(Connection connection) throws Exception; void onLocalOpen(Connection connection) throws Exception; http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java index eb95dec..918b383 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/proton/handler/ProtonHandler.java @@ -18,7 +18,6 @@ package org.apache.activemq.artemis.protocol.amqp.proton.handler; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; @@ -63,12 +62,12 @@ public class ProtonHandler extends ProtonInitializable { private Sasl serverSasl; + private ServerSASL chosenMechanism; + private final ReentrantLock lock = new ReentrantLock(); private final long creationTime; - private Map<String, ServerSASL> saslHandlers; - private SASLResult saslResult; protected volatile boolean dataReceived; @@ -157,17 +156,10 @@ public class ProtonHandler extends ProtonInitializable { return this; } - public void createServerSASL(ServerSASL[] handlers) { + public void createServerSASL(String[] mechanisms) { 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(); - serverSasl.setMechanisms(names); + serverSasl.setMechanisms(mechanisms); } public void flushBytes() { @@ -292,9 +284,14 @@ public class ProtonHandler extends ProtonInitializable { protected void checkServerSASL() { if (serverSasl != null && serverSasl.getRemoteMechanisms().length > 0) { - // TODO: should we look at the first only? - ServerSASL mechanism = saslHandlers.get(serverSasl.getRemoteMechanisms()[0]); - if (mechanism != null) { + + if (chosenMechanism == null) { + if (log.isTraceEnabled()) { + log.trace("SASL chosenMechanism: " + serverSasl.getRemoteMechanisms()[0]); + } + dispatchRemoteMechanismChosen(serverSasl.getRemoteMechanisms()[0]); + } + if (chosenMechanism != null) { byte[] dataSASL = new byte[serverSasl.pending()]; 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")); } - saslResult = mechanism.processSASL(dataSASL); + byte[] response = chosenMechanism.processSASL(dataSASL); + if (response != null) { + serverSasl.send(response, 0, response.length); + } + saslResult = chosenMechanism.result(); - if (saslResult != null && saslResult.isSuccess()) { - serverSasl.done(Sasl.SaslOutcome.PN_SASL_OK); - serverSasl = null; - saslHandlers.clear(); - saslHandlers = null; - } else { - serverSasl.done(Sasl.SaslOutcome.PN_SASL_AUTH); + if (saslResult != null) { + if (saslResult.isSuccess()) { + saslComplete(Sasl.SaslOutcome.PN_SASL_OK); + } else { + saslComplete(Sasl.SaslOutcome.PN_SASL_AUTH); + } } - serverSasl = null; } else { // 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) { for (EventHandler h : handlers) { h.onAuthInit(this, getConnection(), sasl); } } + private void dispatchRemoteMechanismChosen(final String mech) { + for (EventHandler h : handlers) { + h.onSaslRemoteMechanismChosen(this, mech); + } + } + private void dispatch() { Event ev; @@ -376,4 +389,8 @@ public class ProtonHandler extends ProtonInitializable { this.connection.open(); flush(); } + + public void setChosenMechanism(ServerSASL chosenMechanism) { + this.chosenMechanism = chosenMechanism; + } } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/AnonymousServerSASL.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/AnonymousServerSASL.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/AnonymousServerSASL.java index 013b73b..63f320d 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/AnonymousServerSASL.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/AnonymousServerSASL.java @@ -18,17 +18,29 @@ package org.apache.activemq.artemis.protocol.amqp.sasl; public class AnonymousServerSASL implements ServerSASL { + public static final String NAME = "ANONYMOUS"; + public static final String[] ANONYMOUS_MECH = new String[] {NAME}; + public AnonymousServerSASL() { } @Override public String getName() { - return "ANONYMOUS"; + return NAME; + } + + @Override + public byte[] processSASL(byte[] bytes) { + return null; } @Override - public SASLResult processSASL(byte[] bytes) { + public SASLResult result() { return new PlainSASLResult(true, null, null); } + + @Override + public void done() { + } } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPISASLResult.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPISASLResult.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPISASLResult.java new file mode 100644 index 0000000..0b6e378 --- /dev/null +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPISASLResult.java @@ -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; + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPIServerSASL.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPIServerSASL.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPIServerSASL.java new file mode 100644 index 0000000..e89d548 --- /dev/null +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/GSSAPIServerSASL.java @@ -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; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/MechanismFinder.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/MechanismFinder.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/MechanismFinder.java new file mode 100644 index 0000000..4a8b420 --- /dev/null +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/MechanismFinder.java @@ -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, GSSAPIServerSASL.NAME, AnonymousServerSASL.NAME}; + + public static String[] getKnownMechanisms() { + return KNOWN_MECHANISMS; + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLResult.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLResult.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLResult.java index f138ae3..47683b3 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLResult.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLResult.java @@ -16,6 +16,8 @@ */ package org.apache.activemq.artemis.protocol.amqp.sasl; +import javax.security.auth.Subject; + public class PlainSASLResult implements SASLResult { private boolean success; @@ -29,6 +31,11 @@ public class PlainSASLResult implements SASLResult { } @Override + public Subject getSubject() { + return null; + } + + @Override public String getUser() { return user; } @@ -41,4 +48,5 @@ public class PlainSASLResult implements SASLResult { public boolean isSuccess() { return success; } + } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/SASLResult.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/SASLResult.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/SASLResult.java index f8c4297..37324a4 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/SASLResult.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/SASLResult.java @@ -16,9 +16,13 @@ */ package org.apache.activemq.artemis.protocol.amqp.sasl; +import javax.security.auth.Subject; + public interface SASLResult { String getUser(); + Subject getSubject(); + boolean isSuccess(); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASL.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASL.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASL.java index 43d57d0..f62b730 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASL.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASL.java @@ -20,5 +20,9 @@ public interface ServerSASL { String getName(); - SASLResult processSASL(byte[] bytes); + byte[] processSASL(byte[] bytes); + + SASLResult result(); + + void done(); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASLPlain.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASLPlain.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASLPlain.java index 177334c..42d9f94 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASLPlain.java +++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/sasl/ServerSASLPlain.java @@ -19,6 +19,7 @@ package org.apache.activemq.artemis.protocol.amqp.sasl; public class ServerSASLPlain implements ServerSASL { public static final String NAME = "PLAIN"; + private SASLResult result = null; @Override public String getName() { @@ -26,7 +27,7 @@ public class ServerSASLPlain implements ServerSASL { } @Override - public SASLResult processSASL(byte[] data) { + public byte[] processSASL(byte[] data) { String username = null; String password = null; String bytes = new String(data); @@ -47,7 +48,18 @@ public class ServerSASLPlain implements ServerSASL { 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() { } /** http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLTest.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLTest.java b/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLTest.java index d259de2..9a2a0a2 100644 --- a/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLTest.java +++ b/artemis-protocols/artemis-amqp-protocol/src/test/java/org/apache/activemq/artemis/protocol/amqp/sasl/PlainSASLTest.java @@ -27,7 +27,8 @@ public class PlainSASLTest { byte[] bytesResult = plainSASL.getBytes(); 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("password-secret", result.getPassword()); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnection.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnection.java b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnection.java index 446e362..e1afcb0 100644 --- a/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnection.java +++ b/artemis-protocols/artemis-mqtt-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/mqtt/MQTTConnection.java @@ -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.ReadyListener; +import javax.security.auth.Subject; + public class MQTTConnection implements RemotingConnection { private final Connection transportConnection; @@ -226,4 +228,9 @@ public class MQTTConnection implements RemotingConnection { public boolean isSupportsFlowControl() { return false; } + + @Override + public Subject getSubject() { + return null; + } } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java index a4acdeb..237789f 100644 --- a/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java +++ b/artemis-protocols/artemis-openwire-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/openwire/OpenWireProtocolManager.java @@ -459,7 +459,7 @@ public class OpenWireProtocolManager implements ProtocolManager<Interceptor>, Cl } 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 { http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java index db5dfd6..3bf2b1e 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java @@ -51,6 +51,8 @@ import org.apache.activemq.artemis.utils.ConfigurationHelper; import org.apache.activemq.artemis.utils.ExecutorFactory; import org.apache.activemq.artemis.utils.VersionLoader; +import javax.security.auth.Subject; + import static org.apache.activemq.artemis.core.protocol.stomp.ActiveMQStompProtocolMessageBundle.BUNDLE; public final class StompConnection implements RemotingConnection { @@ -560,7 +562,7 @@ public final class StompConnection implements RemotingConnection { 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); if (valid) { this.login = login; @@ -779,4 +781,9 @@ public final class StompConnection implements RemotingConnection { public boolean isSupportsFlowControl() { return false; } + + @Override + public Subject getSubject() { + return null; + } } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java index fb60847..84c78c2 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompProtocolManager.java @@ -320,16 +320,16 @@ public class StompProtocolManager extends AbstractProtocolManager<StompFrame, St return "activemq"; } - public boolean validateUser(String login, String passcode, Connection connection) { + public boolean validateUser(String login, String passcode, RemotingConnection remotingConnection) { boolean validated = true; ActiveMQSecurityManager sm = server.getSecurityManager(); if (sm != null && server.getConfiguration().isSecurityEnabled()) { 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) { - validated = ((ActiveMQSecurityManager2) sm).validateUser(login, passcode, CertificateUtil.getCertsFromConnection(connection)); + validated = ((ActiveMQSecurityManager2) sm).validateUser(login, passcode, CertificateUtil.getCertsFromConnection(remotingConnection)); } else { validated = sm.validateUser(login, passcode); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v10/StompFrameHandlerV10.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v10/StompFrameHandlerV10.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v10/StompFrameHandlerV10.java index 51abf50..5633987 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v10/StompFrameHandlerV10.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v10/StompFrameHandlerV10.java @@ -52,7 +52,7 @@ public class StompFrameHandlerV10 extends VersionedStompFrameHandler implements String clientID = headers.get(Stomp.Headers.Connect.CLIENT_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.setValid(true); http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java ---------------------------------------------------------------------- diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java index 9e013f8..f9af9f2 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java @@ -68,7 +68,7 @@ public class StompFrameHandlerV11 extends VersionedStompFrameHandler implements String requestID = headers.get(Stomp.Headers.Connect.REQUEST_ID); try { - if (connection.validateUser(login, passcode, connection.getTransportConnection())) { + if (connection.validateUser(login, passcode, connection)) { connection.setClientID(clientID); connection.setValid(true); http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/SecurityStore.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/SecurityStore.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/SecurityStore.java index 1f65443..987faad 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/SecurityStore.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/SecurityStore.java @@ -17,11 +17,11 @@ package org.apache.activemq.artemis.core.security; 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 { - 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; http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java index 9d769db..f4a7013 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/security/impl/SecurityStoreImpl.java @@ -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.settings.HierarchicalRepository; 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.ActiveMQSecurityManager2; import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3; @@ -104,7 +104,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC @Override public String authenticate(final String user, final String password, - Connection connection) throws Exception { + RemotingConnection connection) throws Exception { if (securityEnabled) { if (managementClusterUser.equals(user)) { @@ -185,7 +185,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC final boolean validated; if (securityManager instanceof ActiveMQSecurityManager3) { 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) { final ActiveMQSecurityManager2 securityManager2 = (ActiveMQSecurityManager2) securityManager; validated = securityManager2.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress, session.getRemotingConnection()); http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java index 4856d8b..8d9ce99 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java @@ -1394,7 +1394,7 @@ public class ActiveMQServerImpl implements ActiveMQServer { String validatedUser = ""; if (securityStore != null) { - validatedUser = securityStore.authenticate(username, password, connection.getTransportConnection()); + validatedUser = securityStore.authenticate(username, password, connection); } checkSessionLimit(validatedUser); http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java index dc4e3a8..aaaec82 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQJAASSecurityManager.java @@ -29,7 +29,7 @@ import java.util.Set; import org.apache.activemq.artemis.core.config.impl.SecurityConfiguration; import org.apache.activemq.artemis.core.security.CheckType; 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.RolePrincipal; import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal; @@ -88,9 +88,9 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 { } @Override - public String validateUser(final String user, final String password, Connection connection) { + public String validateUser(final String user, final String password, RemotingConnection remotingConnection) { try { - return getUserFromSubject(getAuthenticatedSubject(user, password, connection)); + return getUserFromSubject(getAuthenticatedSubject(user, password, remotingConnection)); } catch (LoginException e) { if (logger.isDebugEnabled()) { logger.debug("Couldn't validate user", e); @@ -121,10 +121,10 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 { final Set<Role> roles, final CheckType checkType, final String address, - final Connection connection) { + final RemotingConnection remotingConnection) { Subject localSubject; try { - localSubject = getAuthenticatedSubject(user, password, connection); + localSubject = getAuthenticatedSubject(user, password, remotingConnection); } catch (LoginException e) { if (logger.isDebugEnabled()) { logger.debug("Couldn't validate user", e); @@ -170,7 +170,7 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 { private Subject getAuthenticatedSubject(final String user, final String password, - final Connection connection) throws LoginException { + final RemotingConnection remotingConnection) throws LoginException { LoginContext lc; ClassLoader currentLoader = Thread.currentThread().getContextClassLoader(); ClassLoader thisLoader = this.getClass().getClassLoader(); @@ -178,10 +178,10 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager3 { if (thisLoader != currentLoader) { Thread.currentThread().setContextClassLoader(thisLoader); } - if (certificateConfigurationName != null && certificateConfigurationName.length() > 0 && getCertsFromConnection(connection) != null) { - lc = new LoginContext(certificateConfigurationName, null, new JaasCallbackHandler(user, password, connection), certificateConfiguration); + if (certificateConfigurationName != null && certificateConfigurationName.length() > 0 && getCertsFromConnection(remotingConnection) != null) { + lc = new LoginContext(certificateConfigurationName, null, new JaasCallbackHandler(user, password, remotingConnection), certificateConfiguration); } 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(); return lc.getSubject(); http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager3.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager3.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager3.java index 336e812..3a42fc1 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager3.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager3.java @@ -20,7 +20,7 @@ import java.util.Set; import org.apache.activemq.artemis.core.security.CheckType; 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 @@ -40,9 +40,10 @@ public interface ActiveMQSecurityManager3 extends ActiveMQSecurityManager { * * @param user the user * @param password the users password + * @param remotingConnection * @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 @@ -56,7 +57,7 @@ public interface ActiveMQSecurityManager3 extends ActiveMQSecurityManager { * @param roles the user's roles * @param checkType which permission to validate * @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 */ String validateUserAndRole(String user, @@ -64,5 +65,5 @@ public interface ActiveMQSecurityManager3 extends ActiveMQSecurityManager { Set<Role> roles, CheckType checkType, String address, - Connection connection); + RemotingConnection remotingConnection); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCallbackHandler.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCallbackHandler.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCallbackHandler.java index a02d237..a765f45 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCallbackHandler.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCallbackHandler.java @@ -16,14 +16,17 @@ */ 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.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.kerberos.KerberosPrincipal; 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.getPeerPrincipalFromConnection; @@ -35,12 +38,12 @@ public class JaasCallbackHandler implements CallbackHandler { private final String username; 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.password = password; - this.connection = connection; + this.remotingConnection = remotingConnection; } @Override @@ -63,11 +66,19 @@ public class JaasCallbackHandler implements CallbackHandler { } else if (callback instanceof CertificateCallback) { CertificateCallback certCallback = (CertificateCallback) callback; - certCallback.setCertificates(getCertsFromConnection(connection)); - } else if (callback instanceof Krb5SslCallback) { - Krb5SslCallback krb5SslCallback = (Krb5SslCallback) callback; + certCallback.setCertificates(getCertsFromConnection(remotingConnection)); + } else if (callback instanceof Krb5Callback) { + 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 { throw new UnsupportedCallbackException(callback); } http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5Callback.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5Callback.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5Callback.java new file mode 100644 index 0000000..9306d5f --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5Callback.java @@ -0,0 +1,46 @@ +/* + * 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.spi.core.security.jaas; + +import javax.security.auth.callback.Callback; +import java.security.Principal; + +/** + * A Callback for kerberos peer principal. + */ +public class Krb5Callback implements Callback { + + Principal peerPrincipal; + + /** + * Setter for peer Principal. + * + * @param principal The certificates to be returned. + */ + public void setPeerPrincipal(Principal principal) { + peerPrincipal = principal; + } + + /** + * Getter for peer Principal. + * + * @return The principal being carried. + */ + public Principal getPeerPrincipal() { + return peerPrincipal; + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5LoginModule.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5LoginModule.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5LoginModule.java new file mode 100644 index 0000000..3396c81 --- /dev/null +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5LoginModule.java @@ -0,0 +1,112 @@ +/* + * 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.spi.core.security.jaas; + +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.login.LoginException; +import javax.security.auth.spi.LoginModule; +import java.io.IOException; +import java.security.Principal; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * populate a subject with kerberos credential from the handler + */ +public class Krb5LoginModule implements LoginModule { + + private static final Logger logger = Logger.getLogger(Krb5LoginModule.class); + + private Subject subject; + private final List<Principal> principals = new LinkedList<>(); + private CallbackHandler callbackHandler; + private boolean loginSucceeded; + + @Override + public void initialize(Subject subject, + CallbackHandler callbackHandler, + Map<String, ?> sharedState, + Map<String, ?> options) { + this.subject = subject; + this.callbackHandler = callbackHandler; + } + + @Override + public boolean login() throws LoginException { + Callback[] callbacks = new Callback[1]; + + callbacks[0] = new Krb5Callback(); + try { + callbackHandler.handle(callbacks); + } catch (IOException ioe) { + throw new LoginException(ioe.getMessage()); + } catch (UnsupportedCallbackException uce) { + throw new LoginException(uce.getMessage() + " not available to obtain information from user"); + } + principals.add(((Krb5Callback)callbacks[0]).getPeerPrincipal()); + if (!principals.isEmpty()) { + loginSucceeded = true; + } + logger.debug("login " + principals); + return loginSucceeded; + } + + @Override + public boolean commit() throws LoginException { + boolean result = loginSucceeded; + if (result) { + principals.add(new UserPrincipal(principals.get(0).getName())); + subject.getPrincipals().addAll(principals); + } + + clear(); + + logger.debug("commit, result: " + result); + + return result; + } + + @Override + public boolean abort() throws LoginException { + clear(); + + logger.debug("abort"); + + return true; + } + + private void clear() { + loginSucceeded = false; + } + + @Override + public boolean logout() throws LoginException { + subject.getPrincipals().removeAll(principals); + principals.clear(); + clear(); + + logger.debug("logout"); + + return true; + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslCallback.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslCallback.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslCallback.java deleted file mode 100644 index 62c80db..0000000 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslCallback.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.spi.core.security.jaas; - -import javax.security.auth.callback.Callback; -import java.security.Principal; - -/** - * A Callback for SSL kerberos peer principal. - */ -public class Krb5SslCallback implements Callback { - - Principal peerPrincipal; - - /** - * Setter for peer Principal. - * - * @param principal The certificates to be returned. - */ - public void setPeerPrincipal(Principal principal) { - peerPrincipal = principal; - } - - /** - * Getter for peer Principal. - * - * @return The principal being carried. - */ - public Principal getPeerPrincipal() { - return peerPrincipal; - } -} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslLoginModule.java ---------------------------------------------------------------------- diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslLoginModule.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslLoginModule.java deleted file mode 100644 index 1f6b5b1..0000000 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/Krb5SslLoginModule.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.spi.core.security.jaas; - -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.login.LoginException; -import javax.security.auth.spi.LoginModule; -import java.io.IOException; -import java.security.Principal; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * populate a subject with kerberos and UserPrincipal from SSLContext peerPrincipal - */ -public class Krb5SslLoginModule implements LoginModule { - - private static final Logger logger = Logger.getLogger(Krb5SslLoginModule.class); - - private Subject subject; - private final List<Principal> principals = new LinkedList<>(); - private CallbackHandler callbackHandler; - private boolean loginSucceeded; - - @Override - public void initialize(Subject subject, - CallbackHandler callbackHandler, - Map<String, ?> sharedState, - Map<String, ?> options) { - this.subject = subject; - this.callbackHandler = callbackHandler; - } - - @Override - public boolean login() throws LoginException { - Callback[] callbacks = new Callback[1]; - - callbacks[0] = new Krb5SslCallback(); - try { - callbackHandler.handle(callbacks); - } catch (IOException ioe) { - throw new LoginException(ioe.getMessage()); - } catch (UnsupportedCallbackException uce) { - throw new LoginException(uce.getMessage() + " not available to obtain information from user"); - } - principals.add(((Krb5SslCallback)callbacks[0]).getPeerPrincipal()); - if (!principals.isEmpty()) { - loginSucceeded = true; - } - logger.debug("login " + principals); - return loginSucceeded; - } - - @Override - public boolean commit() throws LoginException { - boolean result = loginSucceeded; - if (result) { - principals.add(new UserPrincipal(principals.get(0).getName())); - subject.getPrincipals().addAll(principals); - } - - clear(); - - logger.debug("commit, result: " + result); - - return result; - } - - @Override - public boolean abort() throws LoginException { - clear(); - - logger.debug("abort"); - - return true; - } - - private void clear() { - loginSucceeded = false; - } - - @Override - public boolean logout() throws LoginException { - subject.getPrincipals().removeAll(principals); - principals.clear(); - clear(); - - logger.debug("logout"); - - return true; - } -} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/docs/user-manual/en/security.md ---------------------------------------------------------------------- diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md index f744c92..9173f2f 100644 --- a/docs/user-manual/en/security.md +++ b/docs/user-manual/en/security.md @@ -649,6 +649,25 @@ like the following: The simplest way to make the login configuration available to JAAS is to add the directory containing the file, `login.config`, to your CLASSPATH. +### Kerberos Authentication + +The [https://docs.oracle.com/javase/7/docs/jre/api/security/jaas/spec/com/sun/security/auth/module/Krb5LoginModule.html] +can be used with JAAS on both the client and server to authenticate with Kerberos. + +Using SASL over AMQP, Kerberos authentication is supported using the `GSSAPI` SASL mechanism. By default the server will use a +JAAS login configuration scope named `amqp-sasl-gssapi` to obtain it acceptor Kerberos credentials. The config scope can be +specified explicitly on the amqp acceptor url using the parameter: `saslLoginConfigScope=<some other scope>`. + +On the server, the Kerberos authenticated peer Principal can be extracted from the calling context as a UserPrincipal +using a dedicated login module: + + org.apache.activemq.artemis.spi.core.security.jaas.Krb5LoginModule + +The legacy [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 http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/ca7197b5/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSConnectionWithSecurityTest.java ---------------------------------------------------------------------- diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSConnectionWithSecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSConnectionWithSecurityTest.java index ee82e3d..3bc2354 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSConnectionWithSecurityTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/JMSConnectionWithSecurityTest.java @@ -36,6 +36,11 @@ public class JMSConnectionWithSecurityTest extends JMSClientTestSupport { return true; } + @Override + protected String getJmsConnectionURIOptions() { + return "amqp.saslMechanisms=PLAIN"; + } + @Test(timeout = 10000) public void testNoUserOrPassword() throws Exception { Connection connection = null;