Basic and Digest Authentication for a REST Service with Spring Security

Table of Contents

1. Overview

This article discusses how to set up both Basic and Digest Authentication on the same URI structure of a REST API. In a previous article, we discussed another method of securing the REST Service – form based authentication, so Basic and Digest authentication is the natural alternative, as well as the more RESTful one.

2. Configuration of Basic Authentication

The main reason that form based authentication is not ideal for a RESTful Service is that Spring Security will make use of Sessions – this is of course state on the server, so the statelessness constraints in REST is practically ignored.

We’ll start by setting up Basic Authentication – first we remove the old custom entry point and filter from the main <http> security element:

<http create-session="stateless">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

   <http-basic />
</http>

Note how support for basic authentication has been added with a single configuration line – <http-basic /> – which handles the creation and wiring of both the BasicAuthenticationFilter and the BasicAuthenticationEntryPoint.

2.1. Satisfying the stateless constraint – getting rid of sessions

One of the main constraints of the RESTful architectural style is that the client-server communication is fully stateless, as the original dissertation reads:

    5.1.3 Stateless

We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.

The concept of Session on the server is one with a long history in Spring Security, and removing it entirely has been difficult until now, especially when configuration was done by using the namespace. However, Spring Security 3.1 augments the namespace configuration with a new stateless option for session creation, which effectively guarantees that no session will be created or used by Spring. What this new option does is completely removes all session related filters from the security filter chain, ensuring that authentication is performed for each request.

3. Configuration of Digest Authentication

Starting with the previous configuration, the filter and entry point necessary to set up digest authentication will be defined as beans. Then, the digest entry point will override the one created by <http-basic> behind the scenes. Finally, the custom digest filter will be introduced in the security filter chain using the after semantics of the security namespace to position it directly after the basic authentication filter.

<http create-session="stateless" entry-point-ref="digestEntryPoint">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

   <http-basic />
   <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
</http>

<beans:bean id="digestFilter" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
   <beans:property name="userDetailsService" ref="userService" />
   <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" />
</beans:bean>

<beans:bean id="digestEntryPoint" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
   <beans:property name="realmName" value="Contacts Realm via Digest Authentication"/>
   <beans:property name="key" value="acegi" />
</beans:bean>

<authentication-manager>
   <authentication-provider>
      <user-service id="userService">
         <user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" />
         <user name="user" password="user" authorities="ROLE_USER" />
      </user-service>
   </authentication-provider>
</authentication-manager>

Unfortunately there is no support in the security namespace to automatically configure the digest authentication the way basic authentication can be configured with <http-basic>. Because of that, the necessary beans had to be defined and wired manually into the security configuration.

4. Supporting both authentication protocols in the same RESTful service

Basic or Digest authentication alone can be easily implemented in Spring Security 3.x; it is supporting both of them for the same RESTful web service, on the same URI mappings that introduces a new level of complexity into the configuration and testing of the service.

4.1. Anonymous request

With both basic and digest filters in the security chain, the way a anonymous request – a request containing no authentication credentials (Authorization HTTP header) – is processed by Spring Security is – the two authentication filters will find no credentials and will continue execution of the filter chain. Then, seeing how the request wasn’t authenticated, an AccessDeniedException is thrown and caught in the ExceptionTranslationFilter, which commences the digest entry point, prompting the client for credentials.

The responsibilities of both the basic and digest filters are very narrow – they will continue to execute the security filter chain if they are unable to identify the type of authentication credentials in the request. It is because of this that Spring Security can have the flexibility to be configured with support for multiple authentication protocols on the same URI.

When a request is made containing the correct authentication credentials – either basic or digest – that protocol will be rightly used. However, for an anonymous request, the client will get prompted only for digest authentication credentials. This is because the digest entry point is configured as the main and single entry point of the Spring Security chain; as such digest authentication can be considered the default.

4.2. Request with authentication credentials

A request with credentials for Basic authentication will be identified by the Authorization header starting with the prefix “Basic”. When processing such a request, the credentials will be decoded in the basic authentication filter and the request will be authorized. Similarly, a request with credentials for Digest authentication will use the prefix “Digest”  for it’s Authorization header.

5. Testing both scenarios

The tests will consume the REST service by creating a new resource after authenticating with either basic or digest:

@Test
public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( paths.getFooURL() );

   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}
@Test
public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( paths.getFooURL() );

   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}

Note that the test using basic authentication adds credentials to the request preemptively, regardless if the server has challenged for authentication or not. This is to ensure that the server doesn’t need to challenge the client for credentials, because if it did, the challenge would be for Digest credentials, since that is the default.

6. Conclusion

This article covered the configuration and implementation of both Basic and Digest authentication for a RESTful service, using mostly Spring Security 3.0 namespace support as well as some new features added by Spring Security 3.1.

For the full implementation, check out the github project.

I usually post about Security on Google+ - you can follow me there:

GET THE 3 EBOOKS >>
Download the 3 eBooks: "Rest with Spring", "Persistence with Spring" and "Learn HttpClient"
×
Build Your Web App with Spring (and quickly prototype it to 90%)

, ,

  • https://plus.google.com/u/0/110597455915090373579/posts JT

    Thanks for posting this super informative blog post. When do you plan to release your next article on OAuth? I am working on a learning project which focus on “Secure REST API with OAuth 2.0″. Currently, I have these two projects (REST and OAuth Facebook) sitting independently and I am having hard time integrating these two. The goal is to write a pure REST service in Java which will be accessed through Backbone.js (client library). Authentication will be provided by Facebook before user could do CRUD through REST API.

    If you could give me some guidance (link to sample) on this problem would be great. Thanks again. Keep up the good work.

  • Dave

    Is there a way to have a “fallback” to another authentication method? Some clients do not support a Digest authentication prompt (e.g. Apple TV). I’d like Digest to be my main entry point, but if I detect that a user-agent does not support Digest authentication then I’d like to route the user to a form authentication or something.

    • baeldung

      Yes – the fallback is Basic Authentication – as security is configured so that both Basic and Digest are active, and the client can pick between them. Hope that helps.

  • Amit Singh

    I have customized custom authentication manager in my application but now i want to use digest authentication ….as in example i can see we can inject only userdetailservice…. is it possible to digest authentication with custom authentication manager

  • Yogesh gupta

    Hi, Thanks for a great post can you please tell me how to pass the username and password in basic authentication from the client side in java. Will it be like –

    requestHeaders.set(“Basic”, “username:password”);

    or

    requestHeaders.set(“Authorization”, “Basic:username:password”);

    • baeldung

      The “username:password” needs to be Base 64 encoded. Then, the prefix: “Basic ” needs to be added – that is the value of the “Authorization” header. Better yet, use a higher level library – no sense in mucking about with the raw headers.
      Hope this helps. Eugen.

  • Nikolay Rusev

    Hello, I cannot find exactly this project on github?can you please give me url to github if you have it?

    • baeldung

      The URL should be right at the end of the article. Cheers.

  • Rakesh Ranjan

    Hi – I am getting error from Angular.Js side while accessing the Rest API – No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:9000′ is therefore not allowed access.
    Could you help me out to resolve the issues.

  • Juan Mendoza

    Hi,

    I have a question, I try to test my secured application across a rest client. but I cant send the parameters user and password.

    ¿How should they be send in the header of the request?

    usrer:user1 and password:user1Pass

    Thanks.

    • http://www.baeldung.com/ Eugen Paraschiv

      Hey Juan,
      Check out the article about doing basic authentiation with HttpClient (for example).
      Hope this helps.
      Cheers.
      Eugen.

    • Juan Mendoza

      Thanks Eugen.

      The problem was that the parameters we should send encoded in base64, so adding the header “Authorization: Basic user:userPass didn’t work, but when I sending they encoded, it’s works

      It send it as “Authorization: Basic:dXNlcjp1c2Vy” ( I encoded the string user:user with online encoder tool “http://www.motobit.com/util/base64-decoder-encoder.asp”)

      Thanks for your quick response!

  • Justin

    Hi Eugen,

    Thanks for the useful post! I was just curious to see what your thoughts are about storing the user’s password on the client side. I am trying to write my first SPA (first webapp in general) with Backbone.js and am trying to figure out what the best practice is with regards to doing stateless authentication using digest authentication.

    What I’m understanding (and what’s bothering me) is that it seems that – given a login form – the user’s plain text password needs to be extracted from the form and an AJAX call made. If successful, I’m assuming a cookie will need to be used to store that information for future calls until expiry.

    Is this really best practice? I mean the password is being stored plain text in a cookie (or perhaps hashed and stored in cookie… and then sent hashed? In which case the server would have to know to avoid hashing the hash and just compare right?). Either my understanding is not correct or I’m making a big deal out of nothing (or both?).

    Thank you for your time.

    Regards,
    Justin

    • http://www.baeldung.com/ Eugen Paraschiv

      Hey Justin – your understanding is correct – storing the credentials on the client side does indeed open up the system to additional types of exploits. Here’s my answer to a similar question a few months back – hope it helps. Cheers,
      Eugen.

      • Justin

        Hi Eugen,

        Thanks for the reply!

        The proxy approach sounds interesting (but also more complex). What is the benefit of going down that road? From what I can tell it’s in order to avoid storing session information on the REST server … to avoid running out of memory perhaps? But if the proxy and the REST server are hosted on the same physical server, I guess there’s no benefit in that regards.

        When compared to digest authentication, you’re not storing the credentials on the client browser, so the proxy using session + cookie is a plus. But then (apart from 1. memory 2. it’s according to REST statelessness) why not use session + cookie in the REST server straight away making do without the proxy?

        Regards,
        Justin

        • http://www.baeldung.com/ Eugen Paraschiv

          Yes, the proxy solution is somewhat more complex (there are libraries that can help with that). One of the main architectural constraints of a RESTful API is statelessness – and a session is – by itself – state. Now – REST is a good set of constraints and a solid architectural style, but it’s not the only one. So – if that constraint doesn’t make sense in some case, then it’s perfectly fine not to use it. So – with that in mind, the if the hybrid approach works and you have a good understanding of why statelessness is important for REST and that it’s an OK compromise to make in your particular situation, my suggestion is to go for it. Hope that makes sense. Cheers,
          Eugen.

          • Justin

            Makes perfect sense!

            Cheers, I think I have made up my mind now :)

            Regards,
            Justin