ARTEMIS-229 validate user and role with address
This commit is contained in:
parent
4cdcc618ff
commit
6890f126cb
|
@ -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.HierarchicalRepository;
|
||||||
import org.apache.activemq.artemis.core.settings.HierarchicalRepositoryChangeListener;
|
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.ActiveMQSecurityManager;
|
||||||
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager2;
|
||||||
import org.apache.activemq.artemis.utils.ConcurrentHashSet;
|
import org.apache.activemq.artemis.utils.ConcurrentHashSet;
|
||||||
import org.apache.activemq.artemis.utils.TypedProperties;
|
import org.apache.activemq.artemis.utils.TypedProperties;
|
||||||
|
|
||||||
|
@ -159,7 +160,16 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
|
||||||
return;
|
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) {
|
if (notificationService != null) {
|
||||||
TypedProperties props = new TypedProperties();
|
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.CreateMessage;
|
||||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||||
import org.apache.activemq.artemis.core.config.Configuration;
|
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.security.Role;
|
||||||
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
import org.apache.activemq.artemis.core.server.ActiveMQServer;
|
||||||
import org.apache.activemq.artemis.core.server.Queue;
|
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.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.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManagerImpl;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
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
|
// Check the user connection has both send and receive permissions on the queue
|
||||||
private void checkUserSendAndReceive(final String genericQueueName,
|
private void checkUserSendAndReceive(final String genericQueueName,
|
||||||
final ClientSession connection) throws Exception {
|
final ClientSession connection) throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue