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 }