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 }