Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: net/sf/acegisecurity/intercept/web/SecurityEnforcementFilter.java


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 net.sf.acegisecurity.intercept.web;
17  
18  import net.sf.acegisecurity.AccessDeniedException;
19  import net.sf.acegisecurity.AuthenticationException;
20  import net.sf.acegisecurity.AuthenticationTrustResolver;
21  import net.sf.acegisecurity.AuthenticationTrustResolverImpl;
22  import net.sf.acegisecurity.InsufficientAuthenticationException;
23  import net.sf.acegisecurity.context.security.SecureContextUtils;
24  import net.sf.acegisecurity.ui.AbstractProcessingFilter;
25  import net.sf.acegisecurity.util.PortResolver;
26  import net.sf.acegisecurity.util.PortResolverImpl;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  import org.springframework.beans.factory.InitializingBean;
32  
33  import org.springframework.util.Assert;
34  
35  import java.io.IOException;
36  
37  import javax.servlet.Filter;
38  import javax.servlet.FilterChain;
39  import javax.servlet.FilterConfig;
40  import javax.servlet.ServletException;
41  import javax.servlet.ServletRequest;
42  import javax.servlet.ServletResponse;
43  import javax.servlet.http.HttpServletRequest;
44  import javax.servlet.http.HttpServletResponse;
45  
46  
47  /**
48   * Wraps requests to the {@link FilterSecurityInterceptor}.
49   * 
50   * <p>
51   * This filter is necessary because it provides the bridge between incoming
52   * requests and the <code>FilterSecurityInterceptor</code> instance.
53   * </p>
54   * 
55   * <p>
56   * If an {@link AuthenticationException} is detected, the filter will launch the
57   * <code>authenticationEntryPoint</code>. This allows common handling of
58   * authentication failures originating from any subclass of {@link
59   * net.sf.acegisecurity.intercept.AbstractSecurityInterceptor}.
60   * </p>
61   * 
62   * <p>
63   * If an {@link AccessDeniedException} is detected, the filter will determine
64   * whether or not the user is an anonymous user. If they are an anonymous
65   * user, the <code>authenticationEntryPoint</code> will be launched. If they
66   * are not an anonymous user, the filter will respond with a
67   * <code>HttpServletResponse.SC_FORBIDDEN</code> (403 error).  In addition,
68   * the <code>AccessDeniedException</code> itself will be placed in the
69   * <code>HttpSession</code> attribute keyed against {@link
70   * #ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY} (to allow access to the stack
71   * trace etc). Again, this allows common access denied handling irrespective
72   * of the originating security interceptor.
73   * </p>
74   * 
75   * <p>
76   * To use this filter, it is necessary to specify the following properties:
77   * </p>
78   * 
79   * <ul>
80   * <li>
81   * <code>filterSecurityInterceptor</code> indicates the
82   * <code>FilterSecurityInterceptor</code> to delegate HTTP security decisions
83   * to.
84   * </li>
85   * <li>
86   * <code>authenticationEntryPoint</code> indicates the handler that should
87   * commence the authentication process if an
88   * <code>AuthenticationException</code> is detected. Note that this may also
89   * switch the current protocol from http to https for an SSL login.
90   * </li>
91   * <li>
92   * <code>portResolver</code> is used to determine the "real" port that a
93   * request was received on.
94   * </li>
95   * </ul>
96   * 
97   * <P>
98   * <B>Do not use this class directly.</B> Instead configure
99   * <code>web.xml</code> to use the {@link
100  * net.sf.acegisecurity.util.FilterToBeanProxy}.
101  * </p>
102  *
103  * @author Ben Alex
104  * @author colin sampaleanu
105  * @version $Id: SecurityEnforcementFilter.java,v 1.16 2005/03/16 16:57:28 luke_t Exp $
106  */
107 public class SecurityEnforcementFilter implements Filter, InitializingBean {
108     //~ Static fields/initializers =============================================
109 
110     private static final Log logger = LogFactory.getLog(SecurityEnforcementFilter.class);
111     public static final String ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY = "ACEGI_SECURITY_403_EXCEPTION";
112 
113     //~ Instance fields ========================================================
114 
115     private AuthenticationEntryPoint authenticationEntryPoint;
116     private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
117     private FilterSecurityInterceptor filterSecurityInterceptor;
118     private PortResolver portResolver = new PortResolverImpl();
119 
120     //~ Methods ================================================================
121 
122     public void setAuthenticationEntryPoint(
123         AuthenticationEntryPoint authenticationEntryPoint) {
124         this.authenticationEntryPoint = authenticationEntryPoint;
125     }
126 
127     public AuthenticationEntryPoint getAuthenticationEntryPoint() {
128         return authenticationEntryPoint;
129     }
130 
131     public void setAuthenticationTrustResolver(
132         AuthenticationTrustResolver authenticationTrustResolver) {
133         this.authenticationTrustResolver = authenticationTrustResolver;
134     }
135 
136     public AuthenticationTrustResolver getAuthenticationTrustResolver() {
137         return authenticationTrustResolver;
138     }
139 
140     public void setFilterSecurityInterceptor(
141         FilterSecurityInterceptor filterSecurityInterceptor) {
142         this.filterSecurityInterceptor = filterSecurityInterceptor;
143     }
144 
145     public FilterSecurityInterceptor getFilterSecurityInterceptor() {
146         return filterSecurityInterceptor;
147     }
148 
149     public void setPortResolver(PortResolver portResolver) {
150         this.portResolver = portResolver;
151     }
152 
153     public PortResolver getPortResolver() {
154         return portResolver;
155     }
156 
157     public void afterPropertiesSet() throws Exception {
158         Assert.notNull(authenticationEntryPoint,
159             "authenticationEntryPoint must be specified");
160         Assert.notNull(filterSecurityInterceptor,
161             "filterSecurityInterceptor must be specified");
162         Assert.notNull(portResolver, "portResolver must be specified");
163         Assert.notNull(authenticationTrustResolver,
164             "authenticationTrustResolver must be specified");
165     }
166 
167     public void destroy() {}
168 
169     public void doFilter(ServletRequest request, ServletResponse response,
170         FilterChain chain) throws IOException, ServletException {
171         if (!(request instanceof HttpServletRequest)) {
172             throw new ServletException("HttpServletRequest required");
173         }
174 
175         if (!(response instanceof HttpServletResponse)) {
176             throw new ServletException("HttpServletResponse required");
177         }
178 
179         FilterInvocation fi = new FilterInvocation(request, response, chain);
180 
181         try {
182             filterSecurityInterceptor.invoke(fi);
183 
184             if (logger.isDebugEnabled()) {
185                 logger.debug("Chain processed normally");
186             }
187         } catch (AuthenticationException authentication) {
188             if (logger.isDebugEnabled()) {
189                 logger.debug("Authentication exception occurred; redirecting to authentication entry point",
190                     authentication);
191             }
192 
193             sendStartAuthentication(fi, authentication);
194         } catch (AccessDeniedException accessDenied) {
195             if (authenticationTrustResolver.isAnonymous(
196                     SecureContextUtils.getSecureContext().getAuthentication())) {
197                 if (logger.isDebugEnabled()) {
198                     logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
199                         accessDenied);
200                 }
201 
202                 sendStartAuthentication(fi,
203                     new InsufficientAuthenticationException(
204                         "Full authentication is required to access this resource"));
205             } else {
206                 if (logger.isDebugEnabled()) {
207                     logger.debug("Access is denied (user is not anonymous); sending back forbidden response",
208                         accessDenied);
209                 }
210 
211                 sendAccessDeniedError(fi, accessDenied);
212             }
213         } catch (Throwable otherException) {
214             throw new ServletException(otherException);
215         }
216     }
217 
218     public void init(FilterConfig filterConfig) throws ServletException {}
219 
220     protected void sendAccessDeniedError(FilterInvocation fi,
221         AccessDeniedException accessDenied)
222         throws ServletException, IOException {
223         ((HttpServletRequest) fi.getRequest()).getSession().setAttribute(ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY,
224             accessDenied);
225         ((HttpServletResponse) fi.getResponse()).sendError(HttpServletResponse.SC_FORBIDDEN,
226             accessDenied.getMessage()); // 403
227     }
228 
229     protected void sendStartAuthentication(FilterInvocation fi,
230         AuthenticationException reason) throws ServletException, IOException {
231         HttpServletRequest request = (HttpServletRequest) fi.getRequest();
232 
233         int port = portResolver.getServerPort(request);
234         boolean includePort = true;
235 
236         if ("http".equals(request.getScheme().toLowerCase()) && (port == 80)) {
237             includePort = false;
238         }
239 
240         if ("https".equals(request.getScheme().toLowerCase()) && (port == 443)) {
241             includePort = false;
242         }
243 
244         String targetUrl = request.getScheme() + "://"
245             + request.getServerName() + ((includePort) ? (":" + port) : "")
246             + request.getContextPath() + fi.getRequestUrl();
247 
248         if (logger.isDebugEnabled()) {
249             logger.debug(
250                 "Authentication entry point being called; target URL added to Session: "
251                 + targetUrl);
252         }
253 
254         ((HttpServletRequest) request).getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
255             targetUrl);
256         authenticationEntryPoint.commence(request,
257             (HttpServletResponse) fi.getResponse(), reason);
258     }
259 }