diff --git a/activemq-core/src/main/java/org/apache/activemq/broker/BrokerService.java b/activemq-core/src/main/java/org/apache/activemq/broker/BrokerService.java
index 2ecd746915..f0dc47217c 100644
--- a/activemq-core/src/main/java/org/apache/activemq/broker/BrokerService.java
+++ b/activemq-core/src/main/java/org/apache/activemq/broker/BrokerService.java
@@ -113,6 +113,8 @@ public class BrokerService implements Service {
private boolean enableStatistics = true;
private boolean persistent = true;
private boolean populateJMSXUserID;
+ private boolean useAuthenticatedPrincipalForJMXUserID;
+
private boolean useShutdownHook = true;
private boolean useLoggingForShutdownErrors;
private boolean shutdownOnMasterFailure;
@@ -1882,7 +1884,9 @@ public class BrokerService implements Service {
broker = new CompositeDestinationBroker(broker);
broker = new TransactionBroker(broker, getPersistenceAdapter().createTransactionStore());
if (isPopulateJMSXUserID()) {
- broker = new UserIDBroker(broker);
+ UserIDBroker userIDBroker = new UserIDBroker(broker);
+ userIDBroker.setUseAuthenticatePrincipal(isUseAuthenticatedPrincipalForJMXUserID());
+ broker = userIDBroker;
}
if (isMonitorConnectionSplits()) {
broker = new ConnectionSplitBroker(broker);
@@ -2338,4 +2342,12 @@ public class BrokerService implements Service {
public void setBrokerId(String brokerId) {
this.brokerId = new BrokerId(brokerId);
}
+
+ public boolean isUseAuthenticatedPrincipalForJMXUserID() {
+ return useAuthenticatedPrincipalForJMXUserID;
+ }
+
+ public void setUseAuthenticatedPrincipalForJMXUserID(boolean useAuthenticatedPrincipalForJMXUserID) {
+ this.useAuthenticatedPrincipalForJMXUserID = useAuthenticatedPrincipalForJMXUserID;
+ }
}
diff --git a/activemq-core/src/main/java/org/apache/activemq/broker/UserIDBroker.java b/activemq-core/src/main/java/org/apache/activemq/broker/UserIDBroker.java
index 84f9be34c4..2d5dea5b15 100644
--- a/activemq-core/src/main/java/org/apache/activemq/broker/UserIDBroker.java
+++ b/activemq-core/src/main/java/org/apache/activemq/broker/UserIDBroker.java
@@ -16,7 +16,10 @@
*/
package org.apache.activemq.broker;
+import java.util.Set;
import org.apache.activemq.command.Message;
+import org.apache.activemq.jaas.UserPrincipal;
+import org.apache.activemq.security.SecurityContext;
/**
* This broker filter will append the producer's user ID into the JMSXUserID header
@@ -27,7 +30,7 @@ import org.apache.activemq.command.Message;
*
*/
public class UserIDBroker extends BrokerFilter {
-
+ boolean useAuthenticatePrincipal = false;
public UserIDBroker(Broker next) {
super(next);
}
@@ -35,7 +38,30 @@ public class UserIDBroker extends BrokerFilter {
public void send(ProducerBrokerExchange producerExchange, Message messageSend) throws Exception {
final ConnectionContext context = producerExchange.getConnectionContext();
String userID = context.getUserName();
+ if (isUseAuthenticatePrincipal()) {
+ SecurityContext securityContext = context.getSecurityContext();
+ if (securityContext != null) {
+ Set> principals = securityContext.getPrincipals();
+ if (principals != null) {
+ for (Object candidate : principals) {
+ if (candidate instanceof UserPrincipal) {
+ userID = ((UserPrincipal)candidate).getName();
+ break;
+ }
+ }
+ }
+ }
+ }
messageSend.setUserID(userID);
super.send(producerExchange, messageSend);
}
+
+
+ public boolean isUseAuthenticatePrincipal() {
+ return useAuthenticatePrincipal;
+ }
+
+ public void setUseAuthenticatePrincipal(boolean useAuthenticatePrincipal) {
+ this.useAuthenticatePrincipal = useAuthenticatePrincipal;
+ }
}
diff --git a/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java b/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java
index b76879e6b2..d9a6f80ad2 100644
--- a/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java
+++ b/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java
@@ -108,15 +108,15 @@ public class JaasDualAuthenticationBroker extends BrokerFilter {
Connector connector = context.getConnector();
if (connector instanceof ManagedTransportConnector) {
ManagedTransportConnector managedTransportConnector = (ManagedTransportConnector) connector;
- isSSL = (managedTransportConnector.getServer() instanceof SslTransportServer);
- } else {
- isSSL = false;
- }
+ isSSL = (managedTransportConnector.getServer() instanceof SslTransportServer);
+ } else {
+ isSSL = false;
+ }
+ super.removeConnection(context, info, error);
if (isSSL) {
this.sslBroker.removeConnection(context, info, error);
} else {
this.nonSslBroker.removeConnection(context, info, error);
}
- super.removeConnection(context, info, error);
}
}
diff --git a/activemq-core/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestTest.java b/activemq-core/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestTest.java
new file mode 100644
index 0000000000..114517bc07
--- /dev/null
+++ b/activemq-core/src/test/java/org/apache/activemq/security/XBeanSecurityWithGuestTest.java
@@ -0,0 +1,125 @@
+/**
+ * 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.security;
+
+import java.net.URI;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import junit.framework.Test;
+import org.apache.activemq.ActiveMQConnection;
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.activemq.CombinationTestSupport;
+import org.apache.activemq.JmsTestSupport;
+import org.apache.activemq.broker.BrokerFactory;
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.command.ActiveMQDestination;
+import org.apache.activemq.command.ActiveMQMessage;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.apache.activemq.command.ActiveMQTopic;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class XBeanSecurityWithGuestTest extends JmsTestSupport {
+
+ private static final Logger LOG = LoggerFactory.getLogger(XBeanSecurityWithGuestTest.class);
+ public ActiveMQDestination destination;
+
+ public static Test suite() {
+ return suite(XBeanSecurityWithGuestTest.class);
+ }
+
+ public void testUserSendGoodPassword() throws JMSException {
+ Message m = doSend(false);
+ assertEquals("system", ((ActiveMQMessage)m).getUserID());
+ assertEquals("system", m.getStringProperty("JMSXUserID"));
+ }
+
+ public void testUserSendWrongPassword() throws JMSException {
+ Message m = doSend(false);
+ // note brokerService.useAuthenticatedPrincipalForJMXUserID=true for this
+ assertEquals("guest", ((ActiveMQMessage)m).getUserID());
+ assertEquals("guest", m.getStringProperty("JMSXUserID"));
+ }
+
+ protected BrokerService createBroker() throws Exception {
+ return createBroker("org/apache/activemq/security/jaas-broker-guest.xml");
+ }
+
+ protected BrokerService createBroker(String uri) throws Exception {
+ LOG.info("Loading broker configuration from the classpath with URI: " + uri);
+ return BrokerFactory.createBroker(new URI("xbean:" + uri));
+ }
+
+ public Message doSend(boolean fail) throws JMSException {
+
+ Connection adminConnection = factory.createConnection("system", "manager");
+ connections.add(adminConnection);
+
+ adminConnection.start();
+ Session adminSession = adminConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = adminSession.createConsumer(destination);
+
+ connections.remove(connection);
+ connection = (ActiveMQConnection)factory.createConnection(userName, password);
+ connections.add(connection);
+
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ try {
+ sendMessages(session, destination, 1);
+ } catch (JMSException e) {
+ // If test is expected to fail, the cause must only be a
+ // SecurityException
+ // otherwise rethrow the exception
+ if (!fail || !(e.getCause() instanceof SecurityException)) {
+ throw e;
+ }
+ }
+
+ Message m = consumer.receive(1000);
+ if (fail) {
+ assertNull(m);
+ } else {
+ assertNotNull(m);
+ assertEquals("0", ((TextMessage)m).getText());
+ assertNull(consumer.receiveNoWait());
+ }
+ return m;
+ }
+
+ /**
+ * @see {@link CombinationTestSupport}
+ */
+ public void initCombosForTestUserSendGoodPassword() {
+ addCombinationValues("userName", new Object[] {"system"});
+ addCombinationValues("password", new Object[] {"manager"});
+ addCombinationValues("destination", new Object[] {new ActiveMQQueue("test"), new ActiveMQTopic("test")});
+ }
+
+ /**
+ * @see {@link CombinationTestSupport}
+ */
+ public void initCombosForTestUserSendWrongPassword() {
+ addCombinationValues("userName", new Object[] {"system"});
+ addCombinationValues("password", new Object[] {"wrongpassword"});
+ addCombinationValues("destination", new Object[] {new ActiveMQQueue("GuestQueue")});
+ }
+}
diff --git a/activemq-core/src/test/resources/login.config b/activemq-core/src/test/resources/login.config
index 6b6529cebc..b8a008e7ea 100644
--- a/activemq-core/src/test/resources/login.config
+++ b/activemq-core/src/test/resources/login.config
@@ -21,6 +21,17 @@ activemq-domain {
org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties";
};
+activemq-guest-domain {
+ org.apache.activemq.jaas.PropertiesLoginModule sufficient
+ debug=true
+ org.apache.activemq.jaas.properties.user="org/apache/activemq/security/users.properties"
+ org.apache.activemq.jaas.properties.group="org/apache/activemq/security/groups.properties";
+ org.apache.activemq.jaas.GuestLoginModule sufficient
+ debug=true
+ org.apache.activemq.jaas.guest.user="guest"
+ org.apache.activemq.jaas.guest.group="guests";
+};
+
cert-login {
org.apache.activemq.jaas.TextFileCertificateLoginModule required
debug=true
@@ -41,4 +52,4 @@ broker2 {
debug=true
org.apache.activemq.jaas.textfiledn.user="org/apache/activemq/security/users2.properties"
org.apache.activemq.jaas.textfiledn.group="org/apache/activemq/security/groups.properties";
-};
\ No newline at end of file
+};
diff --git a/activemq-core/src/test/resources/org/apache/activemq/security/jaas-broker-guest.xml b/activemq-core/src/test/resources/org/apache/activemq/security/jaas-broker-guest.xml
new file mode 100644
index 0000000000..a1072083d6
--- /dev/null
+++ b/activemq-core/src/test/resources/org/apache/activemq/security/jaas-broker-guest.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoginModule.java b/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoginModule.java
index 268e85d039..ae8a98de31 100644
--- a/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoginModule.java
+++ b/activemq-jaas/src/main/java/org/apache/activemq/jaas/PropertiesLoginModule.java
@@ -59,10 +59,12 @@ public class PropertiesLoginModule implements LoginModule {
private String user;
private Set principals = new HashSet();
private File baseDir;
+ private boolean loginSucceeded;
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
+ loginSucceeded = false;
if (System.getProperty("java.security.auth.login.config") != null) {
baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile();
@@ -121,36 +123,41 @@ public class PropertiesLoginModule implements LoginModule {
if (!password.equals(new String(tmpPassword))) {
throw new FailedLoginException("Password does not match");
}
+ loginSucceeded = true;
users.clear();
if (debug) {
LOG.debug("login " + user);
}
- return true;
+ return loginSucceeded;
}
public boolean commit() throws LoginException {
- principals.add(new UserPrincipal(user));
+ boolean result = loginSucceeded;
+ if (result) {
+ principals.add(new UserPrincipal(user));
- for (Enumeration enumeration = groups.keys(); enumeration.hasMoreElements();) {
- String name = (String)enumeration.nextElement();
- String[] userList = ((String)groups.getProperty(name) + "").split(",");
- for (int i = 0; i < userList.length; i++) {
- if (user.equals(userList[i])) {
- principals.add(new GroupPrincipal(name));
- break;
+ for (Enumeration enumeration = groups.keys(); enumeration.hasMoreElements();) {
+ String name = (String)enumeration.nextElement();
+ String[] userList = ((String)groups.getProperty(name) + "").split(",");
+ for (int i = 0; i < userList.length; i++) {
+ if (user.equals(userList[i])) {
+ principals.add(new GroupPrincipal(name));
+ break;
+ }
}
}
+
+ subject.getPrincipals().addAll(principals);
}
- subject.getPrincipals().addAll(principals);
-
+ // will whack loginSucceeded
clear();
if (debug) {
- LOG.debug("commit");
+ LOG.debug("commit, result: " + result);
}
- return true;
+ return result;
}
public boolean abort() throws LoginException {
@@ -165,7 +172,7 @@ public class PropertiesLoginModule implements LoginModule {
public boolean logout() throws LoginException {
subject.getPrincipals().removeAll(principals);
principals.clear();
-
+ clear();
if (debug) {
LOG.debug("logout");
}
@@ -175,5 +182,6 @@ public class PropertiesLoginModule implements LoginModule {
private void clear() {
groups.clear();
user = null;
+ loginSucceeded = false;
}
}