001: /*
002: * Copyright 2006 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013:
014: package org.wings.plaf.css.dwr;
015:
016: import java.lang.reflect.Method;
017: import java.lang.reflect.Modifier;
018: import java.util.ArrayList;
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.Set;
024: import java.util.WeakHashMap;
025: import org.directwebremoting.extend.AccessControl;
026: import org.directwebremoting.extend.Creator;
027: import org.directwebremoting.WebContextFactory;
028: import javax.servlet.http.HttpSession;
029: import javax.servlet.http.HttpServletRequest;
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032:
033: /**
034: * Control who should be accessing which methods on which classes.
035: * Specialized to use in sessions.
036: *
037: * @author Christian Schyma
038: */
039: public class SessionAccessControl implements AccessControl {
040:
041: private final transient static Log log = LogFactory
042: .getLog(SessionAccessControl.class);
043:
044: /**
045: * ban DWR classes from being created or marshalled
046: */
047: private static final String PACKAGE_DWR_DENY = "org.directwebremoting.";
048:
049: public void addRoleRestriction(String scriptName,
050: String methodName, String role) {
051: String key = scriptName + '.' + methodName;
052: Set roles = (Set) getRoleRestrictMap().get(key);
053: if (roles == null) {
054: roles = new HashSet();
055: getRoleRestrictMap().put(key, roles);
056: }
057:
058: roles.add(role);
059: }
060:
061: public void addIncludeRule(String scriptName, String methodName) {
062: Policy policy = getPolicy(scriptName);
063:
064: // If the policy for the given type is defaultAllow then we need to go
065: // to default disallow mode, and check that the are not rules applied
066: if (policy.defaultAllow) {
067: if (policy.rules.size() > 0) {
068: throw new IllegalArgumentException(
069: "ACL rules mixed includes/exluded for script: "
070: + scriptName);
071: }
072:
073: policy.defaultAllow = false;
074: }
075:
076: // Add the rule to this policy
077: policy.rules.add(methodName);
078: }
079:
080: public void addExcludeRule(String scriptName, String methodName) {
081: Policy policy = getPolicy(scriptName);
082:
083: // If the policy for the given type is defaultAllow then we need to go
084: // to default disallow mode, and check that the are not rules applied
085: if (!policy.defaultAllow) {
086: if (policy.rules.size() > 0) {
087: throw new IllegalArgumentException(
088: "ACL rules mixed includes/exluded for script: "
089: + scriptName);
090: }
091:
092: policy.defaultAllow = true;
093: }
094:
095: // Add the rule to this policy
096: policy.rules.add(methodName);
097: }
098:
099: /**
100: * @param scriptName The name of the creator to Javascript
101: * @param methodName The name of the method (without brackets)
102: * @return A Set of all the roles for the given script and method
103: */
104: private Set getRoleRestrictions(String scriptName, String methodName) {
105: String key = scriptName + '.' + methodName;
106: return (Set) getRoleRestrictMap().get(key);
107: }
108:
109: /**
110: * Test to see if a method is excluded or included.
111: * @param scriptName The name of the creator to Javascript
112: * @param methodName The name of the method (without brackets)
113: * @return true if the method is allowed by the rules in addIncludeRule()
114: * @see AccessControl#addIncludeRule(String, String)
115: */
116: private boolean isExecutable(String scriptName, String methodName) {
117: Policy policy = (Policy) getPolicyMap().get(scriptName);
118: if (policy == null) {
119: return true;
120: }
121:
122: // Find a match for this method in the policy rules
123: String match = null;
124: for (Iterator it = policy.rules.iterator(); it.hasNext()
125: && match == null;) {
126: String test = (String) it.next();
127:
128: // If at some point we wish to do regex matching on rules, here is
129: // the place to do it.
130: if (methodName.equals(test)) {
131: match = test;
132: }
133: }
134:
135: if (policy.defaultAllow && match != null) {
136: // We are in default allow mode so the rules are exclusions and we
137: // have a match, so this method is excluded.
138: //log.debug("method excluded for creator " + type + " due to defaultAllow=" + policy.defaultAllow + " and rule: " + match);
139: return false;
140: }
141:
142: // There may be a more optimized if statement here, but I value code
143: // clarity over performance.
144: //noinspection RedundantIfStatement
145:
146: if (!policy.defaultAllow && match == null) {
147: // We are in default deny mode so the rules are inclusions and we
148: // do not have a match, so this method is excluded.
149: //log.debug("method excluded for creator " + type + " due to defaultAllow=" + policy.defaultAllow + " and rule: " + match);
150: return false;
151: }
152:
153: return true;
154: }
155:
156: /**
157: * Find the policy for the given type and create one if none exists.
158: * @param type The name of the creator
159: * @return The policy for the given Creator
160: */
161: private Policy getPolicy(String type) {
162: Policy policy = (Policy) getPolicyMap().get(type);
163: if (policy == null) {
164: policy = new Policy();
165: getPolicyMap().put(type, policy);
166: }
167:
168: return policy;
169: }
170:
171: /**
172: * Get AccessMap from session.
173: */
174: private Map getAccessMap() {
175: HttpSession session = WebContextFactory.get().getSession();
176: Map map = (Map) session.getAttribute("AccessMap");
177: if (map == null) {
178: map = new WeakHashMap();
179: session.setAttribute("AccessMap", map);
180: }
181: return map;
182: }
183:
184: /**
185: * Get PolicyMap from session.
186: */
187: private Map getPolicyMap() {
188: HttpSession session = WebContextFactory.get().getSession();
189: Map map = (Map) session.getAttribute("PolicyMap");
190: if (map == null) {
191: map = new WeakHashMap();
192: session.setAttribute("PolicyMap", map);
193: }
194:
195: return map;
196: }
197:
198: /**
199: * Get RolseRestrictMap from session.
200: */
201: private Map getRoleRestrictMap() {
202: HttpSession session = WebContextFactory.get().getSession();
203: Map map = (Map) session.getAttribute("RoleRestrictMap");
204: if (map == null) {
205: map = new WeakHashMap();
206: session.setAttribute("RoleRestrictMap", map);
207: }
208:
209: return map;
210: }
211:
212: public void assertExecutionIsPossible(Creator creator,
213: String className, Method method) throws SecurityException {
214: String methodName = method.getName();
215:
216: // What if there is some J2EE role based restriction?
217: Set roles = getRoleRestrictions(className, methodName);
218: if (roles != null) {
219: boolean allowed = false;
220:
221: HttpServletRequest req = WebContextFactory.get()
222: .getHttpServletRequest();
223: if (req == null) {
224: log
225: .warn("Missing HttpServletRequest roles can not be checked");
226: } else {
227: for (Iterator it = roles.iterator(); it.hasNext()
228: && !allowed;) {
229: String role = (String) it.next();
230: if (req.isUserInRole(role)) {
231: allowed = true;
232: }
233: }
234: }
235:
236: if (!allowed) {
237: // This just creates a list of allowed roles for better debugging
238: StringBuffer buffer = new StringBuffer();
239: for (Iterator it = roles.iterator(); it.hasNext();) {
240: String role = (String) it.next();
241: buffer.append(role);
242: if (it.hasNext()) {
243: buffer.append(", ");
244: }
245: }
246:
247: throw new SecurityException(
248: "DWR method invocation denied by J2EE role definition: "
249: + buffer.toString());
250: }
251: }
252:
253: }
254:
255: public void assertIsDisplayable(Creator creator, String className,
256: Method method) throws SecurityException {
257: String methodName = method.getName();
258:
259: // Is it public
260: if (!Modifier.isPublic(method.getModifiers())) {
261: throw new SecurityException(
262: "Denied DWR invocation of non-public method.");
263: }
264:
265: // Do access controls allow it?
266: if (!isExecutable(className, methodName)) {
267: throw new SecurityException(
268: "Method access is denied by rules");
269: }
270:
271: // We ban some methods from Object too
272: if (method.getDeclaringClass() == Object.class) {
273: throw new SecurityException(
274: "Security denied a DWR call to an Method declared in class Object");
275: }
276:
277: if (creator.getType().getName().startsWith(PACKAGE_DWR_DENY)) {
278: throw new SecurityException(
279: "Security denied a DWR call to an Method declared in the DWR framework");
280: }
281:
282: // Check the parameters are not DWR internal either
283: for (int j = 0; j < method.getParameterTypes().length; j++) {
284: Class paramType = method.getParameterTypes()[j];
285:
286: if (paramType.getName().startsWith(PACKAGE_DWR_DENY)) {
287: throw new SecurityException(
288: "Denied remote DWR invocation of a DWR framework method.");
289: }
290: }
291:
292: }
293:
294: /**
295: * A struct that contains a method access policy for a Creator
296: */
297: static class Policy {
298: boolean defaultAllow = false;
299: List rules = new ArrayList();
300: }
301:
302: }
|