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.adapters.jboss;
17  
18  import junit.framework.TestCase;
19  
20  import org.acegisecurity.adapters.PrincipalAcegiUserToken;
21  
22  import org.jboss.security.SimplePrincipal;
23  
24  import java.io.IOException;
25  
26  import java.security.Principal;
27  import java.security.acl.Group;
28  
29  import java.util.Properties;
30  
31  import javax.security.auth.Subject;
32  import javax.security.auth.callback.Callback;
33  import javax.security.auth.callback.CallbackHandler;
34  import javax.security.auth.callback.NameCallback;
35  import javax.security.auth.callback.PasswordCallback;
36  import javax.security.auth.callback.UnsupportedCallbackException;
37  import javax.security.auth.login.FailedLoginException;
38  import javax.security.auth.login.LoginException;
39  
40  
41  /***
42   * Tests {@link JbossAcegiLoginModule}.
43   *
44   * @author Ben Alex
45   * @version $Id: JbossAcegiLoginModuleTests.java,v 1.2 2005/11/17 00:56:10 benalex Exp $
46   */
47  public class JbossAcegiLoginModuleTests extends TestCase {
48      //~ Instance fields ========================================================
49  
50      private final String ADAPTER_KEY = "my_key";
51  
52      //~ Constructors ===========================================================
53  
54      public JbossAcegiLoginModuleTests() {
55          super();
56      }
57  
58      public JbossAcegiLoginModuleTests(String arg0) {
59          super(arg0);
60      }
61  
62      //~ Methods ================================================================
63  
64      public final void setUp() throws Exception {
65          super.setUp();
66      }
67  
68      public static void main(String[] args) {
69          junit.textui.TestRunner.run(JbossAcegiLoginModuleTests.class);
70      }
71  
72      public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
73          throws Exception {
74          JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
75          Properties props = new Properties();
76          props.put("key", ADAPTER_KEY);
77          props.put("appContextLocation",
78              "org/acegisecurity/adapters/adaptertest-invalid.xml");
79  
80          try {
81              adapter.initialize(null, null, null, props);
82              fail("Should have thrown IllegalArgumentException");
83          } catch (IllegalArgumentException expected) {
84              assertTrue(true);
85          }
86      }
87  
88      public void testAdapterAbortsIfNoAppContextSpecified()
89          throws Exception {
90          JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
91  
92          Properties props = new Properties();
93          props.put("key", ADAPTER_KEY);
94  
95          try {
96              adapter.initialize(null, null, null, props);
97              fail("Should have thrown IllegalArgumentException");
98          } catch (IllegalArgumentException expected) {
99              assertEquals("appContextLocation must be defined",
100                 expected.getMessage());
101         }
102 
103         props = new Properties();
104         props.put("key", ADAPTER_KEY);
105         props.put("appContextLocation", "");
106 
107         try {
108             adapter.initialize(null, null, null, props);
109             fail("Should have thrown IllegalArgumentException");
110         } catch (IllegalArgumentException expected) {
111             assertEquals("appContextLocation must be defined",
112                 expected.getMessage());
113         }
114     }
115 
116     public void testAdapterAbortsIfNoKeySpecified() throws Exception {
117         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
118 
119         Properties props = new Properties();
120         props.put("appContextLocation",
121             "org/acegisecurity/adapters/adaptertest-valid.xml");
122 
123         try {
124             adapter.initialize(null, null, null, props);
125             fail("Should have thrown IllegalArgumentException");
126         } catch (IllegalArgumentException expected) {
127             assertEquals("key must be defined", expected.getMessage());
128         }
129 
130         props = new Properties();
131         props.put("key", "");
132         props.put("appContextLocation",
133             "org/acegisecurity/adapters/adaptertest-valid.xml");
134 
135         try {
136             adapter.initialize(null, null, null, props);
137             fail("Should have thrown IllegalArgumentException");
138         } catch (IllegalArgumentException expected) {
139             assertEquals("key must be defined", expected.getMessage());
140         }
141     }
142 
143     public void testAdapterAbortsWithIncorrectApplicationContextLocation()
144         throws Exception {
145         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
146 
147         Properties props = new Properties();
148         props.put("key", ADAPTER_KEY);
149         props.put("appContextLocation", "INVALID_PATH");
150 
151         try {
152             adapter.initialize(null, null, null, props);
153             fail("Should have thrown IllegalArgumentException");
154         } catch (IllegalArgumentException expected) {
155             assertTrue("Cannot locate INVALID_PATH".equals(
156                     expected.getMessage()));
157         }
158     }
159 
160     public void testAdapterFailsToAuthenticateIfNoCallbackHandlerAvailable()
161         throws Exception {
162         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
163         Properties props = new Properties();
164         props.put("key", ADAPTER_KEY);
165         props.put("appContextLocation",
166             "org/acegisecurity/adapters/adaptertest-valid.xml");
167 
168         Subject subject = new Subject();
169 
170         adapter.initialize(subject, null, null, props);
171 
172         try {
173             adapter.login();
174         } catch (LoginException loginException) {
175             assertEquals("Error: no CallbackHandler available to collect authentication information",
176                 loginException.getMessage());
177         }
178     }
179 
180     public void testAdapterStartsUpSuccess() throws Exception {
181         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
182         Properties props = new Properties();
183         props.put("key", ADAPTER_KEY);
184         props.put("appContextLocation",
185             "org/acegisecurity/adapters/adaptertest-valid.xml");
186         adapter.initialize(null, null, null, props);
187         assertTrue(true);
188     }
189 
190     public void testAuthenticationFailsForIncorrectPassword()
191         throws Exception {
192         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
193         Properties props = new Properties();
194         props.put("key", ADAPTER_KEY);
195         props.put("appContextLocation",
196             "org/acegisecurity/adapters/adaptertest-valid.xml");
197 
198         Subject subject = new Subject();
199         CallbackHandler callback = new MockCallbackHandler("marissa", "kangaroo");
200 
201         adapter.initialize(subject, callback, null, props);
202 
203         try {
204             adapter.login();
205             fail("Should have thrown FailedLoginException");
206         } catch (FailedLoginException expected) {
207             assertTrue(true);
208         }
209     }
210 
211     public void testAuthenticationFailsForIncorrectUserName()
212         throws Exception {
213         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
214         Properties props = new Properties();
215         props.put("key", ADAPTER_KEY);
216         props.put("appContextLocation",
217             "org/acegisecurity/adapters/adaptertest-valid.xml");
218 
219         Subject subject = new Subject();
220         CallbackHandler callback = new MockCallbackHandler("melissa", "koala");
221 
222         adapter.initialize(subject, callback, null, props);
223 
224         try {
225             adapter.login();
226             fail("Should have thrown FailedLoginException");
227         } catch (FailedLoginException expected) {
228             assertTrue(true);
229         }
230     }
231 
232     public void testAuthenticationSuccess() throws Exception {
233         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
234         Properties props = new Properties();
235         props.put("key", ADAPTER_KEY);
236         props.put("appContextLocation",
237             "org/acegisecurity/adapters/adaptertest-valid.xml");
238 
239         Subject subject = new Subject();
240         CallbackHandler callback = new MockCallbackHandler("marissa", "koala");
241 
242         adapter.initialize(subject, callback, null, props);
243         assertTrue(adapter.login());
244 
245         Principal result = adapter.getIdentity();
246 
247         if (!(result instanceof PrincipalAcegiUserToken)) {
248             fail("Should have returned PrincipalAcegiUserToken");
249         }
250 
251         PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
252         assertEquals("marissa", castResult.getPrincipal());
253         assertEquals("koala", castResult.getCredentials());
254         assertEquals("ROLE_TELLER",
255             castResult.getAuthorities()[0].getAuthority());
256         assertEquals("ROLE_SUPERVISOR",
257             castResult.getAuthorities()[1].getAuthority());
258         assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
259     }
260 
261     public void testAuthenticationWithNullPasswordHandledGracefully()
262         throws Exception {
263         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
264         Properties props = new Properties();
265         props.put("key", ADAPTER_KEY);
266         props.put("appContextLocation",
267             "org/acegisecurity/adapters/adaptertest-valid.xml");
268 
269         Subject subject = new Subject();
270         CallbackHandler callback = new MockCallbackHandler("marissa", null);
271 
272         adapter.initialize(subject, callback, null, props);
273 
274         try {
275             adapter.login();
276             fail("Should have thrown FailedLoginException");
277         } catch (FailedLoginException expected) {
278             assertTrue(true);
279         }
280     }
281 
282     public void testAuthenticationWithNullUserNameAndNullPasswordHandledGracefully()
283         throws Exception {
284         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
285         Properties props = new Properties();
286         props.put("key", ADAPTER_KEY);
287         props.put("appContextLocation",
288             "org/acegisecurity/adapters/adaptertest-valid.xml");
289 
290         Subject subject = new Subject();
291         CallbackHandler callback = new MockCallbackHandler(null, null);
292 
293         adapter.initialize(subject, callback, null, props);
294 
295         try {
296             adapter.login();
297             fail("Should have thrown FailedLoginException");
298         } catch (FailedLoginException expected) {
299             assertTrue(true);
300         }
301     }
302 
303     public void testAuthenticationWithNullUserNameHandledGracefully()
304         throws Exception {
305         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
306         Properties props = new Properties();
307         props.put("key", ADAPTER_KEY);
308         props.put("appContextLocation",
309             "org/acegisecurity/adapters/adaptertest-valid.xml");
310 
311         Subject subject = new Subject();
312         CallbackHandler callback = new MockCallbackHandler(null, "kangaroo");
313 
314         adapter.initialize(subject, callback, null, props);
315 
316         try {
317             adapter.login();
318             fail("Should have thrown FailedLoginException");
319         } catch (FailedLoginException expected) {
320             assertTrue(true);
321         }
322     }
323 
324     public void testGetRoleSets() throws Exception {
325         JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
326         Properties props = new Properties();
327         props.put("key", ADAPTER_KEY);
328         props.put("appContextLocation",
329             "org/acegisecurity/adapters/adaptertest-valid.xml");
330 
331         Subject subject = new Subject();
332         CallbackHandler callback = new MockCallbackHandler("marissa", "koala");
333 
334         adapter.initialize(subject, callback, null, props);
335         assertTrue(adapter.login());
336 
337         Group[] result = adapter.getRoleSets();
338         assertEquals(1, result.length); // SimpleGroup called "Roles"
339 
340         Group roles = result[0];
341         assertTrue(roles.isMember(new SimplePrincipal("ROLE_TELLER")));
342         assertTrue(roles.isMember(new SimplePrincipal("ROLE_SUPERVISOR")));
343     }
344 
345     //~ Inner Classes ==========================================================
346 
347     private class MockCallbackHandler implements CallbackHandler {
348         private String password;
349         private String username;
350 
351         public MockCallbackHandler(String username, String password) {
352             this.username = username;
353             this.password = password;
354         }
355 
356         private MockCallbackHandler() {
357             super();
358         }
359 
360         public void handle(Callback[] callbacks)
361             throws IOException, UnsupportedCallbackException {
362             for (int i = 0; i < callbacks.length; i++) {
363                 if (callbacks[i] instanceof NameCallback) {
364                     ((NameCallback) callbacks[i]).setName(username);
365                 } else if (callbacks[i] instanceof PasswordCallback) {
366                     if (this.password == null) {
367                         ((PasswordCallback) callbacks[i]).setPassword(null);
368                     } else {
369                         ((PasswordCallback) callbacks[i]).setPassword(password
370                             .toCharArray());
371                     }
372                 } else {
373                     throw new UnsupportedCallbackException(callbacks[i]);
374                 }
375             }
376         }
377     }
378 }