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.
- Provide username and password for the authorization point.
- Receive access token.
- Send access token to the resource server.
- Resource server authenticate the ticket.
- 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.
- OAuth authorization server, which takes care of authorizing clients and their token requests.
- Resource server, which is in charge of securing access to the resources delegated to it and granting access.
- 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:
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..