View Javadoc

    1   /* Copyright 2004 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.securechannel;
    17
    18  import org.acegisecurity.ConfigAttribute;
    19  import org.acegisecurity.ConfigAttributeDefinition;
    20  import org.acegisecurity.intercept.web.FilterInvocation;
    21  import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
    22
    23  import org.apache.commons.logging.Log;
    24  import org.apache.commons.logging.LogFactory;
    25
    26  import org.springframework.beans.factory.InitializingBean;
    27  import org.springframework.util.Assert;
    28
    29  import java.io.IOException;
    30
    31  import java.util.HashSet;
    32  import java.util.Iterator;
    33  import java.util.Set;
    34
    35  import javax.servlet.Filter;
    36  import javax.servlet.FilterChain;
    37  import javax.servlet.FilterConfig;
    38  import javax.servlet.ServletException;
    39  import javax.servlet.ServletRequest;
    40  import javax.servlet.ServletResponse;
    41  import javax.servlet.http.HttpServletRequest;
    42  import javax.servlet.http.HttpServletResponse;
    43
    44
    45  /***
    46   * Ensures a web request is delivered over the required channel.
    47   *
    48   * <p>
    49   * Internally uses a {@link FilterInvocation} to represent the request, so that
    50   * the <code>FilterInvocation</code>-related property editors and lookup
    51   * classes can be used.
    52   * </p>
    53   *
    54   * <P>
    55   * Delegates the actual channel security decisions and necessary actions to the
    56   * configured {@link ChannelDecisionManager}. If a response is committed by
    57   * the <code>ChannelDecisionManager</code>, the filter chain will not proceed.
    58   * </p>
    59   *
    60   * <P>
    61   * <B>Do not use this class directly.</B> Instead configure
    62   * <code>web.xml</code> to use the {@link
    63   * org.acegisecurity.util.FilterToBeanProxy}.
    64   * </p>
    65   *
    66   * @author Ben Alex
    67   * @version $Id: ChannelProcessingFilter.java,v 1.5 2005/11/17 00:55:50 benalex Exp $
    68   */
    69  public class ChannelProcessingFilter implements InitializingBean, Filter {
    70      //~ Static fields/initializers =============================================
    71
    72      private static final Log logger = LogFactory.getLog(ChannelProcessingFilter.class);
    73
    74      //~ Instance fields ========================================================
    75
    76      private ChannelDecisionManager channelDecisionManager;
    77      private FilterInvocationDefinitionSource filterInvocationDefinitionSource;
    78
    79      //~ Methods ================================================================
    80
    81      public void setChannelDecisionManager(
    82          ChannelDecisionManager channelDecisionManager) {
    83          this.channelDecisionManager = channelDecisionManager;
    84      }
    85
    86      public ChannelDecisionManager getChannelDecisionManager() {
    87          return channelDecisionManager;
    88      }
    89
    90      public void setFilterInvocationDefinitionSource(
    91          FilterInvocationDefinitionSource filterInvocationDefinitionSource) {
    92          this.filterInvocationDefinitionSource = filterInvocationDefinitionSource;
    93      }
    94
    95      public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
    96          return filterInvocationDefinitionSource;
    97      }
    98
    99      public void afterPropertiesSet() throws Exception {
    100         Assert.notNull(filterInvocationDefinitionSource, "filterInvocationDefinitionSource must be specified");
    101         Assert.notNull(channelDecisionManager, "channelDecisionManager must be specified");
    102
    103         Iterator iter = this.filterInvocationDefinitionSource
    104                 .getConfigAttributeDefinitions();
    105
    106         if (iter == null) {
    107             if (logger.isWarnEnabled()) {
    108                 logger.warn("Could not validate configuration attributes as the FilterInvocationDefinitionSource did not return a ConfigAttributeDefinition Iterator");
    109             }
    110
    111             return;
    112         }
    113
    114         Set set = new HashSet();
    115
    116         while (iter.hasNext()) {
    117             ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter
    118                     .next();
    119             Iterator attributes = def.getConfigAttributes();
    120
    121             while (attributes.hasNext()) {
    122                 ConfigAttribute attr = (ConfigAttribute) attributes.next();
    123
    124                 if (!this.channelDecisionManager.supports(attr)) {
    125                     set.add(attr);
    126                 }
    127             }
    128         }
    129
    130         if (set.size() == 0) {
    131             if (logger.isInfoEnabled()) {
    132                 logger.info("Validated configuration attributes");
    133             }
    134         } else {
    135             throw new IllegalArgumentException("Unsupported configuration attributes: " + set.toString());
    136         }
    137     }
    138
    139     public void destroy() {}
    140
    141     public void doFilter(ServletRequest request, ServletResponse response,
    142         FilterChain chain) throws IOException, ServletException {
    143         if (!(request instanceof HttpServletRequest)) {
    144             throw new ServletException("HttpServletRequest required");
    145         }
    146
    147         if (!(response instanceof HttpServletResponse)) {
    148             throw new ServletException("HttpServletResponse required");
    149         }
    150
    151         FilterInvocation fi = new FilterInvocation(request, response, chain);
    152         ConfigAttributeDefinition attr = this.filterInvocationDefinitionSource
    153             .getAttributes(fi);
    154
    155         if (attr != null) {
    156             if (logger.isDebugEnabled()) {
    157                 logger.debug("Request: " + fi.getFullRequestUrl()
    158                     + "; ConfigAttributes: " + attr.toString());
    159             }
    160
    161             channelDecisionManager.decide(fi, attr);
    162
    163             if (fi.getResponse().isCommitted()) {
    164                 return;
    165             }
    166         }
    167
    168         chain.doFilter(request, response);
    169     }
    170
    171     public void init(FilterConfig filterConfig) throws ServletException {}
    172 }