If you have a few years of experience in the Java ecosystem, and you're interested in sharing that experience with the community (and getting paid for your work of course), have a look at the "Write for Us" page. Cheers. Eugen

The new Certification Class of Learn Spring Security is out:

>> CHECK OUT THE COURSE

Table of Contents

1. Overview

This tutorial shows how to Secure a REST Service using Spring and Spring Security 4 with Java based configuration. The article will focus on how to set up the Security Configuration specifically for the REST API using a Login and Cookie approach.

2. Spring Security in the web.xml

The architecture of Spring Security is based entirely on Servlet Filters and, as such, comes before Spring MVC in regards to the processing of HTTP requests. Keeping this in mind, to begin with, a filter needs to be declared in the web.xml of the application:

<filter>
   <filter-name>springSecurityFilterChain</filter-name>
   <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
   <filter-name>springSecurityFilterChain</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

The filter must necessarily be named ‘springSecurityFilterChain’  to match the default bean created by Spring Security in the container.

Note that the defined filter is not the actual class implementing the security logic but a DelegatingFilterProxy with the purpose of delegating the Filter’s methods to an internal bean. This is done so that the target bean can still benefit from the Spring context lifecycle and flexibility.

The URL pattern used to configure the Filter is /* even though the entire web service is mapped to /api/* so that the security configuration has the option to secure other possible mappings as well if required.

3. The XML Security Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
   xmlns="http://www.springframework.org/schema/security"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:beans="http://www.springframework.org/schema/beans"
   xmlns:sec="http://www.springframework.org/schema/security"
   xsi:schemaLocation="
      http://www.springframework.org/schema/security 
      http://www.springframework.org/schema/security/spring-security-4.0.xsd
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

   <http entry-point-ref="restAuthenticationEntryPoint">
      <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN"/>

      <form-login 
         authentication-success-handler-ref="mySuccessHandler" 
         authentication-failure-handler-ref="myFailureHandler"
      />

      <logout />
   </http>

   <beans:bean id="mySuccessHandler"
      class="org.rest.security.MySavedRequestAwareAuthenticationSuccessHandler"/>
   <beans:bean id="myFailureHandler" class=
     "org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"/>

   <authentication-manager alias="authenticationManager">
      <authentication-provider>
         <user-service>
            <user name="temporary" password="temporary" authorities="ROLE_ADMIN"/>
            <user name="user" password="user" authorities="ROLE_USER"/>
         </user-service>
      </authentication-provider>
   </authentication-manager>

</beans:beans>

Most of the configuration is done using the security namespace – for this to be enabled, the schema locations must be defined and pointed to the correct 4.x XSD versions. The namespace is designed so that it expresses the common use cases of Spring Security while still providing hooks raw beans to accommodate more advanced scenarios.

>> Signup for my Course on Building a REST API with Spring 4

3.1. The <http> Element

The <http> element is the main container element for HTTP security configuration. In the current implementation, it only secured a single mapping: /api/admin/**. Note that the mapping is relative to the root context of the web application, not to the rest Servlet; this is because the entire security configuration lives in the root Spring context and not in the child context of the Servlet.

3.2. The Entry Point

In a standard web application, the authentication process may be automatically triggered when the client tries to access a secured resource without being authenticated – this is usually done by redirecting to a login page so that the user can enter credentials. However, for a REST Web Service, this behavior doesn’t make much sense – Authentication should only be done by a request to the correct URI and all other requests should simply fail with a 401 UNAUTHORIZED status code if the user is not authenticated.

Spring Security handles this automatic triggering of the authentication process with the concept of an Entry Point – this is a required part of the configuration, and can be injected via the entry-point-ref attribute of the <http> element. Keeping in mind that this functionality doesn’t make sense in the context of the REST Service, the new custom entry point is defined to simply return 401 whenever it is triggered:

@Component( "restAuthenticationEntryPoint" )
public class RestAuthenticationEntryPoint
  implements AuthenticationEntryPoint{

   @Override
   public void commence(
     HttpServletRequest request,
     HttpServletResponse response, 
     AuthenticationException authException) throws IOException {
 
      response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" );
   }
}

A quick side note here is that the 401 is sent without the WWW-Authenticate header, as required by the HTTP Spec – we can, of course, set the value manually if we need to.

3.3. The Login Form for REST

There are multiple ways to do Authentication for a REST API – one of the defaults Spring Security provides is Form Login – which uses an authentication processing filter – org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.

The <form-login> element will create this filter and will also allow us to set our custom authentication success handler on it. This can also be done manually by using the <custom-filter> element to register a filter at the position FORM_LOGIN_FILTER – but the namespace support is flexible enough.

Note that for a standard web application, the auto-config attribute of the <http> element is shorthand syntax for some useful security configuration. While this may be appropriate for some very simple configurations, it doesn’t fit and should not be used for a REST API.

3.4. Authentication should Return 200 Instead of 301

By default, form login will answer a successful authentication request with a 301 MOVED PERMANENTLY status code; this makes sense in the context of an actual login form which needs to redirect after login. For a RESTful web service, however, the desired response for a successful authentication should be 200 OK.

This is done by injecting a custom authentication success handler in the form login filter, to replace the default one. The new handler implements the exact same login as the default org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler with one notable difference – the redirect logic is removed:

public class MySavedRequestAwareAuthenticationSuccessHandler 
  extends SimpleUrlAuthenticationSuccessHandler {

    private RequestCache requestCache = new HttpSessionRequestCache();

    @Override
    public void onAuthenticationSuccess(
      HttpServletRequest request,
      HttpServletResponse response, 
      Authentication authentication) 
      throws ServletException, IOException {
 
        SavedRequest savedRequest
          = requestCache.getRequest(request, response);

        if (savedRequest == null) {
            clearAuthenticationAttributes(request);
            return;
        }
        String targetUrlParam = getTargetUrlParameter();
        if (isAlwaysUseDefaultTargetUrl()
          || (targetUrlParam != null
          && StringUtils.hasText(request.getParameter(targetUrlParam)))) {
            requestCache.removeRequest(request, response);
            clearAuthenticationAttributes(request);
            return;
        }

        clearAuthenticationAttributes(request);
    }

    public void setRequestCache(RequestCache requestCache) {
        this.requestCache = requestCache;
    }
}

3.5. Failed Authentication should return 401 instead of 302

Similarly – we configured the authentication failure handler – the same way we did with the success handler.

Luckily – in this case, we don’t need to actually define a new class for this handler – the standard implementation – SimpleUrlAuthenticationFailureHandler – does just fine.

The only difference is that – now that we’re defining this explicitly in our XML config – it’s not going to get a default defaultFailureUrl from Spring – and so it won’t redirect.

3.6. The Authentication Manager and Provider

The authentication process uses an in-memory provider to perform authentication – this is meant to simplify the configuration as a production implementation of these artifacts is outside the scope of this post.

3.7. Finally – Authentication against the running REST Service

Now let’s see how we can authenticate against the REST API – the URL for login is /login – and a simple curl command performing login would be:

curl -i -X POST -d username=user -d password=userPass
http://localhost:8080/spring-security-rest/login

This request will return the Cookie which will then be used by any subsequent request against the REST Service.

We can use curl to authentication and store the cookie it receives in a file:

curl -i -X POST -d username=user -d password=userPass -c /opt/cookies.txt 
http://localhost:8080/spring-security-rest/login

Then we can use the cookie from the file to do further authenticated requests:

curl -i --header "Accept:application/json" -X GET -b /opt/cookies.txt 
http://localhost:8080/spring-security-rest/api/foos

This authenticated request will correctly result in a 200 OK:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 24 Jul 2013 20:31:13 GMT

[{"id":0,"name":"JbidXc"}]

4. The Java Security Configuration

Here’s how the Java configuration would look like:

@Configuration
@EnableWebSecurity
@ComponentScan("org.baeldung.security")
public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    private MySavedRequestAwareAuthenticationSuccessHandler
      authenticationSuccessHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
      throws Exception {
 
        auth.inMemoryAuthentication()
          .withUser("temporary").password("temporary").roles("ADMIN")
          .and()
          .withUser("user").password("userPass").roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception { 
        http
        .csrf().disable()
        .exceptionHandling()
        .authenticationEntryPoint(restAuthenticationEntryPoint)
        .and()
        .authorizeRequests()
        .antMatchers("/api/foos").authenticated()
        .and()
        .formLogin()
        .successHandler(authenticationSuccessHandler)
        .failureHandler(new SimpleUrlAuthenticationFailureHandler())
        .and()
        .logout();
    }

    @Bean
    public MySavedRequestAwareAuthenticationSuccessHandler mySuccessHandler(){
        return new MySavedRequestAwareAuthenticationSuccessHandler();
    }
    @Bean
    public SimpleUrlAuthenticationFailureHandler myFailureHandler(){
        return new SimpleUrlAuthenticationFailureHandler();
    }
}

A quick note, the Spring Security 4 config has changed the old defaults for XML configuration to be the same as Java defaults.

Old XML Configuration defaults – before Spring Security 4:

  • loginProcessingUrl: /j_spring_security_check
  • usernameParameter: j_username
  • passwordParameter: j_password

Current XML Configuration defaults:

  • loginProcessingUrl: /login
  • usernameParameter: username
  • passwordParameter: password

5. Maven and Other Troubles

The Spring core dependencies necessary for a web application and for the REST Service have been discussed in detail. For security, we’ll need to add: spring-security-web and spring-security-config – all of these have also been covered in the Maven for Spring Security tutorial.

It’s worth paying close attention to the way Maven will resolve the older Spring dependencies – the resolution strategy will start causing problems once the security artifacts are added to the pom.

To address this problem, some of the core dependencies will need to be overridden in order to keep them at the right version.

6. Conclusion

This post covered the basic security configuration and implementation for a RESTful Service using Spring Security 4, discussing the web.xml, the security configuration, the HTTP status codes for the authentication process and the Maven resolution of the security artifacts.

And, as always, the full implementation is available over on Github.

Go deeper into Spring Security with the course:

>> LEARN SPRING SECURITY

Sort by:   newest | oldest | most voted
Sigmund Lundgren
Guest

Hmm successful auth still redirects for my, done in the spring base class. Had to comment this line in the successhandler:

//super.onAuthenticationSuccess(request, response, authentication);

René Fleischhauer
Guest

Hi Sigmund, all,

I have the same problem…

super.onAuthenticationSuccess(request, response, authentication) calls SimpleUrlAuthenticationSuccessHandler#handle which contains the following line

redirectStrategy.sendRedirect(request, response, targetUrl);

Seems to be pretty non-sense to call the super method and therefore, I also removed it. Additionally I added a response.setStatus(200) for safety purposes…

Best,
René

fadi
Guest

Hi,

Am having a problem in understanding one thing, how the actual login will be done. I added the configuration and when trying to access a rest method/url I get 401 error, but am unable to figure out how and where to login. can help me pleas?

fadi
Guest

Thank you for the response, but am using FF plugin and I added the Authorization header to the url, the only place fired in my code is the EntryPoint and it never enters my AuthenticationProvider. which makes wounder if am doing something wrong!

Thanks

Eugen Paraschiv
Guest

Not sure how you can add the header to the URL – do you mean you added the header to the request? Also, to follow some working examples, you can always clone the project from github and run the tests.

DropDeadFred
Guest

If you are using the REST service through AJAX from a browser can you had the necessary Authentication headers? For example, if you are using form based authentication to your website and want to retrieve data from your REST service. I guess I must just be missing something here.

Eugen Paraschiv
Guest

You can take a look at: http://code.google.com/p/crypto-js/

Branislav Vidovic
Guest

This is the most interesting part in my opinion…. I am interested which other additional component of spring security you have extended to read request headers and build a required authentication object. Besides i had a look into your git project but in there you did not do it totally like in this post..

Eugen Paraschiv
Guest

The article is now updated with the exact process of how to perform the login and how to use the cookie in further requests.

René Fleischhauer
Guest
Hi all, thanks for the tutorial. Great stuff! I have a minor question: I added within the element in order to customize the login url. After starting the application again the following exception occurs: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Filter beans ” and ” have the same ‘order’ value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from and avoiding the use of . The problem is clear, however I’m not sure how I can avoid the use of j_spring_security_check. I’d highly… Read more »
Eugen Paraschiv
Guest

Hi – yes, using the element is a good alternative as it does keep the configuration simple – please check out the updated configuration section and the new github project for a working implementation. Thanks.

glz
Guest

Great article, however every time I get 401 Unauthorized, regardless sending or not valid username and password (temporary/temporary) in username or j_username and password or j_password. Tried to figure it out looking at your git project, but there seems to be a lot of other stuff, and the only authentication used in this project is Digest authentication. Did I miss something important here?

Eugen Paraschiv
Guest

Hi – I updated the article to better explain how to perform login and how to interact with the service; I also added a specific github project to only cover this article – should be simpler to understand. Thanks.

bhecht
Guest

This was very helpful.

I as well got an 401 Unauthorized.
After dubugging i found out the problem is at UsernamePasswordAuthenticationFilter.requiresAuthentication() which returns true only if the URI ends with /j_spring_security_check.
I had to override this class and return true in the requiresAuthentication(), so it will work.

Eugen Paraschiv
Guest

Hi – the article is now updated to better explain how to interact with the REST Service – in short, yes, the first request is to /j_spring_security_check – this will return the Cookie which will be used in any further requests against the service.

wpDiscuz