1   /* Copyright 2004 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.providers.jaas;
17  
18  import junit.framework.TestCase;
19  import org.acegisecurity.*;
20  import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
21  import org.acegisecurity.context.SecurityContextImpl;
22  import org.acegisecurity.ui.session.HttpSessionDestroyedEvent;
23  import org.acegisecurity.providers.TestingAuthenticationToken;
24  import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
25  import org.springframework.context.ApplicationContext;
26  import org.springframework.context.support.ClassPathXmlApplicationContext;
27  import org.springframework.mock.web.MockHttpSession;
28  
29  import javax.security.auth.login.LoginException;
30  import javax.security.auth.login.LoginContext;
31  import java.net.URL;
32  import java.security.Security;
33  import java.util.Arrays;
34  import java.util.List;
35  
36  
37  /***
38   * Tests for the JaasAuthenticationProvider
39   *
40   * @author Ray Krueger
41   * @version $Id: JaasAuthenticationProviderTests.java,v 1.11 2005/11/17 00:55:47 benalex Exp $
42   */
43  public class JaasAuthenticationProviderTests extends TestCase {
44      //~ Instance fields ========================================================
45  
46      private ApplicationContext context;
47      private JaasAuthenticationProvider jaasProvider;
48      private JaasEventCheck eventCheck;
49  
50      //~ Methods ================================================================
51  
52      public void testBadPassword() {
53          try {
54              jaasProvider.authenticate(new UsernamePasswordAuthenticationToken("user", "asdf"));
55              fail("LoginException should have been thrown for the bad password");
56          } catch (AuthenticationException e) {
57          }
58  
59          assertNotNull("Failure event not fired", eventCheck.failedEvent);
60          assertNotNull("Failure event exception was null",
61                  eventCheck.failedEvent.getException());
62          assertNull("Success event was fired", eventCheck.successEvent);
63      }
64  
65      public void testBadUser() {
66          try {
67              jaasProvider.authenticate(new UsernamePasswordAuthenticationToken("asdf", "password"));
68              fail("LoginException should have been thrown for the bad user");
69          } catch (AuthenticationException e) {
70          }
71  
72          assertNotNull("Failure event not fired", eventCheck.failedEvent);
73          assertNotNull("Failure event exception was null",
74                  eventCheck.failedEvent.getException());
75          assertNull("Success event was fired", eventCheck.successEvent);
76      }
77  
78      public void testConfigurationLoop() throws Exception {
79          String resName = "/" + getClass().getName().replace('.', '/') + ".conf";
80          URL url = getClass().getResource(resName);
81  
82          Security.setProperty("login.config.url.1", url.toString());
83  
84          setUp();
85          testFull();
86      }
87  
88      public void testDetectsMissingLoginConfig() throws Exception {
89          JaasAuthenticationProvider myJaasProvider = new JaasAuthenticationProvider();
90          myJaasProvider.setApplicationContext(context);
91          myJaasProvider.setAuthorityGranters(jaasProvider.getAuthorityGranters());
92          myJaasProvider.setCallbackHandlers(jaasProvider.getCallbackHandlers());
93          myJaasProvider.setLoginContextName(jaasProvider.getLoginContextName());
94  
95          try {
96              myJaasProvider.afterPropertiesSet();
97              fail("Should have thrown ApplicationContextException");
98          } catch (IllegalArgumentException expected) {
99              assertTrue(expected.getMessage().startsWith("loginConfig must be set on"));
100         }
101     }
102 
103     public void testDetectsMissingLoginContextName() throws Exception {
104         JaasAuthenticationProvider myJaasProvider = new JaasAuthenticationProvider();
105         myJaasProvider.setApplicationContext(context);
106         myJaasProvider.setAuthorityGranters(jaasProvider.getAuthorityGranters());
107         myJaasProvider.setCallbackHandlers(jaasProvider.getCallbackHandlers());
108         myJaasProvider.setLoginConfig(jaasProvider.getLoginConfig());
109         myJaasProvider.setLoginContextName(null);
110 
111         try {
112             myJaasProvider.afterPropertiesSet();
113             fail("Should have thrown IllegalArgumentException");
114         } catch (IllegalArgumentException expected) {
115             assertTrue(expected.getMessage().startsWith("loginContextName must be set on"));
116         }
117 
118         myJaasProvider.setLoginContextName("");
119 
120         try {
121             myJaasProvider.afterPropertiesSet();
122             fail("Should have thrown IllegalArgumentException");
123         } catch (IllegalArgumentException expected) {
124             assertTrue(expected.getMessage().startsWith("loginContextName must be set on"));
125         }
126     }
127 
128     public void testFull() throws Exception {
129         GrantedAuthorityImpl role1 = new GrantedAuthorityImpl("ROLE_1");
130         GrantedAuthorityImpl role2 = new GrantedAuthorityImpl("ROLE_2");
131 
132         GrantedAuthority[] defaultAuths = new GrantedAuthority[]{role1, role2, };
133 
134         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user",
135                 "password", defaultAuths);
136 
137         assertTrue(jaasProvider.supports(UsernamePasswordAuthenticationToken.class));
138 
139         Authentication auth = jaasProvider.authenticate(token);
140 
141         assertNotNull(jaasProvider.getAuthorityGranters());
142         assertNotNull(jaasProvider.getCallbackHandlers());
143         assertNotNull(jaasProvider.getLoginConfig());
144         assertNotNull(jaasProvider.getLoginContextName());
145 
146         List list = Arrays.asList(auth.getAuthorities());
147 
148         assertTrue("GrantedAuthorities should contain ROLE_TEST1",
149                 list.contains(new GrantedAuthorityImpl("ROLE_TEST1")));
150 
151         assertTrue("GrantedAuthorities should contain ROLE_TEST2",
152                 list.contains(new GrantedAuthorityImpl("ROLE_TEST2")));
153 
154         assertTrue("GrantedAuthorities should contain ROLE_1",
155                 list.contains(role1));
156 
157         assertTrue("GrantedAuthorities should contain ROLE_2",
158                 list.contains(role2));
159 
160         boolean foundit = false;
161 
162         for (int i = 0; i < list.size(); i++) {
163             Object obj = list.get(i);
164 
165             if (obj instanceof JaasGrantedAuthority) {
166                 JaasGrantedAuthority grant = (JaasGrantedAuthority) obj;
167                 assertNotNull("Principal was null on JaasGrantedAuthority",
168                         grant.getPrincipal());
169                 foundit = true;
170             }
171         }
172 
173         assertTrue("Could not find a JaasGrantedAuthority", foundit);
174 
175         assertNotNull("Success event not fired", eventCheck.successEvent);
176         assertEquals("Auth objects are not equal", auth,
177                 eventCheck.successEvent.getAuthentication());
178 
179         assertNull("Failure event was fired", eventCheck.failedEvent);
180     }
181 
182     public void testLoginExceptionResolver() {
183         assertNotNull(jaasProvider.getLoginExceptionResolver());
184         jaasProvider.setLoginExceptionResolver(new LoginExceptionResolver() {
185             public AcegiSecurityException resolveException(LoginException e) {
186                 return new LockedException("This is just a test!");
187             }
188         });
189 
190         try {
191             jaasProvider.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
192         } catch (LockedException e) {
193         } catch (Exception e) {
194             fail("LockedException should have been thrown and caught");
195         }
196     }
197 
198     public void testNullDefaultAuthorities() {
199         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user",
200                 "password", null);
201 
202         assertTrue(jaasProvider.supports(UsernamePasswordAuthenticationToken.class));
203 
204         Authentication auth = jaasProvider.authenticate(token);
205         assertTrue("Only ROLE_TEST1 and ROLE_TEST2 should have been returned",
206                 auth.getAuthorities().length == 2);
207     }
208 
209     public void testGetApplicationContext() throws Exception {
210         assertNotNull(jaasProvider.getApplicationContext());
211     }
212 
213     public void testUnsupportedAuthenticationObjectReturnsNull() {
214         assertNull(jaasProvider.authenticate(new TestingAuthenticationToken("foo", "bar",
215                 new GrantedAuthority[]{})));
216     }
217 
218     public void testLogout() throws Exception {
219 
220         MockLoginContext loginContext = new MockLoginContext(jaasProvider.getLoginContextName());
221 
222         JaasAuthenticationToken token = new JaasAuthenticationToken(null, null, loginContext);
223 
224         SecurityContextImpl context = new SecurityContextImpl();
225         context.setAuthentication(token);
226 
227         MockHttpSession mockSession = new MockHttpSession();
228         mockSession.setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, context);
229 
230         jaasProvider.onApplicationEvent(new HttpSessionDestroyedEvent(mockSession));
231 
232         assertTrue(loginContext.loggedOut);
233     }
234 
235     protected void setUp() throws Exception {
236         String resName = "/" + getClass().getName().replace('.', '/') + ".xml";
237         context = new ClassPathXmlApplicationContext(resName);
238         eventCheck = (JaasEventCheck) context.getBean("eventCheck");
239         jaasProvider = (JaasAuthenticationProvider) context.getBean("jaasAuthenticationProvider");
240     }
241 
242     private static class MockLoginContext extends LoginContext {
243 
244         boolean loggedOut = false;
245 
246         public MockLoginContext(String loginModule) throws LoginException {
247             super(loginModule);
248         }
249 
250         public void logout() throws LoginException {
251             this.loggedOut = true;
252         }
253     }
254 }