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