You are on page 1of 17

Securing REST WebServices with Spring Security and Custom HTTP Request Factories

Jorge Sim ao Jorge.Simao@glintt.com GLINTT November 2, 2011


Abstract I show how to implement secure REST WebServices using HTTP authentication and Spring Security framework. I review the server side conguration for Spring Security to setup Basic and Digest HTTP authentication. For the client side the Spring Framework class RestTemplate is tailored with a custom ClientHttpRequestFactory so that the HTTP headers are set with the required HTTP authentication information.

Keywords: REST WebServices, HTTP Basic and Digest Authentication, Spring Security, RestTemplate

Introduction

Rest web-services (REST-WS) provide an eective and portable away to implement distributed services based on HTTP 1.1 protocol. HTTP species two standard mechanisms for authentication: Basic and Digest. These two elements suggest that Rest web services can naturally be secured with the authentication mechanisms of HTTP. Spring security is a framework that can be used to secure Java based services in a declarative away, including those based on HTTP and Servlet. Spring security has many built-in authentication mechanisms, including Basic and Digest HTTP authentication. Setting up these authentication mechanisms in the server side is a simple matter of conguring Spring Security appropriately. For the client side, assuming a Java implementation, the Spring Framework class RestTemplate provides a intuitive API to invoke REST-WS. in client application. There is no out-of-the-box implementation of RestTemplate implementing HTTP authentication. However, RestTemplate is highly customizable, and allows setting of a custom factory bean to create HTTP connections. This strategy bean is dened by type ClientHttpRequestFactory, and application can provide implementation suiting their needs. By providing a custom ClientHttpRequestFactory that sets HTTP headers appropriately, is possible to implement secure REST-WS based on HTTP authentication. In this article, I show how to use the above approach to implement secure REST-WS. I start with Basic HTTP authentication, and later repeat the approach for Digest HTTP authentication. For the Basic authentication, I use the 1 Sponsors

Java HttpConnection as a low-level factory for HTTP connections. For Digest authentication I use the Apache HttpClient library to simplify development.

Securing REST Web Services: Basic Authentication

Setting up a secure REST-WS with Spring Framework and Spring Security, involves three steps: Implement the resource(s) to be secured, such as REST controllers implemented with Spring MVC; Congure Spring Security with the desired authentication and access control rule for the secured resources; Install Spring Security lter-chain as part of the application deployment descriptor (/WEB-INF/web.xml).

2.1

Implementing a Secure REST Web Service Controller

Server-side security involves performing user authentication and checking for allowed access to secured resources. For illustration purpose, I dene a simple resource to be secured a handler method of a controller that implements a REST-WS. Below, I show a Spring MVC enabled web controller (SecuredRestWSController) for a REST-WS with a single method that to be secured the secured() method. The method is mapped to URL /secured and HTTP method GET. The return value of the method is a String value that is to be marshalled in the HTTP response message body. This is specied with annotation @ResponseBody.
@Controller public c l a s s S e c u r e d R e s t W S C o n t r o l l e r { ... @RequestMapping ( v a l u e = "/ secured " , method = RequestMethod . GET) public @ResponseBody S t r i n g s e c u r e d ( ) { return " SECURED : " + new Date ( ) ; } }

2.2

Spring Security Conguration

Spring security is most commonly congured in a Spring beans XML conguration le, importing the Spring security XML namespace. Below, I review the typical top-level structure of a XML conguration le using Spring Security namespace set as the default namespace.
<? xml version=" 1.0 " encoding=" UTF -8 " ?> <beans:beans xmlns:beans=" http: // www . springframework . org / schema / beans " xmlns=" http: // www . springframework . org / schema / security "

2
Sponsors

xmlns:xsi=" http: // www . w3 . org /2001/ XMLSchema - instance " xsi:schemaLocation=" http: // www . springframework . org / schema / security http: // www . springframework . org / schema / security / spring - security . xsd http: // www . springframework . org / schema / beans http: // www . springframework . org / schema / beans / spring - beans . xsd "> ... </ beans:beans>

With the security namespace set as default, security conguration elements can be conveniently used without an XML namespace prex. The Spring beans namespace is also imported to dene the top-level element <beans:beans>. The schema location for these two namespaces is specied to enable tool-driven XML validation. Application security bean les should be included from the le(s) for the main application context, for the Spring MVC application context. Below, I show how to setup the Spring Security conguration to secure the SecuredRestWSController web-service with Basic HTTP authentication. The element <http> is used to encapsulate all HTTP specic conguration.
<http> <httpbasic /> <intercept url pattern="/ secured ** " access=" ROLE_ADMIN " /> </ http>

Most of the beans required to setup HTTP Basic authentication are automatically created and congured by the handler of the element <httpbasic>. The element intercept url is used to dene a control access rule for the URL pattern /secured**, which conveniently matches the REST-WS web-service resource that we want to secure. The other beans required to setup the authentication conguration are the repositories with user credentials (user-name and passwords), and their and their authorities (roles). This is done with element <authenticationmanager > that is set with one (or more) authentication providers. Below, I use a simple in-memory list of user credentials specied with <userservice>. Other authentication providers could used.
<authentication manager> <authentication provider> <userservice> <user name=" admin " password=" admin " a u t h o r i t i e s=" ROLE_USER , ROLE_ADMIN " /> <user name=" jsimao " password=" jsimao " a u t h o r i t i e s=" ROLE_USER , ROLE_ADMIN " /> <user name=" guest " password=" guest " a u t h o r i t i e s=" ROLE_GUEST " /> </ userservice> </ authentication provider> </ authentication manager>

2.3

Conguring the Security Filter Chain

The nal step to setup Spring Security is to setup the lter chain that intercepts HTTP requests before they reach the corresponding Servlets and application 3 Sponsors

components such as the Spring MVC DispatcherServlet and the managed application web-controllers. This is done in the web application descriptor le located in /WEB-INF/web.xml, by conguring a lter of type DelegatingFilterProxy with name springSecurityFilterChain. The lter mapping is set to match (at least) the set of URLs we want to secure.
< f i l t e r> < f i l t e r name> s p r i n g S e c u r i t y F i l t e r C h a i n</ f i l t e r name> < f i l t e r c l a s s> o r g . s p r i n g f r a m e w o r k . web . f i l t e r . D e l e g a t i n g F i l t e r P r o x y</ f i l t e r c l a s s> </ f i l t e r > < f i l t e r mapping> < f i l t e r name> s p r i n g S e c u r i t y F i l t e r C h a i n</ f i l t e r name> <url pattern>/ s e c u r e d</ url pattern> </ f i l t e r mapping>

Building a Client for Secured Rest Web Services

This section shows how to implementing a Java client of secured REST-WS. The Spring Framework class RestTemplate is congured appropriately to support HTTP Basic authentication. The solution is specic to Java clients using Spring Framework, but porting to other client environments is also feasible. Spring RestTemplate API provides methods that roughly correspond to the HTTP methods sent in a request. For example, to obtain a remote resource using an HTTP GET request we use RestTemplate.getForObject(). RestTemplate automatically perform marsalling and unmarshalling of Java objects and HTTP responses. Since Spring Security was congured in your sample REST-WS to require HTTP Basic authentication, we need to tailor the behavior of RestTemplate so that the appropriate HTTP authentication headers are set. Fortunately, RestTemplate has extension point that allow for this. The strategy interface ClientHttpRequestFactory is used by RestTemplate to create the actual connection to the HTTP server. Two implementations are provided out-of-the-box: one implementation that wraps the java .net.HttpConnection class, this is SimpleClientHttpRequestFactory ; and another that wraps the third-party open-source Apache HttpClient class. Because BASIC authentication is simple enough, I will start by using Java java .net.HttpConnection and SimpleClientHttpRequestFactory.

3.1

Invoking the Secure REST Web-Service

Below, I show the code for a simple REST-WS client that invokes a secured method. This is done by class RestClient. A Spring RestTemplate is dened as a data-eld for the RestClient class, congured in the constructor. The conguration is done by setting a custom ClientHttpRequestFactory of type BasicSecureSimpleClientHttpRequestFactory though a call to the property setter method RestTemplate.setRequestFactory.
package o r g . h e l l o a p p . r e s t s e c u r i t y . c l i e n t ;

4
Sponsors

import o r g . s p r i n g f r a m e w o r k . web . c l i e n t . RestTemplate ; public c l a s s R e s t C l i e n t { RestTemplate r e s t T e m p l a t e = new RestTemplate ( ) ; s t a t i c f i n a l S t r i n g URL = " http :// localhost :8081/ rest security / secured " ; s t a t i c f i n a l S t r i n g username = " admin " ; s t a t i c f i n a l S t r i n g password = " admin " ; public R e s t C l i e n t ( ) { BasicSecureSimpleClientHttpRequestFactory requestFactory = new B a s i c S e c u r e S i m p l e C l i e n t H t t p R e q u e s t F a c t o r y ( ) ; r e q u e s t F a c t o r y . s e t C r e d e n t i a l s P r o v i d e r ( new S i m p l e C r e n d e n t i a l s P r o v i d e r ( new C r e d e n t i a l s ( username , password ) ) ) ; restTemplate . setRequestFactory ( requestFactory ) ; } public void e x e c ( ) { S t r i n g r e s p o n s e = r e s t T e m p l a t e . g e t F o r O b j e c t (URL, S t r i n g . class ) ; System . out . p r i n t l n ( " Response : " + r e s p o n s e ) ; } s t a t i c public void main ( S t r i n g [ ] a r g s ) { R e s t C l i e n t c l i e n t = new R e s t C l i e n t ( ) ; c l i e n t . exec ( ) ; } }

The custom class BasicSecureSimpleClientHttpRequestFactory is an extension to the default implementation used by RestTemplate. Its specic feature is to support Basic HTTP authentication. The instance of the custom class is further congured by setting a CredentialsProvider which is the object responsible to provide the user credentials information on request namely, the username and password. Method RestClient.exec() invokes the REST web-service using the RestTemplate congured with BasicSecureSimpleClientHttpRequestFactory. Method RestTemplate .getForObject() invokes the service URL to get the response value sent by the server method SecuredRestWSController.secured(). Method RestClient.main() is used to run the client as standalone Java application.

3.2

Implementing Secure ClientHttpRequestFactory

The next step in our solution is to implement BasicSecureSimpleClientHttpRequestFactory . For this purpose, I dene an abstract support class SecureSimpleClientHttpRequestFactory , that encapsulates much of the logic of implementing a secure REST-WS based java .net.HttpConnection. In particular, it allows the details of concrete security protocols to be pluged-in by implementing the abstract method prepareSecureConnection (). Although it is be used here to implement HTTP Basic authentication, it can also be extended to support other protocols such as HTTP Digest authentica-

5 Sponsors

tion. Below, I show the code for SecureSimpleClientHttpRequestFactory:


package o r g . h e l l o a p p . r e s t s e c u r i t y . c l i e n t ; import j a v a . i o . IOException ; import j a v a . n e t . HttpURLConnection ; import j a v a . n e t . URI ; import o r g . s p r i n g f r a m e w o r k . h t t p . HttpMethod ; import o r g . s p r i n g f r a m e w o r k . h t t p . c l i e n t . C l i e n t H t t p R e q u e s t ; import o r g . s p r i n g f r a m e w o r k . h t t p . c l i e n t . SimpleClientHttpRequestFactory ;

abstract public c l a s s S e c u r e S i m p l e C l i e n t H t t p R e q u e s t F a c t o r y extends S i m p l e C l i e n t H t t p R e q u e s t F a c t o r y { protected C r e d e n t i a l s P r o v i d e r c r e d e n t i a l s P r o v i d e r ; public S e c u r e S i m p l e C l i e n t H t t p R e q u e s t F a c t o r y ( ) { } public C r e d e n t i a l s P r o v i d e r g e t C r e d e n t i a l s P r o v i d e r ( ) { return c r e d e n t i a l s P r o v i d e r ; } public void s e t C r e d e n t i a l s P r o v i d e r ( C r e d e n t i a l s P r o v i d e r credentialsProvider ) { this . c r e d e n t i a l s P r o v i d e r = c r e d e n t i a l s P r o v i d e r ; } @Override public C l i e n t H t t p R e q u e s t c r e a t e R e q u e s t (URI u r i , HttpMethod httpMethod ) throws IOException { HttpURLConnection c o n n e c t i o n = openConnection ( u r i . toURL ( ) , null ) ; p r e p a r e C o n n e c t i o n ( c o n n e c t i o n , httpMethod . name ( ) ) ; prepareSecureConnection ( connection ) ; return new S e c u r e S i m p l e C l i e n t H t t p R e q u e s t ( c o n n e c t i o n ) ; } abstract protected void p r e p a r e S e c u r e C o n n e c t i o n ( HttpURLConnection c o n n e c t i o n ) ; }

Method SimpleClientHttpRequestFactory.createRequest() return an instance of a ClientHttpRequest. This is the abstraction used by RestTemplate to create HTTP request messages (with headers and body). The implementation of ClientHttpRequest used by the default is SimpleClientHttpRequestFactory, but because it is dened with only a package visibility constructor it can not be used directly. In stead, I dene a custom class SecureSimpleClientHttpRequestFactory that extends the support abstract class AbstractClientHttpRequest shipped with Spring Framework. 6 Sponsors

Method prepareSecureConnection() is called by createRequest() to setup the HttpURLConnection that is going to be used to perform the request. Since this is protocol specic, the method is dened as abstract and should be implemented by derived classes. SimpleClientHttpRequestFactory has a property for a CredentialsProvider. This is object that can be used by derived classes to get user credentials information. The specication for this interface is show below:
public i n t e r f a c e C r e d e n t i a l s P r o v i d e r { C r e d e n t i a l s g e t C r e d e n t i a l s ( S t r i n g realm ) ; } Credentials is simple data (transport) object that carries the user name and

password:
public c l a s s C r e d e n t i a l s { protected S t r i n g userName ; protected S t r i n g password ; // c o n s t r u c t o r s // s e t t e r s and g e t t e r s f o r p r o p e r t i e s userName and password . }

3.3

Implementing a Basic HTTP Secure RequestFactory

The nal step in our client implementation is to extend SecureSimpleClientHttpRequestFactory and specialized it for HTTP BASIC authentication. This involves dening method prepareSecureConnection() to setup the HTTP header Authorization with the user credentials. Below, I show the implementation:
public c l a s s B a s i c S e c u r e S i m p l e C l i e n t H t t p R e q u e s t F a c t o r y extends SecureSimpleClientHttpRequestFactory { public B a s i c S e c u r e S i m p l e C l i e n t H t t p R e q u e s t F a c t o r y ( ) { } protected void p r e p a r e S e c u r e C o n n e c t i o n ( HttpURLConnection connection ) { i f ( c r e d e n t i a l s P r o v i d e r==null ) { return ; } Credentials credentials = credentialsProvider . g e t C r e d e n t i a l s ( null ) ; S t r i n g token = c r e d e n t i a l s . getUserName ( ) + ":" + c r e d e n t i a l s . getUserName ( ) ; BASE64Encoder enc = new sun . misc . BASE64Encoder ( ) ; S t r i n g e n c o d e d A u t h o r i z a t i o n = enc . encode ( token . g e t B y t e s () ) ; c o n n e c t i o n . s e t R e q u e s t P r o p e r t y ( " Authorization " , " Basic " + encodedAuthorization ) ; } }

7 Sponsors

The HTTP Basic authentication protocol requires that the client send a HTTP request header named Authorization with the following form: Authorization: Basic BASE64Encoded[userName : password] The string Basic is used to specify that the provided credentials follow the HTTP Basic format. This is a BASE64 character encoded string with the name of the user and password concatenated with the double-column character :. Since custom coding the details of BASE64 encoding can be lead to implementation errors and is extra work, I use an existing implementation for the encoding. Namely, the class sun.misc.BASE64Encoder that is packaged with the Java SDK. The server extracts the user credentials information by applying the reverse decoding operation. Since the decoding operation can be done without any sort of secret parameter, it can potentially be done by eavesdropper that intercept client messages. For all intends and purposes, it is as if the credentials are sent has plain text through the wire. This means that Basic HTTP authentication provides limited security again this kinds of attacks. There are two turn around for HTTP limited security against eavesdropping: either drop the HTTP Basic authentication and use a more secure solution such as HTTP Digest authentication; or, alternatively, use a secure HTTP(/TCP/IP) channel between the client and the server. Channel security is usually implemented using an HTTPS connection that add an SSL layer on top of TCP/IP, to build the protocol stack: HTTPS = HTTP/SSL/TCP/IP. A modern variant is of SSL is TLS. Note that if no CredentialsProvider is congured, then authentication headers can not be set. This is likely to cause the server to deny access to the resource and have an exception eventually throw by RestTemplate. An alternative approach would be to have the prepareSecureConnection() method throw a RuntimeException, so that no request is sent to the server in the rst place.

3.4

Basic HTTP Client Authenthication with Apache Commons HttpClient

In the approach described above, I implemented a ClientHttpRequestFactory for Basic HTTP authentication that manually sets the HTTP Authenticate header on Java SDK HttpURLConnection. An alternative, and very popular, abstraction for HTTP communication in the client side is the Apache Commons HttpClient. Apache HttpClient has the advantage over Java HttpURLConnection that it has built-in support for dierent authentication protocols, including Basic and Digest HTTP authentication. This means that HttpClient can be used to implementing Java clients for secure REST-WS without having to deal directly with HTTP headers for authentication. Spring Framework also comes with an implementation of a ClientHttpRequestFactory that uses the Apache HttpClient this is the class CommonsClientHttpRequestFactory. Thus, HttpClient is an additional natural choice for implementing secure REST-WS with Spring Framework. Below, I show the code for a custom ClientHttpRequestFactory that extends Spring CommonsClientHttpRequestFactory to work with HTTP authentication the class SecureCommonsClientHttpRequestFactory.
package o r g . h e l l o a p p . r e s t s e c u r i t y . c l i e n t ;

8
Sponsors

import o r g . apache . commons . h t t p c l i e n t . UsernamePasswordCredentials ; import o r g . apache . commons . h t t p c l i e n t . auth . AuthScope ; import o r g . s p r i n g f r a m e w o r k . h t t p . c l i e n t . CommonsClientHttpRequestFactory ; public c l a s s SecureCommonsClientHttpRequestFactory extends CommonsClientHttpRequestFactory { protected C r e d e n t i a l s P r o v i d e r c r e d e n t i a l s P r o v i d e r ; public SecureCommonsClientHttpRequestFactory ( ) { } public C r e d e n t i a l s P r o v i d e r g e t C r e d e n t i a l s P r o v i d e r ( ) { return c r e d e n t i a l s P r o v i d e r ; } public void s e t C r e d e n t i a l s P r o v i d e r ( C r e d e n t i a l s P r o v i d e r credentialsProvider ) { this . c r e d e n t i a l s P r o v i d e r = c r e d e n t i a l s P r o v i d e r ; C r e d e n t i a l s c r e d = c r e d e n t i a l s P r o v i d e r . g e t C r e d e n t i a l s ( null ); U s e r n a m e P a s s w o r d C r e d e n t i a l s d e f a u l t c r e d s = new U s e r n a m e P a s s w o r d C r e d e n t i a l s ( c r e d . getUserName ( ) , c r e d . getPassword ( ) ) ; g e t H t t p C l i e n t ( ) . g e t S t a t e ( ) . s e t C r e d e n t i a l s ( AuthScope .ANY, defaultcreds ) ; } }

The key aspect of the implementation of Spring CommonsClientHttpRequestFactory is that an instance of HttpClient instance created and made available as a property. In the custom derived class above the HttpClient is congured to work with HTTP authentication by setting the user credential with method HttpClient.getState() . setCredentials () . Because, in the test client code only one server (and realm) is considered, I assumed for simplication that the provided credentials are correct in all contexts rather than use a dierent username or password for each host and realm. This authentication scope information is specied to HttpClient with parameter value AuthScope.ANY. Below, I show the HTTP request message sent by the REST client and the corresponding response sent by Spring MVC and Spring Security enabled REST-WS (captured and proxied with Eclipse TCP/IP Monitor tool): Client HTTP Request Message:
GET / r e s t s e c u r i t y / s e c u r e d HTTP/ 1 . 1 Accept : t e x t / p l a i n , / User Agent : J a k a r t a CommonsH t t p C l i e n t / 3 . 1 A u t h o r i z a t i o n : B a s i c YWRtaW46YWRtaW4= Host : l o c a l h o s t : 8 0 8 0 Cookie : $ V e r s i o n =0; JSESSIONID=434 A851852D7146B3C1608F6E38EB147 ; $Path=/ r e s t s e c u r i t y

Server HTTP Response Message: 9


Sponsors

HTTP/ 1 . 1 200 OK S e r v e r : ApacheCoyote / 1 . 1 Set Cookie : JSESSIONID=9B3F0F0F021EF330E35C6A3A902C8BBD ; Path =/ r e s t s e c u r i t y ; HttpOnly Content Type : t e x t / p l a i n Content Length : 38 Date : Wed, 28 Sep 2011 1 6 : 1 8 : 1 6 GMT SECURED: Wed Sep 28 1 6 : 1 8 : 1 6 WEST 2011

Note that the client is sending the Authorization header already in the rst (and only) request message. This prevents the server to deny the rst request by lack of Authorization header, and for the client to have to send two requests.

Securing REST Web Services: Digest Authentication

For communication channels that transport highly sensitive information, HTTPS and SSL are a good solution to implement secure HTTP channels and complement HTTP Basic authentication. On the other hand, if not all the information to move around is sensible then encrypting data with HTTPS/SSL is an overkill. This is because encrypting large amounts of data is costly to the client, and specially, to the server that may need to serve large number of concurrent clients. If the only requirement for the HTTP channel is to protected the user password from easy disclosure, HTTP Digest authentication is a more recommended option. In Digest authentication user information, such as name and password, are never sent has plain text on the wire. Rather, both client and server use the message digest algorithm MD5 to scramble the bits of security sensitive information. Because MD5 digests can not be reversed except by brute force analysis, there is limited possibilities of disclosure of sensitive information. Digest authentication also requires that a server provides a limited lifetime nonce (semi-random sequence of bits) to the client, and that the client includes this nonce in the computations for digests of security token. This further reduces the changes for attackers to replay security tokens previous sent on the wire. Digest authentication piggybacks on HTTP protocol the same way as Basic authentication. Namely, clients needs to set the Authorization HTTP header with the appropriate security token. A key dierence is, of course, that security token are encrypted with MD5. Another important dierence, is that the rst request sent by a client is always rejected because creating a valid Authorization needs a server provided nonce.

4.1

Additional Secured Resource

Because the implementation of secured service is independent of the security mechanisms used, we can often upgrade authentication mechanisms without any change on the service. For example, we can upgrade a service initially secured with Basic authentication to Digest authentication. On the other hand, is possible to have dierent services secured with dierent mechanisms. 10 Sponsors

For the sample REST-WS used in this article, I would like to keep the
SecuredRestWSController.secure() method secured with Basic authentication. So

I will dene an additional method to be secured with Digest authentication. Below, I show the denition of this additional REST-WS method SecuredRestWSController .xsecured() accessible from URL /xsecured.
@Controller public c l a s s S e c u r e d R e s t W S C o n t r o l l e r { ... @RequestMapping ( v a l u e = "/ xsecured " , method = RequestMethod . GET) public @ResponseBody S t r i n g x s e c u r e d ( ) { return " XSECURED : " + new Date ( ) ; } }

4.2

Conguring Spring Security for Digest Authentication

As hinted above, Spring Security uses a lter chain that is setup with a DelegatingFilterProxy congured in the application descriptor le web.xml. Internally, this works by having the DelegatingFilterProxy creating a Spring bean with type FilterChainProxy and with the same name as the lter name used for the DelegatingFilterProxy. DelegatingFilterProxy delegates the actual work of ltering incoming HTTP request to an instance of FilterChainProxy. FilterChainProxy in turn takes the responsability of creating the individual lters and assemble them in the right order. Performing user authentication and authorizing access to resources is the outcome of the combined work of this individual lters. Unless one explicitly congures a FilterChainProxy bean, the lter name for the DelegatingFilterProxy should be springSecurityFilterChain. This is because the Spring Security namespace conguration creates and congures a instance of type FilterChainProxy automatically with this bean name. And is the bean with this name that is lookedup in the root application context by DelegatingFilterProxy. For security congurations with extensive XML namespace support, explicitly dening a FilterChainProxy Spring bean is usually not necessary. However, doing that allows additional or alternative lters to be congured as Spring bean les. The need for a custom chain exist because conguring HTTP Digest authentication requires conguring specialized lter(s) and beans. Unfortunately, Spring Security XML namespace support does not cover all the features of Spring Security. For Basic HTTP authentication the element <httpbasic> sets up all the required infrastructure, but for Digest authentication there is no corresponding <httpdigest>. Below, we show an example of an explicit conguration of a FilterChainProxy to setup basic, digest, and form based authentication. The element <lter chain> is used as a convenient way to specify a concrete lter chain for a particular URL pattern.
<beans:bean id=" filterChainProxy " c l a s s=" org . springframework . security . web . FilterChainProxy "> <beans:constructor arg> < b e a n s : l i s t>

11
Sponsors

< f i l t e r chain pattern="/ secured /** " f i l t e r s =" securityContextPersistenceFilterWithASCFalse , basicAuthenticationFilter , exceptionTranslationFilter , filterSecurityInterceptor " /> < f i l t e r chain pattern="/ xsecured /" f i l t e r s =" securityContextPersistenceFilterWithASCFalse , basicAuthenticationFilter , exceptionTranslationFilter , filterSecurityInterceptor " /> < f i l t e r chain pattern=" /** " f i l t e r s =" securityContextPersistenceFilterWithASCTrue , formLoginFilter , exceptionTranslationFilter , filterSecurityInterceptor " /> </ b e a n s : l i s t> </ beans:constructor arg> </ beans:bean>

The above conguration of FilterChainProxy is a bit verbose, because we are completely redening the chain of lters to use. And since dierent URL prexes use dierent authentication mechanisms, we need to setup a dierent chain for each URL pattern. (You can check the Spring Security reference documentation for a detailed explanation of the purpose and conguration of each of these lters). Explicitly dening all the lter of a chain is somewhat an overkill if one only wants to provide one or a few additional custom lter(s). An alternative approach, is to let Spring Security namespace setup common lters and have the application conguration add extra lter(s) somewhere along the chain. Below, I show how to use XML namespace support to setup custom lters for Digest authentication (while retaining Basic authentication for some URLs):
<http pattern="/ secured ** "> <httpbasic /> <intercept url pattern="/ secured ** " access=" ROLE_ADMIN " /> </ http> <http pattern="/ xsecured ** " entrypointr e f=" digestEntryPoint " > <custom f i l t e r r e f=" digestFilter " position=" BASIC_AUTH_FILTER " /> <intercept url pattern="/ xsecured ** " access=" ROLE_ADMIN " /> </ http>

Note that we are using multiple top-level <http> elements matching different URL prexes (a feature introduced since Spring Security 3.x). The rst <http> element is used to congure the Basic HTTP authentication, as discussed in previous sections, but this time restricting the URL prex that is mapped and secured. The second <http> element is used to congure the Digest authentication and mapped to URL prex /xsecured**. The novel element for the conguration of digest authentication is the use of <custom-filter> to setup a lter that perform Digest authentication. Because the XML namespace handler for <http> element automatically creates 12 Sponsors

all other lters that are required to make a fully functional chain namely, securityContextPersistenceHolder, exceptionTranslationFilter , and lterSecurityInterceptor , only the Digest authentication lter needs to be congured. For Basic authentication, the element <httpbasic/> takes care of creating the authentication lter and conguring it in the chain type BasicAuthenticationFilter. For Digest authentication, explicitly conguration is required. The lter for Digest authentication should be an instance of DigestAuthenticationFilter . Because it takes the same functional role as the BasicAuthenticationFilter, we have inserted in the chain in the same relative position. This is done by specifying attribute position="BASIC_AUTH_FILTER". The actual denition of the DigestAuthenticationFilter is show below as bean digestFilter :
<beans:bean id=" digestFilter " c l a s s=" org . springframework . security . web . authentication . www . DigestAuthenticationFilter "> <beans:property name=" userDetailsService " r e f=" userService " / > <beans:property name=" authenticationEntryPoint " r e f=" digestEntryPoint " /> </ beans:bean>

The property userDetailsService is a reference to the user service that provides credentials information. The same user credential database is being used for Basic and Digest authentication. So a reference to the same bean can be used (repeated below):
<authentication manager> <authentication provider> <userservice id=" userService "> ... </ userservice> </ authentication provider> </ authentication manager>

The other dependency of digestFilter is an instance of DigestAuthenticationEntryPoint . This is the bean responsible to setup the HTTP headers for Unauthorized responses, when the user does not provide adequate credentials information in the Authorization header. Below, I show the conguration of DigestAuthenticationEntryPoint as bean digestEntryPoint:
<beans:bean id=" digestEntryPoint " c l a s s=" org . springframework . security . web . authentication . www . DigestAuthenticationEntryPoint "> <beans:property name=" realmName " value=" My Digest Secure REST - WS " /> <beans:property name=" key " value=" somenouncekey " /> <beans:property name=" nonceValiditySeconds " value=" 10 " /> </ beans:bean>

Property realmName species the identier that is shown to the user when requested for credentials. It also needs to be included in security token by clients. Property key is a random string used as an additional piece of data insert in the nonces generated by the server. Property nonceValiditySeconds species the 13 Sponsors

validity of server nonces. Smaller values imply more secure applications, but also that the client will get more Unauthorized messages asking to refresh the authentication with a new nonce. Probably you have noticed that the bean digestEntryPoint is specied also in attribute entrypointref="digestEntryPoint" of element <http>. This is required because the digestEntryPoint is also a dependency for the exceptionTranslationFilter create by <http>. At this point we are ready to deploy the REST-WS with the extra method secured with Digest authentication (in addition to previous method secured with the simpler Basic authentication). An worthy exercise is to try to invoke the Digest secured method xsecured(), through URL /xsecured, in a client that only support Basic authentication. Below, we see the typical response of the server with HTTP status code 401 Unauthorized (captured and proxied with Eclipse TCP/IP Monitor tool). Server HTTP response Message for:
HTTP/ 1 . 1 401 U n a u t h o r i z e d S e r v e r : ApacheCoyote / 1 . 1 Set Cookie : JSESSIONID=CD4D053FEBCFA6577FC98721E403C33C ; Path =/ r e s t s e c u r i t y ; HttpOnly W W W A u t h e n t i c a t e : D i g e s t realm=My D i g e s t S e c u r e REST WS , qop =auth , nonce= MTMxNzA1MDEwOTk0MTo0MmZhNWIyMjkzYWQwN2U3MGM2YjY1N2UzYTZhMWM3NA == Content Type : t e x t / html ; c h a r s e t=u t f 8 Content Length : 1187 Date : Mon, 26 Sep 2011 1 5 : 1 4 : 5 9 GMT

Because the server response includes the header WWW-Authenticate: Digest, we can make a good guess that the DigestAuthenticationEntryPoint and the lter chain for Digest authentication is setup appropriately. The next, and nal, step is to invoke the REST-WS with a Digest authentication aware client.

REST Client with Digest Authentication

Fortunately for us, Apache Commons HttpClient as built-in support not only for Basic HTTP authentication, but also Digest HTTP authentication. Moreover, HttpClient is able to detect from the rst server response which authentication protocol is mandated by the server for a particular URL. This means that we can use the same custom implementation SecureCommonsClientHttpRequestFactory that was used for Basic authentication.

5.1

Digest HTTP Client Authenthication with Apache Commons HttpClient

Below, I show a sample of the HTTP messages exchanged between a REST-WS client, implemented with RestTemplate congured with SecureCommonsClientHttpRequestFactory , and the server: Client HTTP First Request Message:
GET / r e s t s e c u r i t y / x s e c u r e d HTTP/ 1 . 1

14
Sponsors

Accept : t e x t / p l a i n , / User Agent : J a k a r t a CommonsH t t p C l i e n t / 3 . 1 Host : l o c a l h o s t : 8 0 8 0

Server HTTP First Response Message:


HTTP/ 1 . 1 401 U n a u t h o r i z e d S e r v e r : ApacheCoyote / 1 . 1 Set Cookie : JSESSIONID=214B34FA1CA1EAD298A88405DF1658F9 ; Path =/ r e s t s e c u r i t y ; HttpOnly W W W A u t h e n t i c a t e : D i g e s t realm=My D i g e s t S e c u r e REST WS , qop =auth , nonce= MTMxNzIyNzEzNjA5MTo5YTM4MTAwOTIxZTI4MWEyOGNkMGI4ZTcyMzM1ODYzMA == Content Type : t e x t / html ; c h a r s e t=u t f 8 Content Length : 1187 Date : Wed, 28 Sep 2011 1 6 : 2 5 : 2 6 GMT

Note, again, that the rst HTTP response sent by the server has status code 401 Unauthorized. This is because the clients rst request does not have the appropriate Authorization header. Fortunately, the server provides in the HTTP header WWW-Authenticate all the information the client needs to build the Authorization header, including: the nonce generated by Spring Security, the realm name that was congured in the <http> XML element, and the quality-of-protocol (qop) attribute that for Spring Security is always auth. In the second HTTP request sent by the client, the header Authorization is set by Apache HttpClient as expected by the Digest secured server. The client request also includes a client generated nonce, as header attribute cnonce, for increased security. Client HTTP Second Request Message:
GET / r e s t s e c u r i t y / x s e c u r e d HTTP/ 1 . 1 Accept : t e x t / p l a i n , / User Agent : J a k a r t a CommonsH t t p C l i e n t / 3 . 1 A u t h o r i z a t i o n : D i g e s t username=admin , realm=My D i g e s t S e c u r e REST WS , nonce= MTMxNzIyNzEzNjA5MTo5YTM4MTAwOTIxZTI4MWEyOGNkMGI4ZTcyMzM1ODYzMA ==, u r i =/ r e s t s e c u r i t y / x s e c u r e d , r e s p o n s e =4 f 3 e 4 7 7 1 b b 5 f 8 6 4 9 b 9 5 5 c c 2 b 5 2 6 9 d f 4 c , qop=auth , nc =00000001 , cnonce=b f 6 7 1 b 5 5 9 b f 5 3 a 7 7 b 7 d 7 7 a 7 b 4 f f a f 6 7 4 Host : l o c a l h o s t : 8 0 8 0 Cookie : $ V e r s i o n =0; JSESSIONID=214 B34FA1CA1EAD298A88405DF1658F9 ; $Path=/ r e s t s e c u r i t y

The Spring Security enable server recognizes the clients eort to sent the correct Digest authentication information, and responds with the status code 200 OK and the return value of the REST-WS method xsecured() marshalled in the body of the response. Server HTTP Second Response Message:
HTTP/ 1 . 1 200 OK S e r v e r : ApacheCoyote / 1 . 1 Set Cookie : JSESSIONID=2BCF410FB3422FD6D68691E32FB331FC ; Path =/ r e s t s e c u r i t y ; HttpOnly

15
Sponsors

Content Type : t e x t / p l a i n Content Length : 39 Date : Wed, 28 Sep 2011 1 6 : 2 5 : 2 6 GMT XSECURED: Wed Sep 28 1 7 : 2 5 : 2 6 WEST 2011

Summary and Conclusions

I have shown how to implement REST-WS based on Spring Security and RestTemplate . Conguring Spring security for Basic HTTP authentication is very simple, due to the provided namespace support. Digest HTTP authentication requires a bit more conguration. On the client side, I used custom ClientHttpRequestFactory to congure a RestTemplate instance to have the client send authentication information as requested or expected by the server. Implementing Basic authentication is simple enough that security header can be set using a HttpConnection. For Digest authentication it is more convenient to use Apache HttpClient library to set HTTP headers.

Exercises to the Reader


Below, I present some suggestions to possible extensions to approach outline in this article to secure REST-WS based on Spring Framework RestTemplate. Features that requires extra work and/or are more dicult to implement are marked with . All the beans required to implement RestClient(s) , such as RestTemplate, particular types of ClientHttpRequestFactory, and CredentialsProvider were created and congured in Java code. Since we are using Spring Framework both on the the client and server side, we can also dene these bean in a Spring Bean denition le. Create one or more Spring beans XML les to perform the conguration of the client. Use Spring class ClassPathXmlApplicationContext to read the XML les and congure the client application. Note that BasicSecureSimpleClientHttpRequestFactory and SecureCommonsClientHttpRequestFactory are not passing the realm name provided by the server to the CrendentialProvider . This is because the client is using preemptive authentication that is, it sends the authentication information on the rst (and only) request. Read the documentation of HttpClient and see how this could be xed for SecureCommonsClientHttpRequestFactory. I have used a very simple implementation of a user credentials provider that provides a pre-congured username and a password. A more general approach is to have an implementation based on GUI modal dialog, that asks the user for a name and password. Using your favorite widget toolkit for Java, such as Swing or SWT, implement a GUI based implementation of a credentials provider. I showed how to use Apache HttpClient to implement Digest HTTP authentication. Implementing Digest based authentication directly with 16 Sponsors

Java HttpConnection is much more tricky and requires detailed study of the Digest HTTP authentication header. Implement a class DigestSecureSimpleClientHttpRequestFactory that does this. To perform the digest computations based on MD5 algorithm use the Java security static method MessageDigest.getInstance("MD5").

Resources

HTML version of this article http://www.jpalace.org/docs/tech-notes/spring/rest-security.

External References

Spring Security 3.1.x Online Reference Manual http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurit HTTP Basic Authentication at Wikipedia.org http://en.wikipedia.org/wiki/HTTP authentication HTTP Digest Authentication at Wikipedia.org http://en.wikipedia.org/wiki/Digest Access Authentication

Software
Source code for this article - rest-security.zip, rest-security.jar

Acknowledgements
If you have any comments or suggestions that you think may improve this document please send an e-mail to the author.

About the Author


Jorge Sim ao is currently a GLINTT trainer and consulter, in partnership with SpringSource/VMWare. Before this, he was a Computer Science and Articial Intelligence professor at Faculty of Sciences of University of Porto, and a researcher in Intelligent Computing and Cognitive Modeling. He has a Ph.D., MSc., and B.Sc. in Computer Science and Engineer. His Ph.D. work focused on Social Simulation, and M.Sc. work focused on Reliable Distributed Computing. He is a highly experienced trainer, and a experience software engineer with 15+ years in software development and with hands-on prociency in a wide range of computing technologies.

17 Sponsors

You might also like