Feb
15
2015

Spring OAuth 2 Token Based Authentication

Token based authentication is a method that is used to provide authorized access to resources for a pre-authenticated client. It basically needs the client to provide username and password as identity and receive a token. This token will then be used to access the protected resources for that client and grants access temporarily with an expiration period. The steps of token based authentication are illustrated as follows.

  1. Provide username and password for the authorization point.
  2. Receive access token.
  3. Send access token to the resource server.
  4. Resource server authenticate the ticket.
  5. Resource server supplies the requested resource.

OAuth

OAuth is an open standard of authorization. It allows secure access to resources for clients on behalf of the resource owner by token based authentication. It has the following 3 main components.

  1. OAuth authorization server, which takes care of authorizing clients and their token requests.
  2. Resource server, which is in charge of securing access to the resources delegated to it and granting access.
  3. Access token, the token that is used to pass authentication.

Value Card Project

These OAuth configurations were required for the Value card project which is currently ongoing at Mazarin. The Value card project in basic terms is a system that would support Gift card, Loyalty card or Debit card management facilities and infrastructures to Enterprises and merchants that requires such an implementation. Facilities such as creating card programs, ordering cards, card issuing and redeeming are provided by the system.

Value card also provides a REST API for POS systems to consume Value card services.

A REST API provides a set of services that communicate over HTTP using HTTP verbs such as GET, POST, DELETE, PUT etc. By using one of those REST methods and a URL, a service client can access a resource hosted at that URL. Generally there are certain abilities assigned to those methods but they are not strict. But it is always good to follow guidelines when implementing RESTful web services.

When providing these REST services the security aspect is of concern. While some resources can be provided readily, others might need authentication. For this requirement OAuth proves to be a good tool.

Spring OAuth 2

Spring framework has its’ implementation of OAuth and has support for OAuth1 and OAuth2. This post will focus on the use of OAuth2 by using Spring support provided for it.

Spring OAuth provider has mainly 2 parts that matches the OAuth standards. An authorization server and resource server. Spring applications can be modified to have one authorization server and one or more resource server(s) that can be configured to use the same authorization server. It also involves configuring clients to use OAuth and token related configuration. It is highly customizable to meet the application requirements. The requests to OAuth tokens are handled by Spring MVC controllers. Granting access to the protected resources are handled by the Spring security filter chain.

Now let’s take a look at how to implement Spring OAuth2 in your application.

The dependency to add OAuth2 (2.0.1 release )to your maven build is.

<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>

HttpSecurity Configuration

The first point to identify is what and how do you want to secure your application. OAuth2 security is suggested as most suitable to secure some resources that you want to expose within your application to a pre authenticated entity. In the Value Card application which OAuth was implemented the requirement was to secure some resources exposed by the REST API. The considerations here was that the application already had in place a security implementation in the security xml that was used for the web application which has the following basic setup. This uses the default authentication manager with a user detail service that has user details from application user accounts in the database.

<http access-decision-manager-ref="accessDecisionManager" auto-config="true">
	<intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>
	<intercept-url pattern="/logout*" access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="https"/>
	<intercept-url pattern="/**" access="" requires-channel="https"/>
	<form-login login-page="/login.html" always-use-default-target="true" default-target-url="/home.html" authentication-failure-url="/login.html?error"/>
	</http>

The REST API was exposed with the /api/* endpoints. A servlet was declared separately to handle these calls in the web.xml

<servlet>
 <servlet-name>rest</servlet-name>
 <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
 </servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>rest</servlet-name>
  <url-pattern>/api/*</url-pattern>
</servlet-mapping>

The secured endpoints that requires the token are at /api/secure/*
All these http security configurations should be included in the security xml. The order is important so that the URL intercept won’t be overridden by a another intercept. To ensure this the more specified endpoints should be declared before. So the order of declaration would be

  • /api/secure/*
  • /api/*
  • /**

The secured resources under /api/secure/* use the OAuth authentication. Besides these all the rest of the services fall under the /api/* mapping including the token request which will be under /api/oauth/token. All these services need to have some kind of authentication too. Otherwise they will be free to used by anyone. So they will use basic authentication based on a client ID and client secret which also can be setup using Spring OAuth provider.

Client Authentication

To add client authentication we added a clientAuthenticationManager, which is additional to the default authentication manager.

<authentication-manager id="clientAuthenticationManager">
  <authentication-provider user-service-ref="clientDetailsUserService">
  </authentication-provider>
</authentication-manager>

The client authentication manager can be programmed to use its own user detail service. We defined it as a clientUserDetailService that will use clientDetails as follows.

<beans:bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client
                   .ClientDetailsUserDetailsService">
	<beans:constructor-arg ref="clientDetails" />
	</beans:bean>

	<oauth2:client-details-service id="clientDetails"/>

	<oauth2:client
           client-id="foo"
           secret="seCre1"
           authorized-grant-types="password,refresh_token"
           authorities="ROLE_CLIENT"
	 />
	</oauth2:client-details-service>

(oauth2 xml namespace is atxmlns:oauth2=”http://www.springframework.org/schema/security/oauth2″ with xsi:schemalocations http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd”)

We can add multiple clients to this. Clients listed here will be granted access to the web services. They have the client id and a client secret.

Then this needs to be added to the authentication entry point of /api/* services. The http security configuration is as follows with the required beans.

<http
	pattern="/api/**"
	create-session="stateless"
	authentication-manager-ref="clientAuthenticationManager">

	<intercept-url
		pattern="/api/oauth/token"
		access="<granted roles>"
		requires-channel="https"/>

        <intercept-url
		pattern="/api/**"
		access="IS_AUTHENTICATED_FULLY"
		requires-channel="https"/>

    <anonymous enabled="false"/>
    <http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
    <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER"/>
    <access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>

	<beans:bean id="clientAuthenticationEntryPoint" 	class="org.springframework.security.oauth2.provider.error
  .OAuth2AuthenticationEntryPoint">
	<beans:property name="realmName" value="<realmName>" />
	<beans:property name="typeName" value="Basic" />
	</beans:bean>

	<beans:bean id="clientCredentialsTokenEndpointFilter"                				class="org.springframework.security.oauth2.provider.client.
ClientCredentialsTokenEndpointFilter">
<beans:property name="authenticationManager" ref="clientAuthenticationManager"/>
	</beans:bean>

	<beans:bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.
OAuth2AccessDeniedHandler" />

To access the services the client needs to add the client ID and the client secret encoded in base64 to the Authorization header (Basic) of the service call.

Authorization: Basic

The token endpoint /oauth/token is also secured by this.

OAuth Authentication

The secured resources are under /api/secure/*. These are allowed access to authenticated users of the application. So access to these resources will require username password authentication of user accounts or user details configured for the system and who are in the database. To do this the user can use a login service that passes the username and password, when these are authenticated the user will be given a token. This token is required to access the resources under /api/secure/*. All this can be delegated to the OAuth authentication mechanism.

First of all need to add the authorization service. Which is as follows.

<oauth2:authorization-server
		client-details-service-ref="clientDetails"
		token-services-ref="tokenServices" >

		<oauth2:authorization-code />
		<oauth2:implicit/>
		<oauth2:refresh-token/>
		<oauth2:client-credentials />
		<oauth2:password authentication-manager-
				ref="authenticationManager"/>

	</oauth2:authorization-server>

Then a token service and the token store need to be configured. The token store uses an in memory token store. An alternative would be to use a persisted token store which can be configured using a JDBCTokenStore. We used the in memory token store.

	<beans:bean id="tokenServices"
		class="org.springframework.security.oauth2.provider.token
                                       .DefaultTokenServices">

	<beans:property name="tokenStore" ref="tokenStore" />
	<beans:property name="supportRefreshToken" value="true"/>
	<beans:property name="accessTokenValiditySeconds" value="64800"/>
	<beans:property name="clientDetailsService" ref="clientDetails"/>

	</beans:bean>

	<beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store
                                                     .InMemoryTokenStore">
	</beans:bean>

The resource server needs to be added so it will be take care of securing the secured service.

<oauth2:resource-server
		id="resourceServerFilter"
		resource-id="valuecard"
		token-services-ref="tokenServices"/>

To connect the /api/secure/* mapping to this token authentication the http security configuration has to be configured as follows.

<http
		pattern="/api/v1/secured/**"
		use-expressions="true"
		create-session="never"
		entry-point-ref="oauthAuthenticationEntryPoint">

		<anonymous enabled="false"/>
	        <intercept-url pattern="/api/v1/secured/**"
			access="isAuthenticated()"
			requires-channel="https"/>

	<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
	<access-denied-handler ref="oauthAccessDeniedHandler"/>
	</http>

	<beans:bean id="oauthAuthenticationEntryPoint"
                          class="org.springframework.security.oauth2.provider.error
                        .OAuth2AuthenticationEntryPoint"/>

When all these are in place the secured services can be accessed with the token. When a user tries to access the api/secure/* service without the token a response similar to following will be given.

<oauth>
	<error_description>An Authentication object was not found in the
		SecurityContext
	</error_description>
	<error>unauthorized</error>
</oauth>

Now we need to request the token.

Requesting a token

The token endpoint is at api/oauth/token. This is as described under client authentication. To request for the token a POST request is made to this endpoint with the client authorization header.

When the OAuth authorization service is configured these token endpoint mappings are configured with that. But in any case if we need to add a custom controller to this mapping it’s possible too. This custom token endpoint request controller is as follows.

@RequestMapping(value = "/token", method = RequestMethod.POST, headers = "Content-Type=application/json")
public OAuth2AccessToken token(@RequestBody AppUser user) {
.......
}

The authentication manager for the application user accounts are injected in to the controller. The user credentials are passed in the request body. This is mapped to an AppUser object which is a Spring SecurityUserDetail implementation that are the users of the system. These credentials are authorized with the default authentication manager. If they are authorized, then the token is created and returned from the above service. Following is an example of the token.

{
   "access_token": "c258dcb6-2d8e-404a-b427-3a841386bd1c",
    "token_type": "bearer",
    "refresh_token": "04af89d7-f801-4424-b843-2860bf940470",
    "expires_in": 64799,
    "scope": "read, trust write,"
}


Accessing secured resources

The secured resources can be accessed now by passing the token in the Authorization header.
Authorization: bearer c258dcb6-2d8e-404a-b427-3a841386bd1c

This token will expire at the configured time period. If another user requests for a token by using the login service a different token will be granted, these multiple tokens will work simultaneously. This is made possible by Spring OAuth2 configuration.

References:

  1. https://github.com/royclarkson/spring-rest-service-oauth
  2. http://porterhead.blogspot.com/2014/05/securing-rest-services-with-spring.html
  3. http://projects.spring.io/spring-security-oauth/docs/oauth2.html
  4. https://techannotation.wordpress.com/2014/04/29/5-minutes-with-spring-oauth-2-0/

Related Posts

avatar

About the Author: Samitha Jayathilaka

Samitha is a Software Engineer working at Mazarin (Pvt) Limited doing Java development work. He has hands on experience in J2EE development and Test driven development. In the recent years he worked on mobile development on the Android platform and now learning his way in to iPhone development. Being a graduate from University of Moratuwa he completed a GSoC project in 2012 for the Catroid organization (now known as Catrobat).

6 Comments + Add Comment

  • avatar

    Hi, Great Tutorial! Can you please tell me how do you give the clientdetails to be stored in LDAP directory rather than hardcoding? Would be of great help, I’m trying on that too..

    • avatar

      Hi,

      The above configurations used for the clientDetail and ClientDetailUserService can be customized to use a reference of an implementation of org.springframework.security.oauth2.provider.ClientDetailsService.

      <beans:bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
              <beans:constructor-arg ref="clientDetails"/>
        </beans:bean>
      
            <beans:bean id="clientDetails" class="foo.bar.CustomClientDetailServiceImpl">
            </beans:bean>
      

      Setting the grant types can be done in the implementation itself in the loadClientByClientId method implementation of CustomClientDetailServiceImpl. There you’ll be able to use the LDAP implementation to load the client and authenticate it.

      Appreciate the response and feedback. Hope this helped.

      Thank you!

  • avatar

    Can i intercept rest api call in spring oauth2?

    • avatar

      Of course you can.
      The API should provide a method to get the auth-token which will call the token endpoint explained above. After authentication the auth token will be with the API client. Thereafter all subsequent requests to the API should send the auth token to authorize those request.
      The process explained in the post can be used to achieve this.

  • avatar

    When an access token is created, the authentication must be stored so that resources accepting the access token can reference it later.

  • avatar

    Perfectly written content material, appreciatge it for entropy.

Leave a comment

*