activemq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clebertsuco...@apache.org
Subject [3/3] activemq-artemis git commit: ARTEMIS-261 cert-based auth
Date Wed, 04 Nov 2015 20:57:50 GMT
ARTEMIS-261 cert-based auth


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/0c407922
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/0c407922
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/0c407922

Branch: refs/heads/master
Commit: 0c407922a862a199843a75df433e45cd34068779
Parents: e1fa9bc
Author: jbertram <jbertram@apache.org>
Authored: Wed Oct 28 15:43:33 2015 -0500
Committer: Clebert Suconic <clebertsuconic@apache.org>
Committed: Wed Nov 4 15:56:33 2015 -0500

----------------------------------------------------------------------
 .../activemq/artemis/utils/CertificateUtil.java |  48 +++
 .../artemis/core/security/SecurityStore.java    |   4 +-
 .../core/security/impl/SecurityStoreImpl.java   |  18 +-
 .../core/server/ActiveMQMessageBundle.java      |   4 +-
 .../core/server/impl/ActiveMQServerImpl.java    |   9 +-
 .../security/ActiveMQJAASSecurityManager.java   |  44 ++-
 .../core/security/ActiveMQSecurityManager2.java |  15 +-
 .../core/security/jaas/CertificateCallback.java |   2 +-
 .../security/jaas/CertificateLoginModule.java   |  22 +-
 .../core/security/jaas/JaasCallbackHandler.java |  74 +++++
 .../jaas/JaasCertificateCallbackHandler.java    |  65 ----
 .../jaas/JaasCredentialCallbackHandler.java     |  63 ----
 .../jaas/TextFileCertificateLoginModule.java    |  46 +--
 .../jaas/CertificateLoginModuleTest.java        |  38 +--
 .../PropertiesLoginModuleRaceConditionTest.java |  10 +-
 .../jaas/StubCertificateLoginModule.java        |   4 +-
 docs/user-manual/en/security.md                 | 105 ++++++-
 .../management/SecurityNotificationTest.java    |   1 -
 .../integration/security/SecurityTest.java      | 296 ++++++++++++++++++-
 .../ssl/CoreClientOverOneWaySSLTest.java        |   4 +-
 .../ssl/CoreClientOverTwoWaySSLTest.java        |   6 +-
 .../src/test/resources/cert-roles.properties    |  18 ++
 .../src/test/resources/cert-users.properties    |  18 ++
 .../src/test/resources/login.config             |   7 +
 .../test/resources/bad-client-side-keystore.jks | Bin 0 -> 1277 bytes
 .../test/resources/client-side-keystore.jceks   | Bin 1256 -> 1277 bytes
 .../src/test/resources/client-side-keystore.jks | Bin 1300 -> 1303 bytes
 .../test/resources/client-side-truststore.jceks | Bin 877 -> 897 bytes
 .../test/resources/client-side-truststore.jks   | Bin 1515 -> 963 bytes
 .../test/resources/server-side-keystore.jceks   | Bin 1257 -> 1277 bytes
 .../src/test/resources/server-side-keystore.jks | Bin 2627 -> 2253 bytes
 .../test/resources/server-side-truststore.jceks | Bin 876 -> 897 bytes
 .../test/resources/server-side-truststore.jks   | Bin 893 -> 1732 bytes
 33 files changed, 703 insertions(+), 218 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java
----------------------------------------------------------------------
diff --git a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java
new file mode 100644
index 0000000..5e96687
--- /dev/null
+++ b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/CertificateUtil.java
@@ -0,0 +1,48 @@
+/**
+ * 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.utils;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.security.cert.X509Certificate;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.handler.ssl.SslHandler;
+
+public class CertificateUtil {
+   public static X509Certificate[] getCertsFromChannel(Channel channel) {
+      X509Certificate[] certificates = null;
+      ChannelHandler channelHandler = channel
+         .pipeline()
+         .get("ssl");
+      if (channelHandler != null && channelHandler instanceof SslHandler) {
+         SslHandler sslHandler = (SslHandler) channelHandler;
+         try {
+            certificates = sslHandler
+               .engine()
+               .getSession()
+               .getPeerCertificateChain();
+         }
+         catch (SSLPeerUnverifiedException e) {
+            // ignore
+         }
+      }
+
+      return certificates;
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/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 466e7cf..88fab08 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
@@ -16,11 +16,13 @@
  */
 package org.apache.activemq.artemis.core.security;
 
+import javax.security.cert.X509Certificate;
+
 import org.apache.activemq.artemis.api.core.SimpleString;
 
 public interface SecurityStore {
 
-   void authenticate(String user, String password) throws Exception;
+   void authenticate(String user, String password, X509Certificate[] certificates) throws Exception;
 
    void check(SimpleString address, CheckType checkType, SecurityAuth session) throws Exception;
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/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 d3c7d03..3a20952 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
@@ -16,6 +16,7 @@
  */
 package org.apache.activemq.artemis.core.security.impl;
 
+import javax.security.cert.X509Certificate;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -101,7 +102,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
       securityRepository.unRegisterListener(this);
    }
 
-   public void authenticate(final String user, final String password) throws Exception {
+   public void authenticate(final String user, final String password, X509Certificate[] certificates) throws Exception {
       if (securityEnabled) {
 
          if (managementClusterUser.equals(user)) {
@@ -121,18 +122,25 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
             }
          }
 
-         if (!securityManager.validateUser(user, password)) {
+         boolean userIsValid = false;
+
+         if (securityManager instanceof ActiveMQSecurityManager2) {
+            userIsValid = ((ActiveMQSecurityManager2)securityManager).validateUser(user, password, certificates);
+         }
+         else {
+            userIsValid = securityManager.validateUser(user, password);
+         }
+
+         if (!userIsValid) {
             if (notificationService != null) {
                TypedProperties props = new TypedProperties();
 
-               props.putSimpleStringProperty(ManagementHelper.HDR_USER, SimpleString.toSimpleString(user));
-
                Notification notification = new Notification(null, CoreNotificationType.SECURITY_AUTHENTICATION_VIOLATION, props);
 
                notificationService.sendNotification(notification);
             }
 
-            throw ActiveMQMessageBundle.BUNDLE.unableToValidateUser(user);
+            throw ActiveMQMessageBundle.BUNDLE.unableToValidateUser();
          }
       }
    }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java
index 3d57ade..a08a1f4 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java
@@ -149,8 +149,8 @@ public interface ActiveMQMessageBundle {
    @Message(id = 119030, value = "large-message not initialized on server")
    ActiveMQIllegalStateException largeMessageNotInitialised();
 
-   @Message(id = 119031, value = "Unable to validate user: {0}", format = Message.Format.MESSAGE_FORMAT)
-   ActiveMQSecurityException unableToValidateUser(String user);
+   @Message(id = 119031, value = "Unable to validate user", format = Message.Format.MESSAGE_FORMAT)
+   ActiveMQSecurityException unableToValidateUser();
 
    @Message(id = 119032, value = "User: {0} does not have permission=''{1}'' on address {2}", format = Message.Format.MESSAGE_FORMAT)
    ActiveMQSecurityException userNoPermissions(String username, CheckType checkType, String saddress);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/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 0cc0172..e7d4c5f 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
@@ -17,6 +17,7 @@
 package org.apache.activemq.artemis.core.server.impl;
 
 import javax.management.MBeanServer;
+import javax.security.cert.X509Certificate;
 import java.io.File;
 import java.io.FilenameFilter;
 import java.io.PrintWriter;
@@ -77,6 +78,7 @@ import org.apache.activemq.artemis.core.postoffice.QueueBinding;
 import org.apache.activemq.artemis.core.postoffice.impl.DivertBinding;
 import org.apache.activemq.artemis.core.postoffice.impl.LocalQueueBinding;
 import org.apache.activemq.artemis.core.postoffice.impl.PostOfficeImpl;
+import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnection;
 import org.apache.activemq.artemis.core.remoting.server.RemotingService;
 import org.apache.activemq.artemis.core.remoting.server.impl.RemotingServiceImpl;
 import org.apache.activemq.artemis.core.replication.ReplicationManager;
@@ -125,6 +127,7 @@ import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
 import org.apache.activemq.artemis.spi.core.protocol.SessionCallback;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
 import org.apache.activemq.artemis.utils.ActiveMQThreadFactory;
+import org.apache.activemq.artemis.utils.CertificateUtil;
 import org.apache.activemq.artemis.utils.ConcurrentHashSet;
 import org.apache.activemq.artemis.utils.ExecutorFactory;
 import org.apache.activemq.artemis.utils.OrderedExecutorFactory;
@@ -932,7 +935,11 @@ public class ActiveMQServerImpl implements ActiveMQServer {
                                       final boolean autoCreateQueues) throws Exception {
 
       if (securityStore != null) {
-         securityStore.authenticate(username, password);
+         X509Certificate[] certificates = null;
+         if (connection.getTransportConnection() instanceof NettyConnection) {
+            certificates = CertificateUtil.getCertsFromChannel(((NettyConnection)connection.getTransportConnection()).getChannel());
+         }
+         securityStore.authenticate(username, password, certificates);
       }
 
       checkSessionLimit(username);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/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 6a13f22..71f4511 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
@@ -19,16 +19,20 @@ package org.apache.activemq.artemis.spi.core.security;
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
+import javax.security.cert.X509Certificate;
 import java.security.Principal;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 
+import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnection;
 import org.apache.activemq.artemis.core.security.CheckType;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
-import org.apache.activemq.artemis.spi.core.security.jaas.JaasCredentialCallbackHandler;
+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.utils.CertificateUtil;
 
 /**
  * This implementation delegates to the JAAS security interfaces.
@@ -36,33 +40,51 @@ import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal;
  * The {@link Subject} returned by the login context is expecting to have a set of {@link RolePrincipal} for each
  * role of the user.
  */
-public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager {
+public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager2 {
 
    private final boolean trace = ActiveMQServerLogger.LOGGER.isTraceEnabled();
 
    private String configurationName;
 
-   public boolean validateUser(final String user, final String password) {
+   @Override
+   public boolean validateUser(String user, String password) {
+      throw new UnsupportedOperationException("Invoke validateUser(String, String, X509Certificate[]) instead");
+   }
+
+   @Override
+   public boolean validateUser(final String user, final String password, X509Certificate[] certificates) {
       try {
-         getAuthenticatedSubject(user, password);
+         getAuthenticatedSubject(user, password, certificates);
          return true;
       }
       catch (LoginException e) {
-         ActiveMQServerLogger.LOGGER.debug("Couldn't validate user: " + user, e);
+         ActiveMQServerLogger.LOGGER.debug("Couldn't validate user", e);
          return false;
       }
    }
 
+   @Override
+   public boolean validateUserAndRole(String user, String password, Set<Role> roles, CheckType checkType) {
+      throw new UnsupportedOperationException("Invoke validateUserAndRole(String, String, Set<Role>, CheckType, String, RemotingConnection) instead");
+   }
+
+   @Override
    public boolean validateUserAndRole(final String user,
                                       final String password,
                                       final Set<Role> roles,
-                                      final CheckType checkType) {
+                                      final CheckType checkType,
+                                      final String address,
+                                      final RemotingConnection connection) {
+      X509Certificate[] certificates = null;
+      if (connection.getTransportConnection() instanceof NettyConnection) {
+         certificates = CertificateUtil.getCertsFromChannel(((NettyConnection) connection.getTransportConnection()).getChannel());
+      }
       Subject localSubject;
       try {
-         localSubject = getAuthenticatedSubject(user, password);
+         localSubject = getAuthenticatedSubject(user, password, certificates);
       }
       catch (LoginException e) {
-         ActiveMQServerLogger.LOGGER.debug("Couldn't validate user: " + user, e);
+         ActiveMQServerLogger.LOGGER.debug("Couldn't validate user", e);
          return false;
       }
 
@@ -85,15 +107,15 @@ public class ActiveMQJAASSecurityManager implements ActiveMQSecurityManager {
          }
 
          if (trace) {
-            ActiveMQServerLogger.LOGGER.trace("user " + user + (authorized ? " is " : " is NOT ") + "authorized");
+            ActiveMQServerLogger.LOGGER.trace("user " + (authorized ? " is " : " is NOT ") + "authorized");
          }
       }
 
       return authorized;
    }
 
-   private Subject getAuthenticatedSubject(final String user, final String password) throws LoginException {
-      LoginContext lc = new LoginContext(configurationName, new JaasCredentialCallbackHandler(user, password));
+   private Subject getAuthenticatedSubject(final String user, final String password, final X509Certificate[] certificates) throws LoginException {
+      LoginContext lc = new LoginContext(configurationName, new JaasCallbackHandler(user, password, certificates));
       lc.login();
       return lc.getSubject();
    }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
index 72b4121..e44a785 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/ActiveMQSecurityManager2.java
@@ -16,6 +16,7 @@
  */
 package org.apache.activemq.artemis.spi.core.security;
 
+import javax.security.cert.X509Certificate;
 import java.util.Set;
 
 import org.apache.activemq.artemis.core.security.CheckType;
@@ -33,11 +34,23 @@ import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
 public interface ActiveMQSecurityManager2 extends ActiveMQSecurityManager {
 
    /**
+    * is this a valid user.
+    *
+    * This method is called instead of
+    * {@link ActiveMQSecurityManager#validateUser(String, String)}.
+    *
+    * @param user     the user
+    * @param password the users password
+    * @return true if a valid user
+    */
+   boolean validateUser(String user, String password, X509Certificate[] certificates);
+
+   /**
     * Determine whether the given user is valid and whether they have
     * the correct role for the given destination address.
     *
     * This method is called instead of
-    * {@link ActiveMQSecurityManager.validateUserAndRole}.
+    * {@link ActiveMQSecurityManager#validateUserAndRole(String, String, Set, CheckType)}.
     *
     * @param user      the user
     * @param password  the user's password

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateCallback.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateCallback.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateCallback.java
index 630dd32..5a2361a 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateCallback.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateCallback.java
@@ -17,7 +17,7 @@
 package org.apache.activemq.artemis.spi.core.security.jaas;
 
 import javax.security.auth.callback.Callback;
-import java.security.cert.X509Certificate;
+import javax.security.cert.X509Certificate;
 
 /**
  * A Callback for SSL certificates.

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateLoginModule.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateLoginModule.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateLoginModule.java
index db8808b..fbacb31 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateLoginModule.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/CertificateLoginModule.java
@@ -23,9 +23,9 @@ import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.security.auth.login.FailedLoginException;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
+import javax.security.cert.X509Certificate;
 import java.io.IOException;
 import java.security.Principal;
-import java.security.cert.X509Certificate;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
@@ -35,7 +35,7 @@ import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
 /**
  * A LoginModule that allows for authentication based on SSL certificates.
  * Allows for subclasses to define methods used to verify user certificates and
- * find user groups. Uses CertificateCallbacks to retrieve certificates.
+ * find user roles. Uses CertificateCallbacks to retrieve certificates.
  */
 public abstract class CertificateLoginModule implements LoginModule {
 
@@ -44,7 +44,7 @@ public abstract class CertificateLoginModule implements LoginModule {
 
    private X509Certificate[] certificates;
    private String username;
-   private Set<String> groups;
+   private Set<String> roles;
    private Set<Principal> principals = new HashSet<Principal>();
    private boolean debug;
 
@@ -87,7 +87,7 @@ public abstract class CertificateLoginModule implements LoginModule {
          throw new FailedLoginException("No user for client certificate: " + getDistinguishedName(certificates));
       }
 
-      groups = getUserGroups(username);
+      roles = getUserRoles(username);
 
       if (debug) {
          ActiveMQServerLogger.LOGGER.debug("Certificate for user: " + username);
@@ -102,8 +102,8 @@ public abstract class CertificateLoginModule implements LoginModule {
    public boolean commit() throws LoginException {
       principals.add(new UserPrincipal(username));
 
-      for (String group : groups) {
-         principals.add(new RolePrincipal(group));
+      for (String role : roles) {
+         principals.add(new RolePrincipal(role));
       }
 
       subject.getPrincipals().addAll(principals);
@@ -147,13 +147,13 @@ public abstract class CertificateLoginModule implements LoginModule {
     * Helper method.
     */
    private void clear() {
-      groups.clear();
+      roles.clear();
       certificates = null;
    }
 
    /**
     * Should return a unique name corresponding to the certificates given. The
-    * name returned will be used to look up access levels as well as group
+    * name returned will be used to look up access levels as well as role
     * associations.
     *
     * @param certs The distinguished name.
@@ -162,14 +162,14 @@ public abstract class CertificateLoginModule implements LoginModule {
    protected abstract String getUserNameForCertificates(final X509Certificate[] certs) throws LoginException;
 
    /**
-    * Should return a set of the groups this user belongs to. The groups
+    * Should return a set of the roles this user belongs to. The roles
     * returned will be added to the user's credentials.
     *
     * @param username The username of the client. This is the same name that
     *                 getUserNameForDn returned for the user's DN.
-    * @return A Set of the names of the groups this user belongs to.
+    * @return A Set of the names of the roles this user belongs to.
     */
-   protected abstract Set<String> getUserGroups(final String username) throws LoginException;
+   protected abstract Set<String> getUserRoles(final String username) throws LoginException;
 
    protected String getDistinguishedName(final X509Certificate[] certs) {
       if (certs != null && certs.length > 0 && certs[0] != null) {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/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
new file mode 100644
index 0000000..71a6172
--- /dev/null
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCallbackHandler.java
@@ -0,0 +1,74 @@
+/*
+ * 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 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.cert.X509Certificate;
+import java.io.IOException;
+
+/**
+ * A JAAS username password CallbackHandler.
+ */
+public class JaasCallbackHandler implements CallbackHandler {
+
+   private final String username;
+   private final String password;
+   final X509Certificate[] certificates;
+
+   public JaasCallbackHandler(String username, String password, X509Certificate[] certs) {
+      this.username = username;
+      this.password = password;
+      this.certificates = certs;
+   }
+
+   @Override
+   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+      for (int i = 0; i < callbacks.length; i++) {
+         Callback callback = callbacks[i];
+         if (callback instanceof PasswordCallback) {
+            PasswordCallback passwordCallback = (PasswordCallback) callback;
+            if (password == null) {
+               passwordCallback.setPassword(null);
+            }
+            else {
+               passwordCallback.setPassword(password.toCharArray());
+            }
+         }
+         else if (callback instanceof NameCallback) {
+            NameCallback nameCallback = (NameCallback) callback;
+            if (username == null) {
+               nameCallback.setName(null);
+            }
+            else {
+               nameCallback.setName(username);
+            }
+         }
+         else if (callback instanceof CertificateCallback) {
+            CertificateCallback certCallback = (CertificateCallback) callback;
+
+            certCallback.setCertificates(certificates);
+         }
+         else {
+            throw new UnsupportedCallbackException(callback);
+         }
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCertificateCallbackHandler.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCertificateCallbackHandler.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCertificateCallbackHandler.java
deleted file mode 100644
index 22ddf54..0000000
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCertificateCallbackHandler.java
+++ /dev/null
@@ -1,65 +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 javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import java.io.IOException;
-import java.security.cert.X509Certificate;
-
-/**
- * A Standard JAAS callback handler for SSL certificate requests. Will only
- * handle callbacks of type CertificateCallback.
- */
-public class JaasCertificateCallbackHandler implements CallbackHandler {
-
-   final X509Certificate[] certificates;
-
-   /**
-    * Basic constructor.
-    *
-    * @param certs The certificate returned when calling back.
-    */
-   public JaasCertificateCallbackHandler(X509Certificate[] certs) {
-      certificates = certs;
-   }
-
-   /**
-    * Overriding handle method to handle certificates.
-    *
-    * @param callbacks The callbacks requested.
-    * @throws IOException
-    * @throws UnsupportedCallbackException Thrown if an unknown Callback type is
-    *                                      encountered.
-    */
-   @Override
-   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-      for (int i = 0; i < callbacks.length; i++) {
-         Callback callback = callbacks[i];
-         if (callback instanceof CertificateCallback) {
-            CertificateCallback certCallback = (CertificateCallback) callback;
-
-            certCallback.setCertificates(certificates);
-
-         }
-         else {
-            throw new UnsupportedCallbackException(callback);
-         }
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCredentialCallbackHandler.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCredentialCallbackHandler.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCredentialCallbackHandler.java
deleted file mode 100644
index 34ae701..0000000
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/JaasCredentialCallbackHandler.java
+++ /dev/null
@@ -1,63 +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 javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import java.io.IOException;
-
-/**
- * A JAAS username password CallbackHandler.
- */
-public class JaasCredentialCallbackHandler implements CallbackHandler {
-
-   private final String username;
-   private final String password;
-
-   public JaasCredentialCallbackHandler(String username, String password) {
-      this.username = username;
-      this.password = password;
-   }
-
-   @Override
-   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-      for (int i = 0; i < callbacks.length; i++) {
-         Callback callback = callbacks[i];
-         if (callback instanceof PasswordCallback) {
-            PasswordCallback passwordCallback = (PasswordCallback) callback;
-            if (password == null) {
-               passwordCallback.setPassword(null);
-            }
-            else {
-               passwordCallback.setPassword(password.toCharArray());
-            }
-         }
-         else if (callback instanceof NameCallback) {
-            NameCallback nameCallback = (NameCallback) callback;
-            if (username == null) {
-               nameCallback.setName(null);
-            }
-            else {
-               nameCallback.setName(username);
-            }
-         }
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/TextFileCertificateLoginModule.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/TextFileCertificateLoginModule.java b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/TextFileCertificateLoginModule.java
index 77f5a43..68639db 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/TextFileCertificateLoginModule.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/spi/core/security/jaas/TextFileCertificateLoginModule.java
@@ -19,9 +19,9 @@ package org.apache.activemq.artemis.spi.core.security.jaas;
 import javax.security.auth.Subject;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.login.LoginException;
+import javax.security.cert.X509Certificate;
 import java.io.File;
 import java.io.IOException;
-import java.security.cert.X509Certificate;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Map;
@@ -32,21 +32,21 @@ import java.util.Set;
  * A LoginModule allowing for SSL certificate based authentication based on
  * Distinguished Names (DN) stored in text files. The DNs are parsed using a
  * Properties class where each line is <user_name>=<user_DN>. This class also
- * uses a group definition file where each line is <group_name>=<user_name_1>,<user_name_2>,etc.
- * The user and group files' locations must be specified in the
+ * uses a group definition file where each line is <role_name>=<user_name_1>,<user_name_2>,etc.
+ * The user and role files' locations must be specified in the
  * org.apache.activemq.jaas.textfiledn.user and
- * org.apache.activemq.jaas.textfiledn.user properties respectively. NOTE: This
+ * org.apache.activemq.jaas.textfiledn.role properties respectively. NOTE: This
  * class will re-read user and group files for every authentication (i.e it does
  * live updates of allowed groups and users).
  */
 public class TextFileCertificateLoginModule extends CertificateLoginModule {
 
    private static final String USER_FILE = "org.apache.activemq.jaas.textfiledn.user";
-   private static final String GROUP_FILE = "org.apache.activemq.jaas.textfiledn.group";
+   private static final String ROLE_FILE = "org.apache.activemq.jaas.textfiledn.role";
 
    private File baseDir;
    private String usersFilePathname;
-   private String groupsFilePathname;
+   private String rolesFilePathname;
 
    /**
     * Performs initialization of file paths. A standard JAAS override.
@@ -61,8 +61,8 @@ public class TextFileCertificateLoginModule extends CertificateLoginModule {
          baseDir = new File(".");
       }
 
-      usersFilePathname = (String) options.get(USER_FILE) + "";
-      groupsFilePathname = (String) options.get(GROUP_FILE) + "";
+      usersFilePathname = options.get(USER_FILE) + "";
+      rolesFilePathname = options.get(ROLE_FILE) + "";
    }
 
    /**
@@ -98,7 +98,7 @@ public class TextFileCertificateLoginModule extends CertificateLoginModule {
 
       Enumeration<Object> keys = users.keys();
       for (Enumeration<Object> vals = users.elements(); vals.hasMoreElements(); ) {
-         if (((String) vals.nextElement()).equals(dn)) {
+         if (vals.nextElement().equals(dn)) {
             return (String) keys.nextElement();
          }
          else {
@@ -110,38 +110,38 @@ public class TextFileCertificateLoginModule extends CertificateLoginModule {
    }
 
    /**
-    * Overriding to allow for group discovery based on text files.
+    * Overriding to allow for role discovery based on text files.
     *
     * @param username The name of the user being examined. This is the same
     *                 name returned by getUserNameForCertificates.
-    * @return A Set of name Strings for groups this user belongs to.
-    * @throws LoginException Thrown if unable to find group definition file.
+    * @return A Set of name Strings for roles this user belongs to.
+    * @throws LoginException Thrown if unable to find role definition file.
     */
    @Override
-   protected Set<String> getUserGroups(String username) throws LoginException {
-      File groupsFile = new File(baseDir, groupsFilePathname);
+   protected Set<String> getUserRoles(String username) throws LoginException {
+      File rolesFile = new File(baseDir, rolesFilePathname);
 
-      Properties groups = new Properties();
+      Properties roles = new Properties();
       try {
-         java.io.FileInputStream in = new java.io.FileInputStream(groupsFile);
-         groups.load(in);
+         java.io.FileInputStream in = new java.io.FileInputStream(rolesFile);
+         roles.load(in);
          in.close();
       }
       catch (IOException ioe) {
-         throw new LoginException("Unable to load group properties file " + groupsFile);
+         throw new LoginException("Unable to load role properties file " + rolesFile);
       }
-      Set<String> userGroups = new HashSet<String>();
-      for (Enumeration<Object> enumeration = groups.keys(); enumeration.hasMoreElements(); ) {
+      Set<String> userRoles = new HashSet<String>();
+      for (Enumeration<Object> enumeration = roles.keys(); enumeration.hasMoreElements(); ) {
          String groupName = (String) enumeration.nextElement();
-         String[] userList = (groups.getProperty(groupName) + "").split(",");
+         String[] userList = (roles.getProperty(groupName) + "").split(",");
          for (int i = 0; i < userList.length; i++) {
             if (username.equals(userList[i])) {
-               userGroups.add(groupName);
+               userRoles.add(groupName);
                break;
             }
          }
       }
 
-      return userGroups;
+      return userRoles;
    }
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/CertificateLoginModuleTest.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/CertificateLoginModuleTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/CertificateLoginModuleTest.java
index 9b3c33d..24069dd 100644
--- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/CertificateLoginModuleTest.java
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/CertificateLoginModuleTest.java
@@ -27,7 +27,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.Vector;
 
-import org.apache.activemq.artemis.spi.core.security.jaas.JaasCertificateCallbackHandler;
+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;
 import org.junit.Assert;
@@ -37,17 +37,17 @@ import org.junit.Test;
 public class CertificateLoginModuleTest extends Assert {
 
    private static final String USER_NAME = "testUser";
-   private static final List<String> GROUP_NAMES = new Vector<String>();
+   private static final List<String> ROLE_NAMES = new Vector<String>();
 
    private StubCertificateLoginModule loginModule;
 
    private Subject subject;
 
    public CertificateLoginModuleTest() {
-      GROUP_NAMES.add("testGroup1");
-      GROUP_NAMES.add("testGroup2");
-      GROUP_NAMES.add("testGroup3");
-      GROUP_NAMES.add("testGroup4");
+      ROLE_NAMES.add("testRole1");
+      ROLE_NAMES.add("testRole2");
+      ROLE_NAMES.add("testRole3");
+      ROLE_NAMES.add("testRole4");
    }
 
    @Before
@@ -55,9 +55,9 @@ public class CertificateLoginModuleTest extends Assert {
       subject = new Subject();
    }
 
-   private void loginWithCredentials(String userName, Set<String> groupNames) throws LoginException {
-      loginModule = new StubCertificateLoginModule(userName, new HashSet<String>(groupNames));
-      JaasCertificateCallbackHandler callbackHandler = new JaasCertificateCallbackHandler(null);
+   private void loginWithCredentials(String userName, Set<String> rolesNames) throws LoginException {
+      loginModule = new StubCertificateLoginModule(userName, new HashSet<String>(rolesNames));
+      JaasCallbackHandler callbackHandler = new JaasCallbackHandler(null, null, null);
 
       loginModule.initialize(subject, callbackHandler, null, new HashMap());
 
@@ -67,9 +67,9 @@ public class CertificateLoginModuleTest extends Assert {
 
    private void checkPrincipalsMatch(Subject subject) {
       boolean nameFound = false;
-      boolean[] groupsFound = new boolean[GROUP_NAMES.size()];
-      for (int i = 0; i < groupsFound.length; ++i) {
-         groupsFound[i] = false;
+      boolean[] rolesFound = new boolean[ROLE_NAMES.size()];
+      for (int i = 0; i < rolesFound.length; ++i) {
+         rolesFound[i] = false;
       }
 
       for (Iterator iter = subject.getPrincipals().iterator(); iter.hasNext(); ) {
@@ -91,17 +91,17 @@ public class CertificateLoginModuleTest extends Assert {
 
          }
          else if (currentPrincipal instanceof RolePrincipal) {
-            int principalIdx = GROUP_NAMES.indexOf(((RolePrincipal) currentPrincipal).getName());
+            int principalIdx = ROLE_NAMES.indexOf(((RolePrincipal) currentPrincipal).getName());
 
             if (principalIdx < 0) {
-               fail("Unknown GroupPrincipal found.");
+               fail("Unknown RolePrincipal found.");
             }
 
-            if (!groupsFound[principalIdx]) {
-               groupsFound[principalIdx] = true;
+            if (!rolesFound[principalIdx]) {
+               rolesFound[principalIdx] = true;
             }
             else {
-               fail("GroupPrincipal found twice.");
+               fail("RolePrincipal found twice.");
             }
          }
          else {
@@ -113,7 +113,7 @@ public class CertificateLoginModuleTest extends Assert {
    @Test
    public void testLoginSuccess() throws IOException {
       try {
-         loginWithCredentials(USER_NAME, new HashSet<String>(GROUP_NAMES));
+         loginWithCredentials(USER_NAME, new HashSet<String>(ROLE_NAMES));
       }
       catch (Exception e) {
          fail("Unable to login: " + e.getMessage());
@@ -141,7 +141,7 @@ public class CertificateLoginModuleTest extends Assert {
    @Test
    public void testLogOut() throws IOException {
       try {
-         loginWithCredentials(USER_NAME, new HashSet<String>(GROUP_NAMES));
+         loginWithCredentials(USER_NAME, new HashSet<String>(ROLE_NAMES));
       }
       catch (Exception e) {
          fail("Unable to login: " + e.getMessage());

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/PropertiesLoginModuleRaceConditionTest.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/PropertiesLoginModuleRaceConditionTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/PropertiesLoginModuleRaceConditionTest.java
index de72563..eb71c4c 100644
--- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/PropertiesLoginModuleRaceConditionTest.java
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/PropertiesLoginModuleRaceConditionTest.java
@@ -32,7 +32,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.activemq.artemis.spi.core.security.jaas.JaasCredentialCallbackHandler;
+import org.apache.activemq.artemis.spi.core.security.jaas.JaasCallbackHandler;
 import org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule;
 import org.junit.After;
 import org.junit.Before;
@@ -46,7 +46,7 @@ import static org.junit.Assert.assertTrue;
 
 public class PropertiesLoginModuleRaceConditionTest {
 
-   private static final String GROUPS_FILE = "roles.properties";
+   private static final String ROLES_FILE = "roles.properties";
    private static final String USERS_FILE = "users.properties";
    private static final String USERNAME = "first";
    private static final String PASSWORD = "secret";
@@ -114,12 +114,12 @@ public class PropertiesLoginModuleRaceConditionTest {
       options.put("reload", "true"); // Used to simplify reproduction of the
       // race condition
       options.put("org.apache.activemq.jaas.properties.user", USERS_FILE);
-      options.put("org.apache.activemq.jaas.properties.role", GROUPS_FILE);
+      options.put("org.apache.activemq.jaas.properties.role", ROLES_FILE);
       options.put("baseDir", temp.getRoot().getAbsolutePath());
 
       errors = new ArrayBlockingQueue<Exception>(processorCount());
       pool = Executors.newFixedThreadPool(processorCount());
-      callback = new JaasCredentialCallbackHandler(USERNAME, PASSWORD);
+      callback = new JaasCallbackHandler(USERNAME, PASSWORD, null);
    }
 
    @After
@@ -182,7 +182,7 @@ public class PropertiesLoginModuleRaceConditionTest {
       for (int i = 0; i < 100; i++) {
          groups.put("group" + i, "first,second,third");
       }
-      store(groups, temp.newFile(GROUPS_FILE));
+      store(groups, temp.newFile(ROLES_FILE));
    }
 
    private void createUsers() throws FileNotFoundException, IOException {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/StubCertificateLoginModule.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/StubCertificateLoginModule.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/StubCertificateLoginModule.java
index 6c7bf24..6474f24 100644
--- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/StubCertificateLoginModule.java
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/security/jaas/StubCertificateLoginModule.java
@@ -17,7 +17,7 @@
 package org.apache.activemq.artemis.core.security.jaas;
 
 import javax.security.auth.login.LoginException;
-import java.security.cert.X509Certificate;
+import javax.security.cert.X509Certificate;
 import java.util.Set;
 
 import org.apache.activemq.artemis.spi.core.security.jaas.CertificateLoginModule;
@@ -40,7 +40,7 @@ public class StubCertificateLoginModule extends CertificateLoginModule {
       return userName;
    }
 
-   protected Set getUserGroups(String username) throws LoginException {
+   protected Set getUserRoles(String username) throws LoginException {
       lastUserName = username;
       return this.groupNames;
    }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/docs/user-manual/en/security.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/security.md b/docs/user-manual/en/security.md
index 4e797f2..263f268 100644
--- a/docs/user-manual/en/security.md
+++ b/docs/user-manual/en/security.md
@@ -522,7 +522,7 @@ managed using the X.500 system. It is implemented by `org.apache.activemq.artemi
         `javax.naming.directory.SearchControls.SUBTREE_SCOPE`).
 
 -   `debug` - boolean flag; if `true`, enable debugging; this is used only for testing or debugging; normally, it 
-should be set to `false`, or omitted; default is `false`
+    should be set to `false`, or omitted; default is `false`
 
 Add user entries under the node specified by the `userBase` option. When creating a new user entry in the directory, 
 choose an object class that supports the `userPassword` attribute (for example, the `person` or `inetOrgPerson` object 
@@ -539,6 +539,109 @@ corresponding user (where the DN is specified either fully, `uid=jdoe,ou=User,ou
 If you want to add roles to user entries, you would need to customize the directory schema, by adding a suitable 
 attribute type to the user entry's object class. The chosen attribute type must be capable of handling multiple values.
 
+#### CertificateLoginModule
+
+The JAAS certificate authentication login module must be used in combination with SSL and the clients must be configured
+with their own certificate. In this scenario, authentication is actually performed during the SSL/TLS handshake, not 
+directly by the JAAS certificate authentication plug-in. The role of the plug-in is as follows:
+
+-   To further constrain the set of acceptable users, because only the user DNs explicitly listed in the relevant 
+    properties file are eligible to be authenticated.
+
+-   To associate a list of groups with the received user identity, facilitating integration with the authorization feature.
+
+-   To require the presence of an incoming certificate (by default, the SSL/TLS layer is configured to treat the 
+    presence of a client certificate as optional).
+
+The JAAS certificate login module stores a collection of certificate DNs in a pair of flat files. The files associate a 
+username and a list of group IDs with each DN.
+
+The certificate login module is implemented by the following class:
+
+    org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule
+
+The following `CertLogin` login entry shows how to configure certificate login module in the login.config file:
+
+    CertLogin {
+        org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule
+            debug=true
+            org.apache.activemq.jaas.textfiledn.user="users.properties"
+            org.apache.activemq.jaas.textfiledn.role="roles.properties";
+    };
+
+In the preceding example, the JAAS realm is configured to use a single `org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule`
+login module. The options supported by this login module are as follows:
+
+-   `debug` - boolean flag; if true, enable debugging; this is used only for testing or debugging; normally, 
+    it should be set to `false`, or omitted; default is `false`
+
+-   `org.apache.activemq.jaas.textfiledn.user` - specifies the location of the user properties file (relative to the 
+     directory containing the login configuration file).
+
+-   `org.apache.activemq.jaas.textfiledn.role` - specifies the location of the role properties file (relative to the 
+    directory containing the login configuration file).
+
+In the context of the certificate login module, the `users.properties` file consists of a list of properties of the form,
+`UserName=StringifiedSubjectDN`. For example, to define the users, system, user, and guest, you could create a file like
+the following:
+
+    system=CN=system,O=Progress,C=US
+    user=CN=humble user,O=Progress,C=US
+    guest=CN=anon,O=Progress,C=DE
+
+Each username is mapped to a subject DN, encoded as a string (where the string encoding is specified by RFC 2253). For 
+example, the system username is mapped to the `CN=system,O=Progress,C=US` subject DN. When performing authentication,
+the plug-in extracts the subject DN from the received certificate, converts it to the standard string format, and 
+compares it with the subject DNs in the `users.properties` file by testing for string equality. Consequently, you must 
+be careful to ensure that the subject DNs appearing in the `users.properties` file are an exact match for the subject
+DNs extracted from the user certificates.
+
+Note: Technically, there is some residual ambiguity in the DN string format. For example, the `domainComponent` attribute
+could be represented in a string either as the string, `DC`, or as the OID, `0.9.2342.19200300.100.1.25`. Normally, you do 
+not need to worry about this ambiguity. But it could potentially be a problem, if you changed the underlying 
+implementation of the Java security layer.
+
+The easiest way to obtain the subject DNs from the user certificates is by invoking the `keytool` utility to print the 
+certificate contents. To print the contents of a certificate in a keystore, perform the following steps:
+
+1.   Export the certificate from the keystore file into a temporary file. For example, to export the certificate with 
+     alias `broker-localhost` from the `broker.ks` keystore file, enter the following command:
+
+        keytool -export -file broker.export -alias broker-localhost -keystore broker.ks -storepass password
+
+     After running this command, the exported certificate is in the file, `broker.export`.
+
+1.   Print out the contents of the exported certificate. For example, to print out the contents of `broker.export`, 
+     enter the following command:
+
+        keytool -printcert -file broker.export
+
+     Which should produce output similar to that shown here:
+
+        Owner: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
+        Issuer: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
+        Serial number: 4537c82e
+        Valid from: Thu Oct 19 19:47:10 BST 2006 until: Wed Jan 17 18:47:10 GMT 2007
+        Certificate fingerprints:
+                 MD5:  3F:6C:0C:89:A8:80:29:CC:F5:2D:DA:5C:D7:3F:AB:37
+                 SHA1: F0:79:0D:04:38:5A:46:CE:86:E1:8A:20:1F:7B:AB:3A:46:E4:34:5C
+
+     The string following `Owner:` gives the subject DN. The format used to enter the subject DN depends on your 
+     platform. The `Owner:` string above could be represented as either `CN=localhost,\ OU=broker,\ O=Unknown,\ L=Unknown,\ ST=Unknown,\ C=Unknown`
+     or `CN=localhost,OU=broker,O=Unknown,L=Unknown,ST=Unknown,C=Unknown`.
+
+The `roles.properties` file consists of a list of properties of the form, `Role=UserList`, where `UserList` is a 
+comma-separated list of users. For example, to define the roles `admins`, `users`, and `guests`, you could create a file
+like the following:
+
+    admins=system
+    users=system,user
+    guests=guest
+
+The simplest way to make the login configuration available to JAAS is to add the directory containing the file, 
+`login.config`, to your CLASSPATH.
+
+
 ## Changing the username/password for clustering
 
 In order for cluster connections to work correctly, each node in the

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java
index 015cbf4..19fd6cf 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/SecurityNotificationTest.java
@@ -81,7 +81,6 @@ public class SecurityNotificationTest extends ActiveMQTestBase {
 
       ClientMessage[] notifications = SecurityNotificationTest.consumeMessages(1, notifConsumer);
       Assert.assertEquals(SECURITY_AUTHENTICATION_VIOLATION.toString(), notifications[0].getObjectProperty(ManagementHelper.HDR_NOTIFICATION_TYPE).toString());
-      Assert.assertEquals(unknownUser, notifications[0].getObjectProperty(ManagementHelper.HDR_USER).toString());
    }
 
    @Test

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
index b45ce45..915e3af 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/security/SecurityTest.java
@@ -16,16 +16,22 @@
  */
 package org.apache.activemq.artemis.tests.integration.security;
 
+import javax.security.cert.X509Certificate;
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
 import java.lang.management.ManagementFactory;
 import java.net.URL;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.activemq.artemis.api.core.ActiveMQException;
+import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
 import org.apache.activemq.artemis.api.core.ActiveMQSecurityException;
 import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.TransportConfiguration;
+import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
 import org.apache.activemq.artemis.api.core.client.ClientConsumer;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
 import org.apache.activemq.artemis.api.core.client.ClientProducer;
@@ -34,6 +40,7 @@ import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
 import org.apache.activemq.artemis.api.core.client.ServerLocator;
 import org.apache.activemq.artemis.core.config.Configuration;
 import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnection;
+import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
 import org.apache.activemq.artemis.core.security.CheckType;
 import org.apache.activemq.artemis.core.security.Role;
 import org.apache.activemq.artemis.core.server.ActiveMQServer;
@@ -42,10 +49,10 @@ import org.apache.activemq.artemis.core.server.Queue;
 import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
 import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
 import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
+import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManagerImpl;
-import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager;
 import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
 import org.apache.activemq.artemis.tests.util.CreateMessage;
 import org.junit.Assert;
@@ -103,6 +110,43 @@ public class SecurityTest extends ActiveMQTestBase {
    }
 
    @Test
+   public void testJAASSecurityManagerAuthenticationWithCerts() throws Exception {
+      ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager();
+      securityManager.setConfigurationName("CertLogin");
+      ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
+
+      Map<String, Object> params = new HashMap<String, Object>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "server-side-keystore.jks");
+      params.put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "server-side-truststore.jks");
+      params.put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, true);
+
+      server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params));
+
+      server.start();
+
+      TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
+      tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "client-side-truststore.jks");
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      tc.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "client-side-keystore.jks");
+      tc.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
+      ClientSessionFactory cf = createSessionFactory(locator);
+
+      try {
+         ClientSession session = cf.createSession();
+         session.close();
+      }
+      catch (ActiveMQException e) {
+         e.printStackTrace();
+         Assert.fail("should not throw exception");
+      }
+   }
+
+   @Test
    public void testJAASSecurityManagerAuthenticationBadPassword() throws Exception {
       ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager();
       securityManager.setConfigurationName("PropertiesLogin");
@@ -119,6 +163,50 @@ public class SecurityTest extends ActiveMQTestBase {
       }
    }
 
+   /**
+    * This test requires a client-side certificate that will be trusted by the server but whose dname will be rejected
+    * by the CertLogin login module. I created this cert with the follow commands:
+    *
+    * keytool -genkey -keystore bad-client-side-keystore.jks -storepass secureexample -keypass secureexample -dname "CN=Bad Client, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ"
+    * keytool -export -keystore bad-client-side-keystore.jks -file activemq-jks.cer -storepass secureexample
+    * keytool -import -keystore server-side-truststore.jks -file activemq-jks.cer -storepass secureexample -keypass secureexample -noprompt -alias bad
+    */
+   @Test
+   public void testJAASSecurityManagerAuthenticationWithBadClientCert() throws Exception {
+      ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager();
+      securityManager.setConfigurationName("CertLogin");
+      ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
+
+      Map<String, Object> params = new HashMap<String, Object>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "server-side-keystore.jks");
+      params.put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "server-side-truststore.jks");
+      params.put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, true);
+
+      server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params));
+
+      server.start();
+
+      TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
+      tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "client-side-truststore.jks");
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      tc.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "bad-client-side-keystore.jks");
+      tc.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
+      ClientSessionFactory cf = createSessionFactory(locator);
+
+      try {
+         cf.createSession();
+         fail("Creating session here should fail due to authentication error.");
+      }
+      catch (ActiveMQException e) {
+         assertTrue(e.getType() == ActiveMQExceptionType.SECURITY_EXCEPTION);
+      }
+   }
+
    @Test
    public void testJAASSecurityManagerAuthenticationGuest() throws Exception {
       ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager();
@@ -223,6 +311,112 @@ public class SecurityTest extends ActiveMQTestBase {
    }
 
    @Test
+   public void testJAASSecurityManagerAuthorizationNegativeWithCerts() throws Exception {
+      final SimpleString ADDRESS = new SimpleString("address");
+      final SimpleString DURABLE_QUEUE = new SimpleString("durableQueue");
+      final SimpleString NON_DURABLE_QUEUE = new SimpleString("nonDurableQueue");
+
+      ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager();
+      securityManager.setConfigurationName("CertLogin");
+      ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
+
+      Map<String, Object> params = new HashMap<String, Object>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "server-side-keystore.jks");
+      params.put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "server-side-truststore.jks");
+      params.put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, true);
+
+      server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params));
+
+      Set<Role> roles = new HashSet<>();
+      roles.add(new Role("programmers", false, false, false, false, false, false, false));
+      server.getConfiguration().getSecurityRoles().put("#", roles);
+
+      server.start();
+
+      TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
+      tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "client-side-truststore.jks");
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      tc.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "client-side-keystore.jks");
+      tc.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
+      ClientSessionFactory cf = createSessionFactory(locator);
+
+      server.createQueue(ADDRESS, DURABLE_QUEUE, null, true, false);
+      server.createQueue(ADDRESS, NON_DURABLE_QUEUE, null, false, false);
+
+      ClientSession session = addClientSession(cf.createSession());
+
+      // CREATE_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, DURABLE_QUEUE, true);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // DELETE_DURABLE_QUEUE
+      try {
+         session.deleteQueue(DURABLE_QUEUE);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // CREATE_NON_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, NON_DURABLE_QUEUE, false);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // DELETE_NON_DURABLE_QUEUE
+      try {
+         session.deleteQueue(NON_DURABLE_QUEUE);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // PRODUCE
+      try {
+         ClientProducer producer = session.createProducer(ADDRESS);
+         producer.send(session.createMessage(true));
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // CONSUME
+      try {
+         ClientConsumer consumer = session.createConsumer(DURABLE_QUEUE);
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+
+      // MANAGE
+      try {
+         ClientProducer producer = session.createProducer(server.getConfiguration().getManagementAddress());
+         producer.send(session.createMessage(true));
+         Assert.fail("should throw exception here");
+      }
+      catch (ActiveMQException e) {
+         // ignore
+      }
+   }
+
+   @Test
    public void testJAASSecurityManagerAuthorizationPositive() throws Exception {
       final SimpleString ADDRESS = new SimpleString("address");
       final SimpleString DURABLE_QUEUE = new SimpleString("durableQueue");
@@ -301,6 +495,102 @@ public class SecurityTest extends ActiveMQTestBase {
    }
 
    @Test
+   public void testJAASSecurityManagerAuthorizationPositiveWithCerts() throws Exception {
+      final SimpleString ADDRESS = new SimpleString("address");
+      final SimpleString DURABLE_QUEUE = new SimpleString("durableQueue");
+      final SimpleString NON_DURABLE_QUEUE = new SimpleString("nonDurableQueue");
+
+      ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager();
+      securityManager.setConfigurationName("CertLogin");
+      ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
+
+      Map<String, Object> params = new HashMap<String, Object>();
+      params.put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      params.put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "server-side-keystore.jks");
+      params.put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "server-side-truststore.jks");
+      params.put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      params.put(TransportConstants.NEED_CLIENT_AUTH_PROP_NAME, true);
+
+      server.getConfiguration().addAcceptorConfiguration(new TransportConfiguration(NETTY_ACCEPTOR_FACTORY, params));
+
+      Set<Role> roles = new HashSet<>();
+      roles.add(new Role("programmers", true, true, true, true, true, true, true));
+      server.getConfiguration().getSecurityRoles().put("#", roles);
+      server.start();
+
+      TransportConfiguration tc = new TransportConfiguration(NETTY_CONNECTOR_FACTORY);
+      tc.getParams().put(TransportConstants.SSL_ENABLED_PROP_NAME, true);
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PATH_PROP_NAME, "client-side-truststore.jks");
+      tc.getParams().put(TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME, "secureexample");
+      tc.getParams().put(TransportConstants.KEYSTORE_PATH_PROP_NAME, "client-side-keystore.jks");
+      tc.getParams().put(TransportConstants.KEYSTORE_PASSWORD_PROP_NAME, "secureexample");
+      ServerLocator locator = addServerLocator(ActiveMQClient.createServerLocatorWithoutHA(tc));
+      ClientSessionFactory cf = createSessionFactory(locator);
+      ClientSession session = addClientSession(cf.createSession());
+
+      // CREATE_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, DURABLE_QUEUE, true);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      // DELETE_DURABLE_QUEUE
+      try {
+         session.deleteQueue(DURABLE_QUEUE);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      // CREATE_NON_DURABLE_QUEUE
+      try {
+         session.createQueue(ADDRESS, NON_DURABLE_QUEUE, false);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      // DELETE_NON_DURABLE_QUEUE
+      try {
+         session.deleteQueue(NON_DURABLE_QUEUE);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      session.createQueue(ADDRESS, DURABLE_QUEUE, true);
+
+      // PRODUCE
+      try {
+         ClientProducer producer = session.createProducer(ADDRESS);
+         producer.send(session.createMessage(true));
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      // CONSUME
+      try {
+         session.createConsumer(DURABLE_QUEUE);
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+
+      // MANAGE
+      try {
+         ClientProducer producer = session.createProducer(server.getConfiguration().getManagementAddress());
+         producer.send(session.createMessage(true));
+      }
+      catch (ActiveMQException e) {
+         Assert.fail("should not throw exception here");
+      }
+   }
+
+   @Test
    public void testJAASSecurityManagerAuthorizationPositiveGuest() throws Exception {
       final SimpleString ADDRESS = new SimpleString("address");
       final SimpleString DURABLE_QUEUE = new SimpleString("durableQueue");
@@ -1454,6 +1744,10 @@ public class SecurityTest extends ActiveMQTestBase {
       final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
       final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager2() {
             public boolean validateUser(final String username, final String password) {
+               fail("Unexpected call to overridden method");
+               return false;
+            }
+            public boolean validateUser(final String username, final String password, final X509Certificate[] certificates) {
                return (username.equals("foo") || username.equals("bar") || username.equals("all")) &&
                   password.equals("frobnicate");
             }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
index 70b2d7c..46c60eb 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverOneWaySSLTest.java
@@ -69,12 +69,12 @@ public class CoreClientOverOneWaySSLTest extends ActiveMQTestBase {
     * These artifacts are required for testing 1-way SSL
     *
     * Commands to create the JKS artifacts:
-    * keytool -genkey -keystore server-side-keystore.jks -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis, OU=ActiveMQ Artemis, O=ActiveMQ Artemis, L=ActiveMQ Artemis, S=ActiveMQ Artemis, C=AMQ"
+    * keytool -genkey -keystore server-side-keystore.jks -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis Server, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ" -keyalg RSA
     * keytool -export -keystore server-side-keystore.jks -file activemq-jks.cer -storepass secureexample
     * keytool -import -keystore client-side-truststore.jks -file activemq-jks.cer -storepass secureexample -keypass secureexample -noprompt
     *
     * Commands to create the JCEKS artifacts:
-    * keytool -genkey -keystore server-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis, OU=ActiveMQ Artemis, O=ActiveMQ Artemis, L=ActiveMQ Artemis, S=ActiveMQ Artemis, C=AMQ"
+    * keytool -genkey -keystore server-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis Server, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ"
     * keytool -export -keystore server-side-keystore.jceks -file activemq-jceks.cer -storetype jceks -storepass secureexample
     * keytool -import -keystore client-side-truststore.jceks -storetype JCEKS -file activemq-jceks.cer -storepass secureexample -keypass secureexample -noprompt
     */

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java
index 0704b6c..00cc0a7 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ssl/CoreClientOverTwoWaySSLTest.java
@@ -70,15 +70,15 @@ public class CoreClientOverTwoWaySSLTest extends ActiveMQTestBase {
    public static final SimpleString QUEUE = new SimpleString("QueueOverSSL");
 
    /**
-    * These artifacts are required for testing 2-way SSL
+    * These artifacts are required for testing 2-way SSL in addition to the artifacts for 1-way SSL
     *
     * Commands to create the JKS artifacts:
-    * keytool -genkey -keystore client-side-keystore.jks -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis, OU=ActiveMQ Artemis, O=ActiveMQ Artemis, L=ActiveMQ Artemis, S=ActiveMQ Artemis, C=AMQ"
+    * keytool -genkey -keystore client-side-keystore.jks -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis Client, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ"
     * keytool -export -keystore client-side-keystore.jks -file activemq-jks.cer -storepass secureexample
     * keytool -import -keystore server-side-truststore.jks -file activemq-jks.cer -storepass secureexample -keypass secureexample -noprompt
     *
     * Commands to create the JCEKS artifacts:
-    * keytool -genkey -keystore client-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis, OU=ActiveMQ Artemis, O=ActiveMQ Artemis, L=ActiveMQ Artemis, S=ActiveMQ Artemis, C=AMQ"
+    * keytool -genkey -keystore client-side-keystore.jceks -storetype JCEKS -storepass secureexample -keypass secureexample -dname "CN=ActiveMQ Artemis Client, OU=Artemis, O=ActiveMQ, L=AMQ, S=AMQ, C=AMQ"
     * keytool -export -keystore client-side-keystore.jceks -file activemq-jceks.cer -storetype jceks -storepass secureexample
     * keytool -import -keystore server-side-truststore.jceks -storetype JCEKS -file activemq-jceks.cer -storepass secureexample -keypass secureexample -noprompt
     */

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/integration-tests/src/test/resources/cert-roles.properties
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/resources/cert-roles.properties b/tests/integration-tests/src/test/resources/cert-roles.properties
new file mode 100644
index 0000000..4f3ba3f
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/cert-roles.properties
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+programmers=first

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/integration-tests/src/test/resources/cert-users.properties
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/resources/cert-users.properties b/tests/integration-tests/src/test/resources/cert-users.properties
new file mode 100644
index 0000000..7bd65f0
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/cert-users.properties
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+first=CN=ActiveMQ Artemis Client, OU=Artemis, O=ActiveMQ, L=AMQ, ST=AMQ, C=AMQ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/integration-tests/src/test/resources/login.config
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/resources/login.config b/tests/integration-tests/src/test/resources/login.config
index 9b1e1c0..7c160c5 100644
--- a/tests/integration-tests/src/test/resources/login.config
+++ b/tests/integration-tests/src/test/resources/login.config
@@ -116,3 +116,10 @@ OpenLdapConfiguration {
         roleSearchSubtree=true
         ;
 };
+
+CertLogin {
+    org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule required
+        debug=true
+        org.apache.activemq.jaas.textfiledn.user="cert-users.properties"
+        org.apache.activemq.jaas.textfiledn.role="cert-roles.properties";
+};

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/unit-tests/src/test/resources/bad-client-side-keystore.jks
----------------------------------------------------------------------
diff --git a/tests/unit-tests/src/test/resources/bad-client-side-keystore.jks b/tests/unit-tests/src/test/resources/bad-client-side-keystore.jks
new file mode 100644
index 0000000..c7f7812
Binary files /dev/null and b/tests/unit-tests/src/test/resources/bad-client-side-keystore.jks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/unit-tests/src/test/resources/client-side-keystore.jceks
----------------------------------------------------------------------
diff --git a/tests/unit-tests/src/test/resources/client-side-keystore.jceks b/tests/unit-tests/src/test/resources/client-side-keystore.jceks
index 0372cf5..5c223a1 100644
Binary files a/tests/unit-tests/src/test/resources/client-side-keystore.jceks and b/tests/unit-tests/src/test/resources/client-side-keystore.jceks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/unit-tests/src/test/resources/client-side-keystore.jks
----------------------------------------------------------------------
diff --git a/tests/unit-tests/src/test/resources/client-side-keystore.jks b/tests/unit-tests/src/test/resources/client-side-keystore.jks
index 07a1f4d..cb65a44 100644
Binary files a/tests/unit-tests/src/test/resources/client-side-keystore.jks and b/tests/unit-tests/src/test/resources/client-side-keystore.jks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/unit-tests/src/test/resources/client-side-truststore.jceks
----------------------------------------------------------------------
diff --git a/tests/unit-tests/src/test/resources/client-side-truststore.jceks b/tests/unit-tests/src/test/resources/client-side-truststore.jceks
index 0947c9a..161154e 100644
Binary files a/tests/unit-tests/src/test/resources/client-side-truststore.jceks and b/tests/unit-tests/src/test/resources/client-side-truststore.jceks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/unit-tests/src/test/resources/client-side-truststore.jks
----------------------------------------------------------------------
diff --git a/tests/unit-tests/src/test/resources/client-side-truststore.jks b/tests/unit-tests/src/test/resources/client-side-truststore.jks
index c82242a..7eb1d56 100644
Binary files a/tests/unit-tests/src/test/resources/client-side-truststore.jks and b/tests/unit-tests/src/test/resources/client-side-truststore.jks differ

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/0c407922/tests/unit-tests/src/test/resources/server-side-keystore.jceks
----------------------------------------------------------------------
diff --git a/tests/unit-tests/src/test/resources/server-side-keystore.jceks b/tests/unit-tests/src/test/resources/server-side-keystore.jceks
index 2a4e72c..dd9962b 100644
Binary files a/tests/unit-tests/src/test/resources/server-side-keystore.jceks and b/tests/unit-tests/src/test/resources/server-side-keystore.jceks differ


Mime
View raw message