- http://oauth.net/2/
- https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
- https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
OK, we are fine now. No more prerequisites.
Not like other tutorials this implementation is using custom JDBCTokenStore to store client id/secrets and user authentication details in MySQL DB.
Source code : https://github.com/rajithd/spring-security-oauth2-rest
Here I'm going to implement 3-legged oauth flow and please check the below diagram in order to understand this.
Lets start,
Step 1
Create database as oauth and then use import.sql file to create tables and add some seed data.
Before running make sure to change the db properties located in resources folder. (https://github.com/rajithd/spring-security-oauth2-rest/blob/master/src/main/resources/database.properties)
create database oauth;
use oauth;
source <path/to/resorce/folder>/import.sql;
Step 2
Build the project using maven
mvn clean install -DskipTests
Step 3
copy the war file into tomcat/webapps then start the tomcat
Fetch request_token
http://localhost:8080/oauth2/oauth/token?grant_type=password&client_id=rajith-client-id&client_secret=12345&username=rajith&password=password
Response
{
access_token: "f833a754-0d6c-4595-92c8-99b202ea6dd4"
token_type: "bearer"
refresh_token: "967068eb-13d1-4d18-8dd8-b89b2124d5d6"
expires_in: 4
scope: "read trust write"
}
Fetch access_token by submitting request_token
http://localhost:8080/oauth2/oauth/token?grant_type=refresh_token&client_id=rajith-client-id&refresh_token=967068eb-13d1-4d18-8dd8-b89b2124d5d6&client_secret=12345
Response
{
access_token: "d78dd4c7-41c3-443d-a85e-3716ceefc66f"
token_type: "bearer"
refresh_token: "967068eb-13d1-4d18-8dd8-b89b2124d5d6"
expires_in: 4
scope: "read trust write"
}
Accessing protected resource
http://localhost:8080/oauth2/test/ateam?access_token=d78dd4c7-41c3-443d-a85e-3716ceefc66f
You can use Authorization header to send the access token for protected resources.
Authorization Bearer d78dd4c7-41c3-443d-a85e-3716ceefc66f
Main configuration file is located in under webapps (spring-security.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
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"/>
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
separately. This isn't mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/test/*" 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="/test/*" access="ROLE_USER"/>
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<constructor-arg name="strength" value="11"/>
</bean>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="userService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Used for the persistenceof tokens (currently an in memory implementation) -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="oAuth2RequestFactory"
class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<constructor-arg ref="clientDetails"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenStore" ref="tokenStore"/>
<property name="requestFactory" ref="oAuth2RequestFactory"/>
</bean>
<!-- authorization-server aka AuthorizationServerTokenServices is an interface that defines everything necessary for token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter" resource-id="test" token-services-ref="tokenServices"/>
<bean id="clientDetails"
class="org.ateam.common.service.ClientService">
</bean>
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<!--you could also wire in the expression handler up at the layer of the http filters. See https://jira.springsource.org/browse/SEC-1452 -->
<sec:expression-handler ref="oauthExpressionHandler"/>
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler"/>
<oauth:web-expression-handler id="oauthWebExpressionHandler"/>
</beans>
Clone the repo and change it accordingly for your needs. Happy coding!
what is difference between first and second access_tokens?
ReplyDeleteSame problem?
DeleteHi sir,
ReplyDeleteThank you for your post.
Can you help me to create Spring Java config of OAuth2 server?
hi, thanks for the great blog!
ReplyDeletei wanna know how to set the expires_in for longer than 5 seconds? I've modified the data but still everytime i restart the server, it got back to 5 seconds ?
Simplest way is to change value of "hibernate.hbm2ddl.auto" create to update
DeleteWhen try to get data from the server, show the follow message:
ReplyDelete{
"error": "access_denied"
"error_description": "Access is denied"
}
All the configuration is ok
Hi Ronald I am also facing same issue. Please let me know if you could solve it.
DeleteHi Ronald I am also facing same issue. Please let me know if you could solve it.
DeleteThis comment has been removed by the author.
Deletefacing same problem
Deletefacing same issue
ReplyDeleteIm also facing the same issue..
ReplyDeletefacing same issue...also confused with first and second access token.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThanks for a great post!! Im also getting access denied... Did any figure out why it is happening. The implementation generates and stores tokens correctly but no access?
ReplyDeleteI implemented in the exact way you have mentioned but unfortunately getting bad credential password not matching issue showing.
ReplyDeleteI implemented in the exact way you have mentioned but unfortunately getting bad credential password not matching issue showing.
ReplyDeleteWhen try to get data from the server, show the follow message:
ReplyDelete{
"error": "access_denied"
"error_description": "Access is denied"
}
All the configuration is ok
When try to get data from the server, show the follow message:
ReplyDelete{
"error": "access_denied"
"error_description": "Access is denied"
}
All the configuration is ok
Nice tutorial sir!
ReplyDeleteAlso getting the below error
ReplyDelete{
"error": "access_denied",
"error_description": "Access is denied"
}
solution on github repo
DeleteWhen try to get data from the server, show the follow message:
ReplyDelete{
"error": "access_denied"
"error_description": "Access is denied"
}
Got this error with valid access token.
ReplyDelete{
"error": "access_denied",
"error_description": "Access is denied"
}
Any solution ??
I am also getting any found solution plz help....
ReplyDelete{
"error": "access_denied",
"error_description": "Access is denied"
}
Remove alias from .
ReplyDeleteUse <authentication-manager id="authenticationManager"
hi Rajith
ReplyDeleteI am facing same issue {
"error": "access_denied",
"error_description": "Access is denied"
}
after debugging spring api i found this due to authority collection getting null value .
These measures act as a physical deterrent to thieves, vandals, and others who may want to do you or your employees harm.guarantor loans
ReplyDeleteThanks for the blog post. Its indeed very helpful.
ReplyDeleteWhat if I am not using Spring Security Password Encoder? I have my own custom password encoding function in a REST API. How can I integrate that here?
ReplyDeleteState privacy guidelines protecting individual data (P.I.) have been built up by more than forty states. mejoresvpn.com/
ReplyDeleteI am glad that I saw this post. It is informative blog for us and we need this type of blog thanks for share this blog, Keep posting such instructional blogs and I am looking forward for your future posts.
ReplyDeleteCyber Security Projects for Final Year
JavaScript Training in Chennai
Project Centers in Chennai
JavaScript Training in Chennai