activemq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clebertsuco...@apache.org
Subject [4/5] activemq-artemis git commit: [ARTEMIS-1310] add amqp sasl gssapi mechanism support
Date Tue, 08 Aug 2017 17:34:03 GMT
[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.tully@gmail.com>
Authored: Fri Jul 28 16:02:32 2017 +0100
Committer: Clebert Suconic <clebertsuconic@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;


Mime
View raw message