001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package javax.security.jacc;
023:
024: import java.io.Serializable;
025: import java.io.ObjectStreamField;
026: import java.io.ObjectInputStream;
027: import java.io.IOException;
028: import java.io.ObjectOutputStream;
029: import java.security.Permission;
030: import java.util.TreeSet;
031: import javax.servlet.http.HttpServletRequest;
032:
033: import org.jboss.util.id.SerialVersion;
034:
035: /** Class for Servlet Web user data permissions. A WebUserDataPermission is a
036: * named permission and has actions.
037: *
038: * The name of a WebUserDataPermission (also referred to as the target name)
039: * identifies a Web resource by its context path relative URL pattern.
040: *
041: * @link http://java.sun.com/j2ee/1.4/docs/api/
042: *
043: * @author Scott.Stark@jboss.org
044: * @author Ron Monzillo, Gary Ellison (javadoc)
045: * @version $Revision: 57196 $
046: */
047: public final class WebUserDataPermission extends Permission implements
048: Serializable {
049: /** @since 4.0.2 */
050: private static final long serialVersionUID;
051: static {
052: if (SerialVersion.version == SerialVersion.LEGACY)
053: serialVersionUID = 141000;
054: else
055: serialVersionUID = 1;
056: }
057:
058: /**
059: * @serialField actions String the actions string.
060: */
061: private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField(
062: "actions", String.class) };
063:
064: private transient URLPatternSpec urlSpec;
065: private transient String httpMethodsString;
066: private transient String transportType;
067: private transient TreeSet httpMethods;
068:
069: /** Creates a new WebUserDataPermission from the HttpServletRequest object.
070: *
071: * @param request - the HttpServletRequest object corresponding to the
072: * Servlet operation to which the permission pertains. The permission name is
073: * the substring of the requestURI (HttpServletRequest.getRequestURI()) that
074: * begins after the contextPath (HttpServletRequest.getContextPath()). When
075: * the substring operation yields the string "/", the permission is
076: * constructed with the empty string as its name. The HTTP method component
077: * of the permission's actions is as obtained from HttpServletRequest.getMethod().
078: * The TransportType component of the permission's actions is determined by
079: * calling HttpServletRequest.isSecure().
080: */
081: public WebUserDataPermission(HttpServletRequest request) {
082: this (WebResourcePermission.requestURI(request),
083: requestActions(request));
084: }
085:
086: /** Creates a new WebUserDataPermission with the specified name and actions.
087: The name contains a URLPatternSpec that identifies the web resources to which
088: the permissions applies. The syntax of a URLPatternSpec is as follows:
089:
090: URLPatternList ::= URLPattern | URLPatternList colon URLPattern
091:
092: URLPatternSpec ::= null | URLPattern | URLPattern colon URLPatternList
093:
094: A null URLPatternSpec is translated to the default URLPattern, "/", by the
095: permission constructor. The empty string is an exact URLPattern, and may
096: occur anywhere in a URLPatternSpec that an exact URLPattern may occur.
097: The first URLPattern in a URLPatternSpec may be any of the pattern types,
098: exact, path-prefix, extension, or default as defined in the Java Servlet
099: Specification). When a URLPatternSpec includes a URLPatternList, the
100: patterns of the URLPatternList identify the resources to which the
101: permission does NOT apply and depend on the pattern type and value of the
102: first pattern as follows:
103:
104: - No pattern may exist in the URLPatternList that matches the first pattern.
105: - If the first pattern is a path-prefix pattern, only exact patterns matched
106: by the first pattern and path-prefix patterns matched by, but different from,
107: the first pattern may occur in the URLPatternList.
108: - If the first pattern is an extension pattern, only exact patterns that are
109: matched by the first pattern and path-prefix patterns may occur in the
110: URLPatternList.
111: - If the first pattern is the default pattern, "/", any pattern except the
112: default pattern may occur in the URLPatternList.
113: - If the first pattern is an exact pattern a URLPatternList must not be
114: present in the URLPatternSpec.
115:
116: The actions parameter contains a comma separated list of HTTP methods that
117: may be followed by a transportType separated from the HTTP method by a colon.
118:
119: HTTPMethod ::= "Get" | "POST" | "PUT" | "DELETE" | "HEAD" |
120: "OPTIONS" | "TRACE"
121:
122: HTTPMethodList ::= HTTPMethod | HTTPMethodList comma HTTPMethod
123:
124: HTTPMethodSpec ::= emptyString | HTTPMethodList
125:
126: transportType ::= "INTEGRAL" | "CONFIDENTIAL" | "NONE"
127:
128: actions ::= null | HTTPMethodSpec |
129: HTTPMethodSpec colon transportType
130:
131:
132: If duplicates occur in the HTTPMethodSpec they must be eliminated by the
133: permission constructor.
134:
135: An empty string HTTPMethodSpec is a shorthand for a List containing all the
136: possible HTTP methods.
137:
138: An actions string without a transportType is a shorthand for a actions string
139: with the value "NONE" as its TransportType.
140:
141: A granted permission representing a transportType of "NONE", indicates that
142: the associated resources may be accessed using any conection type.
143:
144: @param name - the URLPatternSpec that identifies the application specific
145: web resources to which the permission pertains. All URLPatterns in the
146: URLPatternSpec are relative to the context path of the deployed web
147: application module, and the same URLPattern must not occur more than once
148: in a URLPatternSpec. A null URLPatternSpec is translated to the default
149: URLPattern, "/", by the permission constructor.
150: @param actions - identifies the HTTP methods and transport type to which
151: the permission pertains. If the value passed through this parameter is
152: null or the empty string, then the permission is constructed with actions
153: corresponding to all the possible HTTP methods and transportType "NONE".
154: */
155: public WebUserDataPermission(String name, String actions) {
156: super (name == null ? "/" : name);
157: if (name == null)
158: name = "/";
159: this .urlSpec = new URLPatternSpec(name);
160: parseActions(actions);
161: }
162:
163: /** Creates a new WebUserDataPermission with name corresponding to the
164: * URLPatternSpec, and actions composed from the array of HTTP methods and
165: * the transport type.
166: *
167: * @param urlPatternSpec - the URLPatternSpec that identifies the application
168: * specific web resources to which the permission pertains. All URLPatterns
169: * in the URLPatternSpec are relative to the context path of the deployed web
170: * application module, and the same URLPattern must not occur more than once
171: * in a URLPatternSpec. A null URLPatternSpec is translated to the default
172: * URLPattern, "/", by the permission constructor.
173: * @param httpMethods - an array of strings each element of which contains
174: * the value of an HTTP method. If the value passed through this parameter is
175: * null or is an array with no elements, then the permission is constructed
176: * with actions containing all the possible HTTP methods.
177: * @param transportType - a String whose value is a transportType. If the
178: * value passed through this parameter is null, then the permission is
179: * constructed with actions containing transportType "NONE".
180: */
181: public WebUserDataPermission(String urlPatternSpec,
182: String[] httpMethods, String transportType) {
183: super (urlPatternSpec);
184: this .urlSpec = new URLPatternSpec(urlPatternSpec);
185: Object[] methodInfo = WebResourcePermission
186: .canonicalMethods(httpMethods);
187: this .httpMethods = (TreeSet) methodInfo[0];
188: this .httpMethodsString = (String) methodInfo[1];
189: if (transportType != null
190: && transportType.equalsIgnoreCase("NONE"))
191: transportType = null;
192: this .transportType = transportType;
193: }
194:
195: /** Checks two WebUserDataPermission objects for equality. WebUserDataPermission
196: * objects are equivalent if their URLPatternSpec and (canonicalized) actions
197: * values are equivalent. The URLPatternSpec of a reference permission is
198: * equivalent to that of an argument permission if their first patterns are
199: * equivalent, and the patterns of the URLPatternList of the reference
200: * permission collectively match exactly the same set of patterns as are
201: * matched by the patterns of the URLPatternList of the argument permission.
202: *
203: * @param p - the WebUserDataPermission object being tested for equality.
204: * @return true if the argument WebUserDataPermission object is equivalent to
205: * this, false otherwise.
206: */
207: public boolean equals(Object p) {
208: boolean equals = false;
209: if (p == null || !(p instanceof WebUserDataPermission))
210: return false;
211: WebUserDataPermission perm = (WebUserDataPermission) p;
212: equals = urlSpec.equals(perm.urlSpec);
213: if (equals == true) {
214: String a0 = getActions();
215: String a1 = perm.getActions();
216: equals = (a0 != null && a0.equals(a1)) || (a0 == a1);
217: }
218: return equals;
219: }
220:
221: /** Returns a canonical String representation of the actions of this
222: * WebUserDataPermission. The canonical form of the actions of a
223: * WebUserDataPermission is described by the following syntax description.
224: * HTTPMethod ::= "Get" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "TRACE"
225: * HTTPMethodList ::= HTTPMethod | HTTPMethodList comma HTTPMethod
226: * HTTPMethodSpec ::= emptyString | HTTPMethodList
227: * transportType ::= "INTEGRAL" | "CONFIDENTIAL" | "NONE"
228: * actions ::= null | HTTPMethodList | HTTPMethodSpec colon transportType
229: *
230: * If the permission's HTTP methods include the entire HTTP method set and
231: * the permission's transport type is "INTEGRAL" or "CONFIDENTIAL", the HTTP
232: * methods shall be represented in the canonical form by an empty string
233: * HTTPMethodSpec. If the permission's HTTP methods include the entire HTTP
234: * method set and the permission's transport type is not "INTEGRAL"or
235: * "CONFIDENTIAL", the canonical actions value shall be the null value. If
236: * the permission's methods do not include the entire HTTP method set,
237: * duplicates must be eliminated and the remaining elements must be sorted
238: * into ascending lexical order. The resulting HTTPMethodList must be
239: * included in the canonical form, and if the permission's transport type is
240: * not "INTEGRAL" or "CONFIDENTIAL", the canonical actions value must be
241: * exactly the resulting HTTPMethodList.
242: *
243: * @return a String containing the canonicalized actions of this
244: * WebUserDataPermission (or the null value).
245: */
246: public String getActions() {
247: String actions = null;
248: if (httpMethodsString != null) {
249: if (transportType != null)
250: actions = httpMethodsString + ":" + transportType;
251: else
252: actions = httpMethodsString;
253: } else if (transportType != null) {
254: actions = ":" + transportType;
255: }
256: return actions;
257: }
258:
259: /** Returns the hash code value for this WebUserDataPermission. The properties
260: * of the returned hash code must be as follows:
261:
262: * - During the lifetime of a Java application, the hashCode method shall
263: * return the same integer value every time it is called on a
264: * WebUserDataPermission object. The value returned by hashCode for a
265: * particular EJBMethod permission need not remain consistent from one
266: * execution of an application to another.
267: * - If two WebUserDataPermission objects are equal according to the equals
268: * method, then calling the hashCode method on each of the two Permission
269: * objects must produce the same integer result (within an application).
270: * @return the int hash code.
271: */
272: public int hashCode() {
273: int hashCode = urlSpec.hash();
274: if (httpMethods != null)
275: hashCode += httpMethods.hashCode();
276: return hashCode;
277: }
278:
279: /** Determines if the argument Permission is "implied by" this
280: * WebUserDataPermission. For this to be the case all of the following must
281: * be true:
282:
283: * - The argument is an instanceof WebUserDataPermission.
284: * - The first URLPattern in the name of the argument permission is matched
285: * by the first URLPattern in the name of this permission.
286: * - The first URLPattern in the name of the argument permission is NOT
287: * matched by any URLPattern in the URLPatternList of the URLPatternSpec of
288: * this permission.
289: * - If the first URLPattern in the name of the argument permission matches
290: * the first URLPattern in the URLPatternSpec of this permission, then every
291: * URLPattern in the URLPatternList of the URLPatternSpec of this permission
292: * is matched by a URLPattern in the URLPatternList of the argument
293: * permission.
294: * - The HTTP methods in the actions of the argument permission are a subset
295: * of the HTTP methods in the actions of this permission.
296: * - The transportType in the actions of this permission either corresponds
297: * to the value "NONE", or equals the transportType in the actions of the
298: * argument permission.
299: *
300: * URLPattern matching is performed using the Servlet matching rules where
301: * two URL patterns match if they are related as follows:
302:
303: * - their pattern values are String equivalent, or
304: * - this pattern is the path-prefix pattern "/*", or
305: * - this pattern is a path-prefix pattern (that is, it starts with "/" and
306: * ends with "/*") and the argument pattern starts with the substring of this
307: * pattern, minus its last 2 characters, and the next character of the
308: * argument pattern, if there is one, is "/", or
309: * - this pattern is an extension pattern (that is, it starts with "*.") and
310: * the argument pattern ends with this pattern, or
311: * - the reference pattern is the special default pattern, "/", which matches
312: * all argument patterns.
313: *
314: * All of the comparisons described above are case sensitive.
315: *
316: * @param p - the WebUserDataPermission to test
317: * @return true if this implies the argument permission
318: */
319: public boolean implies(Permission p) {
320: if (p == null || !(p instanceof WebUserDataPermission))
321: return false;
322: WebUserDataPermission perm = (WebUserDataPermission) p;
323: // Check the URL patterns
324: boolean implies = urlSpec.implies(perm.urlSpec);
325: if (implies == true) {
326: // Check the http methods
327: if (httpMethods != null)
328: implies = httpMethods.containsAll(perm.httpMethods);
329: // Check the transport guarentee
330: if (implies == true && transportType != null)
331: implies = transportType.equals(perm.transportType);
332: }
333:
334: return implies;
335: }
336:
337: // Private -------------------------------------------------------
338: /** Build the request permission actions from the HTTP method component
339: * using HttpServletRequest.getMethod() + the TransportType component of the
340: * action from HttpServletRequest.isSecure().
341: *
342: * @param request - the servlet request
343: * @return the permission actions string
344: */
345: private static String requestActions(HttpServletRequest request) {
346: String actions = request.getMethod()
347: + (request.isSecure() ? ":CONFIDENTIAL" : "");
348: return actions;
349: }
350:
351: private void parseActions(String actions) {
352: // Remove any transport spec
353: if (actions != null) {
354: int colon = actions.indexOf(':');
355: if (colon >= 0) {
356: this .transportType = actions.substring(colon + 1);
357: if (transportType.equalsIgnoreCase("NONE"))
358: transportType = null;
359: actions = actions.substring(0, colon);
360: }
361: }
362: Object[] methodInfo = WebResourcePermission
363: .canonicalMethods(actions);
364: this .httpMethods = (TreeSet) methodInfo[0];
365: this .httpMethodsString = (String) methodInfo[1];
366: }
367:
368: private void readObject(ObjectInputStream ois)
369: throws ClassNotFoundException, IOException {
370: ObjectInputStream.GetField fields = ois.readFields();
371: String actions = (String) fields.get("actions", null);
372: parseActions(actions);
373: }
374:
375: private void writeObject(ObjectOutputStream oos) throws IOException {
376: ObjectOutputStream.PutField fields = oos.putFields();
377: fields.put("actions", this.getActions());
378: oos.writeFields();
379: }
380: }
|