About Alex Soto

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.

Related Whitepaper:

Best Practices for Secure Software Development

Best practices for all organizations that would like to produce more secure applications!

As part of the software development process, security professionals must make choices about where to invest their budget and staff resources to ensure that homegrown applications are as secure as possible. ESG research found organizations that are considered security leaders tend to make different choices than other firms.

Get it Now!  

14 Responses to "OAuth with Spring Security"

  1. siru vivasayee says:

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

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

      Thanks

  2. Tito George says:

    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?

  3. Bhaskar says:

    Hi,

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

  4. Bhaskar says:

    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 following messages:

    HTTP Status 403 – Error requesting access token.

    description Access to the specified resource (Error requesting access token.) has been forbidden.

  5. Bhaskar says:

    Thanks A TON!! Its working…… :)

    • OAuthUser says:

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

        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.

    • Anandan Rajendran says:

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

      Thanks

  6. Himalaya says:

    Hi, Alex Soto

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

    thanks in advance

Leave a Reply


× six = 36



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books