View Javadoc

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 }