View Javadoc

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.acegisecurity.securechannel;
17  
18  import org.acegisecurity.ConfigAttribute;
19  import org.acegisecurity.ConfigAttributeDefinition;
20  
21  import org.acegisecurity.intercept.web.FilterInvocation;
22  import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import org.springframework.beans.factory.InitializingBean;
28  
29  import org.springframework.util.Assert;
30  
31  import java.io.IOException;
32  
33  import java.util.HashSet;
34  import java.util.Iterator;
35  import java.util.Set;
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   * Ensures a web request is delivered over the required channel.<p>Internally uses a {@link FilterInvocation} to
49   * represent the request, so that the <code>FilterInvocation</code>-related property editors and lookup classes can be
50   * used.</p>
51   *  <P>Delegates the actual channel security decisions and necessary actions to the configured {@link
52   * ChannelDecisionManager}. If a response is committed by the <code>ChannelDecisionManager</code>, the filter chain
53   * will not proceed.</p>
54   *  <P><B>Do not use this class directly.</B> Instead configure <code>web.xml</code> to use the {@link
55   * org.acegisecurity.util.FilterToBeanProxy}.</p>
56   *
57   * @author Ben Alex
58   * @version $Id: ChannelProcessingFilter.java 1784 2007-02-24 21:00:24Z luke_t $
59   */
60  public class ChannelProcessingFilter implements InitializingBean, Filter {
61      //~ Static fields/initializers =====================================================================================
62  
63      private static final Log logger = LogFactory.getLog(ChannelProcessingFilter.class);
64  
65      //~ Instance fields ================================================================================================
66  
67      private ChannelDecisionManager channelDecisionManager;
68      private FilterInvocationDefinitionSource filterInvocationDefinitionSource;
69  
70      //~ Methods ========================================================================================================
71  
72      public void afterPropertiesSet() throws Exception {
73          Assert.notNull(filterInvocationDefinitionSource, "filterInvocationDefinitionSource must be specified");
74          Assert.notNull(channelDecisionManager, "channelDecisionManager must be specified");
75  
76          Iterator iter = this.filterInvocationDefinitionSource.getConfigAttributeDefinitions();
77  
78          if (iter == null) {
79              if (logger.isWarnEnabled()) {
80                  logger.warn("Could not validate configuration attributes as the FilterInvocationDefinitionSource did "
81                          + "not return a ConfigAttributeDefinition Iterator");
82              }
83  
84              return;
85          }
86  
87          Set set = new HashSet();
88  
89          while (iter.hasNext()) {
90              ConfigAttributeDefinition def = (ConfigAttributeDefinition) iter.next();
91              Iterator attributes = def.getConfigAttributes();
92  
93              while (attributes.hasNext()) {
94                  ConfigAttribute attr = (ConfigAttribute) attributes.next();
95  
96                  if (!this.channelDecisionManager.supports(attr)) {
97                      set.add(attr);
98                  }
99              }
100         }
101 
102         if (set.size() == 0) {
103             if (logger.isInfoEnabled()) {
104                 logger.info("Validated configuration attributes");
105             }
106         } else {
107             throw new IllegalArgumentException("Unsupported configuration attributes: " + set.toString());
108         }
109     }
110 
111     public void destroy() {}
112 
113     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
114         throws IOException, ServletException {
115         if (!(request instanceof HttpServletRequest)) {
116             throw new ServletException("HttpServletRequest required");
117         }
118 
119         if (!(response instanceof HttpServletResponse)) {
120             throw new ServletException("HttpServletResponse required");
121         }
122 
123         FilterInvocation fi = new FilterInvocation(request, response, chain);
124         ConfigAttributeDefinition attr = this.filterInvocationDefinitionSource.getAttributes(fi);
125 
126         if (attr != null) {
127             if (logger.isDebugEnabled()) {
128                 logger.debug("Request: " + fi.toString() + "; ConfigAttributes: " + attr.toString());
129             }
130 
131             channelDecisionManager.decide(fi, attr);
132 
133             if (fi.getResponse().isCommitted()) {
134                 return;
135             }
136         }
137 
138         chain.doFilter(request, response);
139     }
140 
141     public ChannelDecisionManager getChannelDecisionManager() {
142         return channelDecisionManager;
143     }
144 
145     public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
146         return filterInvocationDefinitionSource;
147     }
148 
149     public void init(FilterConfig filterConfig) throws ServletException {}
150 
151     public void setChannelDecisionManager(ChannelDecisionManager channelDecisionManager) {
152         this.channelDecisionManager = channelDecisionManager;
153     }
154 
155     public void setFilterInvocationDefinitionSource(FilterInvocationDefinitionSource filterInvocationDefinitionSource) {
156         this.filterInvocationDefinitionSource = filterInvocationDefinitionSource;
157     }
158 }