KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > impl > DefaultAccessControl


1 /*
2  * Copyright 2005 Joe Walker
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.directwebremoting.impl;
17
18 import java.lang.reflect.Method JavaDoc;
19 import java.lang.reflect.Modifier JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Set JavaDoc;
27
28 import javax.servlet.http.HttpServletRequest JavaDoc;
29
30 import org.directwebremoting.WebContextFactory;
31 import org.directwebremoting.extend.AccessControl;
32 import org.directwebremoting.extend.AccessDeniedException;
33 import org.directwebremoting.extend.Creator;
34 import org.directwebremoting.extend.LoginRequiredException;
35 import org.directwebremoting.util.Messages;
36
37 /**
38  * Control who should be accessing which methods on which classes.
39  * @author Joe Walker [joe at getahead dot ltd dot uk]
40  */

41 public class DefaultAccessControl implements AccessControl
42 {
43     /* (non-Javadoc)
44      * @see org.directwebremoting.extend.AccessControl#assertExecutionIsPossible(org.directwebremoting.extend.Creator, java.lang.String, java.lang.reflect.Method)
45      */

46     public void assertExecutionIsPossible(Creator creator, String JavaDoc className, Method JavaDoc method) throws SecurityException JavaDoc
47     {
48         assertIsRestrictedByRole(className, method);
49         assertIsDisplayable(creator, className, method);
50     }
51
52     /* (non-Javadoc)
53      * @see org.directwebremoting.AccessControl#getReasonToNotDisplay(org.directwebremoting.Creator, java.lang.String, java.lang.reflect.Method)
54      */

55     public void assertIsDisplayable(Creator creator, String JavaDoc className, Method JavaDoc method) throws SecurityException JavaDoc
56     {
57         assertIsMethodPublic(method);
58         assertIsExecutable(className, method.getName());
59         assertIsNotOnBaseObject(method);
60
61         if (!exposeInternals)
62         {
63             assertIsClassDwrInternal(creator);
64             assertAreParametersDwrInternal(method);
65         }
66     }
67
68     /* (non-Javadoc)
69      * @see org.directwebremoting.AccessControl#addRoleRestriction(java.lang.String, java.lang.String, java.lang.String)
70      */

71     public void addRoleRestriction(String JavaDoc scriptName, String JavaDoc methodName, String JavaDoc role)
72     {
73         String JavaDoc key = scriptName + '.' + methodName;
74         Set JavaDoc roles = (Set JavaDoc) roleRestrictMap.get(key);
75         if (roles == null)
76         {
77             roles = new HashSet JavaDoc();
78             roleRestrictMap.put(key, roles);
79         }
80
81         roles.add(role);
82     }
83
84     /* (non-Javadoc)
85      * @see org.directwebremoting.AccessControl#addIncludeRule(java.lang.String, java.lang.String)
86      */

87     public void addIncludeRule(String JavaDoc scriptName, String JavaDoc methodName)
88     {
89         Policy policy = getPolicy(scriptName);
90
91         // If the policy for the given type is defaultAllow then we need to go
92
// to default disallow mode, and check that the are not rules applied
93
if (policy.defaultAllow)
94         {
95             if (policy.rules.size() > 0)
96             {
97                 throw new IllegalArgumentException JavaDoc(Messages.getString("DefaultAccessControl.MixedIncludesAndExcludes", scriptName));
98             }
99
100             policy.defaultAllow = false;
101         }
102
103         // Add the rule to this policy
104
policy.rules.add(methodName);
105     }
106
107     /* (non-Javadoc)
108      * @see org.directwebremoting.AccessControl#addExcludeRule(java.lang.String, java.lang.String)
109      */

110     public void addExcludeRule(String JavaDoc scriptName, String JavaDoc methodName)
111     {
112         Policy policy = getPolicy(scriptName);
113
114         // If the policy for the given type is defaultAllow then we need to go
115
// to default disallow mode, and check that the are not rules applied
116
if (!policy.defaultAllow)
117         {
118             if (policy.rules.size() > 0)
119             {
120                 throw new IllegalArgumentException JavaDoc(Messages.getString("DefaultAccessControl.MixedIncludesAndExcludes", scriptName));
121             }
122
123             policy.defaultAllow = true;
124         }
125
126         // Add the rule to this policy
127
policy.rules.add(methodName);
128     }
129
130     /**
131      * @param scriptName The name of the creator to Javascript
132      * @param method The method to execute
133      */

134     protected void assertIsRestrictedByRole(String JavaDoc scriptName, Method JavaDoc method)
135     {
136         String JavaDoc methodName = method.getName();
137
138         // What if there is some J2EE role based restriction?
139
Set JavaDoc roles = getRoleRestrictions(scriptName, methodName);
140         if (roles != null && !roles.isEmpty())
141         {
142             HttpServletRequest JavaDoc req = WebContextFactory.get().getHttpServletRequest();
143
144             assertAuthenticationIsValid(req);
145             assertAllowedByRoles(req, roles);
146         }
147     }
148
149     /**
150      * @param scriptName The name of the creator to Javascript
151      * @param methodName The name of the method (without brackets)
152      * @return A Set of all the roles for the given script and method
153      */

154     protected Set JavaDoc getRoleRestrictions(String JavaDoc scriptName, String JavaDoc methodName)
155     {
156         String JavaDoc key = scriptName + '.' + methodName;
157         return (Set JavaDoc) roleRestrictMap.get(key);
158     }
159
160     /**
161      * Check the users session for validity
162      * @param req The users request
163      * @throws SecurityException if the users session is invalid
164      */

165     protected void assertAuthenticationIsValid(HttpServletRequest JavaDoc req) throws SecurityException JavaDoc
166     {
167         // ensure that at least the next call has a valid session
168
req.getSession();
169
170         // if there was an expired session, the request has to fail
171
if (!req.isRequestedSessionIdValid())
172         {
173             throw new LoginRequiredException(Messages.getString("DefaultAccessControl.DeniedByInvalidSession"));
174         }
175
176         if (req.getRemoteUser() == null)
177         {
178             throw new LoginRequiredException(Messages.getString("DefaultAccessControl.DeniedByAuthenticationRequired"));
179         }
180     }
181
182     /**
183      * Is this current user in the given list of roles
184      * @param req The users request
185      * @param roles The list of roles to check
186      * @throws SecurityException if this user is not allowed by the list of roles
187      */

188     protected void assertAllowedByRoles(HttpServletRequest JavaDoc req, Set JavaDoc roles) throws SecurityException JavaDoc
189     {
190         for (Iterator JavaDoc it = roles.iterator(); it.hasNext();)
191         {
192             String JavaDoc role = (String JavaDoc) it.next();
193             if ("*".equals(role) || req.isUserInRole(role))
194             {
195                 return;
196             }
197         }
198
199         throw new AccessDeniedException(Messages.getString("DefaultAccessControl.DeniedByJ2EERoles", roles.toString()));
200     }
201
202     /**
203      * Is the method public?
204      * @param method The method that we wish to execute
205      */

206     protected void assertIsMethodPublic(Method JavaDoc method)
207     {
208         if (!Modifier.isPublic(method.getModifiers()))
209         {
210             throw new SecurityException JavaDoc(Messages.getString("DefaultAccessControl.DeniedNonPublic"));
211         }
212     }
213
214     /**
215      * We ban some methods from {@link java.lang.Object}
216      * @param method The method that should not be owned by {@link java.lang.Object}
217      */

218     protected void assertIsNotOnBaseObject(Method JavaDoc method)
219     {
220         if (method.getDeclaringClass() == Object JavaDoc.class)
221         {
222             throw new SecurityException JavaDoc(Messages.getString("DefaultAccessControl.DeniedObjectMethod"));
223         }
224     }
225
226     /**
227      * Test to see if a method is excluded or included.
228      * @param scriptName The name of the creator to Javascript
229      * @param methodName The name of the method (without brackets)
230      * @throws SecurityException if the method is allowed by the rules in addIncludeRule()
231      * @see AccessControl#addIncludeRule(String, String)
232      */

233     protected void assertIsExecutable(String JavaDoc scriptName, String JavaDoc methodName) throws SecurityException JavaDoc
234     {
235         Policy policy = (Policy) policyMap.get(scriptName);
236         if (policy == null)
237         {
238             return;
239         }
240
241         // Find a match for this method in the policy rules
242
String JavaDoc match = null;
243         for (Iterator JavaDoc it = policy.rules.iterator(); it.hasNext() && match == null;)
244         {
245             String JavaDoc test = (String JavaDoc) it.next();
246
247             // If at some point we wish to do regex matching on rules, here is
248
// the place to do it.
249
if (methodName.equals(test))
250             {
251                 match = test;
252             }
253         }
254
255         if (policy.defaultAllow && match != null)
256         {
257             // We are in default allow mode so the rules are exclusions and we
258
// have a match, so this method is excluded.
259
//log.debug("method excluded for creator " + type + " due to defaultAllow=" + policy.defaultAllow + " and rule: " + match);
260
throw new SecurityException JavaDoc(Messages.getString("DefaultAccessControl.DeniedByAccessRules"));
261         }
262
263         // There may be a more optimized if statement here, but I value code
264
// clarity over performance.
265
//noinspection RedundantIfStatement
266

267         if (!policy.defaultAllow && match == null)
268         {
269             // We are in default deny mode so the rules are inclusions and we
270
// do not have a match, so this method is excluded.
271
//log.debug("method excluded for creator " + type + " due to defaultAllow=" + policy.defaultAllow + " and rule: " + match);
272
throw new SecurityException JavaDoc(Messages.getString("DefaultAccessControl.DeniedByAccessRules"));
273         }
274     }
275
276     /**
277      * Check the parameters are not DWR internal either
278      * @param method The method that we want to execute
279      */

280     protected void assertAreParametersDwrInternal(Method JavaDoc method)
281     {
282         for (int j = 0; j < method.getParameterTypes().length; j++)
283         {
284             Class JavaDoc paramType = method.getParameterTypes()[j];
285
286             if (paramType.getName().startsWith(PACKAGE_DWR_DENY))
287             {
288                 throw new SecurityException JavaDoc(Messages.getString("DefaultAccessControl.DeniedParamDWR"));
289             }
290         }
291     }
292
293     /**
294      * Is the class that we are executing a method on part of DWR?
295      * @param creator The {@link Creator} that exposes the class
296      */

297     protected void assertIsClassDwrInternal(Creator creator)
298     {
299         if (creator.getType().getName().startsWith(PACKAGE_DWR_DENY))
300         {
301             throw new SecurityException JavaDoc(Messages.getString("DefaultAccessControl.DeniedCoreDWR"));
302         }
303     }
304
305     /**
306      * Find the policy for the given type and create one if none exists.
307      * @param type The name of the creator
308      * @return The policy for the given Creator
309      */

310     protected Policy getPolicy(String JavaDoc type)
311     {
312         Policy policy = (Policy) policyMap.get(type);
313         if (policy == null)
314         {
315             policy = new Policy();
316             policyMap.put(type, policy);
317         }
318
319         return policy;
320     }
321
322     /**
323      * @param exposeInternals the exposeInternals to set
324      */

325     public void setExposeInternals(boolean exposeInternals)
326     {
327         this.exposeInternals = exposeInternals;
328     }
329
330     /**
331      * Do we allow DWR classes to be remoted?
332      * @see #PACKAGE_DWR_DENY
333      */

334     protected boolean exposeInternals = false;
335
336     /**
337      * A map of Creators to policies
338      */

339     protected Map JavaDoc policyMap = new HashMap JavaDoc();
340
341     /**
342      * What role based restrictions are there?
343      */

344     protected Map JavaDoc roleRestrictMap = new HashMap JavaDoc();
345
346     /**
347      * A struct that contains a method access policy for a Creator
348      */

349     static class Policy
350     {
351         boolean defaultAllow = true;
352         List JavaDoc rules = new ArrayList JavaDoc();
353     }
354
355     /**
356      * My package name, so we can ban DWR classes from being created or marshalled
357      */

358     protected static final String JavaDoc PACKAGE_DWR_DENY = "org.directwebremoting.";
359 }
360
Popular Tags