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.captcha;
17  
18  import junit.framework.TestCase;
19  
20  import org.acegisecurity.ConfigAttributeDefinition;
21  import org.acegisecurity.MockFilterChain;
22  import org.acegisecurity.SecurityConfig;
23  
24  import org.acegisecurity.context.SecurityContextHolder;
25  
26  import org.acegisecurity.intercept.web.FilterInvocation;
27  
28  import org.springframework.mock.web.MockHttpServletRequest;
29  import org.springframework.mock.web.MockHttpServletResponse;
30  
31  import java.io.IOException;
32  
33  import javax.servlet.ServletException;
34  
35  
36  /**
37   * Tests {@link org.acegisecurity.captcha.CaptchaChannelProcessorTemplate}
38   *
39   * @author marc antoine Garrigue
40   * @version $Id: CaptchaChannelProcessorTemplateTests.java 1496 2006-05-23 13:38:33Z benalex $
41   */
42  public class CaptchaChannelProcessorTemplateTests extends TestCase {
43      //~ Methods ========================================================================================================
44  
45      private MockHttpServletResponse decideWithNewResponse(ConfigAttributeDefinition cad,
46          CaptchaChannelProcessorTemplate processor, MockHttpServletRequest request)
47          throws IOException, ServletException {
48          MockHttpServletResponse response;
49          MockFilterChain chain;
50          FilterInvocation fi;
51          response = new MockHttpServletResponse();
52          chain = new MockFilterChain();
53          fi = new FilterInvocation(request, response, chain);
54          processor.decide(fi, cad);
55  
56          return response;
57      }
58  
59      public void setUp() {
60          SecurityContextHolder.clearContext();
61      }
62  
63      public void tearDown() {
64          SecurityContextHolder.clearContext();
65      }
66  
67      public void testContextRedirect() throws Exception {
68          CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor();
69          processor.setKeyword("X");
70  
71          ConfigAttributeDefinition cad = new ConfigAttributeDefinition();
72          cad.addConfigAttribute(new SecurityConfig("Y"));
73  
74          CaptchaSecurityContext context = new CaptchaSecurityContextImpl();
75          SecurityContextHolder.setContext(context);
76  
77          CaptchaEntryPoint epoint = new CaptchaEntryPoint();
78          epoint.setCaptchaFormUrl("/jcaptcha.do");
79          epoint.setIncludeOriginalRequest(false);
80  
81          processor.setEntryPoint(epoint);
82  
83          MockHttpServletRequest request = new MockHttpServletRequest();
84          request.setQueryString("info=true");
85          request.setServerName("localhost");
86          request.setContextPath("/demo");
87          request.setServletPath("/restricted");
88          request.setScheme("http");
89          request.setServerPort(8000);
90  
91          MockHttpServletResponse response = new MockHttpServletResponse();
92          MockFilterChain chain = new MockFilterChain();
93          FilterInvocation fi = new FilterInvocation(request, response, chain);
94  
95          processor.decide(fi, cad);
96          assertEquals(null, response.getRedirectedUrl());
97          processor.setKeyword("Y");
98          response = decideWithNewResponse(cad, processor, request);
99          assertEquals("http://localhost:8000/demo/jcaptcha.do", response.getRedirectedUrl());
100         context.setHuman();
101         response = decideWithNewResponse(cad, processor, request);
102         assertEquals(null, response.getRedirectedUrl());
103     }
104 
105     public void testDecideRejectsNulls() throws Exception {
106         CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor();
107         processor.setEntryPoint(new CaptchaEntryPoint());
108         processor.setKeyword("X");
109         processor.afterPropertiesSet();
110 
111         try {
112             processor.decide(null, null);
113             fail("Should have thrown IllegalArgumentException");
114         } catch (IllegalArgumentException expected) {
115             assertTrue(true);
116         }
117     }
118 
119     public void testGettersSetters() {
120         CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor();
121         assertEquals(null, processor.getKeyword());
122         processor.setKeyword("X");
123         assertEquals("X", processor.getKeyword());
124 
125         assertEquals(0, processor.getThresold());
126         processor.setThresold(1);
127         assertEquals(1, processor.getThresold());
128 
129         assertTrue(processor.getEntryPoint() == null);
130         processor.setEntryPoint(new CaptchaEntryPoint());
131         assertTrue(processor.getEntryPoint() != null);
132     }
133 
134     public void testIncrementRequestCount() throws Exception {
135         CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor();
136         processor.setKeyword("X");
137 
138         ConfigAttributeDefinition cad = new ConfigAttributeDefinition();
139         cad.addConfigAttribute(new SecurityConfig("X"));
140 
141         CaptchaSecurityContext context = new CaptchaSecurityContextImpl();
142         SecurityContextHolder.setContext(context);
143 
144         CaptchaEntryPoint epoint = new CaptchaEntryPoint();
145         epoint.setCaptchaFormUrl("/jcaptcha.do");
146         processor.setEntryPoint(epoint);
147 
148         MockHttpServletRequest request = new MockHttpServletRequest();
149         request.setQueryString("info=true");
150         request.setServerName("localhost");
151         request.setContextPath("/demo");
152         request.setServletPath("/restricted");
153         request.setScheme("http");
154         request.setServerPort(8000);
155 
156         MockHttpServletResponse response = new MockHttpServletResponse();
157         MockFilterChain chain = new MockFilterChain();
158         FilterInvocation fi = new FilterInvocation(request, response, chain);
159 
160         processor.decide(fi, cad);
161         assertEquals(0, context.getHumanRestrictedResourcesRequestsCount());
162         context.setHuman();
163         decideWithNewResponse(cad, processor, request);
164         assertEquals(1, context.getHumanRestrictedResourcesRequestsCount());
165         decideWithNewResponse(cad, processor, request);
166         assertEquals(2, context.getHumanRestrictedResourcesRequestsCount());
167         processor.setKeyword("Y");
168         decideWithNewResponse(cad, processor, request);
169         assertEquals(2, context.getHumanRestrictedResourcesRequestsCount());
170         context = new CaptchaSecurityContextImpl();
171         decideWithNewResponse(cad, processor, request);
172         assertEquals(0, context.getHumanRestrictedResourcesRequestsCount());
173     }
174 
175     public void testMissingEntryPoint() throws Exception {
176         CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor();
177         processor.setEntryPoint(null);
178 
179         try {
180             processor.afterPropertiesSet();
181             fail("Should have thrown IllegalArgumentException");
182         } catch (IllegalArgumentException expected) {
183             assertEquals("entryPoint required", expected.getMessage());
184         }
185     }
186 
187     public void testMissingKeyword() throws Exception {
188         CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor();
189         processor.setKeyword(null);
190 
191         try {
192             processor.afterPropertiesSet();
193             fail("Should have thrown IllegalArgumentException");
194         } catch (IllegalArgumentException expected) {}
195 
196         processor.setKeyword("");
197 
198         try {
199             processor.afterPropertiesSet();
200             fail("Should have thrown IllegalArgumentException");
201         } catch (IllegalArgumentException expected) {}
202     }
203 
204     public void testSupports() {
205         CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor();
206         processor.setKeyword("X");
207         assertTrue(processor.supports(new SecurityConfig(processor.getKeyword())));
208 
209         assertTrue(processor.supports(new SecurityConfig("X")));
210 
211         assertFalse(processor.supports(null));
212 
213         assertFalse(processor.supports(new SecurityConfig("NOT_SUPPORTED")));
214     }
215 
216     //~ Inner Classes ==================================================================================================
217 
218     private class TestHumanityCaptchaChannelProcessor extends CaptchaChannelProcessorTemplate {
219         boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) {
220             return context.isHuman();
221         }
222     }
223 }