001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.deploy;
018:
019: import java.io.Serializable;
020:
021: /**
022: * Representation of a security constraint element for a web application,
023: * as represented in a <code><security-constraint></code> element in the
024: * deployment descriptor.
025: * <p>
026: * <b>WARNING</b>: It is assumed that instances of this class will be created
027: * and modified only within the context of a single thread, before the instance
028: * is made visible to the remainder of the application. After that, only read
029: * access is expected. Therefore, none of the read and write access within
030: * this class is synchronized.
031: *
032: * @author Craig R. McClanahan
033: * @version $Revision: 1.4 $ $Date: 2004/05/13 20:40:49 $
034: */
035:
036: public class SecurityConstraint implements Serializable {
037:
038: // ----------------------------------------------------------- Constructors
039:
040: /**
041: * Construct a new security constraint instance with default values.
042: */
043: public SecurityConstraint() {
044:
045: super ();
046:
047: }
048:
049: // ----------------------------------------------------- Instance Variables
050:
051: /**
052: * Was the "all roles" wildcard included in the authorization constraints
053: * for this security constraint?
054: */
055: private boolean allRoles = false;
056:
057: /**
058: * Was an authorization constraint included in this security constraint?
059: * This is necessary to distinguish the case where an auth-constraint with
060: * no roles (signifying no direct access at all) was requested, versus
061: * a lack of auth-constraint which implies no access control checking.
062: */
063: private boolean authConstraint = false;
064:
065: /**
066: * The set of roles permitted to access resources protected by this
067: * security constraint.
068: */
069: private String authRoles[] = new String[0];
070:
071: /**
072: * The set of web resource collections protected by this security
073: * constraint.
074: */
075: private SecurityCollection collections[] = new SecurityCollection[0];
076:
077: /**
078: * The display name of this security constraint.
079: */
080: private String displayName = null;
081:
082: /**
083: * The user data constraint for this security constraint. Must be NONE,
084: * INTEGRAL, or CONFIDENTIAL.
085: */
086: private String userConstraint = "NONE";
087:
088: // ------------------------------------------------------------- Properties
089:
090: /**
091: * Was the "all roles" wildcard included in this authentication
092: * constraint?
093: */
094: public boolean getAllRoles() {
095:
096: return (this .allRoles);
097:
098: }
099:
100: /**
101: * Return the authorization constraint present flag for this security
102: * constraint.
103: */
104: public boolean getAuthConstraint() {
105:
106: return (this .authConstraint);
107:
108: }
109:
110: /**
111: * Set the authorization constraint present flag for this security
112: * constraint.
113: */
114: public void setAuthConstraint(boolean authConstraint) {
115:
116: this .authConstraint = authConstraint;
117:
118: }
119:
120: /**
121: * Return the display name of this security constraint.
122: */
123: public String getDisplayName() {
124:
125: return (this .displayName);
126:
127: }
128:
129: /**
130: * Set the display name of this security constraint.
131: */
132: public void setDisplayName(String displayName) {
133:
134: this .displayName = displayName;
135:
136: }
137:
138: /**
139: * Return the user data constraint for this security constraint.
140: */
141: public String getUserConstraint() {
142:
143: return (userConstraint);
144:
145: }
146:
147: /**
148: * Set the user data constraint for this security constraint.
149: *
150: * @param userConstraint The new user data constraint
151: */
152: public void setUserConstraint(String userConstraint) {
153:
154: if (userConstraint != null)
155: this .userConstraint = userConstraint;
156:
157: }
158:
159: // --------------------------------------------------------- Public Methods
160:
161: /**
162: * Add an authorization role, which is a role name that will be
163: * permitted access to the resources protected by this security constraint.
164: *
165: * @param authRole Role name to be added
166: */
167: public void addAuthRole(String authRole) {
168:
169: if (authRole == null)
170: return;
171: if ("*".equals(authRole)) {
172: allRoles = true;
173: return;
174: }
175: String results[] = new String[authRoles.length + 1];
176: for (int i = 0; i < authRoles.length; i++)
177: results[i] = authRoles[i];
178: results[authRoles.length] = authRole;
179: authRoles = results;
180: authConstraint = true;
181:
182: }
183:
184: /**
185: * Add a new web resource collection to those protected by this
186: * security constraint.
187: *
188: * @param collection The new web resource collection
189: */
190: public void addCollection(SecurityCollection collection) {
191:
192: if (collection == null)
193: return;
194: SecurityCollection results[] = new SecurityCollection[collections.length + 1];
195: for (int i = 0; i < collections.length; i++)
196: results[i] = collections[i];
197: results[collections.length] = collection;
198: collections = results;
199:
200: }
201:
202: /**
203: * Return <code>true</code> if the specified role is permitted access to
204: * the resources protected by this security constraint.
205: *
206: * @param role Role name to be checked
207: */
208: public boolean findAuthRole(String role) {
209:
210: if (role == null)
211: return (false);
212: for (int i = 0; i < authRoles.length; i++) {
213: if (role.equals(authRoles[i]))
214: return (true);
215: }
216: return (false);
217:
218: }
219:
220: /**
221: * Return the set of roles that are permitted access to the resources
222: * protected by this security constraint. If none have been defined,
223: * a zero-length array is returned (which implies that all authenticated
224: * users are permitted access).
225: */
226: public String[] findAuthRoles() {
227:
228: return (authRoles);
229:
230: }
231:
232: /**
233: * Return the web resource collection for the specified name, if any;
234: * otherwise, return <code>null</code>.
235: *
236: * @param name Web resource collection name to return
237: */
238: public SecurityCollection findCollection(String name) {
239:
240: if (name == null)
241: return (null);
242: for (int i = 0; i < collections.length; i++) {
243: if (name.equals(collections[i].getName()))
244: return (collections[i]);
245: }
246: return (null);
247:
248: }
249:
250: /**
251: * Return all of the web resource collections protected by this
252: * security constraint. If there are none, a zero-length array is
253: * returned.
254: */
255: public SecurityCollection[] findCollections() {
256:
257: return (collections);
258:
259: }
260:
261: /**
262: * Return <code>true</code> if the specified context-relative URI (and
263: * associated HTTP method) are protected by this security constraint.
264: *
265: * @param uri Context-relative URI to check
266: * @param method Request method being used
267: */
268: public boolean included(String uri, String method) {
269:
270: // We cannot match without a valid request method
271: if (method == null)
272: return (false);
273:
274: // Check all of the collections included in this constraint
275: for (int i = 0; i < collections.length; i++) {
276: if (!collections[i].findMethod(method))
277: continue;
278: String patterns[] = collections[i].findPatterns();
279: for (int j = 0; j < patterns.length; j++) {
280: if (matchPattern(uri, patterns[j]))
281: return (true);
282: }
283: }
284:
285: // No collection included in this constraint matches this request
286: return (false);
287:
288: }
289:
290: /**
291: * Remove the specified role from the set of roles permitted to access
292: * the resources protected by this security constraint.
293: *
294: * @param authRole Role name to be removed
295: */
296: public void removeAuthRole(String authRole) {
297:
298: if (authRole == null)
299: return;
300: int n = -1;
301: for (int i = 0; i < authRoles.length; i++) {
302: if (authRoles[i].equals(authRole)) {
303: n = i;
304: break;
305: }
306: }
307: if (n >= 0) {
308: int j = 0;
309: String results[] = new String[authRoles.length - 1];
310: for (int i = 0; i < authRoles.length; i++) {
311: if (i != n)
312: results[j++] = authRoles[i];
313: }
314: authRoles = results;
315: }
316:
317: }
318:
319: /**
320: * Remove the specified web resource collection from those protected by
321: * this security constraint.
322: *
323: * @param collection Web resource collection to be removed
324: */
325: public void removeCollection(SecurityCollection collection) {
326:
327: if (collection == null)
328: return;
329: int n = -1;
330: for (int i = 0; i < collections.length; i++) {
331: if (collections[i].equals(collection)) {
332: n = i;
333: break;
334: }
335: }
336: if (n >= 0) {
337: int j = 0;
338: SecurityCollection results[] = new SecurityCollection[collections.length - 1];
339: for (int i = 0; i < collections.length; i++) {
340: if (i != n)
341: results[j++] = collections[i];
342: }
343: collections = results;
344: }
345:
346: }
347:
348: /**
349: * Return a String representation of this security constraint.
350: */
351: public String toString() {
352:
353: StringBuffer sb = new StringBuffer("SecurityConstraint[");
354: for (int i = 0; i < collections.length; i++) {
355: if (i > 0)
356: sb.append(", ");
357: sb.append(collections[i].getName());
358: }
359: sb.append("]");
360: return (sb.toString());
361:
362: }
363:
364: // -------------------------------------------------------- Private Methods
365:
366: /**
367: * Does the specified request path match the specified URL pattern?
368: * This method follows the same rules (in the same order) as those used
369: * for mapping requests to servlets.
370: *
371: * @param path Context-relative request path to be checked
372: * (must start with '/')
373: * @param pattern URL pattern to be compared against
374: */
375: private boolean matchPattern(String path, String pattern) {
376:
377: // Normalize the argument strings
378: if ((path == null) || (path.length() == 0))
379: path = "/";
380: if ((pattern == null) || (pattern.length() == 0))
381: pattern = "/";
382:
383: // Check for exact match
384: if (path.equals(pattern))
385: return (true);
386:
387: // Check for path prefix matching
388: if (pattern.startsWith("/") && pattern.endsWith("/*")) {
389: pattern = pattern.substring(0, pattern.length() - 2);
390: if (pattern.length() == 0)
391: return (true); // "/*" is the same as "/"
392: if (path.endsWith("/"))
393: path = path.substring(0, path.length() - 1);
394: while (true) {
395: if (pattern.equals(path))
396: return (true);
397: int slash = path.lastIndexOf('/');
398: if (slash <= 0)
399: break;
400: path = path.substring(0, slash);
401: }
402: return (false);
403: }
404:
405: // Check for suffix matching
406: if (pattern.startsWith("*.")) {
407: int slash = path.lastIndexOf('/');
408: int period = path.lastIndexOf('.');
409: if ((slash >= 0) && (period > slash)
410: && path.endsWith(pattern.substring(1))) {
411: return (true);
412: }
413: return (false);
414: }
415:
416: // Check for universal mapping
417: if (pattern.equals("/"))
418: return (true);
419:
420: return (false);
421:
422: }
423:
424: }
|