40

I am using Spring Security 3.0.4. I have a bunch of web service which are protected by Spring Security. When I access them as an unauthenticated user, Spring Security redirects to login page. Instead of that, I want to return HTTP 403 error. How can I achieve that?

Here is my security config:

<http auto-config="false" use-expressions="true" >

    <intercept-url pattern="/authorization.jsp" access="permitAll"/>
    <intercept-url pattern="/registration.jsp" access="permitAll"/>
    <intercept-url pattern="/api/authorization/auth" access="permitAll"/>
    <intercept-url pattern="/api/authorization/new" access="permitAll"/>
    <intercept-url pattern="/api/accounts/new" access="permitAll"/>
    <intercept-url pattern="/app/**" access="permitAll"/>
    <intercept-url pattern="/extjs/**" access="permitAll"/>

    <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />

    <form-login login-page="/authorization.jsp"
            default-target-url="/index.jsp"
            authentication-failure-url="/registration.jsp?login_error=1"
            always-use-default-target="true"
            />

    <logout logout-success-url="/authorization.jsp"
            logout-url="/j_spring_security_logout"
            invalidate-session="true"/>        

</http>
artemb
  • 9,251
  • 9
  • 48
  • 68
  • Have you tried removing the "authentication-failure-url" setting on your form login? – Gandalf Nov 29 '10 at 19:13
  • Have you found working solution? I've heard that the way to achieve that is to override 'some Spring filters', but without example, and I think it should be possible to configure because e.g. AJAX application like to do custom loging on JSON channel and JSON channels for data are expected to react with 403 on no rights to service. – Danubian Sailor Dec 22 '11 at 08:18
  • Related: http://stackoverflow.com/questions/3339431/how-to-handle-expired-session-using-spring-security-and-jquery – usethe4ce Nov 02 '12 at 00:27

5 Answers5

16

For java configuration you need to do

http.exceptionHandling().authenticationEntryPoint(alwaysSendUnauthorized401AuthenticationEntryPoint);

Where alwaysSendUnauthorized401AuthenticationEntryPoint is innstance of class

public class AlwaysSendUnauthorized401AuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public final void commence(HttpServletRequest request, HttpServletResponse response,
                               AuthenticationException authException) throws IOException {
        LOGGER.debug("Pre-authenticated entry point called. Rejecting access");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    }
}

This disables default behavior of Spring (redirecting unauthenticated requests to login form).

Side note: for such case HTTP code SC_UNAUTHORIZED(401) is better choice than SC_FORBIDDEN(403).

Bartosz Bilicki
  • 12,599
  • 13
  • 71
  • 113
  • Not sure the exact version where this was added, but there is also `http.exceptionHandling(Customizer>)`, so you can customize the default. For example: `http.exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))`. HttpStatusEntryPoint is also convenient as you don't need to create your own implementation of AuthenticationEntrypPoint. – Daniel Mikusa Feb 01 '21 at 18:30
  • If you don't want it to always return a particular status code, you can also call the customer and add a default entry point, which takes a matcher. If the matcher matches the request, it'll use this entry point. Ex: `customizer.defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), matcher)`, where the matcher is any RequestMatcher implementation. There's many out of the box RequestMatcher's so it's a pretty flexible option. – Daniel Mikusa Feb 01 '21 at 18:33
10

you need to

  • Create a RequestMatcher to determine which requests should get a 403 (AntPathRequestMatcher may suffice in your case).
  • Configure the HttpSessionRequestCache to check the matcher and not store those pages for post-login redirect.
  • Use a DelegatingAuthenticationEntryPoint to either 403 the request outright or redirect to login according to the matcher.

See the example here:

http://distigme.wordpress.com/2012/11/01/ajax-and-spring-security-form-based-login/

Bartosz Bilicki
  • 12,599
  • 13
  • 71
  • 113
usethe4ce
  • 23,261
  • 4
  • 30
  • 30
10

There's an article on the spring forums here that outlines how to get your app determining between the two methods. So far I'm using the following code to secure my data controllers:

<bean id="ep403" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>

<sec:http pattern="/data/**" entry-point-ref="ep403" use-expressions="true">
    <sec:intercept-url pattern="/**" access="isAuthenticated()"/>
</sec:http>

<bean id="epauth" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <constructor-arg value="/login.html"/>
</bean>

<sec:http pattern="/**" entry-point-ref="epauth" use-expressions="true">
    <sec:intercept-url pattern="/**" access="isAuthenticated()"/>
</sec:http>

So the whole DelegatingAuthenticationEntryPoint solution in the article I linked is a bit more heavyweight, but I imagine it does the job just fine as well.

tzrlk
  • 848
  • 1
  • 13
  • 30
0

This solution worked for me (reference)

http
  ...
  .oauth2Login().permitAll()
  .and().exceptionHandling()
  .defaultAuthenticationEntryPointFor(
       new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
       new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"))
            ...
hillel_guy
  • 646
  • 6
  • 17
-4

It should return a 403 error unless you configure it to go to another url with this tag:

<sec:access-denied-handler error-page="/urlToGoIfForbidden" />
Javi
  • 19,387
  • 30
  • 102
  • 135