Enterprise Java

OAuth with Spring Security

From Wikipedia: OAuth (Open Authentication) is an open standard for authentication. It allows users to share their private resources (e.g. photos, videos, contact lists) stored on one site with another site without having to hand out their credentials, typically username and password.

There are a lot of posts talking about OAuth from Client Side, for example how to connect to service providers like Twitter or Facebook, but there are less posts about OAuth but from Server Side, more specificaly how to implement an authentication mechanism using OAuth for protecting resources, and not for accessing them (Client Side Part).

In this post I will talk about how to protect your resources, using Spring Security (Spring Security OAuth). The example will be simple enough to understand the basics for implementing an OAuth service provider.

I have found this post that explains with a simple example, what OAuth is and how it works. I think it is a good starting point with OAuth http://hueniverse.com/2007/10/beginners-guide-to-oauth-part-ii-protocol-workflow/

Now it is time to start writing our service provider. First of all I will explain what our Service Provider will offer.

Imagine you are developing a website (called CV) where users will register and after that they will be able to upload their Curriculum Vitae. Now we are going to transform this website to a Service Provider where OAuth will be used for protecting resources (Curriculm Vitae of registered users). Imagine again that some companies have agreed with CV people that when they publish job vacances, users will have the possibility of uploading their curriculum directly from CV site to HR department instead of sending by email or copy & paste from document. As you can see here is where OAuth starts managing security between CV website and Company RH site.

In summary we have a Curriculum Vitae Service Provider (CV) with protected resource (document itself). Companies that offer users the possibility of acquiring directly their Curriculum Vitae from CV are the Consumers. So when a user visits company job vacancies (in our example called fooCompany) and wants to apply for a job, he only has to authorize FooCompany “Job Vacancies” website with permissions to download its Curriculum Vitae from CV site.

Because we will use Spring Security for OAuth authentication, first of all we are going to configure Spring Security into SpringMVC CV application. Nothing special here:

In web.xml file we define Security Filter:

<filter>
 <filter-name>springSecurityFilterChain</filter-name>
 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
 <filter-name>springSecurityFilterChain</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

And in root-context.xml we define protected resources and authentication manager. In this case In memory apporoach is used:

<http auto-config='true'>
 <intercept-url pattern="/**" access="ROLE_USER" />
</http>

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

Next step, create an Spring Controller that returns the Curriculum Vitae of logged user:

@RequestMapping(value="/cvs", method=RequestMethod.GET)
@ResponseBody
public String loadCV() {
 StringBuilder cv = new StringBuilder();
 cv.append("Curriculum Vitae -- Name: ").append(getUserName()).append(" Experience: Java, Spring Security, ...");
 return cv.toString();
}

private String getUserName() {
 Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
 String username;
 if (principal instanceof UserDetails) {
   username = ((UserDetails)principal).getUsername();
 } else {
   username = principal.toString();
 }
 return username;
}

This controller returns directly a String, instead a ModelView object. This String is sent directly as HttpServletResponse.

Now we have got a simple website that returns the Curriculum Vitae of logged user. If you try to access to /cvs resource, if you are not authenticated, Spring Security will show you a login page, and if you are already logged, your job experience will be returned. Works as any other website that are using Spring Security.

Next step is modifing this project for allowing external sites can access to protected resources using OAuth 2 authentication protocol.

In root-context.xml:

<beans:bean id="tokenServices"
  class="org.springframework.security.oauth2.provider.token.InMemoryOAuth2ProviderTokenServices">
 <beans:property name="supportRefreshToken" value="true" />
</beans:bean>

<oauth:provider client-details-service-ref="clientDetails"
 token-services-ref="tokenServices">
 <oauth:verification-code user-approval-page="/oauth/confirm_access" />
</oauth:provider>

<oauth:client-details-service id="clientDetails">
 <oauth:client clientId="foo" authorizedGrantTypes="authorization_code" />
</oauth:client-details-service>

First bean, is an OAuth2ProviderTokenServices interface implementation with id tokenServices. The OAuth2ProviderTokenServices interface defines operations that are necessary to manage OAuth 2.0 tokens. These tokens should be stored for subsequent access token can reference it. For this example InMemory store is enough.

Next bean is <oauth:provider>. This tag is used to configure the OAuth 2.0 provider mechanism. And in this case three parameters are configured; the first one is a reference to a bean that defines the client details service, explained in next paragraph. The second one is token service for providing tokens, explained in previous paragraph, and the last one is the URL at which a request for authorization token will be serviced. This is the typically Authorize/Denny page where service provider asks to user if it permits the Consumer (in our case fooCompany) accessing to protected resources (its Curriculum Vitae).

Last bean is <oauth:client-details-service>. In this tag you define which clients you authorize to access to protected resources with previous authentication. In this case because CV company has agreed with foo company that they can connect to its Curriculum Vitae Service, a client is defined with id foo.

Now we have our application configured with OAuth. Last step is creating a controller for taking requests from /oauth/confirm_access URL.

private ClientAuthenticationCache authenticationCache = new DefaultClientAuthenticationCache();
private ClientDetailsService clientDetailsService;

@RequestMapping(value="/oauth/confirm_access")
public ModelAndView accessConfirmation(HttpServletRequest request, HttpServletResponse response) {
 ClientAuthenticationToken clientAuth = getAuthenticationCache().getAuthentication(request, response);
    if (clientAuth == null) {
      throw new IllegalStateException("No client authentication request to authorize.");
    }

    ClientDetails client = getClientDetailsService().loadClientByClientId(clientAuth.getClientId());
    TreeMap<String, Object> model = new TreeMap<String, Object>();
    model.put("auth_request", clientAuth);
    model.put("client", client);
    return new ModelAndView("access_confirmation", model);
}

This controller returns a ModelAndView object with client information and which page should be shown for granting permission to protected resources. This JSP page is called access_confirmation.jsp and the most important part is:

<div id="content">

    <% if (session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) != null && !(session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION) instanceof UnapprovedClientAuthenticationException)) { %>
      <div class="error">
        <p>Access could not be granted. (<%= ((AuthenticationException) session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)).getMessage() %>)</p>
      </div>
    <% } %>
    <c:remove scope="session" var="SPRING_SECURITY_LAST_EXCEPTION"/>

    <authz:authorize ifAllGranted="ROLE_USER">
      <h2>Please Confirm</h2>

      <p>You hereby authorize <c:out value="${client.clientId}"/> to access your protected resources.</p>

      <form id="confirmationForm" name="confirmationForm" action="<%=request.getContextPath() + VerificationCodeFilter.DEFAULT_PROCESSING_URL%>" method="post">
        <input name="<%=BasicUserApprovalFilter.DEFAULT_APPROVAL_REQUEST_PARAMETER%>" value="<%=BasicUserApprovalFilter.DEFAULT_APPROVAL_PARAMETER_VALUE%>" type="hidden"/>
        <label><input name="authorize" value="Authorize" type="submit"/></label>
      </form>
      <form id="denialForm" name="denialForm" action="<%=request.getContextPath() + VerificationCodeFilter.DEFAULT_PROCESSING_URL%>" method="post">
        <input name="<%=BasicUserApprovalFilter.DEFAULT_APPROVAL_REQUEST_PARAMETER%>" value="not_<%=BasicUserApprovalFilter.DEFAULT_APPROVAL_PARAMETER_VALUE%>" type="hidden"/>
        <label><input name="deny" value="Deny" type="submit"/></label>
      </form>
    </authz:authorize>
  </div>

As you can see Spring Security OAuth provides helper classes for creating confirmation form and deny form. When the result is submitted, URL /cv/oauth/user/authorize (internally managed) is called, there OAuth decides if returns protected resource (String returned by loadCV() method) to caller or not depending on what option user has chosen.

And that’s all about creating an OAuth 2 system using Spring Security OAuth. But I suppose you are wondering how to test it, so for the same price I will explain how to write the client part (Consumer) using Spring Security OAuth too.

Client application (called fooCompany) is also a SpringMVC web application with Spring Security.

Spring Security part will be ignored here.

The client application contains a home page (home.jsp) that has a link to Spring Controller that will be responsible to download Curriculum Vitae from CV site, and redirecting content to a view (show.jsp).

@RequestMapping(value="/cv")
public ModelAndView getCV() {
 String cv = cvService.getCVContent();
 Map<String, String> params = new HashMap<String, String>();
 params.put("cv", cv);
 ModelAndView modelAndView = new ModelAndView("show", params);
 return modelAndView;

}

As you can see is a simple Controller that calls a Curriculum Vitae service. This service will be responsible to connect to CV website, and download required Curriculum Vitae. Of course it deals with OAuth communication protocol too.

Service looks:

public String getCVContent() {
 byte[] content = (getCvRestTemplate().getForObject(URI.create(cvURL), byte[].class));
 return new String(content);
}

The suggested method for accessing those resources is by using Rest. For this porpose Spring Security OAuth provides an extension of RestTemplate for dealing with OAuth protocol. This class (OAuth2RestTemplate) manages connection to required resources and also manages tokens, OAuth authorization protocol, …

OAuth2RestTemplate is injected into CVService, and it is configured into root-context.xml:

<oauth:client token-services-ref="oauth2TokenServices" />

<beans:bean id="oauth2TokenServices"
 class="org.springframework.security.oauth2.consumer.token.InMemoryOAuth2ClientTokenServices" />

<oauth:resource id="cv" type="authorization_code"
 clientId="foo" accessTokenUri="http://localhost:8080/cv/oauth/authorize"
 userAuthorizationUri="http://localhost:8080/cv/oauth/user/authorize" />

 <beans:bean id="cvService" class="org.springsource.oauth.CVServiceImpl">
  <beans:property name="cvURL" value="http://localhost:8080/cv/cvs"></beans:property>
  <beans:property name="cvRestTemplate">
   <beans:bean class="org.springframework.security.oauth2.consumer.OAuth2RestTemplate">
         <beans:constructor-arg ref="cv"/>
 </beans:bean>
</beans:property>
<beans:property name="tokenServices" ref="oauth2TokenServices"></beans:property>
</beans:bean>

See that OAuth2RestTemplate is created using an OAuth resource that contains all information about where to connect for authorizing access to protected resource, and in this case is CV website, see that we are referencing an external website, although in this example we are using localhost. Also service provider URL (http://localhost:8080/cvs/cv) is set, so RestTemplate can establish a connection to content provider, and in case that authorization process ends successful, retrieving requested information.

<oauth:resource> defines OAuth resources, in this case, the name of the client (remember that this value was configured in server side client details tag for granting access to OAuth protocol). Also userAuthorizationUri is defined. This is the URI to which the user will be redirected if the user is ever needed to authorize access to the resource (this is an internal URI managed by Spring Security OAuth). And finally accessTokenUri, the URI OAuth provider endpoint that provides the access token (internal URI too).

Also creating a consumer using Spring Security OAuth is simple enough.

Now I will explain the sequence of events that happens when a user wants to give access to foo company for retrieving its Curriculum Vitae.

First of all user connects to foo website, and click on post curriculum vitae link. Then getCV method from controller is called. This method calls cvService, that at the same time creates a connection to resource URI (CV) using OAuth2RestTemplate. And this class acts as a black box, from client side, you don’t know exactly what this class will do but it returns your Curriculum Vitae stored in CV website. As you can imagine this class manages all workflow related to OAuth, like managing tokens, executing required URL redirections to get permissions, … and if all steps are performed successful, stored Curriculum Vitae in CV site will be sent to foo company site.

And that’s all steps required to allow your site to act as Service Provider using OAuth2 authorization protocol. Thanks of Spring Security folks, it is much easier that you may think at first.

Hope you find it useful.

Download ServerSide (CV)
Download ClientSide (fooCompany)

Reference: OAuth with Spring Security from our JCG partner Alex Soto at the One Jar To Rule Them All blog.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

24 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
siru vivasayee
siru vivasayee
11 years ago

Hi Eleftheria,

I created war file of both client and server part and deployed in a tomcat server.
Getting the following error … what could be the possible reason 

ERROR: org.springframework.web.context.ContextLoader – Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.context.HttpSessionSecurityContextRepository#0’: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.springframework.security.web.context.HttpSessionSecurityContextRepository]: Constructor threw exception; nested exception is java.lang.ExceptionInInitializerError

siru vivasayee
siru vivasayee
11 years ago
Reply to  siru vivasayee

Changing the tomcat server resolved the issue but any how I need to check the root cause for this issue …

Thanks

Tito George
Tito George
11 years ago

I tried to run your examples. I am getting the following errors.
cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element ‘oauth:provider’.
and
Multiple annotations found at this line: – cvc-complex-type.3.2.2: Attribute ‘clientId’ is not allowed to appear in element ‘oauth:client’. – cvc-complex-type.3.2.2: Attribute ‘authorizedGrantTypes’ is not allowed to appear in element ‘oauth:client’.
I tried lot to get correct xsd version, but could not find. Could you please help?

Harish Reddy
Harish Reddy
11 years ago
Reply to  Tito George

did you find solution?please let me know

Julius Fernandes
Julius Fernandes
10 years ago
Reply to  Harish Reddy

This application uses OAuth 1.0a and needs the following xsd in the xml file.

http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd

Use the following versions of spring jars
Spring- 3.0.x
spring-security-oauth-1.0.0.M3.jar
spring-security–3.0.x.jar

Julius Fernandes
Julius Fernandes
10 years ago

use http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd in your xml file

Use the following jars
Spring- 3.0.x
spring-security-oauth-1.0.0.M3.jar
spring-security–3.0.x.jar

Ahsan Imam
Ahsan Imam
11 years ago
Reply to  Tito George

Same problem here. The project will not compile. Does anyone have a solution?

Bhaskar
Bhaskar
10 years ago

Hi,

Requesting you to please upload screenshots of flow of functionalities !!

Bhaskar
Bhaskar
10 years ago

Hi, Thanks A Lot for your tutorial !! it is simply AWESOME!!!! But i just stuck up at the last point , please look on this ::::: When i clicked on “Authorize” i did not receive “CV” rather my console get populate with following warnings:: WARN : org.springframework.security.oauth2.provider.verification.DefaultClientAuthenticationCache – Unable to save client authentication because the request doesn’t have a session! WARN : org.springframework.web.servlet.PageNotFound – No mapping found for HTTP request with URI [/cv/style.css] in DispatcherServlet with name ‘appServlet’ WARN : org.springframework.web.client.RestTemplate – POST request for “http://localhost:8080/cv/oauth/authorize” resulted in 404 (Not found); invoking error handler And on browser i received… Read more »

Bhaskar
Bhaskar
10 years ago

Thanks A TON!! Its working…… :)

OAuthUser
OAuthUser
10 years ago
Reply to  Bhaskar

Can you let know how you get around this problem

No mapping found for HTTP request with URI [/cv/] in DispatcherServlet with name ‘appServlet’

Anandan Rajendran
Anandan Rajendran
10 years ago
Reply to  OAuthUser

Hello Friends,
I am also getting the following error:

org.springframework.web.servlet.PageNotFound – No mapping found for HTTP request with URI [/cv/cvs/] in DispatcherServlet with name ‘appServlet’

Plz help me, how I can fix this issue.

Thanks.

chandra Rao
chandra Rao
8 years ago
Reply to  OAuthUser

deploy first cv and then fooCompany

after deploy you need to access the from client(fooCompany)

Anandan Rajendran
Anandan Rajendran
10 years ago
Reply to  Bhaskar

How you fixed the problem. can you please explain me the fix.

Thanks

Himalaya
Himalaya
10 years ago

Hi, Alex Soto

The following tutorial was very much useful.
Can you please provide a REST version of the above tutorial.

thanks in advance

Akhlesh Saxena
9 years ago

Is it oauth2 implementation? If not please provide oauth2 + spring code.

Maximiliano
Maximiliano
9 years ago

Hi Alex, I know this is an old post, but I hope you could give me a hand. I’m new to OAuth and I need to create a simple web application for track expenses, with some basic actions (user must be able to create an account and log in, list expenses, edit them, etc) with a REST API for each one, and the trick is that I need to be able to pass credentials to both the webpage and the API. So, after some research I’ve found some examples using Digest Authentication and HMAC Authentication but lot of posts also… Read more »

Jose Cano
Jose Cano
9 years ago

Very good example. Thanks. I intercepted http messages between the client and the provider and attach it here for those interested: Authorization Request: POST /cv/oauth/authorize HTTP/1.1 Accept: application/json, application/x-www-form-urlencoded Content-Type: application/x-www-form-urlencoded User-Agent: Java/1.7.0_67 Host: localhost:8090 Connection: keep-alive Content-Length: 116 grant_type=authorization_code&client_id=foo&code=u6TI91&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2FfooCompany%2Fcv Authorization Response: HTTP/1.1 200 OK Cache-Control: no-store Content-Type: application/json; charset=ISO-8859-1 Expires: Thu, 01-Jan-1970 00:00:00 GMT Set-Cookie: JSESSIONID=i0h538jw605pjijndwas2wn1;Path=/cv Content-Length: 142 Server: Jetty(6.1.25) { “access_token”: “6c481f27-fed5-4600-b407-8532f05191be”, “expires_in”: 43199, “refresh_token”: “2283d538-a60d-4f48-addd-5f794bb1eea4” } Access to resource Request: GET /cv/cvs HTTP/1.1 Authorization: OAuth2 6c481f27-fed5-4600-b407-8532f05191be Accept: application/octet-stream, */* User-Agent: Java/1.7.0_67 Host: localhost:8090 Connection: keep-alive Access to resource Response: HTTP/1.1 200 OK Content-Type: application/octet-stream Accept-Charset: big5, big5-hkscs,… Read more »

Jose Cano
Jose Cano
9 years ago

I’m trying to test an “expired token” scenario , setting the tokenServices as:

but It doesn’t allow me to re-authenticate when the token expires.

Any idea there?

PA
PA
9 years ago

Hello, Thanks for sharing source code. We’re looking for the Spring Security OAuth2 code which will return OAuth_Token, Refresh_Token etc.

I’m inspired by link https://techannotation.wordpress.com/2014/04/29/5-minutes-with-spring-oauth-2-0/, but certainly don’t have proper code to look at it.

Thanks,

Dez Max
Dez Max
9 years ago

The “Authorize” from the CV application doesn’t seem to work while switching to https protocol. Anyone tried this out?

thanks
Dez

Dibyendu Pramanick
Dibyendu Pramanick
8 years ago

Very good example.
This application is working fine for me.
But when I am intercepting the request and response, I can’t see the access token

Neha
Neha
8 years ago

Hello, I see Spring OAuth2 version is using this code is too old. May I request you to update this code for new maven dependencies?

Thanks,
Neha

RAMAKANTH
RAMAKANTH
7 years ago

How to intercept the the messages? Can you please let me know?

Back to top button