4

I have some url secured with spring (configured through xml). It works. However when I try to hit that endpoint with an ajax request I get a 302 (found) response. This redirects my ajax call to the login page (so I GET the html). However I'd like to get a 401 (unauthorized) response with the url of the login page available to the client application, so I can redirect the user there with javascript. This question seems to be the closest to what I want, but there's no example and it suggests changing the controller again. Is there no configuration in spring-security that will give me a 401 and a url (or some other sensible error message and the url of the login page)?

Community
  • 1
  • 1
Josh
  • 801
  • 3
  • 11
  • 16
  • Do you want *all* URLs in your application to return 401 if you're not logged in, or do you want only *some* URLs (the AJAX ones only) to return 401? – gutch Dec 08 '11 at 06:25

2 Answers2

16

You can extend LoginUrlAuthenticationEntryPoint. Here is my one:

package hu.progos.springutils;
// imports omitted
public class AjaxAwareLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
    public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException, ServletException {
        if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
        } else {
            super.commence(request, response, authException);
        }
    }
}

Then configure spring to use your implementation:

<beans:bean id="authEntryPoint" class="hu.progos.springutils.AjaxAwareLoginUrlAuthenticationEntryPoint" scope="singleton>
    <beans:property name="loginFormUrl" value="/login.html" />
</beans:bean>

<http entry-point-ref="authEntryPoint">
  <!-- your settings here -->
</http>
arpad
  • 421
  • 4
  • 9
  • Thanks. this seems like the correct solution. we're not using ajax anymore though, so I won't need this. – Josh Dec 08 '11 at 16:31
  • 1
    This is by far a more elegant solution than using a filter to inspect every request. Thx. – Rori Stumpf Mar 25 '13 at 21:14
  • Very nice solution, thanks! I made a minor change since I got a warning that setting `loginFormUrl` property was deprecated. I added a constructor to the `AjaxAwareLoginUrlAuthenticationEntryPoint` class `super(loginFormUrl);` and changed the bean def to use `constructor-arg value="/login.html" />` – Darren Parker Mar 21 '18 at 19:54
  • I posted an answer with my code here: https://stackoverflow.com/a/49416672/4505142 – Darren Parker Mar 21 '18 at 21:19
0

There are a million ways to do this of course. But the short solution to your problem is this configuration snippet:

<bean id="customAuthEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
   <property name="loginFormUrl" value="/your-custom-login" />
</bean>

I also take a step further and turn off the security auto-config so I can map the above entry point like so:

 <security:http auto-config="false" entry-point-ref="customAuthEntryPoint">
   ...
   ...
 </security:http>

I also override a bunch of spring security classes to get the security model to do exactly what I want. It's a slippery slope, but it's nice having the control once it works the way you want it to.