    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 }