1 /* 2 jGuard is a security framework based on top of jaas (java authentication and authorization security). 3 it is written for web applications, to resolve simply, access control problems. 4 version $Name$ 5 http://sourceforge.net/projects/jguard/ 6 7 Copyright (C) 2004 Charles GAY 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2.1 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 23 24 jGuard project home page: 25 http://sourceforge.net/projects/jguard/ 26 27 */ 28 package net.sf.jguard.core.authorization.policy; 29 30 import java.lang.ref.WeakReference; 31 import java.security.Permission; 32 import java.security.PermissionCollection; 33 import java.security.Permissions; 34 import java.security.Policy; 35 import java.security.Principal; 36 import java.security.ProtectionDomain; 37 import java.util.Iterator; 38 import java.util.Map; 39 import java.util.Set; 40 import java.util.WeakHashMap; 41 42 import java.util.logging.Level; 43 import net.sf.jguard.core.authorization.manager.PermissionProvider; 44 import net.sf.jguard.core.authorization.permissions.AuditPermissionCollection; 45 import net.sf.jguard.core.authorization.permissions.PermissionUtils; 46 import net.sf.jguard.core.principals.JMXPrincipal; 47 import org.slf4j.Logger; 48 import org.slf4j.LoggerFactory; 49 50 51 /** 52 * Jguard Policy implementation: 53 * handle all Authorization decisions. 54 * This implementation handles multiple policies. It is designed for 55 * multiple apps requiring different policies among the same VM. Exemple : webapps. 56 * @author <a href="mailto:diabolo512@users.sourceforge.net">Charles Gay</a> 57 * @author <a href="mailto:zelfdoen@users.sourceforge.net">Theo Niemeijer</a> 58 * @author <a href="mailto:vberetti@users.sourceforge.net">Vincent Beretti</a> 59 * 60 */ 61 public abstract class AbstractMultipleAppPolicy extends JGuardPolicy { 62 63 private static Map permissionProviderRepository; 64 private static Logger logger = LoggerFactory.getLogger(AbstractMultipleAppPolicy.class.getName()); 65 66 /** 67 * constructor. 68 * 69 */ 70 public AbstractMultipleAppPolicy(){ 71 super(); 72 logger.info("####### loading jGuardPolicy "+JGuardPolicy.version+" ###########"); 73 74 permissionProviderRepository = new WeakHashMap(); 75 76 loadDefaultPolicy(); 77 } 78 79 /** 80 * constructor used to include the replaced Policy. 81 * @param oldPolicy replaced by jGuardPolicy 82 */ 83 public AbstractMultipleAppPolicy(Policy oldPolicy){ 84 85 logger.info("####### loading AbstractMultipleAppPolicy "+JGuardPolicy.version+" ###########"); 86 87 permissionProviderRepository = new WeakHashMap(); 88 defaultPolicy = oldPolicy; 89 } 90 91 92 93 /** 94 * refresh all the permissions. 95 * if somes changes are made with the permissionManager implementation, 96 * this method must be called to reflect these changes. 97 * you should use instead <i>public void refresh(Object objectID)</i> JGuardPolicy method 98 * to avoid performance issue (refresh all security configurations for all application policies). 99 * @see AbstractMultipleAppPolicy#refresh(Object objectID) 100 */ 101 public void refresh() { 102 Set keys = permissionProviderRepository.keySet(); 103 Iterator itKeys = keys.iterator(); 104 while(itKeys.hasNext()){ 105 Object objectID = itKeys.next(); 106 refresh(objectID); 107 } 108 109 } 110 111 /** 112 * refresh all the permissions. 113 * if somes changes are made with the permissionManager implementation, 114 * this method must be called to reflect these changes. 115 * @see AbstractMultipleAppPolicy#refresh() 116 * @param objectID webapplication's classloader 117 */ 118 public void refresh(Object objectID) { 119 //we get the webapp corresponding permission manager 120 // and call its refresh method 121 PermissionProvider pm = getContextPermissionProvider(objectID); 122 123 if (pm != null) { 124 // Refresh the permission configuration 125 pm.refresh(); 126 } 127 } 128 129 130 /** 131 * retrieve all user's permissions. 132 * if this protectionDomain is protected by jGuard, 133 * we add the jGuard additional permissions to the permissionCollection 134 * obtained with the defaultPolicy implementation 135 * when the SecurityManager is set. 136 * otherwise, the only PermissionCollection created by jGuard is returned. 137 * @see java.security.Policy#getPermissions(java.security.ProtectionDomain) 138 * @param protectionDomain 139 * @return permissions collection 140 */ 141 public PermissionCollection getPermissions(ProtectionDomain protectionDomain) { 142 143 144 // Get classloader for protection domain 145 ClassLoader cl = protectionDomain.getClassLoader(); 146 // Get permission provider associated with classloader 147 PermissionProvider pm = getContextPermissionProvider(cl); 148 149 PermissionCollection pc = getPermissions(protectionDomain, pm); 150 151 //include permissions from CodeSource 152 PermissionCollection mergedPc = PermissionUtils.mergePermissionCollections(pc,getPermissions(protectionDomain.getCodeSource())); 153 return new AuditPermissionCollection(mergedPc,protectionDomain); 154 } 155 156 /** 157 * Register permission provider. Registers given permission provider instance 158 * with the specified classloader instance. 159 * @param objectID - Object identifier 160 * @param pm - permission provider 161 * 162 */ 163 public void registerPermissionProvider(Object objectID, PermissionProvider pm) { 164 165 if (getContextPermissionProvider(objectID) == null) { 166 // Put permission provider in map keyed by classloader 167 setContextPermissionProvider(objectID, pm); 168 }else{ 169 logger.error("registerPermissionProvider() - two webapps have got the same classLoader ....application will stop"); 170 171 //key is not unique => two webapps will have the same authorisation mechanism....ERROR 172 throw new RuntimeException( 173 " an exception occurs in the registerPermissionProvider method of the JGuardPolicy \n webApplication stops "); 174 } 175 } 176 177 /** 178 * Unregister permission provider. Removes permission provider associated with 179 * the given classloader instance. 180 * 181 * @param objectID - Object identifier 182 * 183 */ 184 public void unregisterPermissionProvider(Object objectID) { 185 186 if (permissionProviderRepository.containsKey(objectID)) { 187 188 // Remove permission provider in map keyed by classloader 189 permissionProviderRepository.remove(objectID); 190 } 191 } 192 193 /** 194 * Get context permission provider. This is a helper method that 195 * uses weakhashmap and weakreferences to ensure that unloaded classes 196 * will become garbage collected. 197 * @param objectID - Object identifier 198 * @return permission provider which can be null if no one is found 199 */ 200 public PermissionProvider getContextPermissionProvider(Object objectID) { 201 202 // Get permission provider associated with classloader 203 WeakReference ref = (WeakReference) permissionProviderRepository.get(objectID); 204 205 if (ref == null) { 206 return null; 207 } 208 209 // Get permission provider from weak reference 210 PermissionProvider pm = (PermissionProvider) ref.get(); 211 212 return pm; 213 } 214 215 /** 216 * Set context permission provider. This is a helper method that 217 * uses weakhashmap and weakreferences to ensure that unloaded classes 218 * will become garbage collected. 219 * 220 * @param objectID - Identifier Object 221 * @param pm - permission provider 222 */ 223 private void setContextPermissionProvider(Object objectID, PermissionProvider pm) { 224 225 // Put classloader and its associated permission provider in map 226 permissionProviderRepository.put(objectID, new WeakReference(pm)); 227 } 228 229 230 /** 231 * sees if domain can match permission 232 * @param domain - 233 * @param permission - permission to be checked 234 * @return <code>true</code> if domain checks permission, <code>false</code> otherwise 235 */ 236 public boolean implies(ProtectionDomain domain, Permission permission) { 237 238 if(domain.getClassLoader() == null){ 239 // domain may be the ProtectionDomain generated 240 // during JMX connection. The JMX generated ProtectionDomain 241 // has null classLoader, null codeSource, empty permissions and 242 // the principals set during JGuardJMXAuthenticator.authenticate(). 243 // This domain is created in JMXSubjectDomainCombiner.combine(...) 244 // It could also simply be a protection domain with null classloader 245 // but not very likely. 246 // 247 // The following test searches for a JMXPrincipal to ensure that 248 // this null classloader protectionDomain is indeed created for JMX. 249 250 Principal[] principals = domain.getPrincipals(); 251 boolean jmxHandled = false; 252 int i = 0; 253 ProtectionDomain newDomain = null; 254 255 while (i < principals.length && !jmxHandled){ 256 if (principals[i] instanceof JMXPrincipal){ 257 newDomain = new ProtectionDomain(domain.getCodeSource(), 258 domain.getPermissions(), 259 (ClassLoader)((JMXPrincipal)principals[i]).getObjectID(), 260 domain.getPrincipals()); 261 jmxHandled = true; 262 } 263 i++; 264 } 265 266 if (newDomain != null){ 267 // domain is the protectionDomain created in JMXSubjectDomainCombiner 268 // a new ProtectionDomain is created based on domain but it adds the 269 // classloader got from the JMXPrincipal. super.implies(newDomain,...); 270 // invokes the method getPermissions(newDomain) and with this new domain, 271 // getPermission is able to get the PermissionProvider of the webapp whose 272 // MBean are monitored by JMX. 273 return super.implies(newDomain, permission); 274 } 275 } 276 return super.implies(domain, permission); 277 } 278 279 280 public void addAlwaysGrantedPermissions(ClassLoader cl,Permissions alwaysGrantedPermissions){ 281 PermissionProvider pm = getContextPermissionProvider(cl); 282 if(pm==null){ 283 logger.error(" classloader is not bound to a PermissionProvider registered in the MultipleAppPolicy "); 284 logger.error(" permissions always granted cannot be added "); 285 }else{ 286 pm.addAlwaysGrantedPermissions(alwaysGrantedPermissions); 287 } 288 } 289 }