Introduction
In this blog we will look at how to perform authentication for an application exposing its functionalities as Rest Services. All requests made to access protected resource of such an application needs to be accessible only to Authenticated Users.
We will use Spring Security with OAuth 2.0 to authenticate Users and provide access to protected resources.
What is Oauth 2.0?
Oauth 2.0 is an open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications. It is a simple way to publish and interact with protected data. It's also a safer and more secure way for server to give access to its protected resources. OAuth protocol enables a user to access protected resources from trusted client through an API.
How it works?
We will use the OAuth - Resource Owner Password Flow protocol to provide access to a protected resource on the server.
Obtain the Access Token
Fig: Resource Owner Password Flow
- Client requests the Server for an AccessToken by providing client credentials (client_id & client_secret) & user credentials (username & password)
- If credentials are valid, Client will get an Access Token in response
The access Token is a string denoting a specific scope, lifetime, and other access attributes
Accessing Protected Resource
Fig: Accessing protected resource
- Client needs to provide the access token retrieved in the above steps along with the request to access the protected resource. Access token will be sent as an authorization parameter in the request header
- Server will authenticate the request based on the token
- If token is valid then client will get an access to protected resource otherwise access is denied
The benefit of OAuth is that the API does not require users to disclose their credentials every time they access a protected resource. User provides the access token obtained during login, for all subsequent requests to access the protected resources.
Implementation
Below are some important configurations that need to be done in the spring-servlet.xml file to configure Oauth 2.0
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="authenticationManager"
xmlns="http://www.springframework.org/schema/security" >
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<bean id="clientDetails" class="demo.oauth2.authentication.security.ClientDetailsServiceImpl"></bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<http> configuration:
This tag is defined to process request for authentication.
- For Authenticating a User the Client application will send request to the URL "/oauth/token". This request will contain the clientId, client password, userName and user password details
- The clientCredentialsTokenEndpointFilter filter will extracts client credentials from request & create authentication object in security context
- Then authentication manager extracts the Authentication Object set in the SecurityContext and passes it to the clientDetailsUserService
- The clientDetailsUserService holds reference to an instance of a custom bean clientDetails. The ClientDetailsServiceImpl class implements the ClientDetailsService interface and implements the method loadClientByClientId. The clientDetailsUserService bean calls this method from to authenticate the client
- If the Client Credentials are valid then authentication manager will update authentication object in the application security context and set the authenticated flag to true
- The request is then forwarded to the Oauth server for retrieving the access token
- If the authentication fails the request is forwarded to the clientAuthenticationEntryPoint which displays the appropriate error to the User
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices">
<oauth:authorization-code />
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials />
<oauth:password authentication-manager-ref="userAuthenticationManager"/>
</oauth:authorization-server>
<authentication-manager id="userAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="customUserAuthenticationProvider">
</authentication-provider>
</authentication-manager>
<bean id="customUserAuthenticationProvider"
class="demo.oauth2.authentication.security.CustomUserAuthenticationProvider">
</bean>
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="accessTokenValiditySeconds" value="900000000"></property>
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
</bean>
<oauth:authorization-server>
This tag is defined to configure authorization-server of oauth. Server serves requests based on grant type.
- The Oauth Server receives the request once the client is authenticated using above steps
- Since the Grant type of request is a password, client and user needs to be authenticated by the Oauth server
- Since the Client is already authenticated in process mentioned above the Oauth server now checks for the User authentication using the userAuthenticationManager
- Then userAuthenticationManager extracts the Authentication Object set in the SecurityContext and passes it to the customUserAuthenticationProvider
- The CustomUserAuthenticationProvider class implements the AuthenticationProvider interface and implements the method authenticate to authenticate the user
- If the User Credentials are valid then authentication manager will update authentication object in the application security context and set the authenticated flag to true
- Then tokenServices will then generate the access token using tokenStore
- The tokenStore uses InMemoryTokenStore to create access token and wraps authentication from SecurityContext into token
- Authorization-server will send the access token in response to user request
- If authentication fails, the request is forwarded to the oauthAuthenticationEntryPoint which displays the appropriate error to the User
<http pattern="/resources/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/resources/**" method="GET" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<oauth:resource-server id="resourceServerFilter"
resource-id="springsec" token-services-ref="tokenServices" />
<http> configuration:
This tag is defined to process request to access protected resource.
- For accessing the protected resource Client application will send request to the URL "/resources/**". This request will contain the access token in request header
- The resourceServerFilter indicates that requested resources is oauth 2 protected
- Then Oauth-authorization-server will retrieve the access token and authenticate the request
- If the token is valid user will be redirected to protected resource otherwise the request is forwarded to the oauthAuthenticationEntryPoint which displays the appropriate error to the User
<http pattern="/logout" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/logout" access="ROLE_CLIENT" method="GET" />
<sec:logout invalidate-session="true" logout-url="/logout" success-handler- ref="logoutSuccessHandler"/>
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="logoutSuccessHandler"
class="demo.oauth2.authentication.security.LogoutImpl" >
<property name="tokenstore" ref="tokenStore"></property>
</bean>
This tag is defined to process request to logout the user from application.
- For logout Client application will send request to the URL "/logout". This request will contain the access token in request header
- This request will be authenticated similar to request of accessing protected resource using resourceServerFilter and accessDecisionManager
- Then session of the user is invalidated and the request is forwarded to the logoutSuccessHandler
- The LogoutImpl class implements LogoutSuccessHandler interface and implements onLogoutSuccess method to remove access token of the user from tokenStore
- The client is successfully logged out
Find the source code in attached ZIP file.
STEPS TO RUN THE APPLICATION:
- Import downloaded source demo.rest.springsecurity.oauth2.0.authentication as maven project in eclipse IDE
- Start the application in Tomcat
- Then use CURL(command line utility) to run HTTP requests using following commands
- Request To authenticate:
curl –X -v –d "username=user1&password=user1&client_id=client1&client_secret=client1&grant_type=password" -X POST"http://localhost:8044/demo.rest.springsecurity.oauth2.0.authentication/oauth/token"
- Response after above request :
{"access_token":"6fd0f4b7-ca03-49ff-ae46-eea5e6929325","token_type":"bearer","re fresh_token":"49bdb713-1827-4d83-83dc-59fe225f4726","expires_in":299999}
Here access token from this response need to be use in every subsequent request to access protected resource as follows.
- Request To access protected resource getMyInfo :
curl -H "Authorization:Bearer 6fd0f4b7-ca03-49ff-ae46-eea5e6929325" "http://localhost:8044/demo.rest.springsecurity.oauth2.0.authentication/getMyInfo”
- Request To logout :
curl -H "Authorization:Bearer 6fd0f4b7-ca03-49ff-ae46-eea5e6929325" "http://localhost:8044/demo.rest.springsecurity.oauth2.0.authentication/logout”