mirror of https://github.com/apache/activemq.git
https://issues.apache.org/activemq/browse/AMQ-2081 - anonymous access
git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@957509 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1f063e8557
commit
eeacd65a2b
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.activemq.security;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -25,6 +26,7 @@ import org.apache.activemq.broker.Broker;
|
|||
import org.apache.activemq.broker.BrokerFilter;
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.jaas.GroupPrincipal;
|
||||
|
||||
/**
|
||||
* Handles authenticating a users against a simple user name/password map.
|
||||
|
@ -33,6 +35,9 @@ import org.apache.activemq.command.ConnectionInfo;
|
|||
*/
|
||||
public class SimpleAuthenticationBroker extends BrokerFilter {
|
||||
|
||||
private boolean anonymousAccessAllowed = false;
|
||||
private String anonymousUser;
|
||||
private String anonymousGroup;
|
||||
private final Map userPasswords;
|
||||
private final Map userGroups;
|
||||
private final CopyOnWriteArrayList<SecurityContext> securityContexts = new CopyOnWriteArrayList<SecurityContext>();
|
||||
|
@ -42,22 +47,47 @@ public class SimpleAuthenticationBroker extends BrokerFilter {
|
|||
this.userPasswords = userPasswords;
|
||||
this.userGroups = userGroups;
|
||||
}
|
||||
|
||||
public void setAnonymousAccessAllowed(boolean anonymousAccessAllowed) {
|
||||
this.anonymousAccessAllowed = anonymousAccessAllowed;
|
||||
}
|
||||
|
||||
public void setAnonymousUser(String anonymousUser) {
|
||||
this.anonymousUser = anonymousUser;
|
||||
}
|
||||
|
||||
public void setAnonymousGroup(String anonymousGroup) {
|
||||
this.anonymousGroup = anonymousGroup;
|
||||
}
|
||||
|
||||
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
|
||||
|
||||
if (context.getSecurityContext() == null) {
|
||||
SecurityContext s = context.getSecurityContext();
|
||||
if (s == null) {
|
||||
// Check the username and password.
|
||||
String pw = (String)userPasswords.get(info.getUserName());
|
||||
if (pw == null || !pw.equals(info.getPassword())) {
|
||||
throw new SecurityException("User name or password is invalid.");
|
||||
}
|
||||
|
||||
final Set groups = (Set)userGroups.get(info.getUserName());
|
||||
SecurityContext s = new SecurityContext(info.getUserName()) {
|
||||
public Set<?> getPrincipals() {
|
||||
return groups;
|
||||
if (anonymousAccessAllowed && info.getUserName() == null && info.getPassword() == null) {
|
||||
info.setUserName(anonymousUser);
|
||||
s = new SecurityContext(info.getUserName()) {
|
||||
public Set getPrincipals() {
|
||||
Set groups = new HashSet();
|
||||
groups.add(new GroupPrincipal(anonymousGroup));
|
||||
return groups;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
String pw = (String) userPasswords.get(info.getUserName());
|
||||
if (pw == null || !pw.equals(info.getPassword())) {
|
||||
throw new SecurityException(
|
||||
"User name or password is invalid.");
|
||||
}
|
||||
};
|
||||
|
||||
final Set groups = (Set) userGroups.get(info.getUserName());
|
||||
s = new SecurityContext(info.getUserName()) {
|
||||
public Set<?> getPrincipals() {
|
||||
return groups;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
context.setSecurityContext(s);
|
||||
securityContexts.add(s);
|
||||
|
|
|
@ -41,6 +41,11 @@ import org.apache.activemq.jaas.GroupPrincipal;
|
|||
public class SimpleAuthenticationPlugin implements BrokerPlugin {
|
||||
private Map<String, String> userPasswords;
|
||||
private Map<String, Set<GroupPrincipal>> userGroups;
|
||||
private static final String DEFAULT_ANONYMOUS_USER = "anonymous";
|
||||
private static final String DEFAULT_ANONYMOUS_GROUP = "anonymous";
|
||||
private String anonymousUser = DEFAULT_ANONYMOUS_USER;
|
||||
private String anonymousGroup = DEFAULT_ANONYMOUS_GROUP;
|
||||
private boolean anonymousAccessAllowed = false;
|
||||
|
||||
public SimpleAuthenticationPlugin() {
|
||||
}
|
||||
|
@ -49,8 +54,12 @@ public class SimpleAuthenticationPlugin implements BrokerPlugin {
|
|||
setUsers(users);
|
||||
}
|
||||
|
||||
public Broker installPlugin(Broker broker) {
|
||||
return new SimpleAuthenticationBroker(broker, userPasswords, userGroups);
|
||||
public Broker installPlugin(Broker parent) {
|
||||
SimpleAuthenticationBroker broker = new SimpleAuthenticationBroker(parent, userPasswords, userGroups);
|
||||
broker.setAnonymousAccessAllowed(anonymousAccessAllowed);
|
||||
broker.setAnonymousUser(anonymousUser);
|
||||
broker.setAnonymousGroup(anonymousGroup);
|
||||
return broker;
|
||||
}
|
||||
|
||||
public Map<String, Set<GroupPrincipal>> getUserGroups() {
|
||||
|
@ -77,6 +86,19 @@ public class SimpleAuthenticationPlugin implements BrokerPlugin {
|
|||
userGroups.put(user.getUsername(), groups);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setAnonymousAccessAllowed(boolean anonymousAccessAllowed) {
|
||||
this.anonymousAccessAllowed = anonymousAccessAllowed;
|
||||
}
|
||||
|
||||
public void setAnonymousUser(String anonymousUser) {
|
||||
this.anonymousUser = anonymousUser;
|
||||
}
|
||||
|
||||
public void setAnonymousGroup(String anonymousGroup) {
|
||||
this.anonymousGroup = anonymousGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the groups a user is in. The key is the user name and the value is a
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* 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 javax.jms.Connection;
|
||||
import javax.jms.JMSException;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.apache.activemq.CombinationTestSupport;
|
||||
import org.apache.activemq.broker.BrokerService;
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.apache.activemq.command.ActiveMQTopic;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
public class SimpleAnonymousPluginTest extends SimpleAuthenticationPluginTest {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(SimpleAnonymousPluginTest.class);
|
||||
|
||||
public static Test suite() {
|
||||
return suite(SimpleAnonymousPluginTest.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(suite());
|
||||
}
|
||||
|
||||
protected BrokerService createBroker() throws Exception {
|
||||
return createBroker("org/apache/activemq/security/simple-anonymous-broker.xml");
|
||||
}
|
||||
|
||||
public void testInvalidAuthentication() throws JMSException {
|
||||
|
||||
try {
|
||||
// Bad password
|
||||
Connection c = factory.createConnection("user", "krap");
|
||||
connections.add(c);
|
||||
c.start();
|
||||
fail("Expected exception.");
|
||||
} catch (JMSException e) {
|
||||
}
|
||||
|
||||
try {
|
||||
// Bad userid
|
||||
Connection c = factory.createConnection("userkrap", null);
|
||||
connections.add(c);
|
||||
c.start();
|
||||
fail("Expected exception.");
|
||||
} catch (JMSException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testAnonymousReceiveSucceeds() throws JMSException {
|
||||
doReceive(false);
|
||||
}
|
||||
|
||||
public void testAnonymousReceiveFails() throws JMSException {
|
||||
doReceive(true);
|
||||
}
|
||||
|
||||
public void testAnonymousSendFails() throws JMSException {
|
||||
doSend(true);
|
||||
}
|
||||
|
||||
public void testAnonymousSendSucceeds() throws JMSException {
|
||||
doSend(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link CombinationTestSupport}
|
||||
*/
|
||||
public void initCombosForTestAnonymousReceiveSucceeds() {
|
||||
addCombinationValues("userName", new Object[] {});
|
||||
addCombinationValues("password", new Object[] {});
|
||||
addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR")});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link CombinationTestSupport}
|
||||
*/
|
||||
public void initCombosForTestAnonymousReceiveFails() {
|
||||
addCombinationValues("userName", new Object[] {});
|
||||
addCombinationValues("password", new Object[] {});
|
||||
addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO") });
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link CombinationTestSupport}
|
||||
*/
|
||||
public void initCombosForTestAnonymousSendFails() {
|
||||
addCombinationValues("userName", new Object[] {});
|
||||
addCombinationValues("password", new Object[] {});
|
||||
addCombinationValues("destination", new Object[] {new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO")});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link CombinationTestSupport}
|
||||
*/
|
||||
public void initCombosForTestAnonymousSendSucceeds() {
|
||||
addCombinationValues("userName", new Object[] {});
|
||||
addCombinationValues("password", new Object[] {});
|
||||
addCombinationValues("destination", new Object[] {new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR")});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- this file can only be parsed using the xbean-spring library -->
|
||||
<!-- START SNIPPET: example -->
|
||||
<beans
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:amq="http://activemq.apache.org/schema/core"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
|
||||
|
||||
<broker useJmx="true" persistent="false" xmlns="http://activemq.apache.org/schema/core" populateJMSXUserID="true">
|
||||
|
||||
<destinations>
|
||||
<queue physicalName="TEST.Q" />
|
||||
</destinations>
|
||||
|
||||
<!-- Use a non-default port in case the default port is in use -->
|
||||
<managementContext>
|
||||
<managementContext connectorPort="1199"/>
|
||||
</managementContext>
|
||||
|
||||
<plugins>
|
||||
<simpleAuthenticationPlugin anonymousAccessAllowed="true">
|
||||
<users>
|
||||
<authenticationUser username="system" password="manager"
|
||||
groups="users,admins"/>
|
||||
<authenticationUser username="user" password="password"
|
||||
groups="users"/>
|
||||
<authenticationUser username="guest" password="password" groups="guests"/>
|
||||
</users>
|
||||
</simpleAuthenticationPlugin>
|
||||
|
||||
|
||||
<!-- lets configure a destination based authorization mechanism -->
|
||||
<authorizationPlugin>
|
||||
<map>
|
||||
<authorizationMap>
|
||||
<authorizationEntries>
|
||||
<authorizationEntry queue=">" read="admins" write="admins" admin="admins" />
|
||||
<authorizationEntry queue="USERS.>" read="users" write="users" admin="users" />
|
||||
<authorizationEntry queue="GUEST.>" read="guests,anonymous" write="guests,users,anonymous" admin="guests,users,anonymous" />
|
||||
|
||||
<authorizationEntry queue="TEST.Q" read="guests" write="guests" />
|
||||
|
||||
<authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
|
||||
<authorizationEntry topic="USERS.>" read="users" write="users" admin="users" />
|
||||
<authorizationEntry topic="GUEST.>" read="guests,anonymous" write="guests,users,anonymous" admin="guests,users,anonymous" />
|
||||
|
||||
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users,anonymous" write="guests,users,anonymous" admin="guests,users,anonymous"/>
|
||||
</authorizationEntries>
|
||||
<tempDestinationAuthorizationEntry>
|
||||
<tempDestinationAuthorizationEntry read="admin" write="admin" admin="admin"/>
|
||||
</tempDestinationAuthorizationEntry>
|
||||
</authorizationMap>
|
||||
</map>
|
||||
</authorizationPlugin>
|
||||
</plugins>
|
||||
</broker>
|
||||
|
||||
</beans>
|
Loading…
Reference in New Issue