Support configuration via Apache Ant paths (not only regular expressions).

This commit is contained in:
Ben Alex
2004-04-09 09:51:23 +00:00
parent 5488bf4ca8
commit bd35a47233
11 changed files with 907 additions and 187 deletions

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}