001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.security; 018 019import java.lang.reflect.Constructor; 020import java.lang.reflect.Method; 021import java.security.Principal; 022import java.util.*; 023 024import org.apache.activemq.command.ActiveMQDestination; 025import org.apache.activemq.filter.DestinationMap; 026import org.apache.activemq.filter.DestinationMapEntry; 027import org.apache.activemq.filter.DestinationMapNode; 028import org.apache.activemq.filter.DestinationNode; 029 030/** 031 * Represents a destination based configuration of policies so that individual 032 * destinations or wildcard hierarchies of destinations can be configured using 033 * different policies. Each entry in the map represents the authorization ACLs 034 * for each operation. 035 * 036 * 037 */ 038public class DefaultAuthorizationMap extends DestinationMap implements AuthorizationMap { 039 040 public static final String DEFAULT_GROUP_CLASS = "org.apache.activemq.jaas.GroupPrincipal"; 041 042 private AuthorizationEntry defaultEntry; 043 044 private TempDestinationAuthorizationEntry tempDestinationAuthorizationEntry; 045 046 protected String groupClass = DEFAULT_GROUP_CLASS; 047 048 public DefaultAuthorizationMap() { 049 } 050 051 @SuppressWarnings("rawtypes") 052 public DefaultAuthorizationMap(List<DestinationMapEntry> authorizationEntries) { 053 setAuthorizationEntries(authorizationEntries); 054 055 } 056 057 public void setTempDestinationAuthorizationEntry(TempDestinationAuthorizationEntry tempDestinationAuthorizationEntry) { 058 this.tempDestinationAuthorizationEntry = tempDestinationAuthorizationEntry; 059 } 060 061 public TempDestinationAuthorizationEntry getTempDestinationAuthorizationEntry() { 062 return this.tempDestinationAuthorizationEntry; 063 } 064 065 @Override 066 public Set<Object> getTempDestinationAdminACLs() { 067 if (tempDestinationAuthorizationEntry != null) { 068 Set<Object> answer = new WildcardAwareSet<Object>(); 069 answer.addAll(tempDestinationAuthorizationEntry.getAdminACLs()); 070 return answer; 071 } else { 072 return null; 073 } 074 } 075 076 @Override 077 public Set<Object> getTempDestinationReadACLs() { 078 if (tempDestinationAuthorizationEntry != null) { 079 Set<Object> answer = new WildcardAwareSet<Object>(); 080 answer.addAll(tempDestinationAuthorizationEntry.getReadACLs()); 081 return answer; 082 } else { 083 return null; 084 } 085 } 086 087 @Override 088 public Set<Object> getTempDestinationWriteACLs() { 089 if (tempDestinationAuthorizationEntry != null) { 090 Set<Object> answer = new WildcardAwareSet<Object>(); 091 answer.addAll(tempDestinationAuthorizationEntry.getWriteACLs()); 092 return answer; 093 } else { 094 return null; 095 } 096 } 097 098 @Override 099 public Set<Object> getAdminACLs(ActiveMQDestination destination) { 100 Set<AuthorizationEntry> entries = getAllEntries(destination); 101 Set<Object> answer = new WildcardAwareSet<Object>(); 102 103 // now lets go through each entry adding individual 104 for (Iterator<AuthorizationEntry> iter = entries.iterator(); iter.hasNext();) { 105 AuthorizationEntry entry = iter.next(); 106 answer.addAll(entry.getAdminACLs()); 107 } 108 return answer; 109 } 110 111 @Override 112 public Set<Object> getReadACLs(ActiveMQDestination destination) { 113 Set<AuthorizationEntry> entries = getAllEntries(destination); 114 Set<Object> answer = new WildcardAwareSet<Object>(); 115 116 // now lets go through each entry adding individual 117 for (Iterator<AuthorizationEntry> iter = entries.iterator(); iter.hasNext();) { 118 AuthorizationEntry entry = iter.next(); 119 answer.addAll(entry.getReadACLs()); 120 } 121 return answer; 122 } 123 124 @Override 125 public Set<Object> getWriteACLs(ActiveMQDestination destination) { 126 Set<AuthorizationEntry> entries = getAllEntries(destination); 127 Set<Object> answer = new WildcardAwareSet<Object>(); 128 129 // now lets go through each entry adding individual 130 for (Iterator<AuthorizationEntry> iter = entries.iterator(); iter.hasNext();) { 131 AuthorizationEntry entry = iter.next(); 132 answer.addAll(entry.getWriteACLs()); 133 } 134 return answer; 135 } 136 137 public AuthorizationEntry getEntryFor(ActiveMQDestination destination) { 138 AuthorizationEntry answer = (AuthorizationEntry)chooseValue(destination); 139 if (answer == null) { 140 answer = getDefaultEntry(); 141 } 142 return answer; 143 } 144 145 146 /** 147 * Looks up the value(s) matching the given Destination key. For simple 148 * destinations this is typically a List of one single value, for wildcards 149 * or composite destinations this will typically be a Union of matching 150 * values. 151 * 152 * @param key the destination to lookup 153 * @return a Union of matching values or an empty list if there are no 154 * matching values. 155 */ 156 @Override 157 @SuppressWarnings("rawtypes") 158 public synchronized Set get(ActiveMQDestination key) { 159 if (key.isComposite()) { 160 ActiveMQDestination[] destinations = key.getCompositeDestinations(); 161 Set answer = null; 162 for (int i = 0; i < destinations.length; i++) { 163 ActiveMQDestination childDestination = destinations[i]; 164 answer = union(answer, get(childDestination)); 165 if (answer == null || answer.isEmpty()) { 166 break; 167 } 168 } 169 return answer; 170 } 171 172 return findWildcardMatches(key, false); 173 } 174 175 176 /** 177 * Sets the individual entries on the authorization map 178 */ 179 @SuppressWarnings("rawtypes") 180 public void setAuthorizationEntries(List<DestinationMapEntry> entries) { 181 super.setEntries(entries); 182 } 183 184 public AuthorizationEntry getDefaultEntry() { 185 return defaultEntry; 186 } 187 188 public void setDefaultEntry(AuthorizationEntry defaultEntry) { 189 this.defaultEntry = defaultEntry; 190 } 191 192 @Override 193 @SuppressWarnings("rawtypes") 194 protected Class<? extends DestinationMapEntry> getEntryClass() { 195 return AuthorizationEntry.class; 196 } 197 198 @SuppressWarnings("unchecked") 199 protected Set<AuthorizationEntry> getAllEntries(ActiveMQDestination destination) { 200 Set<AuthorizationEntry> entries = get(destination); 201 if (defaultEntry != null) { 202 entries.add(defaultEntry); 203 } 204 return entries; 205 } 206 207 public String getGroupClass() { 208 return groupClass; 209 } 210 211 public void setGroupClass(String groupClass) { 212 this.groupClass = groupClass; 213 } 214 215 final static String WILDCARD = "*"; 216 public static Object createGroupPrincipal(String name, String groupClass) throws Exception { 217 if (WILDCARD.equals(name)) { 218 // simple match all group principal - match any name and class 219 return new Principal() { 220 @Override 221 public String getName() { 222 return WILDCARD; 223 } 224 @Override 225 public boolean equals(Object other) { 226 return true; 227 } 228 229 @Override 230 public int hashCode() { 231 return WILDCARD.hashCode(); 232 } 233 }; 234 } 235 Object[] param = new Object[]{name}; 236 237 Class<?> cls = Class.forName(groupClass); 238 239 Constructor<?>[] constructors = cls.getConstructors(); 240 int i; 241 Object instance; 242 for (i = 0; i < constructors.length; i++) { 243 Class<?>[] paramTypes = constructors[i].getParameterTypes(); 244 if (paramTypes.length != 0 && paramTypes[0].equals(String.class)) { 245 break; 246 } 247 } 248 if (i < constructors.length) { 249 instance = constructors[i].newInstance(param); 250 } else { 251 instance = cls.newInstance(); 252 Method[] methods = cls.getMethods(); 253 i = 0; 254 for (i = 0; i < methods.length; i++) { 255 Class<?>[] paramTypes = methods[i].getParameterTypes(); 256 if (paramTypes.length != 0 && methods[i].getName().equals("setName") && paramTypes[0].equals(String.class)) { 257 break; 258 } 259 } 260 261 if (i < methods.length) { 262 methods[i].invoke(instance, param); 263 } else { 264 throw new NoSuchMethodException(); 265 } 266 } 267 268 return instance; 269 } 270 271 class WildcardAwareSet<T> extends HashSet<T> { 272 boolean hasWildcard = false; 273 274 @Override 275 public boolean contains(Object e) { 276 if (hasWildcard) { 277 return true; 278 } else { 279 return super.contains(e); 280 } 281 } 282 283 @Override 284 public boolean addAll(Collection<? extends T> collection) { 285 boolean modified = false; 286 Iterator<? extends T> e = collection.iterator(); 287 while (e.hasNext()) { 288 final T item = e.next(); 289 if (isWildcard(item)) { 290 hasWildcard = true; 291 } 292 if (add(item)) { 293 modified = true; 294 } 295 } 296 return modified; 297 } 298 299 private boolean isWildcard(T item) { 300 try { 301 if (item.getClass().getMethod("getName", new Class[]{}).invoke(item).equals("*")) { 302 return true; 303 } 304 } catch (Exception ignored) { 305 } 306 return false; 307 } 308 } 309}