View Javadoc

    1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
    2    *
    3    * Licensed under the Apache License, Version 2.0 (the "License");
    4    * you may not use this file except in compliance with the License.
    5    * You may obtain a copy of the License at
    6    *
    7    *     http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15
    16  package org.acegisecurity.intercept.web;
    17
    18  import org.acegisecurity.ConfigAttributeDefinition;
    19
    20  import org.apache.commons.logging.Log;
    21  import org.apache.commons.logging.LogFactory;
    22
    23  import org.apache.oro.text.regex.MalformedPatternException;
    24  import org.apache.oro.text.regex.Pattern;
    25  import org.apache.oro.text.regex.PatternMatcher;
    26  import org.apache.oro.text.regex.Perl5Compiler;
    27  import org.apache.oro.text.regex.Perl5Matcher;
    28
    29  import java.util.HashSet;
    30  import java.util.Iterator;
    31  import java.util.List;
    32  import java.util.Set;
    33  import java.util.Vector;
    34
    35
    36  /***
    37   * Maintains a <Code>List</code> of <code>ConfigAttributeDefinition</code>s
    38   * associated with different HTTP request URL regular expression patterns.
    39   *
    40   * <P>
    41   * Regular expressions are used to match a HTTP request URL against a
    42   * <code>ConfigAttributeDefinition</code>.
    43   * </p>
    44   *
    45   * <p>
    46   * The order of registering the regular expressions using the {@link
    47   * #addSecureUrl(String, ConfigAttributeDefinition)} is very important. The
    48   * system will identify the <B>first</B>  matching regular expression for a
    49   * given HTTP URL. It will not proceed to evaluate later regular expressions
    50   * if a match has already been found. Accordingly, the most specific regular
    51   * expressions should be registered first, with the most general regular
    52   * expressions registered last.
    53   * </p>
    54   *
    55   * <P>
    56   * If no registered regular expressions match the HTTP URL, <code>null</code>
    57   * is returned.
    58   * </p>
    59   */
    60  public class RegExpBasedFilterInvocationDefinitionMap
    61      extends AbstractFilterInvocationDefinitionSource
    62      implements FilterInvocationDefinitionMap {
    63      //~ Static fields/initializers =============================================
    64
    65      private static final Log logger = LogFactory.getLog(RegExpBasedFilterInvocationDefinitionMap.class);
    66
    67      //~ Instance fields ========================================================
    68
    69      private List requestMap = new Vector();
    70      private boolean convertUrlToLowercaseBeforeComparison = false;
    71
    72      //~ Methods ================================================================
    73
    74      public Iterator getConfigAttributeDefinitions() {
    75          Set set = new HashSet();
    76          Iterator iter = requestMap.iterator();
    77
    78          while (iter.hasNext()) {
    79              EntryHolder entryHolder = (EntryHolder) iter.next();
    80              set.add(entryHolder.getConfigAttributeDefinition());
    81          }
    82
    83          return set.iterator();
    84      }
    85
    86      public void setConvertUrlToLowercaseBeforeComparison(
    87          boolean convertUrlToLowercaseBeforeComparison) {
    88          this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
    89      }
    90
    91      public boolean isConvertUrlToLowercaseBeforeComparison() {
    92          return convertUrlToLowercaseBeforeComparison;
    93      }
    94
    95      public int getMapSize() {
    96          return this.requestMap.size();
    97      }
    98
    99      public void addSecureUrl(String perl5RegExp, ConfigAttributeDefinition attr) {
    100         Pattern compiledPattern;
    101         Perl5Compiler compiler = new Perl5Compiler();
    102
    103         try {
    104             compiledPattern = compiler.compile(perl5RegExp,
    105                     Perl5Compiler.READ_ONLY_MASK);
    106         } catch (MalformedPatternException mpe) {
    107             throw new IllegalArgumentException("Malformed regular expression: "
    108                 + perl5RegExp);
    109         }
    110
    111         requestMap.add(new EntryHolder(compiledPattern, attr));
    112
    113         if (logger.isDebugEnabled()) {
    114             logger.debug("Added regular expression: "
    115                 + compiledPattern.getPattern().toString() + "; attributes: "
    116                 + attr);
    117         }
    118     }
    119
    120     public ConfigAttributeDefinition lookupAttributes(String url) {
    121         PatternMatcher matcher = new Perl5Matcher();
    122
    123         Iterator iter = requestMap.iterator();
    124
    125         if (convertUrlToLowercaseBeforeComparison) {
    126             url = url.toLowerCase();
    127
    128             if (logger.isDebugEnabled()) {
    129                 logger.debug("Converted URL to lowercase, from: '" + url
    130                     + "'; to: '" + url + "'");
    131             }
    132         }
    133
    134         while (iter.hasNext()) {
    135             EntryHolder entryHolder = (EntryHolder) iter.next();
    136
    137             boolean matched = matcher.matches(url,
    138                     entryHolder.getCompiledPattern());
    139
    140             if (logger.isDebugEnabled()) {
    141                 logger.debug("Candidate is: '" + url + "'; pattern is "
    142                     + entryHolder.getCompiledPattern().getPattern()
    143                     + "; matched=" + matched);
    144             }
    145
    146             if (matched) {
    147                 return entryHolder.getConfigAttributeDefinition();
    148             }
    149         }
    150
    151         return null;
    152     }
    153
    154     //~ Inner Classes ==========================================================
    155
    156     protected class EntryHolder {
    157         private ConfigAttributeDefinition configAttributeDefinition;
    158         private Pattern compiledPattern;
    159
    160         public EntryHolder(Pattern compiledPattern,
    161             ConfigAttributeDefinition attr) {
    162             this.compiledPattern = compiledPattern;
    163             this.configAttributeDefinition = attr;
    164         }
    165
    166         protected EntryHolder() {
    167             throw new IllegalArgumentException("Cannot use default constructor");
    168         }
    169
    170         public Pattern getCompiledPattern() {
    171             return compiledPattern;
    172         }
    173
    174         public ConfigAttributeDefinition getConfigAttributeDefinition() {
    175             return configAttributeDefinition;
    176         }
    177     }
    178 }