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