    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.switchuser;
    17
    18  import junit.framework.TestCase;
    19
    20  import org.acegisecurity.AccountExpiredException;
    21  import org.acegisecurity.Authentication;
    22  import org.acegisecurity.AuthenticationException;
    23  import org.acegisecurity.CredentialsExpiredException;
    24  import org.acegisecurity.DisabledException;
    25  import org.acegisecurity.GrantedAuthority;
    26  import org.acegisecurity.GrantedAuthorityImpl;
    27  import org.acegisecurity.context.SecurityContextHolder;
    28  import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
    29  import org.acegisecurity.userdetails.User;
    30  import org.acegisecurity.userdetails.UserDetails;
    31  import org.acegisecurity.userdetails.UserDetailsService;
    32  import org.acegisecurity.userdetails.UsernameNotFoundException;
    33  import org.acegisecurity.util.MockFilterChain;
    34  import org.springframework.dao.DataAccessException;
    35  import org.springframework.mock.web.MockHttpServletRequest;
    36  import org.springframework.mock.web.MockHttpServletResponse;
    37
    38
    39  /***
    40   * Tests {@link org.acegisecurity.ui.switchuser.SwitchUserProcessingFilter}.
    41   *
    42   * @author Mark St.Godard
    43   * @version $Id: SwitchUserProcessingFilterTests.java,v 1.8 2005/11/30 01:23:34 benalex Exp $
    44   */
    45  public class SwitchUserProcessingFilterTests extends TestCase {
    46      //~ Constructors ===========================================================
    47
    48      public SwitchUserProcessingFilterTests() {
    49          super();
    50      }
    51
    52      public SwitchUserProcessingFilterTests(String arg0) {
    53          super(arg0);
    54      }
    55
    56      //~ Methods ================================================================
    57
    58      public final void setUp() throws Exception {
    59          super.setUp();
    60      }
    61
    62      public static void main(String[] args) {
    63          junit.textui.TestRunner.run(SwitchUserProcessingFilterTests.class);
    64      }
    65
    66      public void testAttemptSwitchToUnknownUser() throws Exception {
    67          // set current user
    68          UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano",
    69                  "hawaii50");
    70          SecurityContextHolder.getContext().setAuthentication(auth);
    71
    72          MockHttpServletRequest request = new MockHttpServletRequest();
    73          request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY,
    74              "user-that-doesnt-exist");
    75
    76          SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    77          filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    78
    79          try {
    80              Authentication result = filter.attemptSwitchUser(request);
    81
    82              fail("Should not be able to switch to unknown user");
    83          } catch (UsernameNotFoundException expected) {}
    84      }
    85
    86      public void testAttemptSwitchToUserThatIsDisabled()
    87          throws Exception {
    88          // set current user
    89          UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano",
    90                  "hawaii50");
    91          SecurityContextHolder.getContext().setAuthentication(auth);
    92
    93          MockHttpServletRequest request = new MockHttpServletRequest();
    94
    95          // this user is disabled
    96          request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY,
    97              "mcgarrett");
    98
    99          SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    100         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    101
    102         try {
    103             Authentication result = filter.attemptSwitchUser(request);
    104
    105             fail("Should not be able to switch to disabled user");
    106         } catch (DisabledException expected) {
    107             // user should be disabled
    108         }
    109     }
    110
    111     public void testAttemptSwitchToUserWithAccountExpired()
    112         throws Exception {
    113         // set current user
    114         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano",
    115                 "hawaii50");
    116         SecurityContextHolder.getContext().setAuthentication(auth);
    117
    118         MockHttpServletRequest request = new MockHttpServletRequest();
    119
    120         // this user is disabled
    121         request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY,
    122             "wofat");
    123
    124         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    125         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    126
    127         try {
    128             Authentication result = filter.attemptSwitchUser(request);
    129
    130             fail("Should not be able to switch to user with expired account");
    131         } catch (AccountExpiredException expected) {
    132             // expected user account expired
    133         }
    134     }
    135
    136     public void testAttemptSwitchToUserWithExpiredCredentials()
    137         throws Exception {
    138         // set current user
    139         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano",
    140                 "hawaii50");
    141         SecurityContextHolder.getContext().setAuthentication(auth);
    142
    143         MockHttpServletRequest request = new MockHttpServletRequest();
    144
    145         // this user is disabled
    146         request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY,
    147             "steve");
    148
    149         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    150         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    151
    152         try {
    153             Authentication result = filter.attemptSwitchUser(request);
    154
    155             fail("Should not be able to switch to user with expired account");
    156         } catch (CredentialsExpiredException expected) {
    157             // user credentials expired
    158         }
    159     }
    160
    161     public void testAttemptSwitchUser() throws Exception {
    162         // set current user
    163         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano",
    164                 "hawaii50");
    165         SecurityContextHolder.getContext().setAuthentication(auth);
    166
    167         MockHttpServletRequest request = new MockHttpServletRequest();
    168         request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY,
    169             "jacklord");
    170
    171         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    172         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    173
    174         Authentication result = filter.attemptSwitchUser(request);
    175         assertTrue(result != null);
    176     }
    177
    178     public void testBadConfigMissingAuthenticationDao() {
    179         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    180         filter.setSwitchUserUrl("/j_acegi_switch_user");
    181         filter.setExitUserUrl("/j_acegi_exit_user");
    182         filter.setTargetUrl("/main.jsp");
    183
    184         try {
    185             filter.afterPropertiesSet();
    186             fail("Expect to fail due to missing 'authenticationDao'");
    187         } catch (Exception expected) {
    188             // expected exception
    189         }
    190     }
    191
    192     public void testBadConfigMissingTargetUrl() {
    193         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    194         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    195         filter.setSwitchUserUrl("/j_acegi_switch_user");
    196         filter.setExitUserUrl("/j_acegi_exit_user");
    197
    198         try {
    199             filter.afterPropertiesSet();
    200             fail("Expect to fail due to missing 'targetUrl'");
    201         } catch (Exception expected) {
    202             // expected exception
    203         }
    204     }
    205
    206     public void testDefaultProcessesFilterUrlWithPathParameter() {
    207         MockHttpServletRequest request = createMockSwitchRequest();
    208         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    209         filter.setSwitchUserUrl("/j_acegi_switch_user");
    210
    211         request.setRequestURI(
    212             "/webapp/j_acegi_switch_user;jsessionid=8JHDUD723J8");
    213         assertTrue(filter.requiresSwitchUser(request));
    214     }
    215
    216     public void testExitRequestUserJackLordToDano() throws Exception {
    217         // original user
    218         GrantedAuthority[] auths = {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
    219                     "ROLE_TWO")};
    220         UsernamePasswordAuthenticationToken source = new UsernamePasswordAuthenticationToken("dano",
    221                 "hawaii50", auths);
    222
    223         // set current user (Admin)
    224         GrantedAuthority[] adminAuths = {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
    225                     "ROLE_TWO"), new SwitchUserGrantedAuthority("PREVIOUS_ADMINISTRATOR",
    226                     source)};
    227         UsernamePasswordAuthenticationToken admin = new UsernamePasswordAuthenticationToken("jacklord",
    228                 "hawaii50", adminAuths);
    229
    230         SecurityContextHolder.getContext().setAuthentication(admin);
    231
    232         // http request
    233         MockHttpServletRequest request = createMockSwitchRequest();
    234         request.setRequestURI("/j_acegi_exit_user");
    235
    236         // http response
    237         MockHttpServletResponse response = new MockHttpServletResponse();
    238
    239         // setup filter
    240         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    241         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    242         filter.setExitUserUrl("/j_acegi_exit_user");
    243
    244         MockFilterChain chain = new MockFilterChain(true);
    245
    246         // run 'exit'
    247         filter.doFilter(request, response, chain);
    248
    249         // check current user, should be back to original user (dano)
    250         Authentication targetAuth = SecurityContextHolder.getContext()
    251                                                          .getAuthentication();
    252         assertNotNull(targetAuth);
    253         assertEquals("dano", targetAuth.getPrincipal());
    254     }
    255
    256     public void testExitUserWithNoCurrentUser() throws Exception {
    257         // no current user in secure context
    258         SecurityContextHolder.getContext().setAuthentication(null);
    259
    260         // http request
    261         MockHttpServletRequest request = createMockSwitchRequest();
    262         request.setRequestURI("/j_acegi_exit_user");
    263
    264         // http response
    265         MockHttpServletResponse response = new MockHttpServletResponse();
    266
    267         // setup filter
    268         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    269         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    270         filter.setExitUserUrl("/j_acegi_exit_user");
    271
    272         MockFilterChain chain = new MockFilterChain(true);
    273
    274         // run 'exit', expect fail due to no current user
    275         try {
    276             filter.doFilter(request, response, chain);
    277
    278             fail("Cannot exit from a user with no current user set!");
    279         } catch (AuthenticationException expected) {}
    280     }
    281
    282     public void testRedirectToTargetUrl() throws Exception {
    283         // set current user
    284         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano",
    285                 "hawaii50");
    286         SecurityContextHolder.getContext().setAuthentication(auth);
    287
    288         MockHttpServletRequest request = createMockSwitchRequest();
    289         request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY,
    290             "jacklord");
    291         request.setRequestURI("/webapp/j_acegi_switch_user");
    292
    293         MockHttpServletResponse response = new MockHttpServletResponse();
    294         MockFilterChain chain = new MockFilterChain(true);
    295
    296         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    297         filter.setSwitchUserUrl("/j_acegi_switch_user");
    298         filter.setTargetUrl("/webapp/someOtherUrl");
    299         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    300
    301         filter.doFilter(request, response, chain);
    302
    303         assertEquals("/webapp/someOtherUrl", response.getRedirectedUrl());
    304     }
    305
    306     public void testRequiresExitUser() {
    307         // filter
    308         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    309         filter.setExitUserUrl("/j_acegi_exit_user");
    310
    311         // request
    312         MockHttpServletRequest request = new MockHttpServletRequest();
    313         request.setRequestURI("/j_acegi_exit_user");
    314
    315         assertTrue(filter.requiresExitUser(request));
    316     }
    317
    318     public void testRequiresSwitch() {
    319         // filter
    320         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    321         filter.setSwitchUserUrl("/j_acegi_switch_user");
    322
    323         // request
    324         MockHttpServletRequest request = createMockSwitchRequest();
    325
    326         assertTrue(filter.requiresSwitchUser(request));
    327     }
    328
    329     public void testSwitchRequestFromDanoToJackLord() throws Exception {
    330         // set current user
    331         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano",
    332                 "hawaii50");
    333         SecurityContextHolder.getContext().setAuthentication(auth);
    334
    335         // http request
    336         MockHttpServletRequest request = new MockHttpServletRequest();
    337         request.setRequestURI("/webapp/j_acegi_switch_user");
    338         request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY,
    339             "jacklord");
    340
    341         // http response
    342         MockHttpServletResponse response = new MockHttpServletResponse();
    343
    344         // setup filter
    345         SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter();
    346         filter.setUserDetailsService(new MockAuthenticationDaoUserJackLord());
    347         filter.setSwitchUserUrl("/j_acegi_switch_user");
    348
    349         MockFilterChain chain = new MockFilterChain(true);
    350
    351         // test updates user token and context
    352         filter.doFilter(request, response, chain);
    353
    354         // check current user
    355         Authentication targetAuth = SecurityContextHolder.getContext()
    356                                                          .getAuthentication();
    357         assertNotNull(targetAuth);
    358         assertTrue(targetAuth.getPrincipal() instanceof UserDetails);
    359         assertEquals("jacklord", ((User)targetAuth.getPrincipal()).getUsername());
    360     }
    361
    362     private MockHttpServletRequest createMockSwitchRequest() {
    363         MockHttpServletRequest request = new MockHttpServletRequest();
    364         request.setScheme("http");
    365         request.setServerName("localhost");
    366         request.setRequestURI("/j_acegi_switch_user");
    367
    368         return request;
    369     }
    370
    371     //~ Inner Classes ==========================================================
    372
    373     private class MockAuthenticationDaoUserJackLord implements UserDetailsService {
    374         private String password = "hawaii50";
    375
    376         public void setPassword(String password) {
    377             this.password = password;
    378         }
    379
    380         public UserDetails loadUserByUsername(String username)
    381             throws UsernameNotFoundException, DataAccessException {
    382             // jacklord, dano  (active)
    383             // mcgarrett (disabled)
    384             // wofat (account expired)
    385             // steve (credentials expired)
    386             if ("jacklord".equals(username) || "dano".equals(username)) {
    387                 return new User(username, password, true, true, true, true,
    388                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
    389                             "ROLE_TWO")});
    390             } else if ("mcgarrett".equals(username)) {
    391                 return new User(username, password, false, true, true, true,
    392                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
    393                             "ROLE_TWO")});
    394             } else if ("wofat".equals(username)) {
    395                 return new User(username, password, true, false, true, true,
    396                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
    397                             "ROLE_TWO")});
    398             } else if ("steve".equals(username)) {
    399                 return new User(username, password, true, true, false, true,
    400                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
    401                             "ROLE_TWO")});
    402             } else {
    403                 throw new UsernameNotFoundException("Could not find: "
    404                     + username);
    405             }
    406         }
    407     }
    408 }