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 }