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