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.providers.anonymous;
    17
    18  import org.acegisecurity.Authentication;
    19  import org.acegisecurity.context.SecurityContextHolder;
    20  import org.acegisecurity.userdetails.memory.UserAttribute;
    21
    22  import org.apache.commons.logging.Log;
    23  import org.apache.commons.logging.LogFactory;
    24
    25  import org.springframework.beans.factory.InitializingBean;
    26
    27  import org.springframework.util.Assert;
    28
    29  import java.io.IOException;
    30
    31  import javax.servlet.Filter;
    32  import javax.servlet.FilterChain;
    33  import javax.servlet.FilterConfig;
    34  import javax.servlet.ServletException;
    35  import javax.servlet.ServletRequest;
    36  import javax.servlet.ServletResponse;
    37
    38
    39  /***
    40   * Detects if there is no <code>Authentication</code> object in the
    41   * <code>SecurityContextHolder</code>,  and populates it with one if needed.
    42   *
    43   * <p>
    44   * <b>Do not use this class directly.</b> Instead configure
    45   * <code>web.xml</code> to use the {@link
    46   * org.acegisecurity.util.FilterToBeanProxy}.
    47   * </p>
    48   *
    49   * @author Ben Alex
    50   * @version $Id: AnonymousProcessingFilter.java,v 1.9 2005/11/29 13:10:13 benalex Exp $
    51   */
    52  public class AnonymousProcessingFilter implements Filter, InitializingBean {
    53      //~ Static fields/initializers =============================================
    54
    55      private static final Log logger = LogFactory.getLog(AnonymousProcessingFilter.class);
    56
    57      //~ Instance fields ========================================================
    58
    59      private String key;
    60      private UserAttribute userAttribute;
    61      private boolean removeAfterRequest = true;
    62
    63      //~ Methods ================================================================
    64
    65      public void setKey(String key) {
    66          this.key = key;
    67      }
    68
    69      public String getKey() {
    70          return key;
    71      }
    72
    73      /***
    74       * Controls whether the filter will remove the Anonymous token after the
    75       * request is complete. Generally this is desired to avoid the expense of
    76       * a session being created by {@link
    77       * org.acegisecurity.context.HttpSessionContextIntegrationFilter
    78       * HttpSessionContextIntegrationFilter} simply to store the Anonymous
    79       * authentication token.
    80       *
    81       * <p>
    82       * Defaults to <code>true</code>, being the most optimal and appropriate
    83       * option (ie <code>AnonymousProcessingFilter</code> will clear the token
    84       * at the end of each request, thus avoiding the session creation overhead
    85       * in a typical configuration.
    86       * </p>
    87       *
    88       * @param removeAfterRequest DOCUMENT ME!
    89       */
    90      public void setRemoveAfterRequest(boolean removeAfterRequest) {
    91          this.removeAfterRequest = removeAfterRequest;
    92      }
    93
    94      public boolean isRemoveAfterRequest() {
    95          return removeAfterRequest;
    96      }
    97
    98      public void setUserAttribute(UserAttribute userAttributeDefinition) {
    99          this.userAttribute = userAttributeDefinition;
    100     }
    101
    102     public UserAttribute getUserAttribute() {
    103         return userAttribute;
    104     }
    105
    106     public void afterPropertiesSet() throws Exception {
    107         Assert.notNull(userAttribute);
    108         Assert.hasLength(key);
    109     }
    110
    111     /***
    112      * Does nothing - we reply on IoC lifecycle services instead.
    113      */
    114     public void destroy() {}
    115
    116     public void doFilter(ServletRequest request, ServletResponse response,
    117         FilterChain chain) throws IOException, ServletException {
    118         boolean addedToken = false;
    119
    120         if (applyAnonymousForThisRequest(request)) {
    121             if (SecurityContextHolder.getContext().getAuthentication() == null) {
    122                 SecurityContextHolder.getContext().setAuthentication(createAuthentication(
    123                         request));
    124                 addedToken = true;
    125
    126                 if (logger.isDebugEnabled()) {
    127                     logger.debug(
    128                         "Populated SecurityContextHolder with anonymous token: '"
    129                         + SecurityContextHolder.getContext().getAuthentication()
    130                         + "'");
    131                 }
    132             } else {
    133                 if (logger.isDebugEnabled()) {
    134                     logger.debug(
    135                         "SecurityContextHolder not populated with anonymous token, as it already contained: '"
    136                         + SecurityContextHolder.getContext().getAuthentication()
    137                         + "'");
    138                 }
    139             }
    140         }
    141
    142         try {
    143             chain.doFilter(request, response);
    144         } finally {
    145             if (addedToken && removeAfterRequest
    146                 && createAuthentication(request).equals(SecurityContextHolder.getContext()
    147                                                                              .getAuthentication())) {
    148                 SecurityContextHolder.getContext().setAuthentication(null);
    149             }
    150         }
    151     }
    152
    153     /***
    154      * Does nothing - we reply on IoC lifecycle services instead.
    155      *
    156      * @param ignored not used
    157      *
    158      * @throws ServletException DOCUMENT ME!
    159      */
    160     public void init(FilterConfig ignored) throws ServletException {}
    161
    162     /***
    163      * Enables subclasses to determine whether or not an anonymous
    164      * authentication token should be setup for this request. This is useful
    165      * if anonymous authentication should be allowed only for specific IP
    166      * subnet ranges etc.
    167      *
    168      * @param request to assist the method determine request details
    169      *
    170      * @return <code>true</code> if the anonymous token should be setup for
    171      *         this request (provided that the request doesn't already have
    172      *         some other <code>Authentication</code> inside it), or
    173      *         <code>false</code> if no anonymous token should be setup for
    174      *         this request
    175      */
    176     protected boolean applyAnonymousForThisRequest(ServletRequest request) {
    177         return true;
    178     }
    179
    180     protected Authentication createAuthentication(ServletRequest request) {
    181         return new AnonymousAuthenticationToken(key,
    182             userAttribute.getPassword(), userAttribute.getAuthorities());
    183     }
    184 }