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 junit.framework.TestCase;
19  
20  import org.acegisecurity.ConfigAttribute;
21  import org.acegisecurity.ConfigAttributeDefinition;
22  import org.acegisecurity.SecurityConfig;
23  
24  import org.acegisecurity.intercept.web.FilterInvocation;
25  import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
26  
27  import org.springframework.mock.web.MockHttpServletRequest;
28  import org.springframework.mock.web.MockHttpServletResponse;
29  
30  import java.io.IOException;
31  
32  import java.util.Iterator;
33  import java.util.List;
34  import java.util.Vector;
35  
36  import javax.servlet.FilterChain;
37  import javax.servlet.ServletException;
38  import javax.servlet.ServletRequest;
39  import javax.servlet.ServletResponse;
40  
41  
42  /**
43   * Tests {@link ChannelProcessingFilter}.
44   *
45   * @author Ben Alex
46   * @version $Id: ChannelProcessingFilterTests.java 1496 2006-05-23 13:38:33Z benalex $
47   */
48  public class ChannelProcessingFilterTests extends TestCase {
49      //~ Methods ========================================================================================================
50  
51      public static void main(String[] args) {
52          junit.textui.TestRunner.run(ChannelProcessingFilterTests.class);
53      }
54  
55      public final void setUp() throws Exception {
56          super.setUp();
57      }
58  
59      public void testDetectsMissingChannelDecisionManager()
60          throws Exception {
61          ChannelProcessingFilter filter = new ChannelProcessingFilter();
62  
63          ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
64          attr.addConfigAttribute(new SecurityConfig("MOCK"));
65  
66          MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", attr, true);
67          filter.setFilterInvocationDefinitionSource(fids);
68  
69          try {
70              filter.afterPropertiesSet();
71              fail("Should have thrown IllegalArgumentException");
72          } catch (IllegalArgumentException expected) {
73              assertEquals("channelDecisionManager must be specified", expected.getMessage());
74          }
75      }
76  
77      public void testDetectsMissingFilterInvocationDefinitionSource()
78          throws Exception {
79          ChannelProcessingFilter filter = new ChannelProcessingFilter();
80          filter.setChannelDecisionManager(new MockChannelDecisionManager(false, "MOCK"));
81  
82          try {
83              filter.afterPropertiesSet();
84              fail("Should have thrown IllegalArgumentException");
85          } catch (IllegalArgumentException expected) {
86              assertEquals("filterInvocationDefinitionSource must be specified", expected.getMessage());
87          }
88      }
89  
90      public void testDetectsSupportedConfigAttribute() throws Exception {
91          ChannelProcessingFilter filter = new ChannelProcessingFilter();
92          filter.setChannelDecisionManager(new MockChannelDecisionManager(false, "SUPPORTS_MOCK_ONLY"));
93  
94          ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
95          attr.addConfigAttribute(new SecurityConfig("SUPPORTS_MOCK_ONLY"));
96  
97          MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", attr, true);
98  
99          filter.setFilterInvocationDefinitionSource(fids);
100 
101         filter.afterPropertiesSet();
102         assertTrue(true);
103     }
104 
105     public void testDetectsUnsupportedConfigAttribute()
106         throws Exception {
107         ChannelProcessingFilter filter = new ChannelProcessingFilter();
108         filter.setChannelDecisionManager(new MockChannelDecisionManager(false, "SUPPORTS_MOCK_ONLY"));
109 
110         ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
111         attr.addConfigAttribute(new SecurityConfig("SUPPORTS_MOCK_ONLY"));
112         attr.addConfigAttribute(new SecurityConfig("INVALID_ATTRIBUTE"));
113 
114         MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", attr, true);
115 
116         filter.setFilterInvocationDefinitionSource(fids);
117 
118         try {
119             filter.afterPropertiesSet();
120             fail("Should have thrown IllegalArgumentException");
121         } catch (IllegalArgumentException expected) {
122             assertTrue(expected.getMessage().startsWith("Unsupported configuration attributes:"));
123         }
124     }
125 
126     public void testDoFilterWhenManagerDoesCommitResponse()
127         throws Exception {
128         ChannelProcessingFilter filter = new ChannelProcessingFilter();
129         filter.setChannelDecisionManager(new MockChannelDecisionManager(true, "SOME_ATTRIBUTE"));
130 
131         ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
132         attr.addConfigAttribute(new SecurityConfig("SOME_ATTRIBUTE"));
133 
134         MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", attr, true);
135 
136         filter.setFilterInvocationDefinitionSource(fids);
137 
138         MockHttpServletRequest request = new MockHttpServletRequest();
139         request.setQueryString("info=now");
140         request.setServletPath("/path");
141 
142         MockHttpServletResponse response = new MockHttpServletResponse();
143         MockFilterChain chain = new MockFilterChain(false);
144 
145         filter.doFilter(request, response, chain);
146         assertTrue(true);
147     }
148 
149     public void testDoFilterWhenManagerDoesNotCommitResponse()
150         throws Exception {
151         ChannelProcessingFilter filter = new ChannelProcessingFilter();
152         filter.setChannelDecisionManager(new MockChannelDecisionManager(false, "SOME_ATTRIBUTE"));
153 
154         ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
155         attr.addConfigAttribute(new SecurityConfig("SOME_ATTRIBUTE"));
156 
157         MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", attr, true);
158 
159         filter.setFilterInvocationDefinitionSource(fids);
160 
161         MockHttpServletRequest request = new MockHttpServletRequest();
162         request.setQueryString("info=now");
163         request.setServletPath("/path");
164 
165         MockHttpServletResponse response = new MockHttpServletResponse();
166         MockFilterChain chain = new MockFilterChain(true);
167 
168         filter.doFilter(request, response, chain);
169         assertTrue(true);
170     }
171 
172     public void testDoFilterWhenNullConfigAttributeReturned()
173         throws Exception {
174         ChannelProcessingFilter filter = new ChannelProcessingFilter();
175         filter.setChannelDecisionManager(new MockChannelDecisionManager(false, "NOT_USED"));
176 
177         ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
178         attr.addConfigAttribute(new SecurityConfig("NOT_USED"));
179 
180         MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", attr, true);
181 
182         filter.setFilterInvocationDefinitionSource(fids);
183 
184         MockHttpServletRequest request = new MockHttpServletRequest();
185         request.setQueryString("info=now");
186         request.setServletPath("/PATH_NOT_MATCHING_CONFIG_ATTRIBUTE");
187 
188         MockHttpServletResponse response = new MockHttpServletResponse();
189         MockFilterChain chain = new MockFilterChain(true);
190 
191         filter.doFilter(request, response, chain);
192         assertTrue(true);
193     }
194 
195     public void testDoFilterWithNonHttpServletRequestDetected()
196         throws Exception {
197         ChannelProcessingFilter filter = new ChannelProcessingFilter();
198 
199         try {
200             filter.doFilter(null, new MockHttpServletResponse(), new MockFilterChain());
201             fail("Should have thrown ServletException");
202         } catch (ServletException expected) {
203             assertEquals("HttpServletRequest required", expected.getMessage());
204         }
205     }
206 
207     public void testDoFilterWithNonHttpServletResponseDetected()
208         throws Exception {
209         ChannelProcessingFilter filter = new ChannelProcessingFilter();
210 
211         try {
212             filter.doFilter(new MockHttpServletRequest(null, null), null, new MockFilterChain());
213             fail("Should have thrown ServletException");
214         } catch (ServletException expected) {
215             assertEquals("HttpServletResponse required", expected.getMessage());
216         }
217     }
218 
219     public void testGetterSetters() throws Exception {
220         ChannelProcessingFilter filter = new ChannelProcessingFilter();
221         filter.setChannelDecisionManager(new MockChannelDecisionManager(false, "MOCK"));
222         assertTrue(filter.getChannelDecisionManager() != null);
223 
224         ConfigAttributeDefinition attr = new ConfigAttributeDefinition();
225         attr.addConfigAttribute(new SecurityConfig("MOCK"));
226 
227         MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", attr, false);
228 
229         filter.setFilterInvocationDefinitionSource(fids);
230         assertTrue(filter.getFilterInvocationDefinitionSource() != null);
231 
232         filter.init(null);
233         filter.afterPropertiesSet();
234         filter.destroy();
235     }
236 
237     //~ Inner Classes ==================================================================================================
238 
239     private class MockChannelDecisionManager implements ChannelDecisionManager {
240         private String supportAttribute;
241         private boolean commitAResponse;
242 
243         public MockChannelDecisionManager(boolean commitAResponse, String supportAttribute) {
244             this.commitAResponse = commitAResponse;
245             this.supportAttribute = supportAttribute;
246         }
247 
248         private MockChannelDecisionManager() {
249             super();
250         }
251 
252         public void decide(FilterInvocation invocation, ConfigAttributeDefinition config)
253             throws IOException, ServletException {
254             if (commitAResponse) {
255                 invocation.getHttpResponse().sendRedirect("/redirected");
256             }
257         }
258 
259         public boolean supports(ConfigAttribute attribute) {
260             if (attribute.getAttribute().equals(supportAttribute)) {
261                 return true;
262             } else {
263                 return false;
264             }
265         }
266     }
267 
268     private class MockFilterChain implements FilterChain {
269         private boolean expectToProceed;
270 
271         public MockFilterChain(boolean expectToProceed) {
272             this.expectToProceed = expectToProceed;
273         }
274 
275         private MockFilterChain() {
276             super();
277         }
278 
279         public void doFilter(ServletRequest request, ServletResponse response)
280             throws IOException, ServletException {
281             if (expectToProceed) {
282                 assertTrue(true);
283             } else {
284                 fail("Did not expect filter chain to proceed");
285             }
286         }
287     }
288 
289     private class MockFilterInvocationDefinitionMap implements FilterInvocationDefinitionSource {
290         private ConfigAttributeDefinition toReturn;
291         private String servletPath;
292         private boolean provideIterator;
293 
294         public MockFilterInvocationDefinitionMap(String servletPath, ConfigAttributeDefinition toReturn,
295             boolean provideIterator) {
296             this.servletPath = servletPath;
297             this.toReturn = toReturn;
298             this.provideIterator = provideIterator;
299         }
300 
301         private MockFilterInvocationDefinitionMap() {
302             super();
303         }
304 
305         public ConfigAttributeDefinition getAttributes(Object object)
306             throws IllegalArgumentException {
307             FilterInvocation fi = (FilterInvocation) object;
308 
309             if (servletPath.equals(fi.getHttpRequest().getServletPath())) {
310                 return toReturn;
311             } else {
312                 return null;
313             }
314         }
315 
316         public Iterator getConfigAttributeDefinitions() {
317             if (!provideIterator) {
318                 return null;
319             }
320 
321             List list = new Vector();
322             list.add(toReturn);
323 
324             return list.iterator();
325         }
326 
327         public boolean supports(Class clazz) {
328             return true;
329         }
330     }
331 }