https://issues.apache.org/jira/browse/AMQ-3851 - refactor AuthorizationBroker so that addDestinationInfo is properly handled

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1393988 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Bosanac Dejan 2012-10-04 11:09:21 +00:00
parent e7137b7eae
commit 205699e11e
5 changed files with 307 additions and 48 deletions

View File

@ -45,25 +45,21 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
super(next);
this.authorizationMap = authorizationMap;
}
@Override
public void addDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception {
addDestination(context, info.getDestination(),true);
super.addDestinationInfo(context, info);
}
@Override
public Destination addDestination(ConnectionContext context, ActiveMQDestination destination,boolean create) throws Exception {
protected SecurityContext checkSecurityContext(ConnectionContext context) throws SecurityException {
final SecurityContext securityContext = context.getSecurityContext();
if (securityContext == null) {
throw new SecurityException("User is not authenticated.");
}
return securityContext;
}
protected boolean checkDestinationAdmin(SecurityContext securityContext, ActiveMQDestination destination) {
Destination existing = this.getDestinationMap().get(destination);
if (existing != null) {
return super.addDestination(context, destination,create);
return true;
}
if (!securityContext.isBrokerContext()) {
Set<?> allowedACLs = null;
if (!destination.isTemporary()) {
@ -73,9 +69,29 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
}
if (allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to create: " + destination);
return false;
}
}
return true;
}
@Override
public void addDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception {
final SecurityContext securityContext = checkSecurityContext(context);
if (!checkDestinationAdmin(securityContext, info.getDestination())) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to create: " + info.getDestination());
}
super.addDestinationInfo(context, info);
}
@Override
public Destination addDestination(ConnectionContext context, ActiveMQDestination destination,boolean create) throws Exception {
final SecurityContext securityContext = checkSecurityContext(context);
if (!checkDestinationAdmin(securityContext, destination)) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to create: " + destination);
}
return super.addDestination(context, destination,create);
@ -83,31 +99,30 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
@Override
public void removeDestination(ConnectionContext context, ActiveMQDestination destination, long timeout) throws Exception {
final SecurityContext securityContext = checkSecurityContext(context);
final SecurityContext securityContext = context.getSecurityContext();
if (securityContext == null) {
throw new SecurityException("User is not authenticated.");
}
Set<?> allowedACLs = null;
if (!destination.isTemporary()) {
allowedACLs = authorizationMap.getAdminACLs(destination);
} else {
allowedACLs = authorizationMap.getTempDestinationAdminACLs();
}
if (!securityContext.isBrokerContext() && allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) {
if (!checkDestinationAdmin(securityContext, destination)) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to remove: " + destination);
}
super.removeDestination(context, destination, timeout);
}
@Override
public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {
public void removeDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception {
final SecurityContext securityContext = checkSecurityContext(context);
final SecurityContext subject = context.getSecurityContext();
if (subject == null) {
throw new SecurityException("User is not authenticated.");
if (!checkDestinationAdmin(securityContext, info.getDestination())) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to remove: " + info.getDestination());
}
super.removeDestinationInfo(context, info);
}
@Override
public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {
final SecurityContext securityContext = checkSecurityContext(context);
Set<?> allowedACLs = null;
if (!info.getDestination().isTemporary()) {
allowedACLs = authorizationMap.getReadACLs(info.getDestination());
@ -115,10 +130,10 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
allowedACLs = authorizationMap.getTempDestinationReadACLs();
}
if (!subject.isBrokerContext() && allowedACLs != null && !subject.isInOneOf(allowedACLs)) {
throw new SecurityException("User " + subject.getUserName() + " is not authorized to read from: " + info.getDestination());
if (!securityContext.isBrokerContext() && allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to read from: " + info.getDestination());
}
subject.getAuthorizedReadDests().put(info.getDestination(), info.getDestination());
securityContext.getAuthorizedReadDests().put(info.getDestination(), info.getDestination());
/*
* Need to think about this a little more. We could do per message
@ -146,12 +161,9 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
@Override
public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception {
final SecurityContext securityContext = checkSecurityContext(context);
SecurityContext subject = context.getSecurityContext();
if (subject == null) {
throw new SecurityException("User is not authenticated.");
}
if (!subject.isBrokerContext() && info.getDestination() != null) {
if (!securityContext.isBrokerContext() && info.getDestination() != null) {
Set<?> allowedACLs = null;
if (!info.getDestination().isTemporary()) {
@ -159,10 +171,10 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
} else {
allowedACLs = authorizationMap.getTempDestinationWriteACLs();
}
if (allowedACLs != null && !subject.isInOneOf(allowedACLs)) {
throw new SecurityException("User " + subject.getUserName() + " is not authorized to write to: " + info.getDestination());
if (allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to write to: " + info.getDestination());
}
subject.getAuthorizedWriteDests().put(info.getDestination(), info.getDestination());
securityContext.getAuthorizedWriteDests().put(info.getDestination(), info.getDestination());
}
super.addProducer(context, info);
@ -170,11 +182,9 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
@Override
public void send(ProducerBrokerExchange producerExchange, Message messageSend) throws Exception {
SecurityContext subject = producerExchange.getConnectionContext().getSecurityContext();
if (subject == null) {
throw new SecurityException("User is not authenticated.");
}
if (!subject.isBrokerContext() && !subject.getAuthorizedWriteDests().contains(messageSend.getDestination())) {
final SecurityContext securityContext = checkSecurityContext(producerExchange.getConnectionContext());
if (!securityContext.isBrokerContext() && !securityContext.getAuthorizedWriteDests().contains(messageSend.getDestination())) {
Set<?> allowedACLs = null;
if (!messageSend.getDestination().isTemporary()) {
@ -183,10 +193,10 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
allowedACLs = authorizationMap.getTempDestinationWriteACLs();
}
if (allowedACLs != null && !subject.isInOneOf(allowedACLs)) {
throw new SecurityException("User " + subject.getUserName() + " is not authorized to write to: " + messageSend.getDestination());
if (allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to write to: " + messageSend.getDestination());
}
subject.getAuthorizedWriteDests().put(messageSend.getDestination(), messageSend.getDestination());
securityContext.getAuthorizedWriteDests().put(messageSend.getDestination(), messageSend.getDestination());
}
super.send(producerExchange, messageSend);

View File

@ -0,0 +1,89 @@
/**
* 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.usecases;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQMessageConsumer;
import org.apache.activemq.JmsMultipleBrokersTestSupport;
import org.apache.activemq.command.ActiveMQQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TemporaryQueue;
public class TwoSecureBrokerRequestReplyTest extends JmsMultipleBrokersTestSupport {
private static final Logger LOG = LoggerFactory.getLogger(TwoSecureBrokerRequestReplyTest.class);
public void setUp() throws Exception {
super.setAutoFail(true);
super.setUp();
createBroker(new ClassPathResource("org/apache/activemq/usecases/sender-secured.xml"));
createBroker(new ClassPathResource("org/apache/activemq/usecases/receiver-secured.xml"));
}
public void testRequestReply() throws Exception {
ActiveMQQueue requestReplyDest = new ActiveMQQueue("RequestReply");
startAllBrokers();
waitForBridgeFormation();
waitForMinTopicRegionConsumerCount("sender", 1);
waitForMinTopicRegionConsumerCount("receiver", 1);
ConnectionFactory factory = getConnectionFactory("sender");
ActiveMQConnection conn = (ActiveMQConnection) factory.createConnection("system", "manager");
conn.setWatchTopicAdvisories(false);
conn.start();
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
ConnectionFactory replyFactory = getConnectionFactory("receiver");
for (int i = 0; i < 2000; i++) {
TemporaryQueue tempDest = session.createTemporaryQueue();
MessageProducer producer = session.createProducer(requestReplyDest);
javax.jms.Message message = session.createTextMessage("req-" + i);
message.setJMSReplyTo(tempDest);
ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer) session.createConsumer(tempDest);
producer.send(message);
ActiveMQConnection replyConnection = (ActiveMQConnection) replyFactory.createConnection("system", "manager");
replyConnection.setWatchTopicAdvisories(false);
replyConnection.start();
Session replySession = replyConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
ActiveMQMessageConsumer replyConsumer = (ActiveMQMessageConsumer) replySession.createConsumer(requestReplyDest);
javax.jms.Message msg = replyConsumer.receive(10000);
assertNotNull("request message not null: " + i, msg);
MessageProducer replyProducer = replySession.createProducer(msg.getJMSReplyTo());
replyProducer.send(session.createTextMessage("reply-" + i));
replyConnection.close();
javax.jms.Message reply = consumer.receive(10000);
assertNotNull("reply message : " + i + ", to: " + tempDest + ", by consumer:" + consumer.getConsumerId(), reply);
consumer.close();
tempDest.delete();
LOG.info("message #" + i + " processed");
}
}
}

View File

@ -76,7 +76,7 @@
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users" admin="guests,users"/>
</authorizationEntries>
<tempDestinationAuthorizationEntry>
<tempDestinationAuthorizationEntry read="admin" write="admin" admin="admin"/>
<tempDestinationAuthorizationEntry read="admins" write="admins" admin="admins"/>
</tempDestinationAuthorizationEntry>
</authorizationMap>
</map>

View File

@ -0,0 +1,78 @@
<?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.
-->
<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">
<broker brokerName="receiver" persistent="false" useJmx="true" allowTempAutoCreationOnSend="true" xmlns="http://activemq.apache.org/schema/core">
<networkConnectors>
<networkConnector uri="static:(tcp://localhost:62001)" userName="system" password="manager"/>
</networkConnectors>
<persistenceAdapter>
<memoryPersistenceAdapter/>
</persistenceAdapter>
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="system" password="manager"
groups="users,admins"/>
<authenticationUser username="user" password="user"
groups="users"/>
<authenticationUser username="guest" password="guest" 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" write="guests,users" admin="guests,users" />
<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" write="guests,users" admin="guests,users" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users" admin="guests,users"/>
</authorizationEntries>
<tempDestinationAuthorizationEntry>
<tempDestinationAuthorizationEntry read="admins" write="admins" admin="admins"/>
</tempDestinationAuthorizationEntry>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
<transportConnectors>
<transportConnector uri="tcp://localhost:62002"/>
</transportConnectors>
</broker>
</beans>

View File

@ -0,0 +1,82 @@
<?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.
-->
<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">
<broker brokerName="sender" persistent="false" useJmx="true" xmlns="http://activemq.apache.org/schema/core">
<networkConnectors>
<networkConnector uri="static:(tcp://localhost:62002)" userName="system" password="manager">
<staticallyIncludedDestinations>
<topic physicalName=">"/>
</staticallyIncludedDestinations>
</networkConnector>
</networkConnectors>
<persistenceAdapter>
<memoryPersistenceAdapter/>
</persistenceAdapter>
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="system" password="manager"
groups="users,admins"/>
<authenticationUser username="user" password="user"
groups="users"/>
<authenticationUser username="guest" password="guest" 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" write="guests,users" admin="guests,users" />
<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" write="guests,users" admin="guests,users" />
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users" admin="guests,users"/>
</authorizationEntries>
<tempDestinationAuthorizationEntry>
<tempDestinationAuthorizationEntry read="admins" write="admins" admin="admins"/>
</tempDestinationAuthorizationEntry>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
<transportConnectors>
<transportConnector uri="tcp://localhost:62001"/>
</transportConnectors>
</broker>
</beans>