Support configuration via Apache Ant paths (not only regular expressions).
This commit is contained in:
@@ -17,164 +17,19 @@ package net.sf.acegisecurity.intercept.web;
|
||||
|
||||
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.apache.oro.text.regex.MalformedPatternException;
|
||||
import org.apache.oro.text.regex.Pattern;
|
||||
import org.apache.oro.text.regex.PatternMatcher;
|
||||
import org.apache.oro.text.regex.Perl5Compiler;
|
||||
import org.apache.oro.text.regex.Perl5Matcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* Maintains a <Code>List</code> of <code>ConfigAttributeDefinition</code>s
|
||||
* associated with different HTTP request URL patterns.
|
||||
*
|
||||
* <P>
|
||||
* Regular expressions are used to match a HTTP request URL against a
|
||||
* <code>ConfigAttributeDefinition</code>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The order of registering the regular expressions using the {@link
|
||||
* #addSecureUrl(String, ConfigAttributeDefinition)} is very important. The
|
||||
* system will identify the <B>first</B> matching regular expression for a
|
||||
* given HTTP URL. It will not proceed to evaluate later regular expressions
|
||||
* if a match has already been found. Accordingly, the most specific regular
|
||||
* expressions should be registered first, with the most general regular
|
||||
* expressions registered last.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* If no registered regular expressions match the HTTP URL, <code>null</code>
|
||||
* is returned.
|
||||
* </p>
|
||||
* Exposes methods required so that a property editor can populate the relevant
|
||||
* {@link FilterInvocationDefinitionSource}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FilterInvocationDefinitionMap
|
||||
extends AbstractFilterInvocationDefinitionSource {
|
||||
//~ Static fields/initializers =============================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(FilterInvocationDefinitionMap.class);
|
||||
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
private List requestMap = new Vector();
|
||||
private boolean convertUrlToLowercaseBeforeComparison = false;
|
||||
|
||||
public interface FilterInvocationDefinitionMap {
|
||||
//~ Methods ================================================================
|
||||
|
||||
public Iterator getConfigAttributeDefinitions() {
|
||||
Set set = new HashSet();
|
||||
Iterator iter = requestMap.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||
set.add(entryHolder.getConfigAttributeDefinition());
|
||||
}
|
||||
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public void setConvertUrlToLowercaseBeforeComparison(
|
||||
boolean convertUrlToLowercaseBeforeComparison) {
|
||||
this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
|
||||
}
|
||||
boolean convertUrlToLowercaseBeforeComparison);
|
||||
|
||||
public boolean isConvertUrlToLowercaseBeforeComparison() {
|
||||
return convertUrlToLowercaseBeforeComparison;
|
||||
}
|
||||
|
||||
public int getMapSize() {
|
||||
return this.requestMap.size();
|
||||
}
|
||||
|
||||
public void addSecureUrl(String perl5RegExp, ConfigAttributeDefinition attr) {
|
||||
Pattern compiledPattern;
|
||||
Perl5Compiler compiler = new Perl5Compiler();
|
||||
|
||||
try {
|
||||
compiledPattern = compiler.compile(perl5RegExp,
|
||||
Perl5Compiler.READ_ONLY_MASK);
|
||||
} catch (MalformedPatternException mpe) {
|
||||
throw new IllegalArgumentException("Malformed regular expression: "
|
||||
+ perl5RegExp);
|
||||
}
|
||||
|
||||
requestMap.add(new EntryHolder(compiledPattern, attr));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added regular expression: "
|
||||
+ compiledPattern.getPattern().toString() + "; attributes: "
|
||||
+ attr.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected ConfigAttributeDefinition lookupAttributes(
|
||||
FilterInvocation filterInvocation) {
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
|
||||
Iterator iter = requestMap.iterator();
|
||||
|
||||
String url = filterInvocation.getRequestUrl();
|
||||
|
||||
if (convertUrlToLowercaseBeforeComparison) {
|
||||
url = url.toLowerCase();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converted URL to lowercase, from: '"
|
||||
+ filterInvocation.getRequest() + "'; to: '" + url + "'");
|
||||
}
|
||||
}
|
||||
|
||||
while (iter.hasNext()) {
|
||||
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||
|
||||
boolean matched = matcher.matches(url,
|
||||
entryHolder.getCompiledPattern());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Candidate is: '" + url + "'; pattern is "
|
||||
+ entryHolder.getCompiledPattern().getPattern()
|
||||
+ "; matched=" + matched);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
return entryHolder.getConfigAttributeDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==========================================================
|
||||
|
||||
protected class EntryHolder {
|
||||
private ConfigAttributeDefinition configAttributeDefinition;
|
||||
private Pattern compiledPattern;
|
||||
|
||||
public EntryHolder(Pattern compiledPattern,
|
||||
ConfigAttributeDefinition attr) {
|
||||
this.compiledPattern = compiledPattern;
|
||||
this.configAttributeDefinition = attr;
|
||||
}
|
||||
|
||||
protected EntryHolder() {
|
||||
throw new IllegalArgumentException("Cannot use default constructor");
|
||||
}
|
||||
|
||||
public Pattern getCompiledPattern() {
|
||||
return compiledPattern;
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition getConfigAttributeDefinition() {
|
||||
return configAttributeDefinition;
|
||||
}
|
||||
}
|
||||
public void addSecureUrl(String expression, ConfigAttributeDefinition attr);
|
||||
}
|
||||
|
||||
@@ -31,11 +31,21 @@ import java.io.StringReader;
|
||||
|
||||
|
||||
/**
|
||||
* Property editor to assist with the setup of {@link
|
||||
* Property editor to assist with the setup of a {@link
|
||||
* FilterInvocationDefinitionSource}.
|
||||
*
|
||||
* <p>
|
||||
* The class creates and populates a {@link FilterInvocationDefinitionMap}.
|
||||
* The class creates and populates a {@link
|
||||
* RegExpBasedFilterInvocationDefinitionMap} or {@link
|
||||
* PathBasedFilterInvocationDefinitionMap} (depending on the type of patterns
|
||||
* presented).
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* By default the class treats presented patterns as regular expressions. If
|
||||
* the keyword <code>PATTERN_TYPE_APACHE_ANT</code> is present (case
|
||||
* sensitive), patterns will be treated as Apache Ant paths rather than
|
||||
* regular expressions.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
@@ -50,11 +60,20 @@ public class FilterInvocationDefinitionSourceEditor
|
||||
//~ Methods ================================================================
|
||||
|
||||
public void setAsText(String s) throws IllegalArgumentException {
|
||||
FilterInvocationDefinitionMap source = new FilterInvocationDefinitionMap();
|
||||
FilterInvocationDefinitionMap source = new RegExpBasedFilterInvocationDefinitionMap();
|
||||
|
||||
if ((s == null) || "".equals(s)) {
|
||||
// Leave value in property editor null
|
||||
// Leave target object empty
|
||||
} else {
|
||||
// Check if we need to override the default definition map
|
||||
if (s.lastIndexOf("PATTERN_TYPE_APACHE_ANT") != -1) {
|
||||
source = new PathBasedFilterInvocationDefinitionMap();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(("Detected PATTERN_TYPE_APACHE_ANT directive; using Apache Ant style path expressions"));
|
||||
}
|
||||
}
|
||||
|
||||
BufferedReader br = new BufferedReader(new StringReader(s));
|
||||
int counter = 0;
|
||||
String line;
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/* Copyright 2004 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.sf.acegisecurity.intercept.web;
|
||||
|
||||
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* Maintains a <Code>List</code> of <code>ConfigAttributeDefinition</code>s
|
||||
* associated with different HTTP request URL Apache Ant path-based patterns.
|
||||
*
|
||||
* <P>
|
||||
* Apache Ant path expressions are used to match a HTTP request URL against a
|
||||
* <code>ConfigAttributeDefinition</code>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The order of registering the Ant paths using the {@link
|
||||
* #addSecureUrl(String, ConfigAttributeDefinition)} is very important. The
|
||||
* system will identify the <B>first</B> matching path for a given HTTP URL.
|
||||
* It will not proceed to evaluate later paths if a match has already been
|
||||
* found. Accordingly, the most specific paths should be registered first,
|
||||
* with the most general paths registered last.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* If no registered paths match the HTTP URL, <code>null</code> is returned.
|
||||
* </p>
|
||||
*/
|
||||
public class PathBasedFilterInvocationDefinitionMap
|
||||
extends AbstractFilterInvocationDefinitionSource
|
||||
implements FilterInvocationDefinitionMap {
|
||||
//~ Static fields/initializers =============================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(PathBasedFilterInvocationDefinitionMap.class);
|
||||
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
private List requestMap = new Vector();
|
||||
private boolean convertUrlToLowercaseBeforeComparison = false;
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public Iterator getConfigAttributeDefinitions() {
|
||||
Set set = new HashSet();
|
||||
Iterator iter = requestMap.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||
set.add(entryHolder.getConfigAttributeDefinition());
|
||||
}
|
||||
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public void setConvertUrlToLowercaseBeforeComparison(
|
||||
boolean convertUrlToLowercaseBeforeComparison) {
|
||||
this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
|
||||
}
|
||||
|
||||
public boolean isConvertUrlToLowercaseBeforeComparison() {
|
||||
return convertUrlToLowercaseBeforeComparison;
|
||||
}
|
||||
|
||||
public int getMapSize() {
|
||||
return this.requestMap.size();
|
||||
}
|
||||
|
||||
public void addSecureUrl(String antPath, ConfigAttributeDefinition attr) {
|
||||
requestMap.add(new EntryHolder(antPath, attr));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added Ant path: " + antPath + "; attributes: "
|
||||
+ attr.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected ConfigAttributeDefinition lookupAttributes(
|
||||
FilterInvocation filterInvocation) {
|
||||
Iterator iter = requestMap.iterator();
|
||||
|
||||
String url = filterInvocation.getRequestUrl();
|
||||
|
||||
if (convertUrlToLowercaseBeforeComparison) {
|
||||
url = url.toLowerCase();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converted URL to lowercase, from: '"
|
||||
+ filterInvocation.getRequest() + "'; to: '" + url + "'");
|
||||
}
|
||||
}
|
||||
|
||||
while (iter.hasNext()) {
|
||||
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||
|
||||
boolean matched = PathMatcher.match(entryHolder.getAntPath(), url);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Candidate is: '" + url + "'; pattern is "
|
||||
+ entryHolder.getAntPath() + "; matched=" + matched);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
return entryHolder.getConfigAttributeDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==========================================================
|
||||
|
||||
protected class EntryHolder {
|
||||
private ConfigAttributeDefinition configAttributeDefinition;
|
||||
private String antPath;
|
||||
|
||||
public EntryHolder(String antPath, ConfigAttributeDefinition attr) {
|
||||
this.antPath = antPath;
|
||||
this.configAttributeDefinition = attr;
|
||||
}
|
||||
|
||||
protected EntryHolder() {
|
||||
throw new IllegalArgumentException("Cannot use default constructor");
|
||||
}
|
||||
|
||||
public String getAntPath() {
|
||||
return antPath;
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition getConfigAttributeDefinition() {
|
||||
return configAttributeDefinition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/* Copyright 2004 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.sf.acegisecurity.intercept.web;
|
||||
|
||||
import net.sf.acegisecurity.ConfigAttributeDefinition;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.apache.oro.text.regex.MalformedPatternException;
|
||||
import org.apache.oro.text.regex.Pattern;
|
||||
import org.apache.oro.text.regex.PatternMatcher;
|
||||
import org.apache.oro.text.regex.Perl5Compiler;
|
||||
import org.apache.oro.text.regex.Perl5Matcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
* Maintains a <Code>List</code> of <code>ConfigAttributeDefinition</code>s
|
||||
* associated with different HTTP request URL regular expression patterns.
|
||||
*
|
||||
* <P>
|
||||
* Regular expressions are used to match a HTTP request URL against a
|
||||
* <code>ConfigAttributeDefinition</code>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The order of registering the regular expressions using the {@link
|
||||
* #addSecureUrl(String, ConfigAttributeDefinition)} is very important. The
|
||||
* system will identify the <B>first</B> matching regular expression for a
|
||||
* given HTTP URL. It will not proceed to evaluate later regular expressions
|
||||
* if a match has already been found. Accordingly, the most specific regular
|
||||
* expressions should be registered first, with the most general regular
|
||||
* expressions registered last.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
* If no registered regular expressions match the HTTP URL, <code>null</code>
|
||||
* is returned.
|
||||
* </p>
|
||||
*/
|
||||
public class RegExpBasedFilterInvocationDefinitionMap
|
||||
extends AbstractFilterInvocationDefinitionSource
|
||||
implements FilterInvocationDefinitionMap {
|
||||
//~ Static fields/initializers =============================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(RegExpBasedFilterInvocationDefinitionMap.class);
|
||||
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
private List requestMap = new Vector();
|
||||
private boolean convertUrlToLowercaseBeforeComparison = false;
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public Iterator getConfigAttributeDefinitions() {
|
||||
Set set = new HashSet();
|
||||
Iterator iter = requestMap.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||
set.add(entryHolder.getConfigAttributeDefinition());
|
||||
}
|
||||
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public void setConvertUrlToLowercaseBeforeComparison(
|
||||
boolean convertUrlToLowercaseBeforeComparison) {
|
||||
this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
|
||||
}
|
||||
|
||||
public boolean isConvertUrlToLowercaseBeforeComparison() {
|
||||
return convertUrlToLowercaseBeforeComparison;
|
||||
}
|
||||
|
||||
public int getMapSize() {
|
||||
return this.requestMap.size();
|
||||
}
|
||||
|
||||
public void addSecureUrl(String perl5RegExp, ConfigAttributeDefinition attr) {
|
||||
Pattern compiledPattern;
|
||||
Perl5Compiler compiler = new Perl5Compiler();
|
||||
|
||||
try {
|
||||
compiledPattern = compiler.compile(perl5RegExp,
|
||||
Perl5Compiler.READ_ONLY_MASK);
|
||||
} catch (MalformedPatternException mpe) {
|
||||
throw new IllegalArgumentException("Malformed regular expression: "
|
||||
+ perl5RegExp);
|
||||
}
|
||||
|
||||
requestMap.add(new EntryHolder(compiledPattern, attr));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added regular expression: "
|
||||
+ compiledPattern.getPattern().toString() + "; attributes: "
|
||||
+ attr.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected ConfigAttributeDefinition lookupAttributes(
|
||||
FilterInvocation filterInvocation) {
|
||||
PatternMatcher matcher = new Perl5Matcher();
|
||||
|
||||
Iterator iter = requestMap.iterator();
|
||||
|
||||
String url = filterInvocation.getRequestUrl();
|
||||
|
||||
if (convertUrlToLowercaseBeforeComparison) {
|
||||
url = url.toLowerCase();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converted URL to lowercase, from: '"
|
||||
+ filterInvocation.getRequest() + "'; to: '" + url + "'");
|
||||
}
|
||||
}
|
||||
|
||||
while (iter.hasNext()) {
|
||||
EntryHolder entryHolder = (EntryHolder) iter.next();
|
||||
|
||||
boolean matched = matcher.matches(url,
|
||||
entryHolder.getCompiledPattern());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Candidate is: '" + url + "'; pattern is "
|
||||
+ entryHolder.getCompiledPattern().getPattern()
|
||||
+ "; matched=" + matched);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
return entryHolder.getConfigAttributeDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==========================================================
|
||||
|
||||
protected class EntryHolder {
|
||||
private ConfigAttributeDefinition configAttributeDefinition;
|
||||
private Pattern compiledPattern;
|
||||
|
||||
public EntryHolder(Pattern compiledPattern,
|
||||
ConfigAttributeDefinition attr) {
|
||||
this.compiledPattern = compiledPattern;
|
||||
this.configAttributeDefinition = attr;
|
||||
}
|
||||
|
||||
protected EntryHolder() {
|
||||
throw new IllegalArgumentException("Cannot use default constructor");
|
||||
}
|
||||
|
||||
public Pattern getCompiledPattern() {
|
||||
return compiledPattern;
|
||||
}
|
||||
|
||||
public ConfigAttributeDefinition getConfigAttributeDefinition() {
|
||||
return configAttributeDefinition;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user