001: /*
002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/deploy/SecurityConstraint.java,v 1.5 2001/07/22 20:25:10 pier Exp $
003: * $Revision: 1.5 $
004: * $Date: 2001/07/22 20:25:10 $
005: *
006: * ====================================================================
007: *
008: * The Apache Software License, Version 1.1
009: *
010: * Copyright (c) 1999 The Apache Software Foundation. All rights
011: * reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions
015: * are met:
016: *
017: * 1. Redistributions of source code must retain the above copyright
018: * notice, this list of conditions and the following disclaimer.
019: *
020: * 2. Redistributions in binary form must reproduce the above copyright
021: * notice, this list of conditions and the following disclaimer in
022: * the documentation and/or other materials provided with the
023: * distribution.
024: *
025: * 3. The end-user documentation included with the redistribution, if
026: * any, must include the following acknowlegement:
027: * "This product includes software developed by the
028: * Apache Software Foundation (http://www.apache.org/)."
029: * Alternately, this acknowlegement may appear in the software itself,
030: * if and wherever such third-party acknowlegements normally appear.
031: *
032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
033: * Foundation" must not be used to endorse or promote products derived
034: * from this software without prior written permission. For written
035: * permission, please contact apache@apache.org.
036: *
037: * 5. Products derived from this software may not be called "Apache"
038: * nor may "Apache" appear in their names without prior written
039: * permission of the Apache Group.
040: *
041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
052: * SUCH DAMAGE.
053: * ====================================================================
054: *
055: * This software consists of voluntary contributions made by many
056: * individuals on behalf of the Apache Software Foundation. For more
057: * information on the Apache Software Foundation, please see
058: * <http://www.apache.org/>.
059: *
060: * [Additional notices, if required by prior licensing conditions]
061: *
062: */
063:
064: package org.apache.catalina.deploy;
065:
066: /**
067: * Representation of a security constraint element for a web application,
068: * as represented in a <code><security-constraint></code> element in the
069: * deployment descriptor.
070: * <p>
071: * <b>WARNING</b>: It is assumed that instances of this class will be created
072: * and modified only within the context of a single thread, before the instance
073: * is made visible to the remainder of the application. After that, only read
074: * access is expected. Therefore, none of the read and write access within
075: * this class is synchronized.
076: *
077: * @author Craig R. McClanahan
078: * @version $Revision: 1.5 $ $Date: 2001/07/22 20:25:10 $
079: */
080:
081: public final class SecurityConstraint {
082:
083: // ----------------------------------------------------------- Constructors
084:
085: /**
086: * Construct a new security constraint instance with default values.
087: */
088: public SecurityConstraint() {
089:
090: super ();
091:
092: }
093:
094: // ----------------------------------------------------- Instance Variables
095:
096: /**
097: * Was the "all roles" wildcard included in the authorization constraints
098: * for this security constraint?
099: */
100: private boolean allRoles = false;
101:
102: /**
103: * Was an authorization constraint included in this security constraint?
104: * This is necessary to distinguish the case where an auth-constraint with
105: * no roles (signifying no direct access at all) was requested, versus
106: * a lack of auth-constraint which implies no access control checking.
107: */
108: private boolean authConstraint = false;
109:
110: /**
111: * The set of roles permitted to access resources protected by this
112: * security constraint.
113: */
114: private String authRoles[] = new String[0];
115:
116: /**
117: * The set of web resource collections protected by this security
118: * constraint.
119: */
120: private SecurityCollection collections[] = new SecurityCollection[0];
121:
122: /**
123: * The display name of this security constraint.
124: */
125: private String displayName = null;
126:
127: /**
128: * The user data constraint for this security constraint. Must be NONE,
129: * INTEGRAL, or CONFIDENTIAL.
130: */
131: private String userConstraint = "NONE";
132:
133: // ------------------------------------------------------------- Properties
134:
135: /**
136: * Was the "all roles" wildcard included in this authentication
137: * constraint?
138: */
139: public boolean getAllRoles() {
140:
141: return (this .allRoles);
142:
143: }
144:
145: /**
146: * Return the authorization constraint present flag for this security
147: * constraint.
148: */
149: public boolean getAuthConstraint() {
150:
151: return (this .authConstraint);
152:
153: }
154:
155: /**
156: * Set the authorization constraint present flag for this security
157: * constraint.
158: */
159: public void setAuthConstraint(boolean authConstraint) {
160:
161: this .authConstraint = authConstraint;
162:
163: }
164:
165: /**
166: * Return the display name of this security constraint.
167: */
168: public String getDisplayName() {
169:
170: return (this .displayName);
171:
172: }
173:
174: /**
175: * Set the display name of this security constraint.
176: */
177: public void setDisplayName(String displayName) {
178:
179: this .displayName = displayName;
180:
181: }
182:
183: /**
184: * Return the user data constraint for this security constraint.
185: */
186: public String getUserConstraint() {
187:
188: return (userConstraint);
189:
190: }
191:
192: /**
193: * Set the user data constraint for this security constraint.
194: *
195: * @param userConstraint The new user data constraint
196: */
197: public void setUserConstraint(String userConstraint) {
198:
199: if (userConstraint != null)
200: this .userConstraint = userConstraint;
201:
202: }
203:
204: // --------------------------------------------------------- Public Methods
205:
206: /**
207: * Add an authorization role, which is a role name that will be
208: * permitted access to the resources protected by this security constraint.
209: *
210: * @param authRole Role name to be added
211: */
212: public void addAuthRole(String authRole) {
213:
214: if (authRole == null)
215: return;
216: if ("*".equals(authRole)) {
217: allRoles = true;
218: return;
219: }
220: String results[] = new String[authRoles.length + 1];
221: for (int i = 0; i < authRoles.length; i++)
222: results[i] = authRoles[i];
223: results[authRoles.length] = authRole;
224: authRoles = results;
225: authConstraint = true;
226:
227: }
228:
229: /**
230: * Add a new web resource collection to those protected by this
231: * security constraint.
232: *
233: * @param collection The new web resource collection
234: */
235: public void addCollection(SecurityCollection collection) {
236:
237: if (collection == null)
238: return;
239: SecurityCollection results[] = new SecurityCollection[collections.length + 1];
240: for (int i = 0; i < collections.length; i++)
241: results[i] = collections[i];
242: results[collections.length] = collection;
243: collections = results;
244:
245: }
246:
247: /**
248: * Return <code>true</code> if the specified role is permitted access to
249: * the resources protected by this security constraint.
250: *
251: * @param role Role name to be checked
252: */
253: public boolean findAuthRole(String role) {
254:
255: if (role == null)
256: return (false);
257: for (int i = 0; i < authRoles.length; i++) {
258: if (role.equals(authRoles[i]))
259: return (true);
260: }
261: return (false);
262:
263: }
264:
265: /**
266: * Return the set of roles that are permitted access to the resources
267: * protected by this security constraint. If none have been defined,
268: * a zero-length array is returned (which implies that all authenticated
269: * users are permitted access).
270: */
271: public String[] findAuthRoles() {
272:
273: return (authRoles);
274:
275: }
276:
277: /**
278: * Return the web resource collection for the specified name, if any;
279: * otherwise, return <code>null</code>.
280: *
281: * @param name Web resource collection name to return
282: */
283: public SecurityCollection findCollection(String name) {
284:
285: if (name == null)
286: return (null);
287: for (int i = 0; i < collections.length; i++) {
288: if (name.equals(collections[i].getName()))
289: return (collections[i]);
290: }
291: return (null);
292:
293: }
294:
295: /**
296: * Return all of the web resource collections protected by this
297: * security constraint. If there are none, a zero-length array is
298: * returned.
299: */
300: public SecurityCollection[] findCollections() {
301:
302: return (collections);
303:
304: }
305:
306: /**
307: * Return <code>true</code> if the specified context-relative URI (and
308: * associated HTTP method) are protected by this security constraint.
309: *
310: * @param uri Context-relative URI to check
311: * @param method Request method being used
312: */
313: public boolean included(String uri, String method) {
314:
315: // We cannot match without a valid request method
316: if (method == null)
317: return (false);
318:
319: // Check all of the collections included in this constraint
320: for (int i = 0; i < collections.length; i++) {
321: if (!collections[i].findMethod(method))
322: continue;
323: String patterns[] = collections[i].findPatterns();
324: for (int j = 0; j < patterns.length; j++) {
325: if (matchPattern(uri, patterns[j]))
326: return (true);
327: }
328: }
329:
330: // No collection included in this constraint matches this request
331: return (false);
332:
333: }
334:
335: /**
336: * Remove the specified role from the set of roles permitted to access
337: * the resources protected by this security constraint.
338: *
339: * @param authRole Role name to be removed
340: */
341: public void removeAuthRole(String authRole) {
342:
343: if (authRole == null)
344: return;
345: int n = -1;
346: for (int i = 0; i < authRoles.length; i++) {
347: if (authRoles[i].equals(authRole)) {
348: n = i;
349: break;
350: }
351: }
352: if (n >= 0) {
353: int j = 0;
354: String results[] = new String[authRoles.length - 1];
355: for (int i = 0; i < authRoles.length; i++) {
356: if (i != n)
357: results[j++] = authRoles[i];
358: }
359: authRoles = results;
360: }
361:
362: }
363:
364: /**
365: * Remove the specified web resource collection from those protected by
366: * this security constraint.
367: *
368: * @param collection Web resource collection to be removed
369: */
370: public void removeCollection(SecurityCollection collection) {
371:
372: if (collection == null)
373: return;
374: int n = -1;
375: for (int i = 0; i < collections.length; i++) {
376: if (collections[i].equals(collection)) {
377: n = i;
378: break;
379: }
380: }
381: if (n >= 0) {
382: int j = 0;
383: SecurityCollection results[] = new SecurityCollection[collections.length - 1];
384: for (int i = 0; i < collections.length; i++) {
385: if (i != n)
386: results[j++] = collections[i];
387: }
388: collections = results;
389: }
390:
391: }
392:
393: /**
394: * Return a String representation of this security constraint.
395: */
396: public String toString() {
397:
398: StringBuffer sb = new StringBuffer("SecurityConstraint[");
399: for (int i = 0; i < collections.length; i++) {
400: if (i > 0)
401: sb.append(", ");
402: sb.append(collections[i].getName());
403: }
404: sb.append("]");
405: return (sb.toString());
406:
407: }
408:
409: // -------------------------------------------------------- Private Methods
410:
411: /**
412: * Does the specified request path match the specified URL pattern?
413: * This method follows the same rules (in the same order) as those used
414: * for mapping requests to servlets.
415: *
416: * @param path Context-relative request path to be checked
417: * (must start with '/')
418: * @param pattern URL pattern to be compared against
419: */
420: private boolean matchPattern(String path, String pattern) {
421:
422: // Normalize the argument strings
423: if ((path == null) || (path.length() == 0))
424: path = "/";
425: if ((pattern == null) || (pattern.length() == 0))
426: pattern = "/";
427:
428: // Check for exact match
429: if (path.equals(pattern))
430: return (true);
431:
432: // Check for path prefix matching
433: if (pattern.startsWith("/") && pattern.endsWith("/*")) {
434: pattern = pattern.substring(0, pattern.length() - 2);
435: if (pattern.length() == 0)
436: return (true); // "/*" is the same as "/"
437: if (path.endsWith("/"))
438: path = path.substring(0, path.length() - 1);
439: while (true) {
440: if (pattern.equals(path))
441: return (true);
442: int slash = path.lastIndexOf('/');
443: if (slash <= 0)
444: break;
445: path = path.substring(0, slash);
446: }
447: return (false);
448: }
449:
450: // Check for suffix matching
451: if (pattern.startsWith("*.")) {
452: int slash = path.lastIndexOf('/');
453: int period = path.lastIndexOf('.');
454: if ((slash >= 0) && (period > slash)
455: && path.endsWith(pattern.substring(1))) {
456: return (true);
457: }
458: return (false);
459: }
460:
461: // Check for universal mapping
462: if (pattern.equals("/"))
463: return (true);
464:
465: return (false);
466:
467: }
468:
469: }
|