Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring security + Ajax session timeout issue

I have an app build with Spring MVC and secured with Spring security, a bunch of the controllers are JSON rest services that are all protected. I'm using LoginUrlAuthenticationEntryPoint to detect AJAX requests and send 403 ERROR CODE if session timeout occurs - all other requests just get redirected back to login page.

Below is the Spring Security XML snippet and the authenticationEntryPoint java class.

The issue is that the first AJAX Request after session timeout, Spring redirects to login page and the returns login page HTML, if I attempt to do AJAX request again (after redirect happens) the authenticationEntryPoint executes and HTTP Error Code 403 is returned. I have attempted the same thing using this mechanism http://distigme.wordpress.com/2012/11/01/ajax-and-spring-security-form-based-login/ and the same exact thing happens (on first AJAX request a redirect occurs, all subsequent AJAX requests HTTP 403 is returned). I do not want to get Redirect to login page for AJAX requests where session is timed out.

Any ideas?

<beans:bean id="authenticationEntryPoint"  class="mojo.ocs.web.AjaxAwareAuthenticationEntryPoint">
    <beans:constructor-arg name="loginUrl" value="/login"/>
</beans:bean>
<!-- ENTRY POINT REF IMPLEMENTATION -->
<http auto-config="true" use-expressions="true" access-denied-page="/accessdenied" entry-point-ref="authenticationEntryPoint">
    <intercept-url pattern="/login" access="isAnonymous()"/>
    <intercept-url pattern="/loginfailed" access="isAnonymous()"/>
    <intercept-url pattern="/welcome" access="isAuthenticated()" />
    <intercept-url pattern="/" access="isAuthenticated()" />
    <intercept-url pattern="/private_res/**" access="isAuthenticated()" />
    <intercept-url pattern="/tne/**" access="isAuthenticated()" />
    <intercept-url pattern="/team_reports/**" access="isAuthenticated()" />
    <form-login login-page="/login" default-target-url="/welcome" always-use-default-target="true" authentication-failure-url="/loginfailed" />
    <logout delete-cookies="JSESSIONID"  logout-success-url="/logout" invalidate-session="true"/>
    <session-management invalid-session-url="/login" />
</http>

Here is the LoginAuthenticationEntryPoint:

public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint     
{
    public AjaxAwareAuthenticationEntryPoint(String loginUrl) {
        super(loginUrl);
    }

    @Override
    public void commence(
        HttpServletRequest request,
        HttpServletResponse response,
        AuthenticationException authException)
        throws IOException, ServletException {
        String ajaxHeader = ((HttpServletRequest) request).getHeader("X-Requested-With");
        boolean isAjax = "XMLHttpRequest".equals(ajaxHeader);
        if (isAjax) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Ajax REquest Denied (Session Expired)");
        } else {
            super.commence(request, response, authException);
        }
    }
}
like image 737
alessandro ferrucci Avatar asked May 28 '14 02:05

alessandro ferrucci


1 Answers

Confirming that this works perfectly fine also with Spring Boot combined with Spring security in the programmatic way to setup security without any required XML, for example:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/admin**").hasRole("ADMIN")
            // everything else
            .anyRequest().fullyAuthenticated()
        .and()
            .exceptionHandling().authenticationEntryPoint(new AjaxAwareAuthenticationEntryPoint("/login"));
}
like image 104
ngeek Avatar answered Nov 15 '22 10:11

ngeek