My recent blog posts were all about OAuth2 from a client perspective. We covered the main flows (Authorization Code Flow, Implicit Flow, Resource Owner Password Flow and Client Credentials Flow) and also discussed how access tokens can be refreshed. To quickly get started, I also showed you how you can use CURL to quickly get an OAuth2 access token.
What’s missing now is the server side, of course. As the hybris eCommerce platform is making heavy use of the Spring Framework, we naturally decided to give the Spring Security OAuth2 Module a try. It turned out to fit nicely into our existing ecosystem and provides support for all flows (that I already demonstrated from a client perspective). While I’ll be focusing on the key configuration that you will want to apply, there are two nice example applications that you should take a look in case you want to dive deeper: that’s the tonr and sparklr sample applications. Things sometimes get a bit confusing when you google for some OAuth information as there was (is) OAuth1… so be sure to always check that you are looking at the OAuth2 versions of these sample applications.
You will probably want to begin your Spring Oauth2 explorations by downloading and building the latest source code. For this, just head over to Github and download the latest code as an archive. Next, unpack the archive in a folder of your choice and cd into the oauth2 (2!) directory and call maven to package build and package the code as a jar file:
cd spring-security-oauth2/ mvn package
If maven is correctly setup (I am currently using Maven 3.0.3) it will wildly download artifacts from all over the internet, compile the source code and then create a target directory with the oauth2 jar file in it (see the ./target directory it created). Take the .jar file and drop into your existing Spring Web Application (that should be already using Spring Security) to proceed.
As this is Spring, the configuration is mostly done in XML configuration files. A full example of how to configure an OAuth2 authorization server using Spring Security OAuth2 can be seen in the sparklr example application and more specifically in the spring-servlet.xml which is the web app’s main Spring configuration file.
It’s a relatively long file and I don’t write a book about all this (I assume someone hopefully works on a good ‘OAuth2 with Spring’ book), but let’s highlight a few key elements. Looking at the file, you will first want to take notice of the oauth (2) namespace:
<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" xmlns:mvc="http://www.springframework.org/schema/mvc" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc-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/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
The most important oauth-namespaced element is the authorization-server:
<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>
The elements therein list are the various flows that this OAuth2 server will provide. If – in your specific use case – you don’t need to support the implicit flow for example, just remove it. It’s of course always best to go with the smallest possible setup for security. The authorization-server element references another key bean, the clientDetails:
<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="sparklr" authorized-grant-types="authorization_code,implicit" authorities="ROLE_CLIENT" scope="read,write" secret="secret" /> </oauth:client-details-service>
As the name tells, this bean will provide all information about OAuth2 clients. Only if a client can be resolved by the client details service, it is valid and may use the OAuth2 authorization server. While a static setup as above may be suitable for a lot of cases, some might want to provide a sign-up page where 3rd party developers can create a new app client. In this case, you’d need to replace the client details service with your own implementation that might lookup the clients from the database. But let’s take a closer look at one client.
<oauth:client client-id="mobile_android" resource-ids="hybris" authorized-grant-types="password,refresh_token" authorities="ROLE_CLIENT" scope="read,write" secret="secret" />
Here, the client ‘mobile_android’, which might be your companies official Android app is configured. It defines a client secret of ‘secret’ and will allow this client to use the resource owner password and refresh_token services. I’ve chosen this client as it is consistent with the examples I’ve shown for the Resource Owner Password flow.
If you are wondering who is creating and keeping track of the tokens (access and refresh tokens), the module comes with an InMemoryTokenStore:
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
This store is referenced from the TokenServices, whose purpose it is to create the tokens:
<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>
One other noteworthy configuration element is the OAuth2 token endpoint. If you remember correctly, the client_id and client_secret parameters can either be supplied via a Basic Authentication (the ‘Authorization’ Header) or in the body of the request. If you choose Basic Auth to transmit the client_id and client_secret, then you shuld keep the Basic Auth Filter below in the configuration, you can remove it otherwise.
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" entry-point-ref="oauthAuthenticationEntryPoint" xmlns="http://www.springframework.org/schema/security"> <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" /> <anonymous enabled="false" /> <http-basic entry-point-ref="oauthAuthenticationEntryPoint" /> <!-- include this only if you need to authenticate clients via request parameters --> <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" /> <access-denied-handler ref="oauthAccessDeniedHandler" /> </http>
Finally, you’ll probably wonder how the real resources that your AP I might offer are now protected. Again, the sample app has a few resoruces for accessing photos that use the OAuth2 protocol configured:
<http pattern="/photos/**" 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="/photos" access="ROLE_USER,SCOPE_READ" /> <intercept-url pattern="/photos/trusted/**" access="ROLE_CLIENT,SCOPE_TRUST" /> <intercept-url pattern="/photos/user/**" access="ROLE_USER,SCOPE_TRUST" /> <intercept-url pattern="/photos/**" access="ROLE_USER,SCOPE_READ" /> <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> <access-denied-handler ref="oauthAccessDeniedHandler" /> </http>
This is pretty default Spring Security configuration. The cool thing in the above is, that the scopes that you were able to define in the client details, can automatically be used in the ‘access’ attribute.
For the purpose of this blog post I really just highlighted the key configuration elements. There’s a lot more to explore, and the best way to do that is to take a look and the sparklr configuration and/or also run both the tonr (client-side) and sparklr (server-side) app.