https://issues.apache.org/jira/browse/AMQ-4682 - support updates to authorizationPlugin/map/authorizationMap

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1517794 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Gary Tully 2013-08-27 11:48:34 +00:00
parent 2b2bdd675d
commit 8d480b451a
15 changed files with 452 additions and 64 deletions

View File

@ -173,7 +173,7 @@ public class BrokerService implements Service {
private boolean useMirroredQueues = false; private boolean useMirroredQueues = false;
private boolean useTempMirroredQueues = true; private boolean useTempMirroredQueues = true;
private BrokerId brokerId; private BrokerId brokerId;
private DestinationInterceptor[] destinationInterceptors; private volatile DestinationInterceptor[] destinationInterceptors;
private ActiveMQDestination[] destinations; private ActiveMQDestination[] destinations;
private PListStore tempDataStore; private PListStore tempDataStore;
private int persistenceThreadPriority = Thread.MAX_PRIORITY; private int persistenceThreadPriority = Thread.MAX_PRIORITY;

View File

@ -27,7 +27,7 @@ import org.apache.activemq.command.ActiveMQDestination;
*/ */
public class CompositeDestinationInterceptor implements DestinationInterceptor { public class CompositeDestinationInterceptor implements DestinationInterceptor {
private DestinationInterceptor[] interceptors; private volatile DestinationInterceptor[] interceptors;
public CompositeDestinationInterceptor(final DestinationInterceptor[] interceptors) { public CompositeDestinationInterceptor(final DestinationInterceptor[] interceptors) {
this.interceptors = interceptors; this.interceptors = interceptors;

View File

@ -39,13 +39,17 @@ import org.apache.activemq.command.ProducerInfo;
*/ */
public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMBean { public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMBean {
private final AuthorizationMap authorizationMap; private volatile AuthorizationMap authorizationMap;
public AuthorizationBroker(Broker next, AuthorizationMap authorizationMap) { public AuthorizationBroker(Broker next, AuthorizationMap authorizationMap) {
super(next); super(next);
this.authorizationMap = authorizationMap; this.authorizationMap = authorizationMap;
} }
public void setAuthorizationMap(AuthorizationMap map) {
authorizationMap = map;
}
protected SecurityContext checkSecurityContext(ConnectionContext context) throws SecurityException { protected SecurityContext checkSecurityContext(ConnectionContext context) throws SecurityException {
final SecurityContext securityContext = context.getSecurityContext(); final SecurityContext securityContext = context.getSecurityContext();
if (securityContext == null) { if (securityContext == null) {
@ -130,7 +134,7 @@ public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMB
allowedACLs = authorizationMap.getTempDestinationReadACLs(); allowedACLs = authorizationMap.getTempDestinationReadACLs();
} }
if (!securityContext.isBrokerContext() && allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) { if (!securityContext.isBrokerContext() && (allowedACLs == null || !securityContext.isInOneOf(allowedACLs))) {
throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to read from: " + info.getDestination()); throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to read from: " + info.getDestination());
} }
securityContext.getAuthorizedReadDests().put(info.getDestination(), info.getDestination()); securityContext.getAuthorizedReadDests().put(info.getDestination(), info.getDestination());

View File

@ -54,7 +54,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.activemq</groupId> <groupId>org.apache.activemq</groupId>
<artifactId>activemq-kahadb-store</artifactId> <artifactId>activemq-jaas</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.activemq</groupId> <groupId>org.apache.activemq</groupId>
@ -154,6 +154,26 @@
</plugins> </plugins>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>always</forkMode>
<systemProperties>
<property>
<name>org.apache.activemq.default.directory.prefix</name>
<value>target/</value>
</property>
<property>
<name>log4j.configuration</name>
<value>file:target/test-classes/log4j.properties</value>
</property>
</systemProperties>
<includes>
<include>**/*Test.*</include>
</includes>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>

View File

@ -38,6 +38,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.validation.Schema; import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory; import javax.xml.validation.SchemaFactory;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter; import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext; import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.broker.jmx.ManagementContext; import org.apache.activemq.broker.jmx.ManagementContext;
@ -45,15 +46,29 @@ import org.apache.activemq.broker.region.CompositeDestinationInterceptor;
import org.apache.activemq.broker.region.Destination; import org.apache.activemq.broker.region.Destination;
import org.apache.activemq.broker.region.DestinationInterceptor; import org.apache.activemq.broker.region.DestinationInterceptor;
import org.apache.activemq.broker.region.RegionBroker; import org.apache.activemq.broker.region.RegionBroker;
import org.apache.activemq.broker.region.virtual.CompositeQueue;
import org.apache.activemq.broker.region.virtual.CompositeTopic;
import org.apache.activemq.broker.region.virtual.VirtualDestination; import org.apache.activemq.broker.region.virtual.VirtualDestination;
import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor;
import org.apache.activemq.broker.region.virtual.VirtualTopic;
import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.filter.DestinationMapEntry;
import org.apache.activemq.network.NetworkConnector;
import org.apache.activemq.plugin.jmx.RuntimeConfigurationView; import org.apache.activemq.plugin.jmx.RuntimeConfigurationView;
import org.apache.activemq.schema.core.Broker; import org.apache.activemq.schema.core.DtoAuthorizationEntry;
import org.apache.activemq.schema.core.CompositeQueue; import org.apache.activemq.schema.core.DtoAuthorizationMap;
import org.apache.activemq.schema.core.CompositeTopic; import org.apache.activemq.schema.core.DtoAuthorizationPlugin;
import org.apache.activemq.schema.core.NetworkConnector; import org.apache.activemq.schema.core.DtoBroker;
import org.apache.activemq.schema.core.VirtualDestinationInterceptor; import org.apache.activemq.schema.core.DtoCompositeQueue;
import org.apache.activemq.schema.core.VirtualTopic; import org.apache.activemq.schema.core.DtoCompositeTopic;
import org.apache.activemq.schema.core.DtoNetworkConnector;
import org.apache.activemq.schema.core.DtoVirtualDestinationInterceptor;
import org.apache.activemq.schema.core.DtoVirtualTopic;
import org.apache.activemq.security.AuthorizationBroker;
import org.apache.activemq.security.AuthorizationMap;
import org.apache.activemq.security.TempDestinationAuthorizationEntry;
import org.apache.activemq.security.XBeanAuthorizationEntry;
import org.apache.activemq.security.XBeanAuthorizationMap;
import org.apache.activemq.spring.Utils; import org.apache.activemq.spring.Utils;
import org.apache.activemq.util.IntrospectionSupport; import org.apache.activemq.util.IntrospectionSupport;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -67,18 +82,18 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
public static final Logger LOG = LoggerFactory.getLogger(RuntimeConfigurationBroker.class); public static final Logger LOG = LoggerFactory.getLogger(RuntimeConfigurationBroker.class);
public static final String objectNamePropsAppendage = ",service=RuntimeConfiguration,name=Plugin"; public static final String objectNamePropsAppendage = ",service=RuntimeConfiguration,name=Plugin";
private final ReentrantReadWriteLock addDestinationBarrier = new ReentrantReadWriteLock();
private long checkPeriod; private long checkPeriod;
private long lastModified = -1; private long lastModified = -1;
private Resource configToMonitor; private Resource configToMonitor;
private Broker currentConfiguration; private DtoBroker currentConfiguration;
private Runnable monitorTask; private Runnable monitorTask;
private ConcurrentLinkedQueue<Runnable> destinationInterceptorUpdateWork = new ConcurrentLinkedQueue<Runnable>(); private ConcurrentLinkedQueue<Runnable> destinationInterceptorUpdateWork = new ConcurrentLinkedQueue<Runnable>();
private final ReentrantReadWriteLock addDestinationBarrier = new ReentrantReadWriteLock();
private ObjectName objectName; private ObjectName objectName;
private String infoString; private String infoString;
private Schema schema; private Schema schema;
public RuntimeConfigurationBroker(org.apache.activemq.broker.Broker next) { public RuntimeConfigurationBroker(Broker next) {
super(next); super(next);
} }
@ -122,7 +137,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
private void unregisterMbean() { private void unregisterMbean() {
if (objectName != null) { if (objectName != null) {
try { try {
getBrokerService().getManagementContext().unregisterMBean(objectName); getBrokerService().getManagementContext().unregisterMBean(objectName);
} catch (JMException ignored) { } catch (JMException ignored) {
@ -200,9 +215,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
} }
private void applyModifications(Resource configToMonitor) { private void applyModifications(Resource configToMonitor) {
Broker changed = loadConfiguration(configToMonitor); DtoBroker changed = loadConfiguration(configToMonitor);
if (changed != null && !currentConfiguration.equals(changed)) { if (changed != null && !currentConfiguration.equals(changed)) {
LOG.info("change in " + configToMonitor + " at: " + new Date(lastModified)); LOG.info("change in " + configToMonitor + " at: " + new Date(lastModified));
LOG.debug("current:" + currentConfiguration); LOG.debug("current:" + currentConfiguration);
@ -214,14 +228,17 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
} }
private void processSelectiveChanges(Broker currentConfiguration, Broker modifiedConfiguration) { private void processSelectiveChanges(DtoBroker currentConfiguration, DtoBroker modifiedConfiguration) {
for (Class upDatable : new Class[]{Broker.NetworkConnectors.class, Broker.DestinationInterceptors.class}) { for (Class upDatable : new Class[]{
processChanges(currentConfiguration, modifiedConfiguration, upDatable); DtoBroker.NetworkConnectors.class,
DtoBroker.DestinationInterceptors.class,
DtoBroker.Plugins.class}) {
processChanges(currentConfiguration, modifiedConfiguration, upDatable);
} }
} }
private void processChanges(Broker currentConfiguration, Broker modifiedConfiguration, Class upDatable) { private void processChanges(DtoBroker currentConfiguration, DtoBroker modifiedConfiguration, Class upDatable) {
List current = filter(currentConfiguration, upDatable); List current = filter(currentConfiguration, upDatable);
List modified = filter(modifiedConfiguration, upDatable); List modified = filter(modifiedConfiguration, upDatable);
@ -263,10 +280,9 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
for (; modIndex < modification.size() && currentIndex < current.size(); modIndex++, currentIndex++) { for (; modIndex < modification.size() && currentIndex < current.size(); modIndex++, currentIndex++) {
Object existing = current.get(currentIndex); Object existing = current.get(currentIndex);
Object candidate = modification.get(modIndex); Object candidate = modification.get(modIndex);
if (! existing.equals(candidate)) { if (!existing.equals(candidate)) {
info("modification to:" + existing + " , with: " + candidate); info("modification to:" + existing + " , with: " + candidate);
remove(existing); modify(existing, candidate);
addNew(candidate);
} }
} }
@ -279,10 +295,59 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
} }
private void modify(Object existing, Object candidate) {
if (candidate instanceof DtoAuthorizationPlugin) {
try {
// replace authorization map - need exclusive write lock to total broker
AuthorizationBroker authorizationBroker =
(AuthorizationBroker) getBrokerService().getBroker().getAdaptor(AuthorizationBroker.class);
authorizationBroker.setAuthorizationMap(fromDto(filter(candidate, DtoAuthorizationPlugin.Map.class)));
} catch (Exception e) {
info("failed to apply modified AuthorizationMap to AuthorizationBroker", e);
}
} else {
remove(existing);
addNew(candidate);
}
}
private AuthorizationMap fromDto(List<Object> map) {
XBeanAuthorizationMap xBeanAuthorizationMap = new XBeanAuthorizationMap();
for (Object o : map) {
if (o instanceof DtoAuthorizationPlugin.Map) {
DtoAuthorizationPlugin.Map dtoMap = (DtoAuthorizationPlugin.Map) o;
List<DestinationMapEntry> entries = new LinkedList<DestinationMapEntry>();
// revisit - would like to map getAuthorizationMap to generic getContents
for (Object authMap : filter(dtoMap.getAuthorizationMap(), DtoAuthorizationMap.AuthorizationEntries.class)) {
for (Object entry : filter(getContents(authMap), DtoAuthorizationEntry.class)) {
entries.add(fromDto(entry, new XBeanAuthorizationEntry()));
}
}
xBeanAuthorizationMap.setAuthorizationEntries(entries);
try {
xBeanAuthorizationMap.afterPropertiesSet();
} catch (Exception e) {
info("failed to update xBeanAuthorizationMap auth entries:", e);
}
for (Object entry : filter(dtoMap.getAuthorizationMap(), DtoAuthorizationMap.TempDestinationAuthorizationEntry.class)) {
// another restriction - would like to be getContents
DtoAuthorizationMap.TempDestinationAuthorizationEntry dtoEntry = (DtoAuthorizationMap.TempDestinationAuthorizationEntry) entry;
xBeanAuthorizationMap.setTempDestinationAuthorizationEntry(fromDto(dtoEntry.getTempDestinationAuthorizationEntry(), new TempDestinationAuthorizationEntry()));
}
} else {
info("No support for updates to: " + o);
}
}
return xBeanAuthorizationMap;
}
private void remove(Object o) { private void remove(Object o) {
if (o instanceof NetworkConnector) { if (o instanceof DtoNetworkConnector) {
NetworkConnector toRemove = (NetworkConnector) o; DtoNetworkConnector toRemove = (DtoNetworkConnector) o;
for (org.apache.activemq.network.NetworkConnector existingCandidate : for (NetworkConnector existingCandidate :
getBrokerService().getNetworkConnectors()) { getBrokerService().getNetworkConnectors()) {
if (configMatch(toRemove, existingCandidate)) { if (configMatch(toRemove, existingCandidate)) {
if (getBrokerService().removeNetworkConnector(existingCandidate)) { if (getBrokerService().removeNetworkConnector(existingCandidate)) {
@ -295,13 +360,13 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
} }
} }
} else if (o instanceof VirtualDestinationInterceptor) { } else if (o instanceof DtoVirtualDestinationInterceptor) {
// whack it // whack it
destinationInterceptorUpdateWork.add(new Runnable() { destinationInterceptorUpdateWork.add(new Runnable() {
public void run() { public void run() {
List<DestinationInterceptor> interceptorsList = new ArrayList<DestinationInterceptor>(); List<DestinationInterceptor> interceptorsList = new ArrayList<DestinationInterceptor>();
for (DestinationInterceptor candidate : getBrokerService().getDestinationInterceptors()) { for (DestinationInterceptor candidate : getBrokerService().getDestinationInterceptors()) {
if (!(candidate instanceof org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor)) { if (!(candidate instanceof VirtualDestinationInterceptor)) {
interceptorsList.add(candidate); interceptorsList.add(candidate);
} }
} }
@ -316,7 +381,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
} }
private boolean configMatch(NetworkConnector dto, org.apache.activemq.network.NetworkConnector candidate) { private boolean configMatch(DtoNetworkConnector dto, NetworkConnector candidate) {
TreeMap<String, String> dtoProps = new TreeMap<String, String>(); TreeMap<String, String> dtoProps = new TreeMap<String, String>();
IntrospectionSupport.getProperties(dto, dtoProps, null); IntrospectionSupport.getProperties(dto, dtoProps, null);
@ -333,11 +398,11 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
private void addNew(Object o) { private void addNew(Object o) {
if (o instanceof NetworkConnector) { if (o instanceof DtoNetworkConnector) {
NetworkConnector networkConnector = (NetworkConnector) o; DtoNetworkConnector networkConnector = (DtoNetworkConnector) o;
if (networkConnector.getUri() != null) { if (networkConnector.getUri() != null) {
try { try {
org.apache.activemq.network.NetworkConnector nc = NetworkConnector nc =
getBrokerService().addNetworkConnector(networkConnector.getUri()); getBrokerService().addNetworkConnector(networkConnector.getUri());
Properties properties = new Properties(); Properties properties = new Properties();
IntrospectionSupport.getProperties(networkConnector, properties, null); IntrospectionSupport.getProperties(networkConnector, properties, null);
@ -350,18 +415,18 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
info("Failed to add new networkConnector " + networkConnector, e); info("Failed to add new networkConnector " + networkConnector, e);
} }
} }
} else if (o instanceof VirtualDestinationInterceptor) { } else if (o instanceof DtoVirtualDestinationInterceptor) {
final VirtualDestinationInterceptor dto = (VirtualDestinationInterceptor) o; final DtoVirtualDestinationInterceptor dto = (DtoVirtualDestinationInterceptor) o;
destinationInterceptorUpdateWork.add(new Runnable() { destinationInterceptorUpdateWork.add(new Runnable() {
public void run() { public void run() {
boolean updatedExistingInterceptor = false; boolean updatedExistingInterceptor = false;
for (DestinationInterceptor destinationInterceptor : getBrokerService().getDestinationInterceptors()) { for (DestinationInterceptor destinationInterceptor : getBrokerService().getDestinationInterceptors()) {
if (destinationInterceptor instanceof org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor) { if (destinationInterceptor instanceof VirtualDestinationInterceptor) {
// update existing interceptor // update existing interceptor
final org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor virtualDestinationInterceptor = final VirtualDestinationInterceptor virtualDestinationInterceptor =
(org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor) destinationInterceptor; (VirtualDestinationInterceptor) destinationInterceptor;
virtualDestinationInterceptor.setVirtualDestinations(fromDto(dto)); virtualDestinationInterceptor.setVirtualDestinations(fromDto(dto));
info("applied updates to: " + virtualDestinationInterceptor); info("applied updates to: " + virtualDestinationInterceptor);
@ -371,8 +436,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
if (!updatedExistingInterceptor) { if (!updatedExistingInterceptor) {
// add // add
org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor virtualDestinationInterceptor = VirtualDestinationInterceptor virtualDestinationInterceptor =
new org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor(); new VirtualDestinationInterceptor();
virtualDestinationInterceptor.setVirtualDestinations(fromDto(dto)); virtualDestinationInterceptor.setVirtualDestinations(fromDto(dto));
List<DestinationInterceptor> interceptorsList = new ArrayList<DestinationInterceptor>(); List<DestinationInterceptor> interceptorsList = new ArrayList<DestinationInterceptor>();
@ -381,8 +446,10 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
DestinationInterceptor[] destinationInterceptors = interceptorsList.toArray(new DestinationInterceptor[]{}); DestinationInterceptor[] destinationInterceptors = interceptorsList.toArray(new DestinationInterceptor[]{});
getBrokerService().setDestinationInterceptors(destinationInterceptors); getBrokerService().setDestinationInterceptors(destinationInterceptors);
((CompositeDestinationInterceptor) ((RegionBroker) getBrokerService().getRegionBroker()).getDestinationInterceptor()).setInterceptors(destinationInterceptors); RegionBroker regionBroker = (RegionBroker) getBrokerService().getRegionBroker();
((CompositeDestinationInterceptor) regionBroker.getDestinationInterceptor()).setInterceptors(destinationInterceptors);
info("applied new: " + interceptorsList); info("applied new: " + interceptorsList);
Thread.dumpStack();
} }
} }
}); });
@ -391,17 +458,17 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
} }
} }
private VirtualDestination[] fromDto(VirtualDestinationInterceptor virtualDestinationInterceptor) { private VirtualDestination[] fromDto(DtoVirtualDestinationInterceptor virtualDestinationInterceptor) {
List<VirtualDestination> answer = new ArrayList<VirtualDestination>(); List<VirtualDestination> answer = new ArrayList<VirtualDestination>();
for (Object vd : filter(virtualDestinationInterceptor, VirtualDestinationInterceptor.VirtualDestinations.class)) { for (Object vd : filter(virtualDestinationInterceptor, DtoVirtualDestinationInterceptor.VirtualDestinations.class)) {
for (Object vt : filter(vd, VirtualTopic.class)) { for (Object vt : filter(vd, DtoVirtualTopic.class)) {
answer.add(fromDto(vt, new org.apache.activemq.broker.region.virtual.VirtualTopic())); answer.add(fromDto(vt, new VirtualTopic()));
} }
for (Object vt : filter(vd, CompositeTopic.class)) { for (Object vt : filter(vd, DtoCompositeTopic.class)) {
answer.add(fromDto(vt, new org.apache.activemq.broker.region.virtual.CompositeTopic())); answer.add(fromDto(vt, new CompositeTopic()));
} }
for (Object vt : filter(vd, CompositeQueue.class)) { for (Object vt : filter(vd, DtoCompositeQueue.class)) {
answer.add(fromDto(vt, new org.apache.activemq.broker.region.virtual.CompositeQueue())); answer.add(fromDto(vt, new CompositeQueue()));
} }
} }
VirtualDestination[] array = new VirtualDestination[answer.size()]; VirtualDestination[] array = new VirtualDestination[answer.size()];
@ -409,7 +476,7 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
return array; return array;
} }
private VirtualDestination fromDto(Object dto, VirtualDestination instance) { private <T> T fromDto(Object dto, T instance) {
Properties properties = new Properties(); Properties properties = new Properties();
IntrospectionSupport.getProperties(dto, properties, null); IntrospectionSupport.getProperties(dto, properties, null);
LOG.trace("applying props: " + properties + ", to " + instance.getClass().getSimpleName()); LOG.trace("applying props: " + properties + ", to " + instance.getClass().getSimpleName());
@ -436,11 +503,11 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
return result; return result;
} }
private Broker loadConfiguration(Resource configToMonitor) { private DtoBroker loadConfiguration(Resource configToMonitor) {
Broker jaxbConfig = null; DtoBroker jaxbConfig = null;
if (configToMonitor != null) { if (configToMonitor != null) {
try { try {
JAXBContext context = JAXBContext.newInstance(Broker.class); JAXBContext context = JAXBContext.newInstance(DtoBroker.class);
Unmarshaller unMarshaller = context.createUnmarshaller(); Unmarshaller unMarshaller = context.createUnmarshaller();
unMarshaller.setSchema(getSchema()); unMarshaller.setSchema(getSchema());
@ -451,8 +518,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
Document doc = db.parse(configToMonitor.getInputStream()); Document doc = db.parse(configToMonitor.getInputStream());
Node brokerRootNode = doc.getElementsByTagName("broker").item(0); Node brokerRootNode = doc.getElementsByTagName("broker").item(0);
JAXBElement<Broker> brokerJAXBElement = JAXBElement<DtoBroker> brokerJAXBElement =
unMarshaller.unmarshal(brokerRootNode, Broker.class); unMarshaller.unmarshal(brokerRootNode, DtoBroker.class);
jaxbConfig = brokerJAXBElement.getValue(); jaxbConfig = brokerJAXBElement.getValue();
// if we can parse we can track mods // if we can parse we can track mods
@ -480,10 +547,6 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
return schema; return schema;
} }
public void setCheckPeriod(long checkPeriod) {
this.checkPeriod = checkPeriod;
}
public long getLastModified() { public long getLastModified() {
return lastModified; return lastModified;
} }
@ -495,4 +558,8 @@ public class RuntimeConfigurationBroker extends BrokerFilter {
public long getCheckPeriod() { public long getCheckPeriod() {
return checkPeriod; return checkPeriod;
} }
public void setCheckPeriod(long checkPeriod) {
this.checkPeriod = checkPeriod;
}
} }

View File

@ -4,6 +4,12 @@
<jxb:bindings schemaLocation="activemq.xsd" node="/xs:schema"> <jxb:bindings schemaLocation="activemq.xsd" node="/xs:schema">
<jxb:schemaBindings>
<jxb:nameXmlTransform>
<jxb:elementName prefix="Dto"/>
</jxb:nameXmlTransform>
</jxb:schemaBindings>
<!-- provide uniform accessor to all interesting elements via getContents() --> <!-- provide uniform accessor to all interesting elements via getContents() -->
<jxb:bindings node="xs:element[@name='broker']/xs:complexType/xs:choice"> <jxb:bindings node="xs:element[@name='broker']/xs:complexType/xs:choice">
<jxb:property name="Contents" /> <jxb:property name="Contents" />
@ -17,6 +23,10 @@
<jxb:property name="Contents" /> <jxb:property name="Contents" />
</jxb:bindings> </jxb:bindings>
<jxb:bindings node="xs:element[@name='broker']/xs:complexType/xs:choice/xs:choice/xs:element[@name='plugins']/xs:complexType/xs:choice">
<jxb:property name="Contents" />
</jxb:bindings>
<jxb:bindings node="xs:element[@name='virtualDestinationInterceptor']/xs:complexType/xs:choice"> <jxb:bindings node="xs:element[@name='virtualDestinationInterceptor']/xs:complexType/xs:choice">
<jxb:property name="Contents" /> <jxb:property name="Contents" />
</jxb:bindings> </jxb:bindings>
@ -25,5 +35,17 @@
<jxb:property name="Contents" /> <jxb:property name="Contents" />
</jxb:bindings> </jxb:bindings>
<jxb:bindings node="xs:element[@name='authorizationPlugin']/xs:complexType/xs:choice">
<jxb:property name="Contents" />
</jxb:bindings>
<jxb:bindings node="xs:element[@name='authorizationMap']/xs:complexType/xs:choice">
<jxb:property name="Contents" />
</jxb:bindings>
<jxb:bindings node="xs:element[@name='authorizationMap']/xs:complexType/xs:choice/xs:choice/xs:element[@name='authorizationEntries']/xs:complexType/xs:sequence">
<jxb:property name="Contents" />
</jxb:bindings>
</jxb:bindings> </jxb:bindings>
</jxb:bindings> </jxb:bindings>

View File

@ -0,0 +1,93 @@
/**
* 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;
import javax.jms.JMSException;
import javax.jms.Session;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class AuthorizationTest extends RuntimeConfigTestSupport {
String configurationSeed = "authorizationTest";
@Test
public void testMod() throws Exception {
final String brokerConfig = configurationSeed + "-auth-broker";
applyNewConfig(brokerConfig, configurationSeed + "-users");
startBroker(brokerConfig);
assertTrue("broker alive", brokerService.isStarted());
assertAllowed("user", "USERS.A");
assertDenied("user", "GUESTS.A");
assertDeniedTemp("guest");
applyNewConfig(brokerConfig, configurationSeed + "-users-guests", SLEEP);
assertAllowed("user", "USERS.A");
assertAllowed("guest", "GUESTS.A");
assertDenied("user", "GUESTS.A");
assertAllowedTemp("guest");
}
private void assertDeniedTemp(String userPass) {
try {
assertAllowedTemp(userPass);
fail("Expected not allowed exception");
} catch (Exception expected) {
LOG.debug("got:" + expected, expected);
}
}
private void assertAllowedTemp(String userPass) throws Exception {
ActiveMQConnection connection = new ActiveMQConnectionFactory("vm://localhost").createActiveMQConnection(userPass, userPass);
connection.start();
try {
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
session.createConsumer(session.createTemporaryQueue());
} finally {
connection.close();
}
}
private void assertDenied(String userPass, String destination) {
try {
assertAllowed(userPass, destination);
fail("Expected not allowed exception");
} catch (JMSException expected) {
LOG.debug("got:" + expected, expected);
}
}
private void assertAllowed(String userPass, String dest) throws JMSException {
ActiveMQConnection connection = new ActiveMQConnectionFactory("vm://localhost").createActiveMQConnection(userPass, userPass);
connection.start();
try {
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
session.createConsumer(session.createQueue(dest));
} finally {
connection.close();
}
}
}

View File

@ -67,5 +67,6 @@ public class RuntimeConfigTestSupport {
@After @After
public void stopBroker() throws Exception { public void stopBroker() throws Exception {
brokerService.stop(); brokerService.stop();
brokerService.waitUntilStopped();
} }
} }

View File

@ -65,7 +65,7 @@ public class VirtualDestTest extends RuntimeConfigTestSupport {
// apply again - ensure no change // apply again - ensure no change
applyNewConfig(brokerConfig, configurationSeed + "-one-vd"); applyNewConfig(brokerConfig, configurationSeed + "-one-vd");
assertSame("same instance", newValue, (((VirtualDestinationInterceptor) brokerService.getDestinationInterceptors()[0]))); assertSame("same instance", newValue, brokerService.getDestinationInterceptors()[0]);
} }
@ -96,7 +96,7 @@ public class VirtualDestTest extends RuntimeConfigTestSupport {
// apply again - ensure no change // apply again - ensure no change
applyNewConfig(brokerConfig, configurationSeed + "-one-vd"); applyNewConfig(brokerConfig, configurationSeed + "-one-vd");
assertSame("same instance", newValue, (((VirtualDestinationInterceptor) brokerService.getDestinationInterceptors()[0]))); assertSame("same instance", newValue, brokerService.getDestinationInterceptors()[0]);
} }
@Test @Test
@ -126,7 +126,7 @@ public class VirtualDestTest extends RuntimeConfigTestSupport {
// apply again - ensure no change // apply again - ensure no change
applyNewConfig(brokerConfig, configurationSeed + "-one-vd"); applyNewConfig(brokerConfig, configurationSeed + "-one-vd");
assertSame("same instance", newValue, (((VirtualDestinationInterceptor) brokerService.getDestinationInterceptors()[0]))); assertSame("same instance", newValue, brokerService.getDestinationInterceptors()[0]);
} }
@Test @Test
@ -216,13 +216,15 @@ public class VirtualDestTest extends RuntimeConfigTestSupport {
connection.start(); connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = session.createConsumer(session.createQueue("Consumer.A." + topic)); ActiveMQMessageConsumer consumer = (ActiveMQMessageConsumer) session.createConsumer(session.createQueue("Consumer.A." + topic));
LOG.info("new consumer for: " + consumer.getDestination());
MessageProducer producer = session.createProducer(session.createTopic(topic)); MessageProducer producer = session.createProducer(session.createTopic(topic));
final String body = "To vt:" + topic; final String body = "To vt:" + topic;
producer.send(session.createTextMessage(body)); producer.send(session.createTextMessage(body));
LOG.info("sent to: " + producer.getDestination());
Message message = null; Message message = null;
for (int i=0; i<5 && message == null; i++) { for (int i=0; i<10 && message == null; i++) {
message = consumer.receive(1000); message = consumer.receive(1000);
} }
assertNotNull("got message", message); assertNotNull("got message", message);

View File

@ -0,0 +1,21 @@
## ---------------------------------------------------------------------------
## 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.
## ---------------------------------------------------------------------------
admins=system
tempDestinationAdmins=admins
users=system,user
guests=guest

View File

@ -0,0 +1,22 @@
/**
* 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.
*/
activemq-domain {
org.apache.activemq.jaas.PropertiesLoginModule required
debug=true
org.apache.activemq.jaas.properties.user="users.properties"
org.apache.activemq.jaas.properties.group="groups.properties";
};

View File

@ -0,0 +1,57 @@
<?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: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 xmlns="http://activemq.apache.org/schema/core" start="false" persistent="false">
<plugins>
<runtimeConfigurationPlugin checkPeriod="1000"/>
<!-- use JAAS to authenticate using the login.config file on the classpath to configure JAAS -->
<jaasAuthenticationPlugin configuration="activemq-domain"/>
<!-- 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="GUESTS.>" 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="GUESTS.>" 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="tempDestinationAdmins,guests" write="tempDestinationAdmins,guests"
admin="tempDestinationAdmins,guests"/>
</tempDestinationAuthorizationEntry>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
</broker>
</beans>

View File

@ -0,0 +1,55 @@
<?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: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 xmlns="http://activemq.apache.org/schema/core" start="false" persistent="false">
<plugins>
<runtimeConfigurationPlugin checkPeriod="1000"/>
<!-- use JAAS to authenticate using the login.config file on the classpath to configure JAAS -->
<jaasAuthenticationPlugin configuration="activemq-domain"/>
<!-- 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 topic=">" read="admins" write="admins" admin="admins"/>
<authorizationEntry topic="USERS.>" read="users" write="users" admin="users"/>
<authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users"
admin="guests,users"/>
</authorizationEntries>
<tempDestinationAuthorizationEntry>
<tempDestinationAuthorizationEntry read="tempDestinationAdmins" write="tempDestinationAdmins"
admin="tempDestinationAdmins"/>
</tempDestinationAuthorizationEntry>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
</broker>
</beans>

View File

@ -0,0 +1,20 @@
## ---------------------------------------------------------------------------
## 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.
## ---------------------------------------------------------------------------
system=system
user=user
guest=guest

View File

@ -79,4 +79,8 @@ public class XBeanAuthorizationEntry extends AuthorizationEntry implements Initi
} }
} }
@Override
public String toString() {
return "XBeanAuthEntry:" + adminRoles + "," + writeRoles + "," + readRoles;
}
} }