From: maxcooper Date: Tue, 17 Dec 2002 15:09:55 +0000 (+0000) Subject: switched to thread safe implementation using Jakarta-ORO X-Git-Tag: rel-2_0-alpha1~155 X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=dbc714e1878a87fb5fad355ac7d229abd72d441c;p=securityfilter.git switched to thread safe implementation using Jakarta-ORO fixed various pattern matching bugs redirects are now URL-encoded --- diff --git a/src/share/org/securityfilter/filter/MatchableURLPattern.java b/src/share/org/securityfilter/filter/MatchableURLPattern.java deleted file mode 100644 index 492f25c..0000000 --- a/src/share/org/securityfilter/filter/MatchableURLPattern.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/Attic/MatchableURLPattern.java,v 1.7 2002/12/10 05:02:18 maxcooper Exp $ - * $Revision: 1.7 $ - * $Date: 2002/12/10 05:02:18 $ - * - * ==================================================================== - * The SecurityFilter Software License, Version 1.1 - * - * (this license is derived and fully compatible with the Apache Software - * License - see http://www.apache.org/LICENSE.txt) - * - * Copyright (c) 2002 SecurityFilter.org. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by - * SecurityFilter.org (http://www.securityfilter.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "SecurityFilter" must not be used to endorse or promote - * products derived from this software without prior written permission. - * For written permission, please contact license@securityfilter.org . - * - * 5. Products derived from this software may not be called "SecurityFilter", - * nor may "SecurityFilter" appear in their name, without prior written - * permission of SecurityFilter.org. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - */ - -package org.securityfilter.filter; - -import org.apache.regexp.RE; -import org.apache.regexp.RECompiler; -import org.apache.regexp.RESyntaxException; -import org.securityfilter.config.SecurityConstraint; -import org.securityfilter.config.WebResourceCollection; - -import java.util.Collection; - -/** - * MatchableURLPattern - Contains matchable URL pattern and the associated SecurityConstraint and WebResourceCollection - * objects for the pattern. Also supports sorting according to the Servlet Spec v2.3. - * - * @author Max Cooper (max@maxcooper.com) - * @version $Revision: 1.7 $ $Date: 2002/12/10 05:02:18 $ - */ -public class MatchableURLPattern implements Comparable { - private String pattern; - private RE patternRE; - private SecurityConstraint constraint; - private WebResourceCollection resourceCollection; - private int order; - private int patternType; - private int pathLength; - - /** - * Construct a new MatchableURLPattern object. - * - * @param pattern the url pattern to match - * @param constraint the SecurityConstraint associated with this pattern - * @param resourceCollection the WebResourceCollection associated with this pattern - * @param order the order in which this pattern occurred in the configuration file - * @param compiler an RECompiler to use to compile this url pattern - * - * @see MatchableURLPatternFactory - */ - public MatchableURLPattern( - String pattern, - SecurityConstraint constraint, - WebResourceCollection resourceCollection, - int order, - RECompiler compiler - ) throws RESyntaxException { - this.pattern = pattern; - this.constraint = constraint; - this.resourceCollection = resourceCollection; - this.order = order; - init(compiler); - } - - /** - * Return true if this pattern matches the passed URL. - * - * @param URL the URL to attempt to match - * @param httpMethod the http method to attempt to match - * @return true if this pattern matches the URL, false otherwise - */ - public boolean match(String URL, String httpMethod) { - if (patternRE.match(URL)) { - Collection methods = resourceCollection.getHttpMethods(); - if (methods.isEmpty() || methods.contains(httpMethod.toUpperCase())) { - return true; - } - } - return false; - } - - /** - * Pattern type for patterns that do not meet the PATH or EXTENSION pattern type specifications. - */ - public static final int EXACT = 1; - /** - * Pattern type for PATH mappings. Starts with '/' and ends with '/*'. - */ - public static final int PATH = 2; - /** - * Pattern type for PATH mappings - */ - public static final int EXTENSION = 3; - - /** - * Get the pattern type. The pattern type will be determined on the first call to this method. - * - * @return EXACT, PATH, or EXTENSION - */ - public int getPatternType() { - return patternType; - } - - /** - * Get the url pattern to match. - */ - public String getPattern() { - return pattern; - } - - /** - * Get the SecurityConstraint object associated with this pattern. - */ - public SecurityConstraint getSecurityConstraint() { - return constraint; - } - - /** - * Get the order value for this pattern (the order in which it appeared in the config file). - */ - public int getOrder() { - return order; - } - - /** - * Get the WebResourceCollection associated with this pattern. - */ - public WebResourceCollection getWebResourceCollection() { - return resourceCollection; - } - - /** - * Test if this pattern is equivalent to another pattern. - * This is implemented so that consistency with the compareTo method results can be maintained. - * - * @param obj the value to test equivalence with - * @return true if the passed object is an equivalent MatchableURLPattern, false if it is not a MatchableURLPattern - * or if it is not equivalent. - */ - public boolean equals(Object obj) { - if (obj instanceof MatchableURLPattern) { - MatchableURLPattern otherPattern = (MatchableURLPattern) obj; - return ( - constraint.equals(otherPattern.getSecurityConstraint()) - && resourceCollection.equals(otherPattern.getWebResourceCollection()) - && pattern.equals(otherPattern.getPattern()) - ); - } - return false; - } - - /** - * Compares this MatchableURLPattern to another to support sorting.

- * - * The sort order is dictated by the servlet spec. EXACT patterns are first, followed by PATH patterns, - * followed by EXTENTION patterns. Ordering among PATH patterns is determined by path length, with the - * longer path coming first. If the path lengths are the same, or both are EXACT or EXTENSION patterns, - * ordering is determined by the order in which the pattern appeared in the config file. - * - * @param another another MatchableURLPattern to compare to - * - * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater - * than the specified object. - * - * @exception ClassCastException thrown if o is not a MatchableURLPattern instance - */ - public int compareTo(Object another) throws ClassCastException { - MatchableURLPattern otherPattern = (MatchableURLPattern) another; - // if the patterns are equivalent, ordering priority is equal - if (this.equals(otherPattern)) { - return 0; - } else { - int otherPatternType = otherPattern.getPatternType(); - // if the pattern types are the same - if (patternType == otherPatternType) { - // if the type is PATH - if (patternType == MatchableURLPattern.PATH) { - int otherPathLength = otherPattern.getPathLength(); - // if path lengths are different, the pattern with longer path length should be first - if (pathLength != otherPathLength) { - return (otherPathLength - pathLength); - // path length are the same, the pattern with the smaller order should be first - } else { - return (order - otherPattern.getOrder()); - } - // for EXACT or EXTENSION, the pattern with the smaller order should be first - } else { - return (order - otherPattern.getOrder()); - } - } else { - // pattern types are not the same, order should be EXACT, PATH, EXTENSION - return (patternType - otherPatternType); - } - } - } - - /** - * Get the path length of the pattern. This is only valid when getPatternType() = PATH.

- * Examples: - *

- * - * @return path length of this pattern - */ - public int getPathLength() { - return pathLength; - } - - /** - * Initialize pattern-related internal variables. - * - * @param compiler an RECompiler - * - * @exception RESyntaxException - */ - private void init(RECompiler compiler) throws RESyntaxException { - // calculate the path length - pathLength = -1; - int pos = pattern.indexOf('/'); - while (pos != -1) { - pathLength++; - pos = pattern.indexOf('/', pos + 1); - } - // determine the pattern type - if (pattern.startsWith("*.")) { - patternType = MatchableURLPattern.EXTENSION; - } else if (pattern.startsWith("/") && pattern.endsWith("/*")) { - patternType = MatchableURLPattern.PATH; - } else { - patternType = MatchableURLPattern.EXACT; - } - // initilize the patternRE - if (compiler == null) { - compiler = new RECompiler(); - } - patternRE = new RE(compiler.compile(getConvertedPattern())); - } - - /** - * Return the pattern string in RE syntax form. - * - * Would the jakarta-oro be more suited for matching than jakarta-regexp? - */ - private String getConvertedPattern() { - StringBuffer buf = new StringBuffer(pattern); - int pos; - // escape '.' characters - pos = buf.toString().indexOf('.'); - while (pos != -1) { - buf.insert(pos, "\\"); - pos = buf.toString().indexOf('.', pos + 2); - } - // replace '*' chars in the pattern with '.*' - pos = buf.toString().indexOf('*'); - while (pos != -1) { - buf.replace(pos, pos + 1, ".*"); - pos = buf.toString().indexOf('*', pos + 2); - } - // adjustments for the different expression types - switch (patternType) { - case PATH: - // make sure it matches from the start of the string - buf.insert(0, '^'); - // make sure /foo/* matches /foo and /foo/morestuff, but not /foobar - buf.insert(buf.length()-3, "($|"); - buf.append(")"); - break; - case EXTENSION: - buf.append('$'); - break; - case EXACT: - buf.insert(0, '^'); - buf.append('$'); - break; - } - return buf.toString(); - } -} - -// ---------------------------------------------------------------------------- -// EOF diff --git a/src/share/org/securityfilter/filter/MatchableURLPatternFactory.java b/src/share/org/securityfilter/filter/MatchableURLPatternFactory.java deleted file mode 100644 index 51e8f99..0000000 --- a/src/share/org/securityfilter/filter/MatchableURLPatternFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/Attic/MatchableURLPatternFactory.java,v 1.4 2002/12/09 10:17:12 maxcooper Exp $ - * $Revision: 1.4 $ - * $Date: 2002/12/09 10:17:12 $ - * - * ==================================================================== - * The SecurityFilter Software License, Version 1.1 - * - * (this license is derived and fully compatible with the Apache Software - * License - see http://www.apache.org/LICENSE.txt) - * - * Copyright (c) 2002 SecurityFilter.org. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by - * SecurityFilter.org (http://www.securityfilter.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The name "SecurityFilter" must not be used to endorse or promote - * products derived from this software without prior written permission. - * For written permission, please contact license@securityfilter.org . - * - * 5. Products derived from this software may not be called "SecurityFilter", - * nor may "SecurityFilter" appear in their name, without prior written - * permission of SecurityFilter.org. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - */ - -package org.securityfilter.filter; - -import org.apache.regexp.RECompiler; -import org.apache.regexp.RESyntaxException; -import org.securityfilter.config.SecurityConstraint; -import org.securityfilter.config.WebResourceCollection; - -/** - * MatchableURLPatternFactory creates MatchableURLPattern instances. It keeps an RECompiler to use for the creation - * of a set of instances. - * - * @author Max Cooper (max@maxcooper.com) - * @version $Revision: 1.4 $ $Date: 2002/12/09 10:17:12 $ - */ -public class MatchableURLPatternFactory { - private RECompiler compiler; - - /** - * Constructor - */ - public MatchableURLPatternFactory() { - compiler = new RECompiler(); - } - - /** - * Create a MatchableURLPattern instance. - * - * @param pattern url pattern in config file syntax - * @param constraint SecurityConstraint object to associate with this pattern - * @param resourceCollection WebResourceCollection to associate with this pattern - * @param order order in which this pattern appeared in the config file - * - * @exception RESyntaxException throws exception if pattern cannot be compiled after conversion to RE syntax - */ - public MatchableURLPattern createMatchableURLPattern( - String pattern, - SecurityConstraint constraint, - WebResourceCollection resourceCollection, - int order - ) throws RESyntaxException { - return new MatchableURLPattern(pattern, constraint, resourceCollection, order, compiler); - } -} - -// ---------------------------------------------------------------------------- -// EOF diff --git a/src/share/org/securityfilter/filter/SecurityFilter.java b/src/share/org/securityfilter/filter/SecurityFilter.java index 8aa21a5..fb8b2a4 100644 --- a/src/share/org/securityfilter/filter/SecurityFilter.java +++ b/src/share/org/securityfilter/filter/SecurityFilter.java @@ -1,7 +1,7 @@ /* - * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/SecurityFilter.java,v 1.9 2002/12/09 10:17:12 maxcooper Exp $ - * $Revision: 1.9 $ - * $Date: 2002/12/09 10:17:12 $ + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/SecurityFilter.java,v 1.10 2002/12/17 15:10:00 maxcooper Exp $ + * $Revision: 1.10 $ + * $Date: 2002/12/17 15:10:00 $ * * ==================================================================== * The SecurityFilter Software License, Version 1.1 @@ -55,9 +55,6 @@ package org.securityfilter.filter; -import org.apache.regexp.RE; -import org.apache.regexp.RECompiler; -import org.apache.regexp.RESyntaxException; import org.securityfilter.config.AuthConstraint; import org.securityfilter.config.SecurityConfig; import org.securityfilter.config.SecurityConstraint; @@ -78,7 +75,7 @@ import java.util.*; * * @author Max Cooper (max@maxcooper.com) * @author Torgeir Veimo (torgeir@pobox.com) - * @version $Revision: 1.9 $ $Date: 2002/12/09 10:17:12 $ + * @version $Revision: 1.10 $ $Date: 2002/12/17 15:10:00 $ */ public class SecurityFilter implements Filter { public static final String SAVED_REQUEST_URL = SecurityFilter.class.getName() + ".SAVED_REQUEST_URL"; @@ -90,17 +87,18 @@ public class SecurityFilter implements Filter { public static final String VALIDATE_KEY = "validate"; public static final String TRUE = "true"; - private FilterConfig config; - private SecurityRealmInterface realm; - private String loginPage; - private String errorPage; - private String defaultPage; - private RE loginSubmitRE; - private List patternList; + protected FilterConfig config; + protected SecurityRealmInterface realm; + protected String loginPage; + protected String errorPage; + protected String defaultPage; + protected URLPatternFactory patternFactory; + protected URLPattern loginSubmitPattern; + protected List patternList; - private static final String FORM_USERNAME = "j_username"; - private static final String FORM_PASSWORD = "j_password"; - private static final String FORM_SUBMIT_PATTERN = ".*/j_security_check"; + protected static final String FORM_USERNAME = "j_username"; + protected static final String FORM_PASSWORD = "j_password"; + protected static final String FORM_SUBMIT_PATTERN = "*/j_security_check"; /** * Perform filtering operation, and optionally pass the request down the chain. @@ -126,6 +124,9 @@ public class SecurityFilter implements Filter { // set an attribute on this request to indicate that it has already been processed request.setAttribute(ALREADY_PROCESSED, "true"); + // get a URLPatternMatcher to use for this thread + URLPatternMatcher patternMatcher = patternFactory.createURLPatternMatcher(); + // get the part of the URL to check for matches String requestURL = getMatchableURL(hReq); @@ -135,14 +136,19 @@ public class SecurityFilter implements Filter { // wrap request wrappedRequest = new SecurityRequestWrapper(hReq, realm, savedRequest); - // check if this is a login form submittal - if (loginSubmitRE.match(requestURL)) { - processLogin(wrappedRequest, hRes); - return; - } + URLPattern match = null; + try { + // check if this is a login form submittal + if (patternMatcher.match(requestURL, loginSubmitPattern)) { + processLogin(wrappedRequest, hRes); + return; + } - // check if request matches security constraint - MatchableURLPattern match = matchPattern(requestURL, wrappedRequest.getMethod()); + // check if request matches security constraint + match = matchPattern(requestURL, wrappedRequest.getMethod(), patternMatcher); + } catch (Exception e) { + throw new ServletException("Error matching patterns", e); + } // check security constraint, if any if (match != null) { @@ -189,11 +195,17 @@ public class SecurityFilter implements Filter { * * @param config filter configuration object */ - public void init(FilterConfig config) { + public void init(FilterConfig config) throws ServletException { this.config = config; try { + patternFactory = new URLPatternFactory(); + // login submit RE - loginSubmitRE = new RE(new RECompiler().compile(FORM_SUBMIT_PATTERN)); + try { + loginSubmitPattern = patternFactory.createURLPattern(FORM_SUBMIT_PATTERN, null, null, 0); + } catch (Exception e) { + throw new ServletException("Error creating login submit pattern", e); + } // parse config file String configFile = config.getInitParameter(CONFIG_FILE_KEY); @@ -213,7 +225,6 @@ public class SecurityFilter implements Filter { // create pattern list patternList = new ArrayList(); - MatchableURLPatternFactory patternFactory = new MatchableURLPatternFactory(); int order = 1; List constraints = securityConfig.getSecurityConstraints(); for (Iterator cIter = constraints.iterator(); cIter.hasNext();) { @@ -221,7 +232,7 @@ public class SecurityFilter implements Filter { for (Iterator rIter = constraint.getWebResourceCollections().iterator(); rIter.hasNext();) { WebResourceCollection resourceCollection = (WebResourceCollection) rIter.next(); for (Iterator pIter = resourceCollection.getURLPatterns().iterator(); pIter.hasNext();) { - MatchableURLPattern pattern = patternFactory.createMatchableURLPattern( + URLPattern pattern = patternFactory.createURLPattern( (String) pIter.next(), constraint, resourceCollection, @@ -233,12 +244,12 @@ public class SecurityFilter implements Filter { } Collections.sort(patternList); - } catch (RESyntaxException rese) { - System.err.println("invalid regular expression pattern: " + rese); } catch (java.io.IOException ioe) { System.err.println("unable to parse input: " + ioe); } catch (org.xml.sax.SAXException se) { System.err.println("unable to parse input: " + se); + } catch (Exception e) { + System.err.println("invalid regular expression pattern: " + e); } } @@ -253,7 +264,7 @@ public class SecurityFilter implements Filter { * * @param config filter configuration object */ - public void setFilterConfig(FilterConfig config) { + public void setFilterConfig(FilterConfig config) throws ServletException { init(config); } @@ -265,19 +276,20 @@ public class SecurityFilter implements Filter { } /** - * Find a match for the requested URL & method, if any. + * Find a match for the requested pattern & method, if any. * - * @param URL the URL to match + * @param pattern the pattern to match * @param httpMethod the HTTP Method to match - * @return the matching MatchableURLPattern object, or null if there is no match. + * @param matcher the thread-local URLPatternMatcher object + * @return the matching URLPattern object, or null if there is no match. */ - protected MatchableURLPattern matchPattern(String URL, String httpMethod) { - // PERFORMANCE IMPROVEMENT OPPORTUNITY: cahce URL pattern matches + protected URLPattern matchPattern(String pattern, String httpMethod, URLPatternMatcher matcher) throws Exception { + // PERFORMANCE IMPROVEMENT OPPORTUNITY: cahce pattern matches Iterator i = patternList.iterator(); while (i.hasNext()) { - MatchableURLPattern pattern = (MatchableURLPattern) i.next(); - if (pattern.match(URL, httpMethod)) { - return pattern; + URLPattern urlPattern = (URLPattern) i.next(); + if (matcher.match(pattern, httpMethod, urlPattern)) { + return urlPattern; } } return null; @@ -298,7 +310,7 @@ public class SecurityFilter implements Filter { // save this request saveRequestInformation(request); // redirect to login page - response.sendRedirect(request.getContextPath() + loginPage); + response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + loginPage)); } /** @@ -320,7 +332,7 @@ public class SecurityFilter implements Filter { // login successful request.setUserPrincipal(principal); String continueToURL = getContinueToURL(request); - response.sendRedirect(continueToURL); + response.sendRedirect(response.encodeRedirectURL(continueToURL)); } else { // login failed, set response status and forward to error page response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); diff --git a/src/share/org/securityfilter/filter/URLPattern.java b/src/share/org/securityfilter/filter/URLPattern.java new file mode 100644 index 0000000..940c1da --- /dev/null +++ b/src/share/org/securityfilter/filter/URLPattern.java @@ -0,0 +1,333 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/URLPattern.java,v 1.1 2002/12/17 15:10:00 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/12/17 15:10:00 $ + * + * ==================================================================== + * The SecurityFilter Software License, Version 1.1 + * + * (this license is derived and fully compatible with the Apache Software + * License - see http://www.apache.org/LICENSE.txt) + * + * Copyright (c) 2002 SecurityFilter.org. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * SecurityFilter.org (http://www.securityfilter.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The name "SecurityFilter" must not be used to endorse or promote + * products derived from this software without prior written permission. + * For written permission, please contact license@securityfilter.org . + * + * 5. Products derived from this software may not be called "SecurityFilter", + * nor may "SecurityFilter" appear in their name, without prior written + * permission of SecurityFilter.org. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.securityfilter.filter; + +import org.apache.oro.text.regex.Pattern; +import org.apache.oro.text.regex.PatternCompiler; +import org.apache.oro.text.regex.Perl5Compiler; +import org.securityfilter.config.SecurityConstraint; +import org.securityfilter.config.WebResourceCollection; + +/** + * URLPattern - Contains matchable URL pattern and the associated + * SecurityConstraint and WebResourceCollection objects for the pattern. + * Also supports sorting according to the Servlet Spec v2.3. + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/12/17 15:10:00 $ + */ +public class URLPattern implements Comparable { + /** + * Pattern type for PATH_TYPE mappings. Starts with '/' and ends with '/*'. + */ + public static final int PATH_TYPE = 1; + /** + * Pattern type for EXTENSION_TYPE mappings. Starts with *. + */ + public static final int EXTENSION_TYPE = 2; + /** + * Pattern type for patterns that do not meet the PATH_TYPE + * or EXTENSION_TYPE pattern type specifications. + */ + public static final int EXACT_TYPE = 3; + + protected String pattern; + protected String convertedPattern; + protected Pattern compiledPattern; + protected SecurityConstraint constraint; + protected WebResourceCollection resourceCollection; + protected int order; + protected int patternType; + protected int pathLength; + + /** + * Construct a new URLPattern object. + * + * @param pattern the url pattern to match + * @param constraint the SecurityConstraint associated with this pattern + * @param resourceCollection the WebResourceCollection associated with this pattern + * @param order the order in which this pattern occurred in the configuration file + * @param compiler a PatternCompiler to use to compile this url pattern + * + * @see URLPatternFactory + */ + public URLPattern( + String pattern, + SecurityConstraint constraint, + WebResourceCollection resourceCollection, + int order, + PatternCompiler compiler + ) throws Exception { + this.pattern = pattern; + this.constraint = constraint; + this.resourceCollection = resourceCollection; + this.order = order; + initPatternType(); + initPathLength(); + initConvertedPattern(); + initCompiledPattern(compiler); + } + + /** + * Get the url pattern to match. + */ + public String getPattern() { + return pattern; + } + + /** + * Get the compiled version of this pattern. + * + * @return compiled version of this pattern + */ + public Pattern getCompiledPattern() { + return compiledPattern; + } + + /** + * Get the pattern type. The pattern type will be determined on the first call to this method. + * + * @return EXACT, PATH, or EXTENSION + */ + public int getPatternType() { + return patternType; + } + + /** + * Get the path length of the pattern. This is only valid when getPatternType() = PATH.

+ * Examples: + *

+ * + * @return path length of this pattern + */ + public int getPathLength() { + return pathLength; + } + + /** + * Get the SecurityConstraint object associated with this pattern. + */ + public SecurityConstraint getSecurityConstraint() { + return constraint; + } + + /** + * Get the order value for this pattern (the order in which it appeared in the config file). + */ + public int getOrder() { + return order; + } + + /** + * Get the WebResourceCollection associated with this pattern. + */ + public WebResourceCollection getWebResourceCollection() { + return resourceCollection; + } + + /** + * Initialize the patternType protected member. + */ + protected void initPatternType() { + if (pattern.startsWith("*.")) { + patternType = URLPattern.EXTENSION_TYPE; + } else if (pattern.startsWith("/") && pattern.endsWith("/*")) { + patternType = URLPattern.PATH_TYPE; + } else { + patternType = URLPattern.EXACT_TYPE; + } + } + + /** + * Initialize the pathLength protected member. + */ + protected void initPathLength() { + pathLength = -1; + int pos = pattern.indexOf('/'); + while (pos != -1) { + pathLength++; + pos = pattern.indexOf('/', pos + 1); + } + } + + /** + * Initialize the convertedPattern protected member. + */ + protected void initConvertedPattern() { + StringBuffer buf = new StringBuffer(pattern); + int pos; + // escape '.' characters + pos = buf.toString().indexOf('.'); + while (pos != -1) { + buf.insert(pos, "\\"); + pos = buf.toString().indexOf('.', pos + 2); + } + // replace '*' chars in the compiledPattern with '.*' + pos = buf.toString().indexOf('*'); + while (pos != -1) { + buf.replace(pos, pos + 1, ".*"); + pos = buf.toString().indexOf('*', pos + 2); + } + // replace '/' chars with '/+' to match one or more consecutive slashes + pos = buf.toString().indexOf('/'); + while (pos != -1) { + buf.replace(pos, pos + 1, "/+"); + pos = buf.toString().indexOf('/', pos + 2); + } + // adjustments for the different expression types + switch (patternType) { + case PATH_TYPE: + // make sure it matches from the start of the string + buf.insert(0, '^'); + // make sure /foo/* matches /foo and /foo/morestuff, but not /foobar + buf.insert(buf.length()-4, "("); + buf.append(")?$"); + break; + case EXTENSION_TYPE: + buf.append('$'); + break; + case EXACT_TYPE: + buf.insert(0, '^'); + buf.append('$'); + break; + } + convertedPattern = buf.toString(); + } + + /** + * Initialize the compiledPattern protected member. + * + * @param compiler + * @throws Exception + */ + protected void initCompiledPattern(PatternCompiler compiler) throws Exception { + compiledPattern = compiler.compile(convertedPattern, Perl5Compiler.READ_ONLY_MASK); + } + + /** + * Test if this pattern is equivalent to another pattern. + * This is implemented so that consistency with the compareTo method results can be maintained. + * + * @param obj the value to test equivalence with + * @return true if the passed object is an equivalent URLPattern, false if it is not a URLPattern + * or if it is not equivalent. + */ + public boolean equals(Object obj) { + if (obj instanceof URLPattern) { + URLPattern otherPattern = (URLPattern) obj; + return ( + constraint.equals(otherPattern.getSecurityConstraint()) + && resourceCollection.equals(otherPattern.getWebResourceCollection()) + && pattern.equals(otherPattern.getPattern()) + ); + } + return false; + } + + /** + * Compares this URLPattern to another to support sorting.

+ * + * The sort order is dictated by the servlet spec. EXACT_TYPE patterns are first, + * followed by PATH_TYPE patterns, followed by EXTENTION_TYPE patterns. Ordering + * among PATH_TYPE patterns is determined by path length, with the longer path + * coming first. If the path lengths are the same, or both are EXACT_TYPE or + * EXTENSION_TYPE patterns, ordering is determined by the order in which the + * pattern appeared in the config file. + * + * @param another another URLPattern to compare to + * + * @return a negative integer, zero, or a positive integer as this object is + * less than, equal to, or greater than the specified object. + * + * @exception ClassCastException thrown if o is not a URLPattern instance + */ + public int compareTo(Object another) throws ClassCastException { + URLPattern otherPattern = (URLPattern) another; + // if the patterns are equivalent, ordering priority is equal + if (this.equals(otherPattern)) { + return 0; + } else { + int otherPatternType = otherPattern.getPatternType(); + // if the compiledPattern types are the same + if (patternType == otherPatternType) { + // if the type is PATH_TYPE + if (patternType == URLPattern.PATH_TYPE) { + int otherPathLength = otherPattern.getPathLength(); + // if path lengths are different, the compiledPattern with longer path length should be first + if (pathLength != otherPathLength) { + return (otherPathLength - pathLength); + // path length are the same, the compiledPattern with the smaller order should be first + } else { + return (order - otherPattern.getOrder()); + } + // for EXACT_TYPE or EXTENSION_TYPE, the compiledPattern with the smaller order should be first + } else { + return (order - otherPattern.getOrder()); + } + } else { + // compiledPattern types are not the same, order should be EXACT_TYPE, PATH_TYPE, EXTENSION_TYPE + return (patternType - otherPatternType); + } + } + } +} + +// ---------------------------------------------------------------------------- +// EOF diff --git a/src/share/org/securityfilter/filter/URLPatternFactory.java b/src/share/org/securityfilter/filter/URLPatternFactory.java new file mode 100644 index 0000000..d68e5ee --- /dev/null +++ b/src/share/org/securityfilter/filter/URLPatternFactory.java @@ -0,0 +1,111 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/URLPatternFactory.java,v 1.1 2002/12/17 15:10:01 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/12/17 15:10:01 $ + * + * ==================================================================== + * The SecurityFilter Software License, Version 1.1 + * + * (this license is derived and fully compatible with the Apache Software + * License - see http://www.apache.org/LICENSE.txt) + * + * Copyright (c) 2002 SecurityFilter.org. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * SecurityFilter.org (http://www.securityfilter.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The name "SecurityFilter" must not be used to endorse or promote + * products derived from this software without prior written permission. + * For written permission, please contact license@securityfilter.org . + * + * 5. Products derived from this software may not be called "SecurityFilter", + * nor may "SecurityFilter" appear in their name, without prior written + * permission of SecurityFilter.org. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.securityfilter.filter; + +import org.apache.oro.text.regex.PatternCompiler; +import org.apache.oro.text.regex.Perl5Compiler; +import org.securityfilter.config.SecurityConstraint; +import org.securityfilter.config.WebResourceCollection; + +/** + * URLPatternFactory creates URLPattern instances. It keeps a Perl5PatternCompiler to use + * for the creation of a set of instances. + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/12/17 15:10:01 $ + */ +public class URLPatternFactory { + protected PatternCompiler compiler; + + /** + * Constructor + */ + public URLPatternFactory() { + compiler = new Perl5Compiler(); + } + + /** + * Create a URLPatternMatcher object that is compatible with the URLPattern + * objects created by this Facotry class. + * + * @return a URLPatternMatcher object compatible with the URLPatterns created by this class + */ + public URLPatternMatcher createURLPatternMatcher() { + return new URLPatternMatcher(); + } + + /** + * Create a URLPattern instance. + * + * @param pattern url pattern in config file syntax + * @param constraint SecurityConstraint object to associate with this pattern + * @param resourceCollection WebResourceCollection to associate with this pattern + * @param order order in which this pattern appeared in the config file + * + * @exception Exception + */ + public URLPattern createURLPattern( + String pattern, + SecurityConstraint constraint, + WebResourceCollection resourceCollection, + int order + ) throws Exception { + return new URLPattern(pattern, constraint, resourceCollection, order, compiler); + } +} + +// ---------------------------------------------------------------------------- +// EOF diff --git a/src/share/org/securityfilter/filter/URLPatternMatcher.java b/src/share/org/securityfilter/filter/URLPatternMatcher.java new file mode 100644 index 0000000..c5307a9 --- /dev/null +++ b/src/share/org/securityfilter/filter/URLPatternMatcher.java @@ -0,0 +1,114 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/URLPatternMatcher.java,v 1.1 2002/12/17 15:10:01 maxcooper Exp $ + * $Revision: 1.1 $ + * $Date: 2002/12/17 15:10:01 $ + * + * ==================================================================== + * The SecurityFilter Software License, Version 1.1 + * + * (this license is derived and fully compatible with the Apache Software + * License - see http://www.apache.org/LICENSE.txt) + * + * Copyright (c) 2002 SecurityFilter.org. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * SecurityFilter.org (http://www.securityfilter.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The name "SecurityFilter" must not be used to endorse or promote + * products derived from this software without prior written permission. + * For written permission, please contact license@securityfilter.org . + * + * 5. Products derived from this software may not be called "SecurityFilter", + * nor may "SecurityFilter" appear in their name, without prior written + * permission of SecurityFilter.org. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.securityfilter.filter; + +import org.apache.oro.text.regex.PatternMatcher; +import org.apache.oro.text.regex.Perl5Matcher; + +import java.util.Collection; + +/** + * URLPatternMatcher - A non-thread safe object to be used to match a request + * pattern with URLPattern objects. + * + * @author Max Cooper (max@maxcooper.com) + * @version $Revision: 1.1 $ $Date: 2002/12/17 15:10:01 $ + */ +public class URLPatternMatcher { + private PatternMatcher patternMatcher; + + /** + * Constructor + */ + public URLPatternMatcher() { + patternMatcher = new Perl5Matcher(); + } + + /** + * Test to see if a string pattern matches a URLPattern. + * + * @param pattern a String pattern to check for a match + * @param urlPattern a URLPattern object to match against + * @return true if the pattern matched the urlPattern, false otherwise + * @throws Exception + */ + public boolean match(String pattern, URLPattern urlPattern) throws Exception { + return patternMatcher.matches(pattern, urlPattern.getCompiledPattern()); + } + + /** + * Test to see if a string pattern and HTTP method matches a URLPattern. + * + * @param pattern a String pattern to check for a match + * @param httpMethod an HTTP pattern to check for a match + * @param urlPattern a URLPattern object to match against + * @return true if the pattern matched the urlPattern, false otherwise + * @throws Exception + */ + public boolean match(String pattern, String httpMethod, URLPattern urlPattern) throws Exception { + if (match(pattern, urlPattern)) { + Collection methods = urlPattern.getWebResourceCollection().getHttpMethods(); + if (methods.isEmpty() || methods.contains(httpMethod.toUpperCase())) { + + return true; + } + } + return false; + } +} + +// ---------------------------------------------------------------------------- +// EOF