Thanks for that. It led me to this configuration which effectively kills all redirects.
Code:
<http auto-config='true' entry-point-ref="authenticationEntryPoint">
<intercept-url pattern="/api/**" access="ROLE_USER"/>
<intercept-url pattern="/**" access="ROLE_ANONYMOUS"/>
<form-login authentication-success-handler-ref="ajaxAuthenticationSuccessHandler"
authentication-failure-handler-ref="ajaxAuthenticationFailureHandler"/>
<logout success-handler-ref="ajaxLogoutSuccessHandler" />
</http>
<beans:bean id="authenticationEntryPoint"
class="com.pykl.spring.security.Http401DeniedEntryPoint"/>
<beans:bean id="ajaxAuthenticationSuccessHandler"
class="com.pykl.spring.security.AjaxAuthenticationSuccessHandler"/>
<beans:bean id="ajaxAuthenticationFailureHandler"
class="com.pykl.spring.security.AjaxAuthenticationFailureHandler"/>
<beans:bean id="ajaxLogoutSuccessHandler"
class="com.pykl.spring.security.AjaxLogoutSuccessHandler"/>
I am developing a single-page application, so page reloading does not typically occur as part of normal navigation. Most content is fetched via AJAX. Here is my standard workflow which is working as expected:
- AJAX request for /api/ping (protected resource)
- Spring Security filter intercepts and my failure handler returns a 401 code.
- AJAX error handler fires, stores the original request locally and displays the auth form to the user.
- User submits form to j_spring_security_check
- Successful submission results in an 'AUTH_SUCCESS' result.
- Security context is stored in HTTP session for this user.
- Client refires original AJAX request
- Protected resource is returned as expected.
And here is the server log showing the expected context created and stored in the session:
Code:
DEBUG Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@1725daf7: Principal: org.springframework.security.core.userdetails.User@acc750af: Username: barney; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff8868: RemoteIpAddress: 0:0:0:0:0:0:0:1%0; SessionId: null; Granted Authorities: ROLE_USER
DEBUG HttpSession being created as SecurityContext is non-default
DEBUG SecurityContext stored to HttpSession: 'org.springframework.security.core.context.SecurityContextImpl@1725daf7: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@1725daf7: Principal: org.springframework.security.core.userdetails.User@acc750af: Username: barney; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff8868: RemoteIpAddress: 0:0:0:0:0:0:0:1%0; SessionId: null; Granted Authorities: ROLE_USER'
DEBUG SecurityContextHolder now cleared, as request processing completed
Now, if I refresh my browser to the / url, something unexpected occurs. I would expect Spring Security to pull my security context from the HTTP Session and everything would display as though I was an authenticated user. Instead, Spring Security cannot find a session (I have made sure the same JSESSIONID is passed in as in prior requests.) and the anonymous user context is created.
Code:
DEBUG / at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG No HttpSession currently exists
DEBUG No SecurityContext was available from the HttpSession: null. A new one will be created.
Seems like I am missing something fundamental.