001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.intercept.web;
017:
018: import org.acegisecurity.ConfigAttributeDefinition;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: import org.springframework.util.AntPathMatcher;
024: import org.springframework.util.PathMatcher;
025:
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Set;
030: import java.util.Vector;
031:
032: /**
033: * Maintains a <code>List</code> of <code>ConfigAttributeDefinition</code>s associated with different HTTP request
034: * URL Apache Ant path-based patterns.<p>Apache Ant path expressions are used to match a HTTP request URL against a
035: * <code>ConfigAttributeDefinition</code>.</p>
036: * <p>The order of registering the Ant paths using the {@link #addSecureUrl(String,ConfigAttributeDefinition)} is
037: * very important. The system will identify the <b>first</b> matching path for a given HTTP URL. It will not proceed
038: * to evaluate later paths if a match has already been found. Accordingly, the most specific paths should be
039: * registered first, with the most general paths registered last.</p>
040: * <p>If no registered paths match the HTTP URL, <code>null</code> is returned.</p>
041: *
042: * @author Ben Alex
043: * @version $Id: PathBasedFilterInvocationDefinitionMap.java 1970 2007-08-28 16:53:05Z luke_t $
044: */
045: public class PathBasedFilterInvocationDefinitionMap extends
046: AbstractFilterInvocationDefinitionSource implements
047: FilterInvocationDefinition {
048: //~ Static fields/initializers =====================================================================================
049:
050: private static final Log logger = LogFactory
051: .getLog(PathBasedFilterInvocationDefinitionMap.class);
052:
053: //~ Instance fields ================================================================================================
054:
055: private List requestMap = new Vector();
056: private PathMatcher pathMatcher = new AntPathMatcher();
057: private boolean convertUrlToLowercaseBeforeComparison = false;
058:
059: //~ Methods ========================================================================================================
060:
061: public void addSecureUrl(String antPath,
062: ConfigAttributeDefinition attr) {
063: // SEC-501: If using lower case comparison, we should convert the paths to lower case
064: // as any upper case characters included by mistake will prevent the URL from ever being matched.
065: if (convertUrlToLowercaseBeforeComparison) {
066: antPath = antPath.toLowerCase();
067: }
068:
069: requestMap.add(new EntryHolder(antPath, attr));
070:
071: if (logger.isDebugEnabled()) {
072: logger.debug("Added Ant path: " + antPath
073: + "; attributes: " + attr);
074: }
075: }
076:
077: public Iterator getConfigAttributeDefinitions() {
078: Set set = new HashSet();
079: Iterator iter = requestMap.iterator();
080:
081: while (iter.hasNext()) {
082: EntryHolder entryHolder = (EntryHolder) iter.next();
083: set.add(entryHolder.getConfigAttributeDefinition());
084: }
085:
086: return set.iterator();
087: }
088:
089: public int getMapSize() {
090: return this .requestMap.size();
091: }
092:
093: public boolean isConvertUrlToLowercaseBeforeComparison() {
094: return convertUrlToLowercaseBeforeComparison;
095: }
096:
097: public ConfigAttributeDefinition lookupAttributes(String url) {
098: // Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
099: int firstQuestionMarkIndex = url.indexOf("?");
100:
101: if (firstQuestionMarkIndex != -1) {
102: url = url.substring(0, firstQuestionMarkIndex);
103: }
104:
105: if (isConvertUrlToLowercaseBeforeComparison()) {
106: url = url.toLowerCase();
107:
108: if (logger.isDebugEnabled()) {
109: logger.debug("Converted URL to lowercase, from: '"
110: + url + "'; to: '" + url + "'");
111: }
112: }
113:
114: Iterator iter = requestMap.iterator();
115:
116: while (iter.hasNext()) {
117: EntryHolder entryHolder = (EntryHolder) iter.next();
118:
119: boolean matched = pathMatcher.match(entryHolder
120: .getAntPath(), url);
121:
122: if (logger.isDebugEnabled()) {
123: logger.debug("Candidate is: '" + url + "'; pattern is "
124: + entryHolder.getAntPath() + "; matched="
125: + matched);
126: }
127:
128: if (matched) {
129: return entryHolder.getConfigAttributeDefinition();
130: }
131: }
132:
133: return null;
134: }
135:
136: public void setConvertUrlToLowercaseBeforeComparison(
137: boolean convertUrlToLowercaseBeforeComparison) {
138: this .convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
139: }
140:
141: //~ Inner Classes ==================================================================================================
142:
143: protected class EntryHolder {
144: private ConfigAttributeDefinition configAttributeDefinition;
145: private String antPath;
146:
147: public EntryHolder(String antPath,
148: ConfigAttributeDefinition attr) {
149: this .antPath = antPath;
150: this .configAttributeDefinition = attr;
151: }
152:
153: protected EntryHolder() {
154: throw new IllegalArgumentException(
155: "Cannot use default constructor");
156: }
157:
158: public String getAntPath() {
159: return antPath;
160: }
161:
162: public ConfigAttributeDefinition getConfigAttributeDefinition() {
163: return configAttributeDefinition;
164: }
165: }
166: }
|