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:
019: /* $Id: BypassableAccessController.java 597145 2007-11-21 16:55:51Z andreas $ */
020:
021: package org.apache.lenya.ac.impl;
022:
023: import java.util.ArrayList;
024: import java.util.List;
025:
026: import org.apache.avalon.framework.configuration.Configuration;
027: import org.apache.avalon.framework.configuration.ConfigurationException;
028: import org.apache.cocoon.environment.Request;
029: import org.apache.cocoon.sitemap.PatternException;
030: import org.apache.lenya.ac.AccessControlException;
031: import org.apache.regexp.RE;
032: import org.apache.regexp.RECompiler;
033: import org.apache.regexp.REProgram;
034: import org.apache.regexp.RESyntaxException;
035:
036: /**
037: * AccessController that can be bypassed for certain URL patterns.
038: */
039: public class BypassableAccessController extends DefaultAccessController {
040:
041: /**
042: * Ctor.
043: */
044: public BypassableAccessController() {
045: // do nothing
046: }
047:
048: private List publicMatchers = new ArrayList();
049: private List publicExtensions = new ArrayList();
050:
051: /**
052: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
053: */
054: public void configure(Configuration conf)
055: throws ConfigurationException {
056: super .configure(conf);
057:
058: getLogger().debug("Configuring bypass patterns");
059:
060: Configuration[] publics = conf.getChildren("public");
061:
062: for (int i = 0; i < publics.length; i++) {
063: String publicHref = publics[i].getValue(null);
064:
065: try {
066: this .publicMatchers.add(preparePattern(publicHref));
067: } catch (PatternException pe) {
068: throw new ConfigurationException(
069: "invalid pattern for public hrefs", pe);
070: }
071:
072: if (getLogger().isDebugEnabled()) {
073: getLogger().debug(
074: "CONFIGURATION: public: " + publicHref);
075: }
076: }
077:
078: Configuration[] extensionConfigs = conf
079: .getChildren("public-extensions");
080: for (int i = 0; i < extensionConfigs.length; i++) {
081: String extensionString = extensionConfigs[i].getValue();
082: String[] extensions = extensionString.split(",");
083: for (int e = 0; e < extensions.length; e++) {
084: String ext = extensions[e].trim();
085: if (!ext.startsWith(".")) {
086: ext = "." + ext;
087: }
088: this .publicExtensions.add(ext);
089: }
090: }
091:
092: }
093:
094: /**
095: * Compile the pattern in a <code>org.apache.regexp.REProgram</code>.
096: * @param pattern The pattern to compile.
097: * @return A RE program representing the pattern.
098: * @throws PatternException when something went wrong.
099: */
100: protected REProgram preparePattern(String pattern)
101: throws PatternException {
102: if (pattern == null) {
103: throw new PatternException("null passed as a pattern", null);
104: }
105:
106: if (pattern.length() == 0) {
107: pattern = "^$";
108:
109: if (getLogger().isWarnEnabled()) {
110: getLogger()
111: .warn(
112: "The empty pattern string was rewritten to '^$'"
113: + " to match for empty strings. If you intended"
114: + " to match all strings, please change your"
115: + " pattern to '.*'");
116: }
117: }
118:
119: try {
120: RECompiler compiler = new RECompiler();
121: REProgram program = compiler.compile(pattern);
122:
123: return program;
124: } catch (RESyntaxException rse) {
125: getLogger().debug(
126: "Failed to compile the pattern '" + pattern + "'",
127: rse);
128: throw new PatternException(rse.getMessage(), rse);
129: }
130: }
131:
132: /**
133: * Matches a string using a prepared pattern program.
134: * @param preparedPattern The pattern program.
135: * @param match The string to match.
136: * @return <code>true</code> if the string matched the pattern, <code>false</code> otherwise.
137: */
138: protected boolean preparedMatch(REProgram preparedPattern,
139: String match) {
140: boolean result = false;
141:
142: if (match != null) {
143: RE re = new RE(preparedPattern);
144: result = re.match(match);
145: }
146: return result;
147: }
148:
149: /**
150: * @see org.apache.lenya.ac.AccessController#authorize(org.apache.cocoon.environment.Request)
151: */
152: public boolean authorize(Request request)
153: throws AccessControlException {
154:
155: assert request != null;
156:
157: resolveRoles(request);
158:
159: boolean authorized = false;
160:
161: String uri = request.getRequestURI();
162: String context = request.getContextPath();
163: if (context == null) {
164: context = "";
165: }
166: uri = uri.substring(context.length());
167:
168: // Check public uris from configuration above. Should only be used during development before the implementation of a concrete authorizer.
169: int i = 0;
170: while (!authorized && i < this .publicMatchers.size()) {
171: getLogger().debug(
172: "Trying pattern: [" + this .publicMatchers.get(i)
173: + "] with URL [" + uri + "]");
174: if (preparedMatch((REProgram) this .publicMatchers.get(i),
175: uri)) {
176: if (getLogger().isDebugEnabled()) {
177: getLogger().debug(
178: "Permission granted for free: [" + uri
179: + "]");
180: }
181: authorized = true;
182: }
183: i++;
184: }
185:
186: i = 0;
187: while (!authorized && i < this .publicExtensions.size()) {
188: String ext = (String) this.publicExtensions.get(i);
189: authorized = uri.endsWith(ext);
190: i++;
191: }
192:
193: if (!authorized) {
194: authorized = super.authorize(request);
195: }
196:
197: return authorized;
198: }
199:
200: }
|