index-1-1.jpg
  • Aurora Solutions

How To: OAuth 2.0 with Spring Security

Today, every one wants security. We build later, secure first. Every one needs security now a days. And web applications need security the most. Because there are thousand ways to hack into a web application. So developers, architects and all the team leave no stone unturned to make their application as secure as possible. There are different protocols and libraries available to protect your API and some of them are very good at what they do. OAuth 2.0 is one of them.


In this tutorial we will implement OAuth 2.0 to our spring project using Spring Security OAuth 2.0


Remember:

Before you go further remember that we are using

  • Maven 3

  • Spring 3.1.1.RELEASE

  • Spring Security 3.1.1.RELEASE

  • Spring Security OAuth2 1.0.0.RELEASE

Background:

You have an API, developed using Spring and Java, that returns a JSON object when you make a call to one of its functions, and you want to protect each call using OAuth 2.0 protocol.


Changes:

pom.xml

Make sure to have following dependencies in your file.

<!-- OAuth 2.0 dependencies -->
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>1.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
</dependency>

<!-- Spring 3 dependencies -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
</dependency>

<!-- Spring Security -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>${spring.version}</version>
</dependency>

and most importantly you need a mirror site for OAuth dependency to be downloaded so add following to Settings.xml in Maven installed directory under mirrors tag

<mirror>
    <id>central</id>
    <mirrorOf>*</mirrorOf>
    <url>http://repo1.maven.org/maven2/</url>
</mirror>

spring-security.xml:

Make spring-security.xml file among other configuration files and make sure it is included in following tag in web.xml so that it is in Context Path.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/mvc-dispatcher-servlet.xml,
    /WEB-INF/spring-security.xml</param-value>
</context-param>

and make sure it has following configuration:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<!-- Just for testing... -->
<http pattern="/oauth/cache_approvals" security="none" xmlns="http://www.springframework.org/schema/security" />
<http pattern="/oauth/uncache_approvals" security="none" xmlns="http://www.springframework.org/schema/security" />

<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="/kfc/brands/*" 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="/kfc/brands/*" access="ROLE_USER" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

<!--http auto-config="true">
<intercept-url pattern="/rest/kfc/brands/*" access="ROLE_USER" />
</http>

<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="password" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager-->

<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>

<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service id="userDetailsService">
<user name="marissa" password="koala" authorities="ROLE_USER" />
<user name="paul" password="emu" authorities="ROLE_USER" />
</user-service>
</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.InMemoryTokenStore" />

<!-- Used to create token and and every thing about them except for their persistence that is reposibility of TokenStore (Given here is a default implementation) -->
<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="userApprovalHandler" class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<property name="tokenServices" ref="tokenServices" />
</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" />
<!-- ClientsDeailsService: Entry Point to clients database (given is in memory implementation) -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="my-trusted-client" authorized-grant-types="password,authorization_code,refresh_token,implicit"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" scope="read,write,trust" access-token-validity="60" />
<oauth:client client-id="my-trusted-client-with-secret" authorized-grant-types="password,authorization_code,refresh_token,implicit"
secret="somesecret" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" />
<oauth:client client-id="my-client-with-secret" authorized-grant-types="client_credentials" authorities="ROLE_CLIENT"
scope="read" secret="secret" />
<oauth:client client-id="my-less-trusted-client" authorized-grant-types="authorization_code,implicit"
authorities="ROLE_CLIENT" />
<oauth:client client-id="my-less-trusted-autoapprove-client" authorized-grant-types="implicit"
authorities="ROLE_CLIENT" />
<oauth:client client-id="my-client-with-registered-redirect" authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_CLIENT" redirect-uri="http://anywhere?key=value" scope="read,trust" />
<oauth:client client-id="my-untrusted-client-with-registered-redirect" authorized-grant-types="authorization_code"
authorities="ROLE_CLIENT" redirect-uri="http://anywhere" scope="read" />
<oauth:client client-id="tonr" resource-ids="test" authorized-grant-types="authorization_code,implicit"
authorities="ROLE_CLIENT" scope="read,write" secret="secret" />
<!--Self defined client-->
<oauth:client client-id="the_client" authorized-grant-types="authorization_code,client_credentials"
authorities="ROLE_USER" scope="read,write,trust" secret="secret" />
</oauth:client-details-service>
<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>

You can get token using 'Password Grant' from the link below:

https://github.com/javajack/SpringOAuth2.0Demo

I hope this will help you to apply OAuth 2.0 to spring projects using spring security OAuth 2.0.


Good Luck :)

0 views0 comments