    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.context;
    17
    18  import junit.framework.TestCase;
    19
    20  import org.acegisecurity.Authentication;
    21  import org.acegisecurity.GrantedAuthority;
    22  import org.acegisecurity.GrantedAuthorityImpl;
    23  import org.acegisecurity.MockFilterConfig;
    24
    25  import org.acegisecurity.adapters.PrincipalAcegiUserToken;
    26
    27  import org.springframework.mock.web.MockHttpServletRequest;
    28  import org.springframework.mock.web.MockHttpServletResponse;
    29
    30  import java.io.IOException;
    31
    32  import javax.servlet.Filter;
    33  import javax.servlet.FilterChain;
    34  import javax.servlet.FilterConfig;
    35  import javax.servlet.ServletException;
    36  import javax.servlet.ServletRequest;
    37  import javax.servlet.ServletResponse;
    38
    39
    40  /***
    41   * Tests {@link HttpSessionContextIntegrationFilter}.
    42   *
    43   * @author Ben Alex
    44   * @version $Id: HttpSessionContextIntegrationFilterTests.java,v 1.9 2005/11/25 00:26:29 benalex Exp $
    45   */
    46  public class HttpSessionContextIntegrationFilterTests extends TestCase {
    47      //~ Constructors ===========================================================
    48
    49      public HttpSessionContextIntegrationFilterTests() {
    50          super();
    51      }
    52
    53      public HttpSessionContextIntegrationFilterTests(String arg0) {
    54          super(arg0);
    55      }
    56
    57      //~ Methods ================================================================
    58
    59      public static void main(String[] args) {
    60          junit.textui.TestRunner.run(HttpSessionContextIntegrationFilterTests.class);
    61      }
    62
    63      public void testDetectsMissingOrInvalidContext() throws Exception {
    64          HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
    65
    66          try {
    67              filter.setContext(null);
    68              filter.afterPropertiesSet();
    69              fail("Shown have thrown IllegalArgumentException");
    70          } catch (IllegalArgumentException expected) {
    71              assertTrue(true);
    72          }
    73
    74          try {
    75              filter.setContext(Integer.class);
    76              assertEquals(Integer.class, filter.getContext());
    77              filter.afterPropertiesSet();
    78              fail("Shown have thrown IllegalArgumentException");
    79          } catch (IllegalArgumentException expected) {
    80              assertTrue(true);
    81          }
    82      }
    83
    84      public void testExceptionWithinFilterChainStillClearsSecurityContextHolder()
    85          throws Exception {
    86          // Build an Authentication object we simulate came from HttpSession
    87          PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key",
    88                  "someone", "password",
    89                  new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")},
    90                  null);
    91
    92          // Build a Context to store in HttpSession (simulating prior request)
    93          SecurityContext sc = new SecurityContextImpl();
    94          sc.setAuthentication(sessionPrincipal);
    95
    96          // Build a mock request
    97          MockHttpServletRequest request = new MockHttpServletRequest();
    98          request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
    99              sc);
    100
    101         MockHttpServletResponse response = new MockHttpServletResponse();
    102         FilterChain chain = new MockFilterChain(sessionPrincipal, null,
    103                 new IOException());
    104
    105         // Prepare filter
    106         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
    107         filter.setContext(SecurityContextImpl.class);
    108         filter.afterPropertiesSet();
    109
    110         // Execute filter
    111         try {
    112             executeFilterInContainerSimulator(new MockFilterConfig(), filter,
    113                 request, response, chain);
    114             fail(
    115                 "We should have received the IOException thrown inside the filter chain here");
    116         } catch (IOException ioe) {
    117             assertTrue(true);
    118         }
    119
    120         // Check the SecurityContextHolder is null, even though an exception was thrown during chain
    121         assertEquals(new SecurityContextImpl(),
    122             SecurityContextHolder.getContext());
    123     }
    124
    125     public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
    126         throws Exception {
    127         // Build an Authentication object we simulate came from HttpSession
    128         PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key",
    129                 "someone", "password",
    130                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")},
    131                 null);
    132
    133         // Build an Authentication object we simulate our Authentication changed it to
    134         PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key",
    135                 "someone", "password",
    136                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")},
    137                 null);
    138
    139         // Build a Context to store in HttpSession (simulating prior request)
    140         SecurityContext sc = new SecurityContextImpl();
    141         sc.setAuthentication(sessionPrincipal);
    142
    143         // Build a mock request
    144         MockHttpServletRequest request = new MockHttpServletRequest();
    145         request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
    146             sc);
    147
    148         MockHttpServletResponse response = new MockHttpServletResponse();
    149         FilterChain chain = new MockFilterChain(sessionPrincipal,
    150                 updatedPrincipal, null);
    151
    152         // Prepare filter
    153         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
    154         filter.setContext(SecurityContextImpl.class);
    155         filter.afterPropertiesSet();
    156
    157         // Execute filter
    158         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
    159             request, response, chain);
    160
    161         // Obtain new/update Authentication from HttpSession
    162         SecurityContext context = (SecurityContext) request.getSession()
    163                                                            .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
    164         assertEquals(updatedPrincipal,
    165             ((SecurityContext) context).getAuthentication());
    166     }
    167
    168     public void testHttpSessionCreatedWhenContextHolderChanges()
    169         throws Exception {
    170         // Build an Authentication object we simulate our Authentication changed it to
    171         PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key",
    172                 "someone", "password",
    173                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")},
    174                 null);
    175
    176         // Build a mock request
    177         MockHttpServletRequest request = new MockHttpServletRequest();
    178         MockHttpServletResponse response = new MockHttpServletResponse();
    179         FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
    180
    181         // Prepare filter
    182         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
    183         filter.setContext(SecurityContextImpl.class);
    184         filter.afterPropertiesSet();
    185
    186         // Execute filter
    187         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
    188             request, response, chain);
    189
    190         // Obtain new/updated Authentication from HttpSession
    191         SecurityContext context = (SecurityContext) request.getSession(false)
    192                                                            .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
    193         assertEquals(updatedPrincipal,
    194             ((SecurityContext) context).getAuthentication());
    195     }
    196
    197     public void testHttpSessionNotCreatedUnlessContextHolderChanges()
    198         throws Exception {
    199         // Build a mock request
    200         MockHttpServletRequest request = new MockHttpServletRequest(null, null);
    201         MockHttpServletResponse response = new MockHttpServletResponse();
    202         FilterChain chain = new MockFilterChain(null, null, null);
    203
    204         // Prepare filter
    205         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
    206         filter.setContext(SecurityContextImpl.class);
    207         filter.afterPropertiesSet();
    208
    209         // Execute filter
    210         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
    211             request, response, chain);
    212
    213         // Check the session is null
    214         assertNull(request.getSession(false));
    215     }
    216
    217     public void testHttpSessionWithNonContextInWellKnownLocationIsOverwritten()
    218         throws Exception {
    219         // Build an Authentication object we simulate our Authentication changed it to
    220         PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key",
    221                 "someone", "password",
    222                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")},
    223                 null);
    224
    225         // Build a mock request
    226         MockHttpServletRequest request = new MockHttpServletRequest();
    227         request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
    228             "NOT_A_CONTEXT_OBJECT");
    229
    230         MockHttpServletResponse response = new MockHttpServletResponse();
    231         FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
    232
    233         // Prepare filter
    234         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
    235         filter.setContext(SecurityContextImpl.class);
    236         filter.afterPropertiesSet();
    237
    238         // Execute filter
    239         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
    240             request, response, chain);
    241
    242         // Obtain new/update Authentication from HttpSession
    243         SecurityContext context = (SecurityContext) request.getSession()
    244                                                            .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
    245         assertEquals(updatedPrincipal,
    246             ((SecurityContext) context).getAuthentication());
    247     }
    248
    249     private void executeFilterInContainerSimulator(FilterConfig filterConfig,
    250         Filter filter, ServletRequest request, ServletResponse response,
    251         FilterChain filterChain) throws ServletException, IOException {
    252         filter.init(filterConfig);
    253         filter.doFilter(request, response, filterChain);
    254         filter.destroy();
    255     }
    256
    257     //~ Inner Classes ==========================================================
    258
    259     private class MockFilterChain extends TestCase implements FilterChain {
    260         private Authentication changeContextHolder;
    261         private Authentication expectedOnContextHolder;
    262         private IOException toThrowDuringChain;
    263
    264         public MockFilterChain(Authentication expectedOnContextHolder,
    265             Authentication changeContextHolder, IOException toThrowDuringChain) {
    266             this.expectedOnContextHolder = expectedOnContextHolder;
    267             this.changeContextHolder = changeContextHolder;
    268             this.toThrowDuringChain = toThrowDuringChain;
    269         }
    270
    271         private MockFilterChain() {}
    272
    273         public void doFilter(ServletRequest arg0, ServletResponse arg1)
    274             throws IOException, ServletException {
    275             if (expectedOnContextHolder != null) {
    276                 assertEquals(expectedOnContextHolder,
    277                     SecurityContextHolder.getContext().getAuthentication());
    278             }
    279
    280             if (changeContextHolder != null) {
    281                 SecurityContext sc = SecurityContextHolder.getContext();
    282                 sc.setAuthentication(changeContextHolder);
    283                 SecurityContextHolder.setContext(sc);
    284             }
    285
    286             if (toThrowDuringChain != null) {
    287                 throw toThrowDuringChain;
    288             }
    289         }
    290     }
    291 }