/** * 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.security; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.security.Principal; import java.util.*; import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.filter.DestinationMap; import org.apache.activemq.filter.DestinationMapEntry; import org.apache.activemq.filter.DestinationMapNode; import org.apache.activemq.filter.DestinationNode; /** * Represents a destination based configuration of policies so that individual * destinations or wildcard hierarchies of destinations can be configured using * different policies. Each entry in the map represents the authorization ACLs * for each operation. * * */ public class DefaultAuthorizationMap extends DestinationMap implements AuthorizationMap { public static final String DEFAULT_GROUP_CLASS = "org.apache.activemq.jaas.GroupPrincipal"; private AuthorizationEntry defaultEntry; private TempDestinationAuthorizationEntry tempDestinationAuthorizationEntry; protected String groupClass = DEFAULT_GROUP_CLASS; public DefaultAuthorizationMap() { } @SuppressWarnings("rawtypes") public DefaultAuthorizationMap(List<DestinationMapEntry> authorizationEntries) { setAuthorizationEntries(authorizationEntries); } public void setTempDestinationAuthorizationEntry(TempDestinationAuthorizationEntry tempDestinationAuthorizationEntry) { this.tempDestinationAuthorizationEntry = tempDestinationAuthorizationEntry; } public TempDestinationAuthorizationEntry getTempDestinationAuthorizationEntry() { return this.tempDestinationAuthorizationEntry; } @Override public Set<Object> getTempDestinationAdminACLs() { if (tempDestinationAuthorizationEntry != null) { Set<Object> answer = new WildcardAwareSet<Object>(); answer.addAll(tempDestinationAuthorizationEntry.getAdminACLs()); return answer; } else { return null; } } @Override public Set<Object> getTempDestinationReadACLs() { if (tempDestinationAuthorizationEntry != null) { Set<Object> answer = new WildcardAwareSet<Object>(); answer.addAll(tempDestinationAuthorizationEntry.getReadACLs()); return answer; } else { return null; } } @Override public Set<Object> getTempDestinationWriteACLs() { if (tempDestinationAuthorizationEntry != null) { Set<Object> answer = new WildcardAwareSet<Object>(); answer.addAll(tempDestinationAuthorizationEntry.getWriteACLs()); return answer; } else { return null; } } @Override public Set<Object> getAdminACLs(ActiveMQDestination destination) { Set<AuthorizationEntry> entries = getAllEntries(destination); Set<Object> answer = new WildcardAwareSet<Object>(); // now lets go through each entry adding individual for (Iterator<AuthorizationEntry> iter = entries.iterator(); iter.hasNext();) { AuthorizationEntry entry = iter.next(); answer.addAll(entry.getAdminACLs()); } return answer; } @Override public Set<Object> getReadACLs(ActiveMQDestination destination) { Set<AuthorizationEntry> entries = getAllEntries(destination); Set<Object> answer = new WildcardAwareSet<Object>(); // now lets go through each entry adding individual for (Iterator<AuthorizationEntry> iter = entries.iterator(); iter.hasNext();) { AuthorizationEntry entry = iter.next(); answer.addAll(entry.getReadACLs()); } return answer; } @Override public Set<Object> getWriteACLs(ActiveMQDestination destination) { Set<AuthorizationEntry> entries = getAllEntries(destination); Set<Object> answer = new WildcardAwareSet<Object>(); // now lets go through each entry adding individual for (Iterator<AuthorizationEntry> iter = entries.iterator(); iter.hasNext();) { AuthorizationEntry entry = iter.next(); answer.addAll(entry.getWriteACLs()); } return answer; } public AuthorizationEntry getEntryFor(ActiveMQDestination destination) { AuthorizationEntry answer = (AuthorizationEntry)chooseValue(destination); if (answer == null) { answer = getDefaultEntry(); } return answer; } /** * Looks up the value(s) matching the given Destination key. For simple * destinations this is typically a List of one single value, for wildcards * or composite destinations this will typically be a Union of matching * values. * * @param key the destination to lookup * @return a Union of matching values or an empty list if there are no * matching values. */ @Override @SuppressWarnings("rawtypes") public synchronized Set get(ActiveMQDestination key) { if (key.isComposite()) { ActiveMQDestination[] destinations = key.getCompositeDestinations(); Set answer = null; for (int i = 0; i < destinations.length; i++) { ActiveMQDestination childDestination = destinations[i]; answer = union(answer, get(childDestination)); if (answer == null || answer.isEmpty()) { break; } } return answer; } return findWildcardMatches(key, false); } /** * Sets the individual entries on the authorization map */ @SuppressWarnings("rawtypes") public void setAuthorizationEntries(List<DestinationMapEntry> entries) { super.setEntries(entries); } public AuthorizationEntry getDefaultEntry() { return defaultEntry; } public void setDefaultEntry(AuthorizationEntry defaultEntry) { this.defaultEntry = defaultEntry; } @Override @SuppressWarnings("rawtypes") protected Class<? extends DestinationMapEntry> getEntryClass() { return AuthorizationEntry.class; } @SuppressWarnings("unchecked") protected Set<AuthorizationEntry> getAllEntries(ActiveMQDestination destination) { Set<AuthorizationEntry> entries = get(destination); if (defaultEntry != null) { entries.add(defaultEntry); } return entries; } public String getGroupClass() { return groupClass; } public void setGroupClass(String groupClass) { this.groupClass = groupClass; } final static String WILDCARD = "*"; public static Object createGroupPrincipal(String name, String groupClass) throws Exception { if (WILDCARD.equals(name)) { // simple match all group principal - match any name and class return new Principal() { @Override public String getName() { return WILDCARD; } @Override public boolean equals(Object other) { return true; } @Override public int hashCode() { return WILDCARD.hashCode(); } }; } Object[] param = new Object[]{name}; Class<?> cls = Class.forName(groupClass); Constructor<?>[] constructors = cls.getConstructors(); int i; Object instance; for (i = 0; i < constructors.length; i++) { Class<?>[] paramTypes = constructors[i].getParameterTypes(); if (paramTypes.length == 1 && paramTypes[0].equals(String.class)) { break; } } if (i < constructors.length) { instance = constructors[i].newInstance(param); } else { instance = cls.newInstance(); Method[] methods = cls.getMethods(); i = 0; for (i = 0; i < methods.length; i++) { Class<?>[] paramTypes = methods[i].getParameterTypes(); if (paramTypes.length == 1 && methods[i].getName().equals("setName") && paramTypes[0].equals(String.class)) { break; } } if (i < methods.length) { methods[i].invoke(instance, param); } else { throw new NoSuchMethodException(); } } return instance; } class WildcardAwareSet<T> extends HashSet<T> { boolean hasWildcard = false; @Override public boolean contains(Object e) { if (hasWildcard) { return true; } else { return super.contains(e); } } @Override public boolean addAll(Collection<? extends T> collection) { boolean modified = false; Iterator<? extends T> e = collection.iterator(); while (e.hasNext()) { final T item = e.next(); if (isWildcard(item)) { hasWildcard = true; } if (add(item)) { modified = true; } } return modified; } private boolean isWildcard(T item) { try { if (item.getClass().getMethod("getName", new Class[]{}).invoke(item).equals("*")) { return true; } } catch (Exception ignored) { } return false; } } }