1   /* Copyright 2004, 2005 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.context;
17  
18  import junit.framework.TestCase;
19  
20  import org.acegisecurity.Authentication;
21  import org.acegisecurity.GrantedAuthority;
22  import org.acegisecurity.GrantedAuthorityImpl;
23  import org.acegisecurity.MockFilterConfig;
24  
25  import org.acegisecurity.adapters.PrincipalAcegiUserToken;
26  
27  import org.springframework.mock.web.MockHttpServletRequest;
28  import org.springframework.mock.web.MockHttpServletResponse;
29  
30  import java.io.IOException;
31  
32  import javax.servlet.Filter;
33  import javax.servlet.FilterChain;
34  import javax.servlet.FilterConfig;
35  import javax.servlet.ServletException;
36  import javax.servlet.ServletRequest;
37  import javax.servlet.ServletResponse;
38  
39  
40  /***
41   * Tests {@link HttpSessionContextIntegrationFilter}.
42   *
43   * @author Ben Alex
44   * @version $Id: HttpSessionContextIntegrationFilterTests.java,v 1.9 2005/11/25 00:26:29 benalex Exp $
45   */
46  public class HttpSessionContextIntegrationFilterTests extends TestCase {
47      //~ Constructors ===========================================================
48  
49      public HttpSessionContextIntegrationFilterTests() {
50          super();
51      }
52  
53      public HttpSessionContextIntegrationFilterTests(String arg0) {
54          super(arg0);
55      }
56  
57      //~ Methods ================================================================
58  
59      public static void main(String[] args) {
60          junit.textui.TestRunner.run(HttpSessionContextIntegrationFilterTests.class);
61      }
62  
63      public void testDetectsMissingOrInvalidContext() throws Exception {
64          HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
65  
66          try {
67              filter.setContext(null);
68              filter.afterPropertiesSet();
69              fail("Shown have thrown IllegalArgumentException");
70          } catch (IllegalArgumentException expected) {
71              assertTrue(true);
72          }
73  
74          try {
75              filter.setContext(Integer.class);
76              assertEquals(Integer.class, filter.getContext());
77              filter.afterPropertiesSet();
78              fail("Shown have thrown IllegalArgumentException");
79          } catch (IllegalArgumentException expected) {
80              assertTrue(true);
81          }
82      }
83  
84      public void testExceptionWithinFilterChainStillClearsSecurityContextHolder()
85          throws Exception {
86          // Build an Authentication object we simulate came from HttpSession
87          PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key",
88                  "someone", "password",
89                  new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")},
90                  null);
91  
92          // Build a Context to store in HttpSession (simulating prior request)
93          SecurityContext sc = new SecurityContextImpl();
94          sc.setAuthentication(sessionPrincipal);
95  
96          // Build a mock request
97          MockHttpServletRequest request = new MockHttpServletRequest();
98          request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
99              sc);
100 
101         MockHttpServletResponse response = new MockHttpServletResponse();
102         FilterChain chain = new MockFilterChain(sessionPrincipal, null,
103                 new IOException());
104 
105         // Prepare filter
106         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
107         filter.setContext(SecurityContextImpl.class);
108         filter.afterPropertiesSet();
109 
110         // Execute filter
111         try {
112             executeFilterInContainerSimulator(new MockFilterConfig(), filter,
113                 request, response, chain);
114             fail(
115                 "We should have received the IOException thrown inside the filter chain here");
116         } catch (IOException ioe) {
117             assertTrue(true);
118         }
119 
120         // Check the SecurityContextHolder is null, even though an exception was thrown during chain
121         assertEquals(new SecurityContextImpl(),
122             SecurityContextHolder.getContext());
123     }
124 
125     public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
126         throws Exception {
127         // Build an Authentication object we simulate came from HttpSession
128         PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key",
129                 "someone", "password",
130                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")},
131                 null);
132 
133         // Build an Authentication object we simulate our Authentication changed it to
134         PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key",
135                 "someone", "password",
136                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")},
137                 null);
138 
139         // Build a Context to store in HttpSession (simulating prior request)
140         SecurityContext sc = new SecurityContextImpl();
141         sc.setAuthentication(sessionPrincipal);
142 
143         // Build a mock request
144         MockHttpServletRequest request = new MockHttpServletRequest();
145         request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
146             sc);
147 
148         MockHttpServletResponse response = new MockHttpServletResponse();
149         FilterChain chain = new MockFilterChain(sessionPrincipal,
150                 updatedPrincipal, null);
151 
152         // Prepare filter
153         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
154         filter.setContext(SecurityContextImpl.class);
155         filter.afterPropertiesSet();
156 
157         // Execute filter
158         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
159             request, response, chain);
160 
161         // Obtain new/update Authentication from HttpSession
162         SecurityContext context = (SecurityContext) request.getSession()
163                                                            .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
164         assertEquals(updatedPrincipal,
165             ((SecurityContext) context).getAuthentication());
166     }
167 
168     public void testHttpSessionCreatedWhenContextHolderChanges()
169         throws Exception {
170         // Build an Authentication object we simulate our Authentication changed it to
171         PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key",
172                 "someone", "password",
173                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")},
174                 null);
175 
176         // Build a mock request
177         MockHttpServletRequest request = new MockHttpServletRequest();
178         MockHttpServletResponse response = new MockHttpServletResponse();
179         FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
180 
181         // Prepare filter
182         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
183         filter.setContext(SecurityContextImpl.class);
184         filter.afterPropertiesSet();
185 
186         // Execute filter
187         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
188             request, response, chain);
189 
190         // Obtain new/updated Authentication from HttpSession
191         SecurityContext context = (SecurityContext) request.getSession(false)
192                                                            .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
193         assertEquals(updatedPrincipal,
194             ((SecurityContext) context).getAuthentication());
195     }
196 
197     public void testHttpSessionNotCreatedUnlessContextHolderChanges()
198         throws Exception {
199         // Build a mock request
200         MockHttpServletRequest request = new MockHttpServletRequest(null, null);
201         MockHttpServletResponse response = new MockHttpServletResponse();
202         FilterChain chain = new MockFilterChain(null, null, null);
203 
204         // Prepare filter
205         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
206         filter.setContext(SecurityContextImpl.class);
207         filter.afterPropertiesSet();
208 
209         // Execute filter
210         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
211             request, response, chain);
212 
213         // Check the session is null
214         assertNull(request.getSession(false));
215     }
216 
217     public void testHttpSessionWithNonContextInWellKnownLocationIsOverwritten()
218         throws Exception {
219         // Build an Authentication object we simulate our Authentication changed it to
220         PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key",
221                 "someone", "password",
222                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")},
223                 null);
224 
225         // Build a mock request
226         MockHttpServletRequest request = new MockHttpServletRequest();
227         request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
228             "NOT_A_CONTEXT_OBJECT");
229 
230         MockHttpServletResponse response = new MockHttpServletResponse();
231         FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
232 
233         // Prepare filter
234         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
235         filter.setContext(SecurityContextImpl.class);
236         filter.afterPropertiesSet();
237 
238         // Execute filter
239         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
240             request, response, chain);
241 
242         // Obtain new/update Authentication from HttpSession
243         SecurityContext context = (SecurityContext) request.getSession()
244                                                            .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
245         assertEquals(updatedPrincipal,
246             ((SecurityContext) context).getAuthentication());
247     }
248 
249     private void executeFilterInContainerSimulator(FilterConfig filterConfig,
250         Filter filter, ServletRequest request, ServletResponse response,
251         FilterChain filterChain) throws ServletException, IOException {
252         filter.init(filterConfig);
253         filter.doFilter(request, response, filterChain);
254         filter.destroy();
255     }
256 
257     //~ Inner Classes ==========================================================
258 
259     private class MockFilterChain extends TestCase implements FilterChain {
260         private Authentication changeContextHolder;
261         private Authentication expectedOnContextHolder;
262         private IOException toThrowDuringChain;
263 
264         public MockFilterChain(Authentication expectedOnContextHolder,
265             Authentication changeContextHolder, IOException toThrowDuringChain) {
266             this.expectedOnContextHolder = expectedOnContextHolder;
267             this.changeContextHolder = changeContextHolder;
268             this.toThrowDuringChain = toThrowDuringChain;
269         }
270 
271         private MockFilterChain() {}
272 
273         public void doFilter(ServletRequest arg0, ServletResponse arg1)
274             throws IOException, ServletException {
275             if (expectedOnContextHolder != null) {
276                 assertEquals(expectedOnContextHolder,
277                     SecurityContextHolder.getContext().getAuthentication());
278             }
279 
280             if (changeContextHolder != null) {
281                 SecurityContext sc = SecurityContextHolder.getContext();
282                 sc.setAuthentication(changeContextHolder);
283                 SecurityContextHolder.setContext(sc);
284             }
285 
286             if (toThrowDuringChain != null) {
287                 throw toThrowDuringChain;
288             }
289         }
290     }
291 }