Refactoring Auth

this is doing some refactoring, making the SecurityStore mechnism possible to be reused on other protocols,
without forcing them to implement ServerSession on checks that won't fit the Server Model from Artemis
This commit is contained in:
Clebert Suconic 2015-08-28 13:47:04 -04:00
parent b91b5a1aae
commit 8d98fc395f
10 changed files with 107 additions and 82 deletions

View File

@ -51,6 +51,7 @@ import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQSingleConsumerB
import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQTransaction;
import org.apache.activemq.artemis.core.remoting.CloseListener;
import org.apache.activemq.artemis.core.remoting.FailureListener;
import org.apache.activemq.artemis.core.security.SecurityAuth;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
import org.apache.activemq.artemis.spi.core.remoting.Acceptor;
@ -105,7 +106,7 @@ import org.apache.activemq.wireformat.WireFormat;
/**
* Represents an activemq connection.
*/
public class OpenWireConnection implements RemotingConnection, CommandVisitor {
public class OpenWireConnection implements RemotingConnection, CommandVisitor, SecurityAuth {
private final OpenWireProtocolManager protocolManager;
@ -190,6 +191,39 @@ public class OpenWireConnection implements RemotingConnection, CommandVisitor {
this.creationTime = System.currentTimeMillis();
}
// SecurityAuth implementation
@Override
public String getUsername() {
ConnectionInfo info = getConnectionInfo();
if (info == null) {
return null;
}
return info.getUserName();
}
// SecurityAuth implementation
@Override
public String getPassword() {
ConnectionInfo info = getConnectionInfo();
if (info == null) {
return null;
}
return info.getPassword();
}
private ConnectionInfo getConnectionInfo() {
if (state == null) {
return null;
}
ConnectionInfo info = state.getInfo();
if (info == null) {
return null;
}
return info;
}
public String getLocalAddress() {
return transportConnection.getLocalAddress();
}

View File

@ -47,14 +47,12 @@ import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQConnectionConte
import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQConsumer;
import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQPersistenceAdapter;
import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQProducerBrokerExchange;
import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQServerSession;
import org.apache.activemq.artemis.core.protocol.openwire.amq.AMQSession;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyServerConnection;
import org.apache.activemq.artemis.core.security.CheckType;
import org.apache.activemq.artemis.core.server.ActiveMQServer;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.Queue;
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
import org.apache.activemq.artemis.core.server.management.ManagementService;
import org.apache.activemq.artemis.core.server.management.Notification;
import org.apache.activemq.artemis.core.server.management.NotificationListener;
@ -583,21 +581,17 @@ public class OpenWireProtocolManager implements ProtocolManager<Interceptor>, No
ActiveMQDestination dest = info.getDestination();
if (dest.isQueue()) {
SimpleString qName = OpenWireUtil.toCoreAddress(dest);
ConnectionState state = connection.getState();
ConnectionInfo connInfo = state.getInfo();
if (connInfo != null) {
String user = connInfo.getUserName();
String pass = connInfo.getPassword();
if (connection.getState().getInfo() != null) {
AMQServerSession fakeSession = new AMQServerSession(user, pass);
CheckType checkType = dest.isTemporary() ? CheckType.CREATE_NON_DURABLE_QUEUE : CheckType.CREATE_DURABLE_QUEUE;
((ActiveMQServerImpl) server).getSecurityStore().check(qName, checkType, fakeSession);
server.getSecurityStore().check(qName, checkType, connection);
((ActiveMQServerImpl) server).checkQueueCreationLimit(user);
server.checkQueueCreationLimit(connection.getUsername());
}
QueueBinding binding = (QueueBinding) server.getPostOffice().getBinding(qName);
if (binding == null) {
ConnectionInfo connInfo = connection.getState().getInfo();
this.server.createQueue(qName, qName, null, connInfo == null ? null : SimpleString.toSimpleString(connInfo.getUserName()), false, dest.isTemporary());
}
if (dest.isTemporary()) {

View File

@ -88,11 +88,6 @@ public class AMQServerSession extends ServerSessionImpl {
super(name, username, password, minLargeMessageSize, autoCommitSends, autoCommitAcks, preAcknowledge, persistDeliveryCountBeforeDelivery, xa, connection, storageManager, postOffice, resourceManager, securityStore, managementService, activeMQServerImpl, managementAddress, simpleString, callback, context, new AMQTransactionFactory(), queueCreator);
}
//create a fake session just for security check
public AMQServerSession(String user, String pass) {
super(user, pass);
}
protected void doClose(final boolean failed) throws Exception {
synchronized (this) {
if (tx != null && tx.getXid() == null) {

View File

@ -0,0 +1,26 @@
/**
* 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.core.security;
public interface SecurityAuth {
String getUsername();
String getPassword();
}

View File

@ -17,13 +17,12 @@
package org.apache.activemq.artemis.core.security;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.server.ServerSession;
public interface SecurityStore {
void authenticate(String user, String password) throws Exception;
void check(SimpleString address, CheckType checkType, ServerSession session) throws Exception;
void check(SimpleString address, CheckType checkType, SecurityAuth session) throws Exception;
boolean isSecurityEnabled();

View File

@ -25,10 +25,10 @@ import org.apache.activemq.artemis.api.core.management.CoreNotificationType;
import org.apache.activemq.artemis.api.core.management.ManagementHelper;
import org.apache.activemq.artemis.core.security.CheckType;
import org.apache.activemq.artemis.core.security.Role;
import org.apache.activemq.artemis.core.security.SecurityAuth;
import org.apache.activemq.artemis.core.security.SecurityStore;
import org.apache.activemq.artemis.core.server.ActiveMQMessageBundle;
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
import org.apache.activemq.artemis.core.server.ServerSession;
import org.apache.activemq.artemis.core.server.management.Notification;
import org.apache.activemq.artemis.core.server.management.NotificationService;
import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
@ -138,7 +138,7 @@ public class SecurityStoreImpl implements SecurityStore, HierarchicalRepositoryC
public void check(final SimpleString address,
final CheckType checkType,
final ServerSession session) throws Exception {
final SecurityAuth session) throws Exception {
if (securityEnabled) {
if (trace) {
ActiveMQServerLogger.LOGGER.trace("checking access permissions to " + address);

View File

@ -33,6 +33,7 @@ import org.apache.activemq.artemis.core.postoffice.PostOffice;
import org.apache.activemq.artemis.core.remoting.server.RemotingService;
import org.apache.activemq.artemis.core.replication.ReplicationManager;
import org.apache.activemq.artemis.core.security.Role;
import org.apache.activemq.artemis.core.security.SecurityAuth;
import org.apache.activemq.artemis.core.security.SecurityStore;
import org.apache.activemq.artemis.core.server.cluster.ClusterManager;
import org.apache.activemq.artemis.core.server.cluster.ha.HAPolicy;
@ -104,6 +105,8 @@ public interface ActiveMQServer extends ActiveMQComponent {
void unregisterActivateCallback(ActivateCallback callback);
void checkQueueCreationLimit(String username) throws Exception;
ServerSession createSession(String name,
String username,
String password,
@ -221,12 +224,12 @@ public interface ActiveMQServer extends ActiveMQComponent {
void destroyQueue(SimpleString queueName) throws Exception;
void destroyQueue(SimpleString queueName, ServerSession session) throws Exception;
void destroyQueue(SimpleString queueName, SecurityAuth session) throws Exception;
void destroyQueue(SimpleString queueName, ServerSession session, boolean checkConsumerCount) throws Exception;
void destroyQueue(SimpleString queueName, SecurityAuth session, boolean checkConsumerCount) throws Exception;
void destroyQueue(SimpleString queueName,
ServerSession session,
SecurityAuth session,
boolean checkConsumerCount,
boolean removeConsumers) throws Exception;

View File

@ -23,18 +23,15 @@ import java.util.Set;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.message.impl.MessageInternal;
import org.apache.activemq.artemis.core.persistence.OperationContext;
import org.apache.activemq.artemis.core.security.SecurityAuth;
import org.apache.activemq.artemis.core.transaction.Transaction;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
import org.apache.activemq.artemis.utils.json.JSONArray;
public interface ServerSession {
public interface ServerSession extends SecurityAuth {
String getName();
String getUsername();
String getPassword();
int getMinLargeMessageSize();
Object getConnectionID();

View File

@ -16,6 +16,30 @@
*/
package org.apache.activemq.artemis.core.server.impl;
import javax.management.MBeanServer;
import java.io.File;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
import org.apache.activemq.artemis.api.core.Pair;
import org.apache.activemq.artemis.api.core.SimpleString;
@ -29,9 +53,9 @@ import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
import org.apache.activemq.artemis.core.filter.Filter;
import org.apache.activemq.artemis.core.filter.impl.FilterImpl;
import org.apache.activemq.artemis.core.io.IOCriticalErrorListener;
import org.apache.activemq.artemis.core.journal.JournalLoadInformation;
import org.apache.activemq.artemis.core.io.SequentialFile;
import org.apache.activemq.artemis.core.io.aio.AIOSequentialFileFactory;
import org.apache.activemq.artemis.core.journal.JournalLoadInformation;
import org.apache.activemq.artemis.core.management.impl.ActiveMQServerControlImpl;
import org.apache.activemq.artemis.core.paging.PagingManager;
import org.apache.activemq.artemis.core.paging.cursor.PageSubscription;
@ -58,6 +82,7 @@ import org.apache.activemq.artemis.core.remoting.server.impl.RemotingServiceImpl
import org.apache.activemq.artemis.core.replication.ReplicationManager;
import org.apache.activemq.artemis.core.security.CheckType;
import org.apache.activemq.artemis.core.security.Role;
import org.apache.activemq.artemis.core.security.SecurityAuth;
import org.apache.activemq.artemis.core.security.SecurityStore;
import org.apache.activemq.artemis.core.security.impl.SecurityStoreImpl;
import org.apache.activemq.artemis.core.server.ActivateCallback;
@ -107,30 +132,6 @@ import org.apache.activemq.artemis.utils.ReusableLatch;
import org.apache.activemq.artemis.utils.SecurityFormatter;
import org.apache.activemq.artemis.utils.VersionLoader;
import javax.management.MBeanServer;
import java.io.File;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* The ActiveMQ Artemis server implementation
*/
@ -1182,18 +1183,18 @@ public class ActiveMQServerImpl implements ActiveMQServer {
destroyQueue(queueName, null, true);
}
public void destroyQueue(final SimpleString queueName, final ServerSession session) throws Exception {
public void destroyQueue(final SimpleString queueName, final SecurityAuth session) throws Exception {
destroyQueue(queueName, session, true);
}
public void destroyQueue(final SimpleString queueName,
final ServerSession session,
final SecurityAuth session,
final boolean checkConsumerCount) throws Exception {
destroyQueue(queueName, session, checkConsumerCount, false);
}
public void destroyQueue(final SimpleString queueName,
final ServerSession session,
final SecurityAuth session,
final boolean checkConsumerCount,
final boolean removeConsumers) throws Exception {
addressSettingsRepository.clearCache();

View File

@ -172,30 +172,6 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
private final TransactionFactory transactionFactory;
//create an 'empty' session. Only used by AMQServerSession
//in order to check username and password
protected ServerSessionImpl(String username, String password) {
this.username = username;
this.password = password;
this.transactionFactory = null;
this.strictUpdateDeliveryCount = false;
this.storageManager = null;
this.server = null;
this.securityStore = null;
this.resourceManager = null;
this.remotingConnection = null;
this.preAcknowledge = false;
this.postOffice = null;
this.name = null;
this.minLargeMessageSize = 0;
this.managementService = null;
this.managementAddress = null;
this.context = null;
this.callback = null;
this.queueCreator = null;
}
public ServerSessionImpl(final String name,
final String username,
final String password,
@ -494,7 +470,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
securityStore.check(address, CheckType.CREATE_NON_DURABLE_QUEUE, this);
}
((ActiveMQServerImpl) server).checkQueueCreationLimit(getUsername());
server.checkQueueCreationLimit(getUsername());
Queue queue;
@ -538,7 +514,7 @@ public class ServerSessionImpl implements ServerSession, FailureListener {
final SimpleString filterString) throws Exception {
securityStore.check(address, CheckType.CREATE_NON_DURABLE_QUEUE, this);
((ActiveMQServerImpl) server).checkQueueCreationLimit(getUsername());
server.checkQueueCreationLimit(getUsername());
server.createSharedQueue(address, name, filterString, SimpleString.toSimpleString(getUsername()), durable);
}