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.
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.
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
The access Token is a string denoting a specific scope, lifetime, and other access attributes
Accessing Protected Resource
Fig: Accessing protected resource
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.
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.
<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.
<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.
<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.
Find the source code in attached ZIP file.
STEPS TO RUN THE APPLICATION:
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"
{"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.
curl -H "Authorization:Bearer 6fd0f4b7-ca03-49ff-ae46-eea5e6929325" "http://localhost:8044/demo.rest.springsecurity.oauth2.0.authentication/getMyInfo”
curl -H "Authorization:Bearer 6fd0f4b7-ca03-49ff-ae46-eea5e6929325" "http://localhost:8044/demo.rest.springsecurity.oauth2.0.authentication/logout”