This closes #175 ARTEMIS-229 address on Security Interface
This commit is contained in:
commit
e85bb3ca4a
|
@ -34,6 +34,7 @@ import org.apache.activemq.artemis.core.server.management.NotificationService;
|
|||
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
|
||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
||||
import org.apache.activemq.artemis.utils.ConcurrentHashSet;
|
||||
import org.apache.activemq.artemis.utils.TypedProperties;
|
||||
|
||||
|
@ -159,7 +160,16 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
|||
return;
|
||||
}
|
||||
|
||||
if (!securityManager.validateUserAndRole(user, session.getPassword(), roles, checkType)) {
|
||||
final boolean validated;
|
||||
if (securityManager instanceof ActiveMQSecurityManager2) {
|
||||
final ActiveMQSecurityManager2 securityManager2 = (ActiveMQSecurityManager2) securityManager;
|
||||
validated = securityManager2.validateUserAndRole(user, session.getPassword(), roles, checkType, saddress);
|
||||
}
|
||||
else {
|
||||
validated = securityManager.validateUserAndRole(user, session.getPassword(), roles, checkType);
|
||||
}
|
||||
|
||||
if (!validated) {
|
||||
if (notificationService != null) {
|
||||
TypedProperties props = new TypedProperties();
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.activemq.artemis.core.security.CheckType;
|
||||
import org.apache.activemq.artemis.core.security.Role;
|
||||
|
||||
/**
|
||||
* Used to validate whether a user is authorized to connect to the
|
||||
* server and perform certain functions on certain destinations.
|
||||
*
|
||||
* This is an evolution of {@link ActiveMQSecurityManager} that adds
|
||||
* the ability to perform authorization taking the destination address
|
||||
* into account.
|
||||
*/
|
||||
public interface ActiveMQSecurityManager2 extends ActiveMQSecurityManager {
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*
|
||||
* @param user the user
|
||||
* @param password the user's password
|
||||
* @param roles the user's roles
|
||||
* @param checkType which permission to validate
|
||||
* @param address the address for which to perform authorization
|
||||
* @return true if the user is valid and they have the correct roles for the given destination address
|
||||
*/
|
||||
boolean validateUserAndRole(String user, String password, Set<Role> roles, CheckType checkType, String address);
|
||||
}
|
|
@ -33,10 +33,14 @@ import org.apache.activemq.artemis.api.core.client.ServerLocator;
|
|||
import org.apache.activemq.artemis.tests.util.CreateMessage;
|
||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||
import org.apache.activemq.artemis.core.config.Configuration;
|
||||
import org.apache.activemq.artemis.core.security.CheckType;
|
||||
import org.apache.activemq.artemis.core.security.Role;
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||
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.security.ActiveMQSecurityManager;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManagerImpl;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
@ -1049,6 +1053,213 @@ public class SecurityTest extends ActiveMQTestBase {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomSecurityManager() throws Exception {
|
||||
final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
|
||||
final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager() {
|
||||
public boolean validateUser(final String username, final String password) {
|
||||
return (username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||
password.equals("frobnicate");
|
||||
}
|
||||
public boolean validateUserAndRole(
|
||||
final String username,
|
||||
final String password,
|
||||
final Set<Role> requiredRoles,
|
||||
final CheckType checkType) {
|
||||
|
||||
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||
password.equals("frobnicate")) {
|
||||
|
||||
if (username.equals("all")) {
|
||||
return true;
|
||||
}
|
||||
else if (username.equals("foo")) {
|
||||
return checkType == CheckType.CONSUME || checkType == CheckType.CREATE_NON_DURABLE_QUEUE;
|
||||
}
|
||||
else if (username.equals("bar")) {
|
||||
return checkType == CheckType.SEND || checkType == CheckType.CREATE_NON_DURABLE_QUEUE;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
final ActiveMQServer server = addServer(new ActiveMQServerImpl(configuration, customSecurityManager));
|
||||
server.start();
|
||||
|
||||
final ServerLocator locator = createInVMNonHALocator();
|
||||
locator.setBlockOnNonDurableSend(true).setBlockOnDurableSend(true);
|
||||
final ClientSessionFactory factory = createSessionFactory(locator);
|
||||
ClientSession adminSession = factory.createSession("all", "frobnicate", false, true, true, false, -1);
|
||||
|
||||
final String queueName = "test.queue";
|
||||
adminSession.createQueue(queueName, queueName, false);
|
||||
|
||||
// Wrong user name
|
||||
try {
|
||||
factory.createSession("baz", "frobnicate", false, true, true, false, -1);
|
||||
Assert.fail("should throw exception");
|
||||
}
|
||||
catch (ActiveMQSecurityException se) {
|
||||
//ok
|
||||
}
|
||||
catch (ActiveMQException e) {
|
||||
fail("Invalid Exception type:" + e.getType());
|
||||
}
|
||||
|
||||
// Wrong password
|
||||
try {
|
||||
factory.createSession("foo", "xxx", false, true, true, false, -1);
|
||||
Assert.fail("should throw exception");
|
||||
}
|
||||
catch (ActiveMQSecurityException se) {
|
||||
//ok
|
||||
}
|
||||
catch (ActiveMQException e) {
|
||||
fail("Invalid Exception type:" + e.getType());
|
||||
}
|
||||
|
||||
// Correct user and password, allowed to send but not receive
|
||||
{
|
||||
final ClientSession session = factory.createSession("foo", "frobnicate", false, true, true, false, -1);
|
||||
checkUserReceiveNoSend(queueName, session, adminSession);
|
||||
}
|
||||
|
||||
// Correct user and password, allowed to receive but not send
|
||||
{
|
||||
final ClientSession session = factory.createSession("bar", "frobnicate", false, true, true, false, -1);
|
||||
checkUserSendNoReceive(queueName, session);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomSecurityManager2() throws Exception {
|
||||
final Configuration configuration = createDefaultInVMConfig().setSecurityEnabled(true);
|
||||
final ActiveMQSecurityManager customSecurityManager = new ActiveMQSecurityManager2() {
|
||||
public boolean validateUser(final String username, final String password) {
|
||||
return (username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||
password.equals("frobnicate");
|
||||
}
|
||||
public boolean validateUserAndRole(
|
||||
final String username,
|
||||
final String password,
|
||||
final Set<Role> requiredRoles,
|
||||
final CheckType checkType) {
|
||||
|
||||
fail("Unexpected call to overridden method");
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean validateUserAndRole(
|
||||
final String username,
|
||||
final String password,
|
||||
final Set<Role> requiredRoles,
|
||||
final CheckType checkType,
|
||||
final String address) {
|
||||
|
||||
if ((username.equals("foo") || username.equals("bar") || username.equals("all")) &&
|
||||
password.equals("frobnicate")) {
|
||||
|
||||
if (username.equals("all")) {
|
||||
return true;
|
||||
}
|
||||
else if (username.equals("foo")) {
|
||||
return address.equals("test.queue") && checkType == CheckType.CONSUME;
|
||||
}
|
||||
else if (username.equals("bar")) {
|
||||
return address.equals("test.queue") && checkType == CheckType.SEND;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
final ActiveMQServer server = addServer(new ActiveMQServerImpl(configuration, customSecurityManager));
|
||||
server.start();
|
||||
|
||||
final ServerLocator locator = createInVMNonHALocator();
|
||||
locator.setBlockOnNonDurableSend(true).setBlockOnDurableSend(true);
|
||||
final ClientSessionFactory factory = createSessionFactory(locator);
|
||||
ClientSession adminSession = factory.createSession("all", "frobnicate", false, true, true, false, -1);
|
||||
|
||||
final String queueName = "test.queue";
|
||||
adminSession.createQueue(queueName, queueName, false);
|
||||
|
||||
final String otherQueueName = "other.queue";
|
||||
adminSession.createQueue(otherQueueName, otherQueueName, false);
|
||||
|
||||
// Wrong user name
|
||||
try {
|
||||
factory.createSession("baz", "frobnicate", false, true, true, false, -1);
|
||||
Assert.fail("should throw exception");
|
||||
}
|
||||
catch (ActiveMQSecurityException se) {
|
||||
//ok
|
||||
}
|
||||
catch (ActiveMQException e) {
|
||||
fail("Invalid Exception type:" + e.getType());
|
||||
}
|
||||
|
||||
// Wrong password
|
||||
try {
|
||||
factory.createSession("foo", "xxx", false, true, true, false, -1);
|
||||
Assert.fail("should throw exception");
|
||||
}
|
||||
catch (ActiveMQSecurityException se) {
|
||||
//ok
|
||||
}
|
||||
catch (ActiveMQException e) {
|
||||
fail("Invalid Exception type:" + e.getType());
|
||||
}
|
||||
|
||||
// Correct user and password, wrong queue for sending
|
||||
try {
|
||||
final ClientSession session = factory.createSession("foo", "frobnicate", false, true, true, false, -1);
|
||||
checkUserReceiveNoSend(otherQueueName, session, adminSession);
|
||||
Assert.fail("should throw exception");
|
||||
}
|
||||
catch (ActiveMQSecurityException se) {
|
||||
//ok
|
||||
}
|
||||
catch (ActiveMQException e) {
|
||||
fail("Invalid Exception type:" + e.getType());
|
||||
}
|
||||
|
||||
// Correct user and password, wrong queue for receiving
|
||||
try {
|
||||
final ClientSession session = factory.createSession("foo", "frobnicate", false, true, true, false, -1);
|
||||
checkUserReceiveNoSend(otherQueueName, session, adminSession);
|
||||
Assert.fail("should throw exception");
|
||||
}
|
||||
catch (ActiveMQSecurityException se) {
|
||||
//ok
|
||||
}
|
||||
catch (ActiveMQException e) {
|
||||
fail("Invalid Exception type:" + e.getType());
|
||||
}
|
||||
|
||||
// Correct user and password, allowed to send but not receive
|
||||
{
|
||||
final ClientSession session = factory.createSession("foo", "frobnicate", false, true, true, false, -1);
|
||||
checkUserReceiveNoSend(queueName, session, adminSession);
|
||||
}
|
||||
|
||||
// Correct user and password, allowed to receive but not send
|
||||
{
|
||||
final ClientSession session = factory.createSession("bar", "frobnicate", false, true, true, false, -1);
|
||||
checkUserSendNoReceive(queueName, session);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the user connection has both send and receive permissions on the queue
|
||||
private void checkUserSendAndReceive(final String genericQueueName,
|
||||
final ClientSession connection) throws Exception {
|
||||
|
|
Loading…
Reference in New Issue