1 /* Copyright 2004, 2005, 2006 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.springframework.security.intercept.web;
17
18 import org.springframework.security.intercept.AbstractSecurityInterceptor;
19 import org.springframework.security.intercept.InterceptorStatusToken;
20 import org.springframework.security.intercept.ObjectDefinitionSource;
21 import org.springframework.security.ui.FilterChainOrder;
22 import org.springframework.core.Ordered;
23
24 import java.io.IOException;
25
26 import javax.servlet.Filter;
27 import javax.servlet.FilterChain;
28 import javax.servlet.FilterConfig;
29 import javax.servlet.ServletException;
30 import javax.servlet.ServletRequest;
31 import javax.servlet.ServletResponse;
32
33
34 /**
35 * Performs security handling of HTTP resources via a filter implementation.<p>The
36 * <code>ObjectDefinitionSource</code> required by this security interceptor is of type {@link
37 * FilterInvocationDefinitionSource}.</p>
38 * <p>Refer to {@link AbstractSecurityInterceptor} for details on the workflow.</p>
39 *
40 * @author Ben Alex
41 * @version $Id: FilterSecurityInterceptor.java 2479 2008-01-19 13:51:03Z luke_t $
42 */
43 public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter, Ordered {
44 //~ Static fields/initializers =====================================================================================
45
46 private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
47
48 //~ Instance fields ================================================================================================
49
50 private FilterInvocationDefinitionSource objectDefinitionSource;
51 private boolean observeOncePerRequest = true;
52
53 //~ Methods ========================================================================================================
54
55 /**
56 * Not used (we rely on IoC container lifecycle services instead)
57 *
58 * @param arg0 ignored
59 *
60 * @throws ServletException never thrown
61 */
62 public void init(FilterConfig arg0) throws ServletException {}
63
64 /**
65 * Not used (we rely on IoC container lifecycle services instead)
66 */
67 public void destroy() {}
68
69 /**
70 * Method that is actually called by the filter chain. Simply delegates to the {@link
71 * #invoke(FilterInvocation)} method.
72 *
73 * @param request the servlet request
74 * @param response the servlet response
75 * @param chain the filter chain
76 *
77 * @throws IOException if the filter chain fails
78 * @throws ServletException if the filter chain fails
79 */
80 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
81 throws IOException, ServletException {
82 FilterInvocation fi = new FilterInvocation(request, response, chain);
83 invoke(fi);
84 }
85
86 public FilterInvocationDefinitionSource getObjectDefinitionSource() {
87 return this.objectDefinitionSource;
88 }
89
90 public Class getSecureObjectClass() {
91 return FilterInvocation.class;
92 }
93
94 public void invoke(FilterInvocation fi) throws IOException, ServletException {
95 if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
96 && observeOncePerRequest) {
97 // filter already applied to this request and user wants us to observce
98 // once-per-request handling, so don't re-do security checking
99 fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
100 } else {
101 // first time this request being called, so perform security checking
102 if (fi.getRequest() != null) {
103 fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
104 }
105
106 InterceptorStatusToken token = super.beforeInvocation(fi);
107
108 try {
109 fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
110 } finally {
111 super.afterInvocation(token, null);
112 }
113 }
114 }
115
116 /**
117 * Indicates whether once-per-request handling will be observed. By default this is <code>true</code>,
118 * meaning the <code>FilterSecurityInterceptor</code> will only execute once-per-request. Sometimes users may wish
119 * it to execute more than once per request, such as when JSP forwards are being used and filter security is
120 * desired on each included fragment of the HTTP request.
121 *
122 * @return <code>true</code> (the default) if once-per-request is honoured, otherwise <code>false</code> if
123 * <code>FilterSecurityInterceptor</code> will enforce authorizations for each and every fragment of the
124 * HTTP request.
125 */
126 public boolean isObserveOncePerRequest() {
127 return observeOncePerRequest;
128 }
129
130 public ObjectDefinitionSource obtainObjectDefinitionSource() {
131 return this.objectDefinitionSource;
132 }
133
134 public void setObjectDefinitionSource(FilterInvocationDefinitionSource newSource) {
135 this.objectDefinitionSource = newSource;
136 }
137
138 public void setObserveOncePerRequest(boolean observeOncePerRequest) {
139 this.observeOncePerRequest = observeOncePerRequest;
140 }
141
142 public int getOrder() {
143 return FilterChainOrder.FILTER_SECURITY_INTERCEPTOR;
144 }
145 }