001: /*
002: * AclSwitchHandler.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 1998-2001 Sun Microsystems, Inc.
007: *
008: * Sun Public License Notice
009: *
010: * The contents of this file are subject to the Sun Public License Version
011: * 1.0 (the "License"). You may not use this file except in compliance with
012: * the License. A copy of the License is included as the file "license.terms",
013: * and also available at http://www.sun.com/
014: *
015: * The Original Code is from:
016: * Brazil project web application Framework release 1.1.
017: * The Initial Developer of the Original Code is: suhler.
018: * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): cstevens, suhler.
022: *
023: * Version: 1.10
024: * Created by suhler on 98/09/21
025: * Last modified by suhler on 01/01/05 11:54:01
026: */
027:
028: package sunlabs.brazil.handler;
029:
030: import java.io.IOException;
031: import java.util.Properties;
032: import java.util.StringTokenizer;
033: import sunlabs.brazil.server.Handler;
034: import sunlabs.brazil.server.Server;
035: import sunlabs.brazil.server.Request;
036: import sunlabs.brazil.util.regexp.Regexp;
037:
038: /**
039: * Simple access control hander based on url prefixes or regexps.
040: * Looks up list of valid prefixes or regular expressions in
041: * {@link sunlabs.brazil.server.Request#props}
042: * , and allows/denies
043: * access based on those prefixes.
044: * This is expected to work in conjunction with an upstream handler,
045: * such as
046: * {@link sunlabs.brazil.handler.RolesHandler}
047: * or
048: * {@link sunlabs.brazil.handler.BasicAuthHandler}
049: * that examines the request, and place credentials into the
050: * request object. The credentials consist of url prefixes
051: * or regular expressions that match classes of url's. Documents
052: * whose URL prefix don't match a credential are rejected.
053: * If a credential does not begin with a slash (/), the {@link #init} prefix
054: * for this handler is prepended.
055: * <p>
056: * Properties:
057: * <dl class=props>
058: * <dt>prefix <dd>The URL prefix that triggers this handler
059: * <dt>authName <dd>The name of the request.props entry to find a
060: * white-space delimited list of url prefixes or
061: * regular expression patterns. (defaults to "roles").
062: * If the items in the list don't start with "/", then
063: * the url prefix is prepended (only for prefix matching).
064: * <dt>redirect <dd>Name of the url to re-direct to if permission is denied.
065: * If not specified, a simple message is sent to the client.
066: * <dt>useRegexp<dd>If provided, the list of credentials is interpreted as
067: * regular expressions, otherwise url prefixes are used.
068: * </dl>
069: *
070: * @author Stephen Uhler
071: * @version 1.10, 01/01/05
072: */
073:
074: public class AclSwitchHandler implements Handler {
075: String propsPrefix; // our name in the properties file
076: String urlPrefix; // our own prefix
077: String aclName; // name of acl property in request obj
078: String redirect; // where to redirect denials to (if any)
079: boolean useRegexp; // interpret strings as exp's
080:
081: /**
082: * Handler configuration property <b>prefix</b>.
083: * Only URL's that begin with this string are considered by this handler.
084: * The default is (/).
085: */
086:
087: static final String PREFIX = "prefix"; // url prefix
088:
089: /**
090: * Handler configuration property <b>authName</b>.
091: * The name of the request property to fine a white space
092: * delimited list of credentials - URL prefixes - for this
093: * request. Defaults to <b>roles</b>.
094: */
095: static final String ACLNAME = "authName"; // authorization template
096:
097: /**
098: * Name of the url to re-direct to if permission is denied.
099: * If not specified, a simple error message is sent to the client
100: */
101:
102: final static String REDIRECT = "redirect";
103:
104: public boolean init(Server server, String prefix) {
105: propsPrefix = prefix;
106: urlPrefix = server.props.getProperty(propsPrefix + PREFIX, "/");
107: aclName = server.props.getProperty(propsPrefix + ACLNAME,
108: "roles");
109: redirect = server.props.getProperty(prefix + REDIRECT);
110: useRegexp = (server.props.getProperty(prefix + "useRegexp") != null);
111: if (urlPrefix.indexOf('/') != 0) {
112: urlPrefix = "/" + urlPrefix;
113: }
114: return true;
115: }
116:
117: public boolean respond(Request request) throws IOException {
118: if (!request.url.startsWith(urlPrefix)) {
119: return false;
120: }
121: String aclList = request.props.getProperty(aclName, null);
122: request.log(Server.LOG_DIAGNOSTIC, propsPrefix,
123: "ACL list found in: " + aclName + ": " + aclList);
124: if (aclList == null) {
125: request.sendError(400, "File Not Found", "No Acl found");
126: return true;
127: }
128:
129: /*
130: * see if our url prefix (or exp) matches anything on the list
131: */
132:
133: StringTokenizer st = new StringTokenizer(aclList);
134: while (st.hasMoreTokens()) {
135: String prefix = st.nextToken();
136: if (!useRegexp && !prefix.startsWith("/")) {
137: prefix = urlPrefix + prefix;
138: }
139: request.log(Server.LOG_DIAGNOSTIC, propsPrefix,
140: "Checking url against: " + prefix);
141: if ((useRegexp && (new Regexp(prefix)).match(request.url,
142: (String[]) null))
143: || request.url.startsWith(prefix)) {
144: return false;
145: }
146: }
147:
148: /*
149: * Either redirect to "permission denied" page, or send a simple
150: * error response
151: */
152:
153: if (redirect != null) {
154: request.redirect(redirect, null);
155: } else {
156: request.sendError(400, "File Not Found",
157: "url doesn't match: " + aclList);
158: }
159: return true;
160: }
161: }
|