4

I've got a secured Backbone.js app (that uses Spring security atm.), so a logged-in user must have a valid session-cookie (JSESSIONID). Now, if this session is invalidated (deleted, expired, whatever) and the user attempts to make a request, Spring security will return a 302 Error as an attempt to redirect the user to a login-form.

As is explained in this answer, this 302 response gets handled by the browser (it doesn't reach my app) so what is returned to my app is a 200 OK response with contenttype="text/html" (containing the login form).

Thats an issue, because when my Backbone model attempts to do a sync to a url, it expects JSON. If this sync happens without a valid session, the 200 "text/html" response is returned when "application/json" is expected, giving me a JSON parse error in jQuery.extend.parseJSON.

With great help from this question/answer, I've overridden the Backbone.sync method in order to use my own error handling. However, since the 302 never reaches my error handler I cannot override the redirect myself.

My situation is very similar to this question, however a final solution to the problem was never posted. Could someone please help me figure out the ideal way to ensure a redirect to the login page happens?

Community
  • 1
  • 1
Aksel Gresvig
  • 715
  • 1
  • 9
  • 21

2 Answers2

3

Instead of returning the login page with HTTP 200 OK, you should configure Spring Security to return HTTP 401 Unauthorized for unauthenticated AJAX requests. You can detect an AJAX request (as opposed to a normal page request) by checking for the X-Requested-With: XMLHttpRequest request header.

You can use the global $.ajaxError handler to check for 401 errors and redirect to the login page there.

This is how we've implemented it and it works nicely. I'm not a Spring guy, though, so I can't really help with the Spring Security configuration.

jevakallio
  • 35,324
  • 3
  • 105
  • 112
  • +1 for detecting AJAX requests and do not use for them default redirect to the login page – Maksym Demidas Jan 11 '13 at 16:28
  • In Spring Security 3.1+ you can define a separate realm (`` tag) for your AJAX URIs, and configure it to use basic HTTP authentication only (see [this answer](http://stackoverflow.com/a/11968411/2842067) but do NOT make AJAX URIs stateless - do not use `create-session="stateless"`). When a session expires you will get 401 responses for these URIs. However, the browser will prompt for a login and password - see [this answer](http://stackoverflow.com/a/9872582/2842067) (with comments) or [this post](http://loudvchar.blogspot.ca/2010/11/avoiding-browser-popup-for-401.html) for a solution. – Alexey Jun 24 '14 at 05:45
0

EDIT. Instead of custom coockie it will be better to use solution provided by @fencliff.

I think you can use some other field of XHR to detect this situation. A special coockie may do the trick.

You can define your own authentication failure handler from Spring Security side. At the moment when redirect to login page occurs you will be able to add some coockie to HttpServletResponse. Your custom Backbone.sync method will check this cookie. If it is present, it will launch your custom handler for this case (do not forget remove the coockie at the same time).

<sec:http ... >
    <sec:form-login login-page='/login.html' authentication-failure-handler-ref="customAuthenticationFailureHandler" />
</sec:http>

<bean id="customAuthenticationFailureHandler" class="com.domain.CustomAuthenticationFailureHandler" />

CustomAuthenticationFailureHandler must implement org.springframework.security.web.authentication.AuthenticationFailureHandler interface. You can add your coockie and then call default SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure(...) implementation.

Maksym Demidas
  • 7,707
  • 1
  • 29
  • 36