added a pure XBean based authorization and authentication mechanism

git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@378006 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
James Strachan 2006-02-15 13:33:52 +00:00
parent f4fc3e9a6d
commit affd134592
10 changed files with 323 additions and 117 deletions

View File

@ -17,9 +17,12 @@
package org.apache.activemq.security;
import org.apache.activemq.filter.DestinationMapEntry;
import org.apache.activemq.jaas.GroupPrincipal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
/**
* Represents an entry in a {@link DefaultAuthorizationMap} for assigning
@ -60,4 +63,27 @@ public class AuthorizationEntry extends DestinationMapEntry {
this.writeACLs = writeACLs;
}
// helper methods for easier configuration in Spring
// -------------------------------------------------------------------------
public void setAdmin(String roles) {
setAdminACLs(parseACLs(roles));
}
public void setRead(String roles) {
setReadACLs(parseACLs(roles));
}
public void setWrite(String roles) {
setWriteACLs(parseACLs(roles));
}
protected Set parseACLs(String roles) {
Set answer = new HashSet();
StringTokenizer iter = new StringTokenizer(roles, ",");
while (iter.hasMoreTokens()) {
String name = iter.nextToken().trim();
answer.add(new GroupPrincipal(name));
}
return answer;
}
}

View File

@ -29,28 +29,28 @@ import org.apache.activemq.broker.BrokerPlugin;
*/
public class AuthorizationPlugin implements BrokerPlugin {
private AuthorizationMap authorizationMap;
private AuthorizationMap map;
public AuthorizationPlugin() {
}
public AuthorizationPlugin(AuthorizationMap authorizationMap) {
this.authorizationMap = authorizationMap;
public AuthorizationPlugin(AuthorizationMap map) {
this.map = map;
}
public Broker installPlugin(Broker broker) {
if (authorizationMap == null) {
throw new IllegalArgumentException("You must configure an 'authorizationMap'");
if (map == null) {
throw new IllegalArgumentException("You must configure a 'map' property");
}
return new AuthorizationBroker(broker, authorizationMap);
return new AuthorizationBroker(broker, map);
}
public AuthorizationMap getAuthorizationMap() {
return authorizationMap;
public AuthorizationMap getMap() {
return map;
}
public void setAuthorizationMap(AuthorizationMap authorizationMap) {
this.authorizationMap = authorizationMap;
public void setMap(AuthorizationMap map) {
this.map = map;
}
}

View File

@ -46,10 +46,8 @@ public class DefaultAuthorizationMap extends DestinationMap implements Authoriza
public Set getAdminACLs(ActiveMQDestination destination) {
Set entries = getAllEntries(destination);
Set answer = new HashSet();
Set entries = get(destination);
entries.add(defaultEntry);
// now lets go through each entry adding individual
for (Iterator iter = entries.iterator(); iter.hasNext();) {
AuthorizationEntry entry = (AuthorizationEntry) iter.next();
@ -59,9 +57,8 @@ public class DefaultAuthorizationMap extends DestinationMap implements Authoriza
}
public Set getReadACLs(ActiveMQDestination destination) {
Set entries = getAllEntries(destination);
Set answer = new HashSet();
Set entries = get(destination);
entries.add(defaultEntry);
// now lets go through each entry adding individual
for (Iterator iter = entries.iterator(); iter.hasNext();) {
@ -72,9 +69,8 @@ public class DefaultAuthorizationMap extends DestinationMap implements Authoriza
}
public Set getWriteACLs(ActiveMQDestination destination) {
Set entries = getAllEntries(destination);
Set answer = new HashSet();
Set entries = get(destination);
entries.add(defaultEntry);
// now lets go through each entry adding individual
for (Iterator iter = entries.iterator(); iter.hasNext();) {
@ -112,4 +108,13 @@ public class DefaultAuthorizationMap extends DestinationMap implements Authoriza
protected Class getEntryClass() {
return AuthorizationEntry.class;
}
protected Set getAllEntries(ActiveMQDestination destination) {
Set entries = get(destination);
if (defaultEntry != null) {
entries.add(defaultEntry);
}
return entries;
}
}

View File

@ -39,10 +39,23 @@ public class JassCredentialCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof PasswordCallback) {
((PasswordCallback) callbacks[i]).setPassword(password.toCharArray());
} else if (callbacks[i] instanceof NameCallback) {
((NameCallback) callbacks[i]).setName(username);
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);
}
}
}
}

View File

@ -0,0 +1,65 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed 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 org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.jaas.GroupPrincipal;
import java.util.*;
import java.util.Set;
import junit.framework.TestCase;
/**
*
* @version $Revision$
*/
public class AuthorizationMapTest extends TestCase {
static final GroupPrincipal guests = new GroupPrincipal("guests");
static final GroupPrincipal users = new GroupPrincipal("users");
static final GroupPrincipal admins = new GroupPrincipal("admins");
public void testAuthorizationMap() {
AuthorizationMap map = createAuthorizationMap();
Set readACLs = map.getReadACLs(new ActiveMQQueue("USERS.FOO.BAR"));
assertEquals("set size: " + readACLs, 2, readACLs.size());
assertTrue("Contains users group", readACLs.contains(admins));
assertTrue("Contains users group", readACLs.contains(users));
}
protected AuthorizationMap createAuthorizationMap() {
DefaultAuthorizationMap answer = new DefaultAuthorizationMap();
List entries = new ArrayList();
AuthorizationEntry entry = new AuthorizationEntry();
entry.setQueue(">");
entry.setRead("admins");
entries.add(entry);
entry = new AuthorizationEntry();
entry.setQueue("USERS.>");
entry.setRead("users");
entries.add(entry);
answer.setAuthorizationEntries(entries);
return answer;
}
}

View File

@ -18,6 +18,8 @@ package org.apache.activemq.security;
import org.apache.activemq.JmsTestSupport;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import javax.jms.Connection;
import javax.jms.JMSException;
@ -165,4 +167,60 @@ public class SecurityTestSupport extends JmsTestSupport {
}
public void initCombosForTestUserReceiveFails() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("GUEST.BAR"),
new ActiveMQTopic("GUEST.BAR"), });
}
public void initCombosForTestInvalidAuthentication() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
}
public void initCombosForTestUserReceiveSucceeds() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO"), });
}
public void initCombosForTestGuestReceiveSucceeds() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR"), });
}
public void initCombosForTestGuestReceiveFails() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"),
new ActiveMQTopic("USERS.FOO"), });
}
public void initCombosForTestUserSendSucceeds() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("USERS.FOO"), new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("USERS.FOO"),
new ActiveMQTopic("GUEST.BAR"), });
}
public void initCombosForTestUserSendFails() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), });
}
public void initCombosForTestGuestSendFails() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"),
new ActiveMQTopic("USERS.FOO"), });
}
public void initCombosForTestGuestSendSucceeds() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR"), });
}
}

View File

@ -0,0 +1,28 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed 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;
/**
*
* @version $Revision$
*/
public class SimpleAuthorizationMapTest extends AuthorizationMapTest {
protected AuthorizationMap createAuthorizationMap() {
return SimpleSecurityBrokerSystemTest.createAuthorizationMap();
}
}

View File

@ -28,6 +28,7 @@ import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import junit.framework.Test;
@ -46,7 +47,27 @@ public class SimpleSecurityBrokerSystemTest extends SecurityTestSupport {
public BrokerPlugin authorizationPlugin;
public BrokerPlugin authenticationPlugin;
public AuthorizationMap createAuthorizationMap() {
static {
String path = System.getProperty("java.security.auth.login.config");
if (path == null) {
URL resource = SimpleSecurityBrokerSystemTest.class.getClassLoader().getResource("login.config");
if (resource != null) {
path = resource.getFile();
System.setProperty("java.security.auth.login.config", path);
}
}
System.out.println("Path to login config: " + path);
}
public static Test suite() {
return suite(SimpleSecurityBrokerSystemTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
public static AuthorizationMap createAuthorizationMap() {
DestinationMap readAccess = new DestinationMap();
readAccess.put(new ActiveMQQueue(">"), admins);
readAccess.put(new ActiveMQQueue("USERS.>"), users);
@ -102,26 +123,6 @@ public class SimpleSecurityBrokerSystemTest extends SecurityTestSupport {
}
}
static {
String path = System.getProperty("java.security.auth.login.config");
if (path == null) {
URL resource = SimpleSecurityBrokerSystemTest.class.getClassLoader().getResource("login.config");
if (resource != null) {
path = resource.getFile();
System.setProperty("java.security.auth.login.config", path);
}
}
System.out.println("Path to login config: " + path);
}
public static Test suite() {
return suite(SimpleSecurityBrokerSystemTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
public void initCombos() {
addCombinationValues("authorizationPlugin", new Object[] { new AuthorizationPlugin(createAuthorizationMap()), });
addCombinationValues("authenticationPlugin", new Object[] { new SimpleAuthenticationFactory(), new JassAuthenticationPlugin(), });
@ -134,60 +135,5 @@ public class SimpleSecurityBrokerSystemTest extends SecurityTestSupport {
return broker;
}
public void initCombosForTestUserReceiveFails() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("GUEST.BAR"),
new ActiveMQTopic("GUEST.BAR"), });
}
public void initCombosForTestInvalidAuthentication() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
}
public void initCombosForTestUserReceiveSucceeds() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("USERS.FOO"), new ActiveMQTopic("USERS.FOO"), });
}
public void initCombosForTestGuestReceiveSucceeds() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR"), });
}
public void initCombosForTestGuestReceiveFails() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"),
new ActiveMQTopic("USERS.FOO"), });
}
public void initCombosForTestUserSendSucceeds() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("USERS.FOO"), new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("USERS.FOO"),
new ActiveMQTopic("GUEST.BAR"), });
}
public void initCombosForTestUserSendFails() {
addCombinationValues("userName", new Object[] { "user" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), });
}
public void initCombosForTestGuestSendFails() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("TEST"), new ActiveMQTopic("TEST"), new ActiveMQQueue("USERS.FOO"),
new ActiveMQTopic("USERS.FOO"), });
}
public void initCombosForTestGuestSendSucceeds() {
addCombinationValues("userName", new Object[] { "guest" });
addCombinationValues("password", new Object[] { "password" });
addCombinationValues("destination", new Object[] { new ActiveMQQueue("GUEST.BAR"), new ActiveMQTopic("GUEST.BAR"), });
}
}

View File

@ -0,0 +1,54 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed 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 org.apache.activemq.broker.BrokerFactory;
import org.apache.activemq.broker.BrokerService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.net.URI;
import junit.framework.Test;
/**
*
* @version $Revision$
*/
public class XBeanSecurityTest extends SecurityTestSupport {
private static final Log log = LogFactory.getLog(XBeanSecurityTest.class);
public static Test suite() {
return suite(XBeanSecurityTest.class);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
protected BrokerService createBroker() throws Exception {
return createBroker("org/apache/activemq/security/jaas-broker.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));
}
}

View File

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2005-2006 The Apache Software Foundation
Licensed 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.
Copyright 2005-2006 The Apache Software Foundation
Licensed 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 -->
@ -23,14 +23,25 @@
<plugins>
<!-- use JAAS to authenticate using the login.config file on the classpath to configure JAAS -->
<jassAuthenticationPlugin configuration="activemq-domain"/>
<!-- lets configure a simple authorization mechanism -->
<jassAuthenticationPlugin configuration="activemq-domain" />
<!-- lets configure a destination based authorization mechanism -->
<authorizationPlugin>
<authorizationEntries>
<authorizationEntry topic=">" read="" write="" admin=""/>
<authorizationEntry queue=">" read="" write="" admin=""/>
</authorizationEntries>
<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" write="guests,users" admin="guests,users" />
<authorizationEntry topic=">" read="admins" write="admins" admin="admins" />
<authorizationEntry topic="USERS.>" read="users" write="users" admin="users" />
<authorizationEntry topic="GUEST.>" read="guests" write="guests,users" admin="guests,users" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users" admin="guests,users"/>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
</broker>