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.ui.x509;
17  
18  import junit.framework.TestCase;
19  
20  import org.acegisecurity.Authentication;
21  import org.acegisecurity.AuthenticationManager;
22  import org.acegisecurity.BadCredentialsException;
23  import org.acegisecurity.MockAuthenticationManager;
24  import org.acegisecurity.context.SecurityContextHolder;
25  import org.acegisecurity.providers.x509.X509AuthenticationToken;
26  import org.acegisecurity.providers.x509.X509TestUtils;
27  import org.acegisecurity.ui.AbstractProcessingFilter;
28  import org.acegisecurity.util.MockFilterChain;
29  
30  import org.springframework.mock.web.MockHttpServletRequest;
31  import org.springframework.mock.web.MockHttpServletResponse;
32  
33  import java.security.cert.X509Certificate;
34  
35  import javax.servlet.FilterChain;
36  import javax.servlet.ServletException;
37  
38  
39  /***
40   * Tests {@link org.acegisecurity.ui.x509.X509ProcessingFilter}.
41   *
42   * @author Luke Taylor
43   * @version $Id: X509ProcessingFilterTests.java,v 1.9 2005/11/17 00:55:49 benalex Exp $
44   */
45  public class X509ProcessingFilterTests extends TestCase {
46      //~ Constructors ===========================================================
47  
48      public X509ProcessingFilterTests() {
49          super();
50      }
51  
52      public X509ProcessingFilterTests(String arg0) {
53          super(arg0);
54      }
55  
56      //~ Methods ================================================================
57  
58      public final void setUp() throws Exception {
59          super.setUp();
60      }
61  
62      public void tearDown() {
63          SecurityContextHolder.getContext().setAuthentication(null);
64      }
65  
66      public void testAuthenticationIsNullWithNoCertificate()
67          throws Exception {
68          MockHttpServletRequest request = new MockHttpServletRequest();
69          MockHttpServletResponse response = new MockHttpServletResponse();
70          FilterChain chain = new MockFilterChain(true);
71  
72          AuthenticationManager authMgr = new MockX509AuthenticationManager();
73          X509ProcessingFilter filter = new X509ProcessingFilter();
74  
75          filter.setAuthenticationManager(authMgr);
76  
77          SecurityContextHolder.getContext().setAuthentication(null);
78          filter.doFilter(request, response, chain);
79  
80          Object lastException = request.getSession().getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY);
81  
82          assertNull("Authentication should be null",
83              SecurityContextHolder.getContext().getAuthentication());
84          assertTrue("BadCredentialsException should have been thrown",
85              lastException instanceof BadCredentialsException);
86      }
87  
88      public void testDoFilterWithNonHttpServletRequestDetected()
89          throws Exception {
90          X509ProcessingFilter filter = new X509ProcessingFilter();
91  
92          try {
93              filter.doFilter(null, new MockHttpServletResponse(),
94                  new MockFilterChain(false));
95              fail("Should have thrown ServletException");
96          } catch (ServletException expected) {
97              assertEquals("Can only process HttpServletRequest",
98                  expected.getMessage());
99          }
100     }
101 
102     public void testDoFilterWithNonHttpServletResponseDetected()
103         throws Exception {
104         X509ProcessingFilter filter = new X509ProcessingFilter();
105 
106         try {
107             filter.doFilter(new MockHttpServletRequest(null, null), null,
108                 new MockFilterChain(false));
109             fail("Should have thrown ServletException");
110         } catch (ServletException expected) {
111             assertEquals("Can only process HttpServletResponse",
112                 expected.getMessage());
113         }
114     }
115 
116     public void testFailedAuthentication() throws Exception {
117         MockHttpServletRequest request = new MockHttpServletRequest();
118         MockHttpServletResponse response = new MockHttpServletResponse();
119         FilterChain chain = new MockFilterChain(true);
120 
121         request.setAttribute("javax.servlet.request.X509Certificate",
122             new X509Certificate[] {X509TestUtils.buildTestCertificate()});
123 
124         AuthenticationManager authMgr = new MockAuthenticationManager(false);
125 
126         SecurityContextHolder.getContext().setAuthentication(null);
127 
128         X509ProcessingFilter filter = new X509ProcessingFilter();
129 
130         filter.setAuthenticationManager(authMgr);
131         filter.afterPropertiesSet();
132         filter.init(null);
133         filter.doFilter(request, response, chain);
134         filter.destroy();
135 
136         Authentication result = SecurityContextHolder.getContext()
137                                                      .getAuthentication();
138 
139         assertNull(result);
140     }
141 
142     public void testNeedsAuthenticationManager() throws Exception {
143         X509ProcessingFilter filter = new X509ProcessingFilter();
144 
145         try {
146             filter.afterPropertiesSet();
147             fail("Expected IllegalArgumentException");
148         } catch (IllegalArgumentException failed) {
149             // ignored
150         }
151     }
152 
153     public void testNormalOperation() throws Exception {
154         MockHttpServletRequest request = new MockHttpServletRequest();
155         MockHttpServletResponse response = new MockHttpServletResponse();
156         FilterChain chain = new MockFilterChain(true);
157 
158         request.setAttribute("javax.servlet.request.X509Certificate",
159             new X509Certificate[] {X509TestUtils.buildTestCertificate()});
160 
161         AuthenticationManager authMgr = new MockX509AuthenticationManager();
162 
163         SecurityContextHolder.getContext().setAuthentication(null);
164 
165         X509ProcessingFilter filter = new X509ProcessingFilter();
166 
167         filter.setAuthenticationManager(authMgr);
168         filter.afterPropertiesSet();
169         filter.init(null);
170         filter.doFilter(request, response, chain);
171         filter.destroy();
172 
173         Authentication result = SecurityContextHolder.getContext()
174                                                      .getAuthentication();
175 
176         assertNotNull(result);
177     }
178 
179     //~ Inner Classes ==========================================================
180 
181     private static class MockX509AuthenticationManager
182         implements AuthenticationManager {
183         public Authentication authenticate(Authentication a) {
184             if (!(a instanceof X509AuthenticationToken)) {
185                 TestCase.fail("Needed an X509Authentication token but found "
186                     + a);
187             }
188 
189             if (a.getCredentials() == null) {
190                 throw new BadCredentialsException(
191                     "Mock authentication manager rejecting null certificate");
192             }
193 
194             return a;
195         }
196     }
197 }