cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache CXF Documentation > JAX-RS OAuth
Date Wed, 09 Nov 2011 23:36:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/1/_/styles/combined.css?spaceKey=CXF20DOC&amp;forWysiwyg=true" type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+OAuth">JAX-RS OAuth</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~sergey_beryozkin">Sergey Beryozkin</a>
    </h4>
        <br/>
                         <h4>Changes (5)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >in this example OAuthServiceExceptions are caught, presumably logged and null values are returned which will indicate to the main code that the request failed. Obviously, OAuthClientUtils can be used directly as well. <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >h1. 2-leg OAuth <span class="diff-changed-words"><span class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;">f</span><span class="diff-added-chars"style="background-color: #dfd;">F</span>low</span> <br></td></tr>
            <tr><td class="diff-unchanged" > <br>The complete 3-leg OAuth flow involves the end user explicitly authorizing the third-party consumer which itself most likely is running as a web server application. In some cases that may not be practical, for example, the end user may just want to let a 3rd party application just keep accessing a given resource it owns until a relevant permission is revoked. This can lead to a simpler so-called 2-leg OAuth flow. <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >OAuth filters will validate such a request nearly the same way they validate the requests where access token and signature parameters are included and pass it through only if during the validation it can additionally be asserted that all the [OAuthPermissions|http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthPermission.java] associated with a given Client have an &quot;authorizationKeyRequired&quot; set to false. <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >What this means is that after a third-party application has been registered, this Client may have got the scopes linking it to such permissions allocated at the very start, or perhaps the resource server application offers an option to registered end users to choose which of the registered third-party applications may access this end user&#39;s resources and <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">update</span> <span class="diff-added-words"style="background-color: #dfd;">add scopes to</span> the registered <span class="diff-changed-words">Clients<span class="diff-deleted-chars"style="color:#999;background-color:#fdd;text-decoration:line-through;"> accordingly</span>.</span> <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">For example, a Client may have readCalendar1 and readCalendar2 scopes assigned to it which will be translated during the validation to two OAuthPermission instances with the &quot;authorizationKeyRequired&quot; property set to false and containing /calendar/1 and /calendar/2 relative URIs respectively, with &quot;1&quot; and &quot;2&quot; representing id of the end users which let a particular Client to read their calendars without regular authorization approvals. A single OAuthPermission containing two URIs would do too.  <br> <br></td></tr>
            <tr><td class="diff-unchanged" >h1. OAuth Without a Browser <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>h1. Design considerations <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2. Sharing the same URI path between end users and consumers <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">This section will talk about various design considerations one need to take into account when deploying OAuth-based solutions. <br> <br>h2. Controlling the Access to Resource Server <br> <br>One of the most important issues one need to resolve is how to partition a URI space of the resource server application. <br> <br>We have two different parties trying to access it, the end users which access the resource server to get to the resources which they own and 3rd party consumers which have been authorized by the end users to access some of their resources.  <br> <br>In the former case the way the authentication is managed is completely up to the resource server application: basic authentication, two-way TLS, OpenId (more on it below), you name it. <br> <br>In the latter case an OAuth filter must enforce that the 3rd party consumer has been registered using the provided consumer key and that it has a valid access token (authorization key in OAuth 2.0) which represents the end user&#39;s approval.  It&#39;s kind of the authentication and the authorization check at the same time. <br> <br>Letting both parties access the resource server via the same URI(s) complicates the life for the security filters but all the parties are only aware of the single resource server URI which all of them will use. <br> <br>Providing different access points to end users and consumers may significantly simplify the authentication process - the possible downside is that multiple access points need to be mantained by the resource server. <br> <br>Both options are discussed next. <br> <br>h3. Sharing the same access path between end users and consumers <br> <br>The first problem which needs to be addressed is how to distinguish end users from third-party consumers and get both parties authenticated as required. <br>Perhaps the simplest option is to extend a CXF OAuth filter (JAX-RS or servlet one), check Authorization header, if it is OAuth then delegate to the superclass, alternatively - proceed with authenticating the end users: <br> <br>{code:java} <br>public class SecurityFilter extends org.apache.cxf.rs.security.oauth.filters.OAuthRequestFilter { <br>   @Context <br>   private HttpHeaders headers; <br> <br>   public Response handleRequest(ClassResourceInfo cri, Message message) { <br>       String header = headers.getRequestHeaders().getFirst(&quot;Authorization&quot;); <br>       if (header.startsWith(&quot;OAuth &quot;)) { <br>           return super.handleRequest(cri, message); <br>       } else { <br>           // authenticate the end user <br>       } <br>   } <br> <br>}  <br>{code}    <br> <br>The next issue is how to enforce that the end users can only access the resources they&#39;ve been authorized to access. <br>For example, consider the following JAX-RS resource class: <br> <br>{code:java} <br>@Path(&quot;calendar&quot;) <br>public class CalendarResource { <br> <br>   @GET <br>   @Path(&quot;{id}&quot;) <br>   public Calendar getPublicCalendar(@PathParam(&quot;id&quot;) long id) { <br>       // return the calendar for a user identified by &#39;id&#39; <br>   } <br> <br>   @GET <br>   @Path(&quot;{id}/private&quot;) <br>   public Calendar getPrivateCalendar(@PathParam(&quot;id&quot;) long id) { <br>       // return the calendar for a user identified by &#39;id&#39; <br>   } <br> <br>   @PUT <br>   @Path(&quot;{id}&quot;) <br>   public void updateCalendar(@PathParam(&quot;id&quot;) long id, Calendar c) { <br>       // update the calendar for a user identified by &#39;id&#39; <br>   } <br>} <br>{code} <br> <br>Lets assume that the 3rd party consumer has been allowed to read the public user Calendars at &quot;/calendar/{id}&quot; only, how to make sure that the consumer won&#39;t try to: <br>1. update the calendar available at the same path  <br>2. read the private Calendars available at &quot;/calendar/{id}/private&quot; <br> <br>As noted above, Client, AccessToken (in its Token superclass) and [OAuthPermission|http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthPermission.java] all have an optional URIs property. Thus one way to solve the problem with the private calendar is to add, say, a uri &quot;/calendar/{id}&quot; or &quot;/calendar/1&quot; (etc) property to OAuthPermission (representing a scope like &quot;readCalendar&quot;) and the OAuth filter will make sure no subresources beyond &quot;/calendar/{id}&quot; can be accessed. Note, adding a &quot;*&quot; at the end of a given URI property, for example, &quot;/a*&quot; will let the consumer to access &quot;/a&quot;, &quot;/a/b&quot;, etc. <br> <br>Solving the problem with preventing the update can be easily solved by adding an httpVerb property to a given OAuthPermission. <br> <br>One more option is to rely on the role-based access control and have @RolesAllowed allocated such that only users in roles like &quot;consumer&quot; or &quot;enduser&quot; can invoke the getCalendar() method and let only those in the &quot;enduser&quot; role access getPrivateCalendar() and updateCalendar(). OAuthPermission can help here too as described in the section on using OAuth fiters. <br> <br>h3. Providing different access points to end users and consumers <br> <br>Rather than letting both the end users and 3rd party consumers use the same URI such as &quot;http://myapp.com/service/calendars/{id}&quot;, one may want to introduce two URIs, one for end users and one for third-party consumers, for example, &quot;http://myapp.com/service/calendars/{id}&quot; - for endusers, &quot;http://myapp.com/partners/calendars/{id}&quot; - for the 3rd party consumers and deploy 2 jaxrs endpoints, where one is protected by the security filter checking the end users, and the one - by OAuth filters.  <br> <br>Additionally the endpoint managing the 3rd party consumers will deploy a resource which will offer a resticted URI space support. For example, if the application will only allow 3rd party consumers to read calendars then this resource will only have a method supporting @GET and &quot;/calendar/{id}&quot;.  <br> <br>h2. Single Sign On <br> <br>When dealing with authenticating the end users, having an SSO solution in place is very handy. This is because the end user interacts with both the third-party and its resource server web application and is also redirected back and forth. OpenID or say WebBrowser SSO profile can help - CXF may offer some support in this area.  <br> <br></td></tr>
            <tr><td class="diff-unchanged" >h1. What Is Next <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <p><span style="font-size:2em;font-weight:bold"> JAX-RS: OAuth </span></p>


<div>
<ul>
    <li><a href='#JAX-RSOAuth-Introduction'>Introduction</a></li>
    <li><a href='#JAX-RSOAuth-Mavendependencies'>Maven dependencies</a></li>
    <li><a href='#JAX-RSOAuth-DevelopingOAuthServers'>Developing OAuth Servers</a></li>
<ul>
    <li><a href='#JAX-RSOAuth-RequestTokenService'>RequestTokenService</a></li>
    <li><a href='#JAX-RSOAuth-AuthorizationRequestService'>AuthorizationRequestService</a></li>
    <li><a href='#JAX-RSOAuth-AccessTokenService'>AccessTokenService</a></li>
    <li><a href='#JAX-RSOAuth-WritingOAuthDataProvider'>Writing OAuthDataProvider</a></li>
    <li><a href='#JAX-RSOAuth-OAuthServerJAXRSendpoints'>OAuth Server JAX-RS endpoints</a></li>
</ul>
    <li><a href='#JAX-RSOAuth-ProtectingresourceswithOAuthfilters'>Protecting resources with OAuth filters</a></li>
    <li><a href='#JAX-RSOAuth-Clientsidesupport'>Client-side support</a></li>
    <li><a href='#JAX-RSOAuth-2legOAuthFlow'>2-leg OAuth Flow</a></li>
    <li><a href='#JAX-RSOAuth-OAuthWithoutaBrowser'>OAuth Without a Browser</a></li>
    <li><a href='#JAX-RSOAuth-Designconsiderations'>Design considerations</a></li>
<ul>
    <li><a href='#JAX-RSOAuth-ControllingtheAccesstoResourceServer'>Controlling the Access to Resource Server</a></li>
<ul>
    <li><a href='#JAX-RSOAuth-Sharingthesameaccesspathbetweenendusersandconsumers'>Sharing the same access path between end users and consumers</a></li>
    <li><a href='#JAX-RSOAuth-Providingdifferentaccesspointstoendusersandconsumers'>Providing different access points to end users and consumers</a></li>
</ul>
    <li><a href='#JAX-RSOAuth-SingleSignOn'>Single Sign On</a></li>
</ul>
    <li><a href='#JAX-RSOAuth-WhatIsNext'>What Is Next</a></li>
</ul></div>

<h1><a name="JAX-RSOAuth-Introduction"></a>Introduction</h1>

<p>CXF 2.5.0 implements <a href="http://tools.ietf.org/html/rfc5849" class="external-link" rel="nofollow">OAuth 1.0</a>. </p>

<p>While <a href="http://oauth.net/2/" class="external-link" rel="nofollow">OAuth 2.0</a> (which is very close to becoming the final recommendation) is the next major version of OAuth, OAuth 1.0 is being supported by many providers and the CXF OAuth module should make it easy for developers to start writing OAuth applications, be it OAuth 1.0 or OAuth 2.0 once the latter gets implemented.   </p>

<p>OAuth offers a complex yet elegant solution toward helping the end users (resource owners) authorize third-party providers to access their resources.</p>

<p>The classical OAuth flow is also called a 3-leg OAuth flow as it involves 3 parties: the end user (resource owner), the third party service (client, consumer) and the resource server which is protected by OAuth filters. Typically a consumer offers a service feature that an end user requests and which requires the former to access one or more resources of this end user which are located at the resource server. For example, the consumer may need to access the end user's photos in order to print them and post to the user or read and possibly update a user's calendar in order to make a booking.</p>

<p>In order to make it happen, the third-party service application/consumer needs to register itself with the OAuth server. This happens out-of-band and after the registration the consumer gets back a consumer key and secret pair. For example, see this page for one <a href="http://code.google.com/apis/accounts/docs/RegistrationForWebAppsAuto.html" class="external-link" rel="nofollow">approach</a>. The registrations of third-party application does not have to be very involved for simpler applications.  </p>

<p>From then on, the typical flows works like this:<br/>
1. End User requests the third-party service using a browser.</p>

<p>2. Third-party service requests a temporarily request token from OAuth RequestToken Service; this token will represent a consumer's intention to access whatever end user resources it needs to complete the current user's request.</p>

<p>3. After getting a request token back, the consumer redirects the end user to OAuth Authorization Service and adds the request token to the target URI.</p>

<p>4. Authorization Service will get all the details about the current consumer using a request token, build an HTML form and return it to the end user. The form will ask the user if a given third-party application can be allowed to access some resources on behalf of this user.     </p>

<p>5. If the user approves it then Authorization Service will redirect the user back to the callback uri provided by the consumer when requesting a request token, including a generated verifier (authorization key) which 'links' the user's approval with the request token. </p>

<p>6. Now the third-party service requests an access token from OAuth AccessToken Service by providing a request token and its verifier. </p>

<p>7. After getting an access token token, the service finally proceeds with accessing the current user's resources and completes the user's request.</p>

<p>As noted above, the consumer needs to register first with the OAuth server. It's a good practice to provide an application name and so called connect URI which is typically a public URI of this application; the former will be used by OAuth Authorization Service at step 4 above and the latter will be used at step 2 to validate the provided callback URI to make sure it starts from the URI which was actually provided during the registration.</p>

<p>As you can see the flow can be complex yet it is functional. A number of issues may need to be taken care along the way such as managing expired tokens, making sure that the OAuth security layer is functioning properly and is not interfering with the end user itself trying to access its own resources, etc.</p>

<p>CXF JAX-RS gives the best effort to making this process as simple as possible and requiring only a minimum effort on behalf of OAuth server developers.<br/>
It also offers the utility code for greatly simplifying the way the third-party application can interact with the OAuth service endpoints.</p>

<p>Now, as far this particular 3-leg flow is concerned, OAuth 2.0 simplifies it by effectively making the steps 3 and 6 (requests for request and access tokens) redundant. Moving to OAuth 2.0 will be straightforward after learning how to build OAuth 1.0 servers with CXF. </p>

<p>Please check the <a href="http://tools.ietf.org/html/rfc5849" class="external-link" rel="nofollow">specification</a> and the <a href="http://en.wikipedia.org/wiki/OAuth" class="external-link" rel="nofollow">Wikipedia article</a> as well as other resources available on the WEB for more information you may need to know about OAuth. </p>

<h1><a name="JAX-RSOAuth-Mavendependencies"></a>Maven dependencies</h1>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;dependency&gt;</span>
  <span class="code-tag">&lt;groupId&gt;</span>org.apache.cxf<span class="code-tag">&lt;/groupId&gt;</span>
  <span class="code-tag">&lt;artifactId&gt;</span>cxf-rt-rs-security-oauth<span class="code-tag">&lt;/artifactId&gt;</span>
  <span class="code-tag">&lt;version&gt;</span>2.5.0<span class="code-tag">&lt;/version&gt;</span>
<span class="code-tag">&lt;/dependency&gt;</span>
</pre>
</div></div>

<h1><a name="JAX-RSOAuth-DevelopingOAuthServers"></a>Developing OAuth Servers</h1>

<p>OAuth server is the core piece of the complete OAuth-based solution. Typically it contains 3 services for:</p>
<ul class="alternate" type="square">
	<li>Initiating the flows by issuing temporarily tokens to consumers</li>
	<li>Authorizing request tokens by asking the end users to let consumers access some of their resources and returning the<br/>
  confirmation back to the consumer</li>
	<li>Exchanging authorized request tokens for access tokens</li>
</ul>


<p>CXF offers 3 JAX-RS service implementations that can be used to create functional OAuth servers fast: <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/services/RequestTokenService.java" class="external-link" rel="nofollow">RequestTokenService</a>, <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/services/AuthorizationRequestService.java" class="external-link" rel="nofollow">AuthorizationRequestService</a> and <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/services/AccessTokenService.java" class="external-link" rel="nofollow">AccessTokenService</a>.</p>

<p>All of these 3 services rely on the custom <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/provider/OAuthDataProvider.java" class="external-link" rel="nofollow">OAuthDataProvider</a> which manages request and access tokens. Writing your own OAuthDataProvider implementations is what is needed to get the OAuth server up and running.</p>

<h2><a name="JAX-RSOAuth-RequestTokenService"></a>RequestTokenService  </h2>

<p>The main responsibility of <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/services/RequestTokenService.java" class="external-link" rel="nofollow">RequestTokenService</a> is to create a temporarily request token and return it back to the consumer. It supports POST and GET requests and return a form payload containing the new request token and its secret.</p>

<p>Here is an example request log:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Address: http://localhost:8080/services/oauth/initiate
Encoding: ISO-8859-1
Http-Method: POST
Content-Type: */*
Headers: {
Accept=[application/x-www-form-urlencoded], 

Content-Length=[0],

Authorization=[OAuth oauth_callback=<span class="code-quote">"http%3A%2F%2Flocalhost%3A8080%2Fservices%2Freservations%2Freserve%2Fcomplete"</span>, 
                     oauth_nonce=<span class="code-quote">"e365fa02-772e-4e33-900d-00a766ccadf8"</span>, 
                     oauth_consumer_key=<span class="code-quote">"123456789"</span>, 
                     oauth_signature_method=<span class="code-quote">"HMAC-SHA1"</span>, 
                     oauth_timestamp=<span class="code-quote">"1320748683"</span>, 
                     oauth_version=<span class="code-quote">"1.0"</span>, 
                     oauth_signature=<span class="code-quote">"ztTQuqaJS7L6dNQwn%2Fqi1MdaqQQ%3D"</span>] 
}
</pre>
</div></div>

<p>It is an empty POST request which includes an Authorization OAuth header. The value of the header has a consumer key (obtained during the third-party registration), callback URI pointing to where AuthorizationRequestService will return an authorized token and a signature which was calculated using a consumer key and secret pair as <a href="http://tools.ietf.org/html/rfc5849#section-3.4.2" class="external-link" rel="nofollow">described in the specification</a>.</p>

<p>First RequestTokenService validates the signature and then it retrieves a <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Client.java" class="external-link" rel="nofollow">Client</a> instance from OAuthDataProvider using a consumer key.</p>

<p>Before asking OAuthDataProvider to generate a request token, it attempts to validate a callback URI against a <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Client.java" class="external-link" rel="nofollow">Client</a>'s application URI.</p>

<p>Finally it delegates to OAuthDataProvider to create a request token, passing to it a populated <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/RequestTokenRegistration.java" class="external-link" rel="nofollow">RequestTokenRegistration</a> bean. </p>

<p>This bean references a Client instance, callback URI and a state. State is something that a consumer may also include during the request token request using a "state" parameter and will be returned back to the consumer alongside the verifier after the request token has been authorized. For example, it may represent a key that a consumer will use to retrieve the state of the request that it was processing when requesting a token. For OAuth 1.0<br/>
consumers, the request token itself may represent a good enough key for such purposes, but "state" may need to be used too and will become more useful for OAuth 2.0.</p>

<p>The bean also includes "issuedAt" and "lifetime" values which represent the time a new token is about to be created and a configurable time in milliseconds that this token will 'live' for. OAuthDataProvider will be free to reset those values if needed before actually creating a request token.</p>

<p>Finally, two more properties may be set on this bean instance: list of scopes and uris. List of scopes represents optional permissions that the consumer may need to access the resources and a list of URIs represents an optional list of relative URIs the consumer will want to use. These can be provided by "x_oauth_scope" (just "scope" in OAuth 2.0) and "x_oauth_uri" request parameters, for example,</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Authorization=[OAuth ..., 
                     x_oauth_scope=<span class="code-quote">"readCalendar updateCalendar"</span>, 
                     x_oauth_uri=<span class="code-quote">"/calendar"</span>]
</pre>
</div></div>  

<p>These two parameters will be covered later.</p>

<p>After a new request token has been created by OAuthDataProvider, RequestTokenService returns the token key and secret pair to the consumer:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Response-Code: 200
Content-Type: application/x-www-form-urlencoded
Headers: {Date=[Tue, 08 Nov 2011 10:38:03 GMT]}
Payload: 
oauth_callback_confirmed=true&amp;oauth_token=6dfd5e52-236c-4939-8df8-a53212f7d2a2&amp;oauth_token_secret=ca8273df-b9b0-43f9-9875-cfbb54ced550
</pre>
</div></div>

<p>The consumer is now ready to redirect the current end user to <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/services/AuthorizationRequestService.java" class="external-link" rel="nofollow">AuthorizationRequestService</a>.</p>

<h2><a name="JAX-RSOAuth-AuthorizationRequestService"></a>AuthorizationRequestService</h2>

<p>The main responsibility of AuthorizationRequestService is to present an end user with a form asking the user to allow or deny the consumer accessing some of the user resources. </p>

<p>Remember that a third-party consumer redirects the current user to AuthorizationRequestService, for example, here is how a redirection may happen:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Response-Code: 303
Headers: {Location=[http://localhost:8080/services/social/authorize?oauth_token=f4415e16-56ea-465f-9df1-8bd769253a7d]}
</pre>
</div></div> 

<p>The consumer application asks the current user (the browser) to go to a new address provided by the Location header and the follow-up request to AuthorizationRequestService will look like this:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Address: http://localhost:8080/services/social/authorize?oauth_token=6dfd5e52-236c-4939-8df8-a53212f7d2a2
Http-Method: GET
Content-Type: 
Headers: {
Accept=[text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8],   
Referer=[http://localhost:8080/services/forms/reservation.jsp], 
...
}
</pre>
</div></div> 

<p>First, AuthorizationRequestService will retrieve <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/RequestToken.java" class="external-link" rel="nofollow">RequestToken</a> (which extends the base <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Token.java" class="external-link" rel="nofollow">Token</a> class) from OAuthDataProvider using the value provided by the "oauth_token" query parameter. </p>

<p>Next it uses this token (which also links to Client) to populate an instance of <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthAuthorizationData.java" class="external-link" rel="nofollow">OAuthAuthorizationData</a> bean and returns it. OAuthAuthorizationData contains application name and URI properties, optional list of <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Permission.java" class="external-link" rel="nofollow">Permission</a>s and URIs. </p>

<p>Note that if a consumer originally specified a list of scopes using an "x_oauth_scope" parameter then AuthorizationRequestService will ask OAuthDataProvider to translate opaque names such as "readCalendar" into <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Permission.java" class="external-link" rel="nofollow">Permission</a>s for a user to see a better description of these scopes. Also a Client representing the third-party consumer may have been allocated some default scopes during the registration in which case those scopes will also be taken into account when populating OAuthAuthorizationData. The same for optional URIs - more on both scopes and URIs below.</p>

<p>Two other important OAuthAuthorizationData properties are "oauthToken" and "authenticityToken", both are important for processing the decision request coming from the authorization form. The former is a request token key which will be used by AuthorizationRequestService to retrieve the RequestToken again and the latter for validating that the current session has not been hijacked - AuthorizationRequestService generates a random key, stores this in Servlet HTTPSession and expects the returned authenticityToken value match it - this is a recommended approach and it also implies that the authenticityToken value is kept is hidden from a user, for example, it's kept in a 'hidden' form field.</p>

<p>The helper "replyTo" property is an absolute URI identifying the AuthorizationRequestService handler processing the user decision and can be used by view handlers when building the forms or by other OAuthAuthorizationData handlers.</p>

<p>So the populated OAuthAuthorizationData is finally returned. Note that it's a JAXB XMLRootElement-annotated bean and can be processed by registered JAXB or JSON providers given that AuthorizationRequestService supports producing "application/xml" and "application/json" (See the OAuth Without Browser section below for more). But in this case we have the end user working with a browser so an HTML form is what is really expected back.</p>

<p>AuthorizationRequestService supports producing "text/html" and it simply relies on a registered <a href="http://cxf.apache.org/docs/jax-rs-redirection.html#JAX-RSRedirection-WithRequestDispatcherProvider" class="external-link" rel="nofollow">RequestDispatcherProvider</a> to set the OAuthAuthorizationData bean as HttpServletRequest attribute and redirect to a view handler (can be JSP or some other servlet) to actually build the form and return it to the user. Alternatively, registering <a href="http://cxf.apache.org/docs/jax-rs-advanced-xml.html#JAX-RSAdvancedXML-XSLTsupport" class="external-link" rel="nofollow">XSLTJaxbProvider</a> would also be a good option for creating HTML views.  </p>

<p>Assuming RequestDispatcherProvider is used, the following example log shows the initial response from AuthorizationRequestService:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
08-Nov-2011 13:32:40 org.apache.cxf.jaxrs.provider.RequestDispatcherProvider logRedirection
INFO: Setting an instance of <span class="code-quote">"org.apache.cxf.rs.security.oauth.data.OAuthAuthorizationData"</span> as HttpServletRequest attribute <span class="code-quote">"data"</span> and redirecting the response to <span class="code-quote">"/forms/oauthAuthorize.jsp"</span>.

08-Nov-2011 13:32:40 org.apache.cxf.interceptor.LoggingOutInterceptor
---------------------------
Response-Code: 200
Content-Type: text/html
</pre>
</div></div>

<p>Note that a "/forms/oauthAuthorize.jsp" view handler will create an HTML view - this is a custom JSP handler and whatever HTML view is required can be created there, using the OAuthAuthorizationData bean. Most likely you will want to present form asking a user to allow or deny the consumer accessing some of users resources. If OAuthAuthorizationData has a list of Permissions set then add the information about the permissions, same for a list of URIs.</p>

<p>Next the user makes a decision and selects a button allowing or denying the consumer accessing the resources. AuthorizationRequestService does not need to know how a user has been asked to make the decision, but it expects to receive a form-based submission containing the following 3 parameters, named "session_authenticity_token" and "oauth_token" with values matching those of OAuthAuthorizationData's "authenticityToken" and "oauthToken" properties, and "oAuthDecision" with either "allow" or "deny" values: </p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Address: http://localhost:8080/services/social/authorize/decision
Http-Method: POST
Content-Type: application/x-www-form-urlencoded
Headers: {
Authorization=[Basic YmFycnlAc29jaWFsLmNvbToxMjM0],
Cookie=[JSESSIONID=eovucah9rwqp], 
Referer=[http://localhost:8080/services/social/authorize?oauth_token=6dfd5e52-236c-4939-8df8-a53212f7d2a2], 
User-Agent=[Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0]}
--------------------------------------
09-Nov-2011 16:41:58 org.apache.cxf.jaxrs.utils.FormUtils logRequestParametersIfNeeded
INFO: session_authenticity_token=e52b5033-9bf5-4b34-9d3a-39a7d5b7e686&amp;oauthDecision=allow&amp;oauth_token=6dfd5e52-236c-4939-8df8-a53212f7d2a2
</pre>
</div></div> 

<p>AuthorizationRequestService will use a session_authenticity_token to validate that the session is valid and will process the user decision next.<br/>
If it is set to "allow" then it will ask OAuthDataProvider to generate an authorization key (verifier) and return this verifier alongside with the request token key and the state if any by redirecting the current user back to the callback URI provided during the request token request:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Response-Code: 303
Headers: {
Location=[http://localhost:8080/services/reservations/reserve/complete?oauth_token=6dfd5e52-236c-4939-8df8-a53212f7d2a2&amp;oauth_verifier=00bd8fa7-4233-42a2-8957-0a0a22c684ba]
}
</pre>
</div></div>  

<p>which leads to a browser redirecting the user:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
Address: http:<span class="code-comment">//localhost:8080/services/reservations/reserve/complete?oauth_token=6dfd5e52-236c-4939-8df8-a53212f7d2a2&amp;oauth_verifier=00bd8fa7-4233-42a2-8957-0a0a22c684ba
</span>Http-Method: GET
Content-Type: 
Headers: {
Authorization=[Basic YmFycnlAc29jaWFsLmNvbToxMjM0], 
Cookie=[JSESSIONID=eovucah9rwqp],
Referer=[http:<span class="code-comment">//localhost:8080/services/social/authorize?oauth_token=6dfd5e52-236c-4939-8df8-a53212f7d2a2], 
</span>User-Agent=[Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0]}
</pre>
</div></div>

<p>If a user decision was set to "deny" then no verifier will be sent back to the consumer.</p>

<p>Assuming the decision was "allow", the consumer has now got back a request token and the verifier and is ready to exchange it for an access token.</p>

<h2><a name="JAX-RSOAuth-AccessTokenService"></a>AccessTokenService </h2>

<p>The role of AccessTokenService is to exchange an authorized request token for a new access token which will be used by the consumer to access the end user's resources. <br/>
Here is an example request log:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Address: http://localhost:8080/services/oauth/token
Http-Method: POST
Headers: {
Accept=[application/x-www-form-urlencoded], 
Authorization=[OAuth oauth_signature_method=<span class="code-quote">"HMAC-SHA1"</span>, 
                     oauth_consumer_key=<span class="code-quote">"123456789"</span>, 
                     oauth_token=<span class="code-quote">"6dfd5e52-236c-4939-8df8-a53212f7d2a2"</span>, 
                     oauth_verifier=<span class="code-quote">"00bd8fa7-4233-42a2-8957-0a0a22c684ba"</span>, 
                     oauth_timestamp=<span class="code-quote">"1320760259"</span>, 
                     oauth_nonce=<span class="code-quote">"16237669362301"</span>, 
                     oauth_version=<span class="code-quote">"1.0"</span>, 
                     oauth_signature=<span class="code-quote">"dU%2BhXPNFfFpX2sC74IOxzTjdVrY%3D"</span>]
}
</pre>
</div></div> 

<p>This request is very similar to a temporarily token request. Note that the request token key is also included and this token key and its secret pair, as well as the consumer key and secret pair are used to calculate the signature.</p>

<p>AccessTokenService validates the signature, asks OAuthDataProvider to remove a RequestToken identified by the "oauth_token" and create a new <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/AccessToken.java" class="external-link" rel="nofollow">AccessToken</a> based on this RequestToken. The resulting access token key and secret pair is returned back to a consumer:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Response-Code: 200
Content-Type: application/x-www-form-urlencoded
Headers: {Date=[Tue, 08 Nov 2011 13:50:59 GMT]}
Payload: oauth_token=abc15aca-2073-4bde-b1be-1a02dc7ccafe&amp;oauth_token_secret=859dfe9e-ca4c-4b36-9e60-044434ab636c
</pre>
</div></div> 

<p>The consumer will use this access token to access the current user's resources in order to complete the original user's request, for example, the request to access a user's calendar may look like this:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Address: http://localhost:8080/services/user/calendar
Http-Method: GET
Headers: {
Accept=[application/XML], 
Authorization=[OAuth oauth_signature_method=<span class="code-quote">"HMAC-SHA1"</span>, 
                     oauth_consumer_key=<span class="code-quote">"123456789"</span>, 
                     oauth_token=<span class="code-quote">"abc15aca-2073-4bde-b1be-1a02dc7ccafe"</span>, 
                     oauth_version=<span class="code-quote">"1.0"</span>, 
                     oauth_signature=<span class="code-quote">"dU%2BhXPNFfFpX2sC74IOxzTjdVrY%3D"</span>]
}
</pre>
</div></div> 

<p>Note that the access token is set and the access token key and secret pair, as well as the consumer key and secret pair are used to create a signature.</p>

<h2><a name="JAX-RSOAuth-WritingOAuthDataProvider"></a>Writing OAuthDataProvider</h2>

<p>Using CXF OAuth service implementations will help a lot with setting up an OAuth server. As you can see from the above sections, these services rely on a custom <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/provider/OAuthDataProvider.java" class="external-link" rel="nofollow">OAuthDataProvider</a> implementation.</p>

<p>The main task of OAuthDataProvider is to persist request and access tokens and generate authorization/verifier keys. The way it's done is really application-specific. Consider starting with a basic memory based implementation and then move on to keeping the data in some DB.</p>

<p>Note that OAuthDataProvider supports retrieving <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Client.java" class="external-link" rel="nofollow">Client</a> instances but it has no methods for creating or removing Clients. The reason for it is that the process of registering third-party consumers is very specific to a partucular OAuth application, so CXF does not offer a registration support service and hence OAuthDataProvider has no Client create/update methods. You will liley need to do something like this:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class CustomOAuthProvider <span class="code-keyword">implements</span> OAuthDataProvider {
   <span class="code-keyword">public</span> Client registerClient(<span class="code-object">String</span> applicationName, <span class="code-object">String</span> applicationURI, ...) {}
   <span class="code-keyword">public</span> void removeClient(<span class="code-object">String</span> cliendId) {}
   <span class="code-comment">// etc
</span>   <span class="code-comment">// OAuthDataProvider methods
</span>}
</pre>
</div></div>

<p>CustomOAuthProvider will also remove all tokens associated with a given Client in removeClient(String cliendId).</p>

<p>When creating RequestToken or AccessToken tokens as well as authorization keys, OAuthDataProvider will need to create unique identifiers.<br/>
The way it's done is application specific and custom implemenations may also use a utility <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/provider/MD5SequenceGenerator.java" class="external-link" rel="nofollow">MD5SequenceGenerator</a> shipped with CXF, for example:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-object">String</span> setRequestTokenVerifier(RequestToken requestToken) <span class="code-keyword">throws</span> OAuthServiceException {
    requestToken.setVerifier(generateSequence());
    <span class="code-keyword">return</span> requestToken.getVerifier();
}

<span class="code-keyword">private</span> <span class="code-object">String</span> generateSequence() <span class="code-keyword">throws</span> OAuthServiceException {
    <span class="code-keyword">try</span> {
       <span class="code-keyword">return</span> tokenGenerator.generate(UUID.randomUUID().toString().getBytes(<span class="code-quote">"UTF-8"</span>));
    } <span class="code-keyword">catch</span> (Exception e) {
       <span class="code-keyword">throw</span> <span class="code-keyword">new</span> OAuthServiceException(<span class="code-quote">"Unable to generate the key"</span>, e.getCause());
    }
}

</pre>
</div></div>

<p>Generating tokens/keys and persisting them effectively is what OAuthDataProvider all about.<br/>
Note that CXF will check that Request and Access tokens have not expired every time it uses them and will ask OAuthDataProvider to remove the expired tokens, but the custom OAuthDataProvider implementation may do its own checks too.</p>

<p>Finally OAuthDataProvider may be asked to convert opaque scope values such as "readCalendar" into a list of <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthPermission.java" class="external-link" rel="nofollow">OAuthPermission</a>s. AuthorizationRequestService and OAuth security filters will depend on it (assuming scopes are used in the first place). In the former case AuthorizationRequestService will use this list to populate <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthAuthorizationData.java" class="external-link" rel="nofollow">OAuthAuthorizationData</a> - the reason this bean only sees <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Permission.java" class="external-link" rel="nofollow">Permission</a>s is that the properties OAuthPermission keeps are of no interest to OAuthAuthorizationData handlers.</p>

<h2><a name="JAX-RSOAuth-OAuthServerJAXRSendpoints"></a>OAuth Server JAX-RS endpoints </h2>

<p>With CXF offering OAuth service implementations and a custom OAuthAuthorizationData provider in place, it is time to deploy the OAuth server.  <br/>
Most likely, you'd want to deploy RequestTokenService and AccessTokenService as two root resources inside a single JAX-RS endpoint (or have one RequestTokenService and one AccessTokenService endpoint), for example:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag"><span class="code-comment">&lt;!-- implements OAuthDataProvider --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"oauthProvider"</span> class=<span class="code-quote">"oauth.manager.OAuthManager"</span>/&gt;</span>

<span class="code-tag">&lt;bean id=<span class="code-quote">"requestTokenService"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.oauth.services.RequestTokenService"</span>&gt;</span>
   <span class="code-tag">&lt;property name=<span class="code-quote">"dataProvider"</span> ref=<span class="code-quote">"oauthProvider"</span>/&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>
     
<span class="code-tag">&lt;bean id=<span class="code-quote">"accessTokenService"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.oauth.services.AccessTokenService"</span>&gt;</span>
  <span class="code-tag">&lt;property name=<span class="code-quote">"dataProvider"</span> ref=<span class="code-quote">"oauthProvider"</span>/&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>

<span class="code-tag">&lt;jaxrs:server id=<span class="code-quote">"oauthServer"</span> address=<span class="code-quote">"/oauth"</span>&gt;</span>
   <span class="code-tag">&lt;jaxrs:serviceBeans&gt;</span>
      <span class="code-tag">&lt;ref bean=<span class="code-quote">"requestTokenService"</span>/&gt;</span>
      <span class="code-tag">&lt;ref bean=<span class="code-quote">"accessTokenService"</span>/&gt;</span>
  <span class="code-tag">&lt;/jaxrs:serviceBeans&gt;</span>
<span class="code-tag">&lt;/jaxrs:server&gt;</span>
</pre>
</div></div>  

<p>RequestTokenService listens on a relative "/initiate" path, AccessTokenService - on "/token". Giving the that jaxrs:server/@adress is "/oauth" and assuming a context name is "/services", the absolute address of RequestTokenService would be something like "http://localhost:8080/services/oauth/initiate" and that of AccessTokenService - "http://localhost:8080/services/oauth/token". </p>

<p>AuthorizationRequestService is better to put where the main application endpoint is. It can be put alongside RequestTokenService and AccessTokenService - but the problem is that the end user is expected to authenticate itself with the resource server after it has been redirected by a third-party consumer to AuthorizationRequestService. That would make it more complex for the OAuth server endpoint to manage both OAuth (third-party consumer) and the regular user authentication - that can be done, see more on it below in the Design considerations section, but the simpler option is to simply get AuthorizationRequestService under the control of the security filter enforcing the end user authentication:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
&lt;bean id=<span class="code-quote">"authorizationService"</span> class=<span class="code-quote">"org.apache.cxf.rs.security.oauth.services.AuthorizationRequestService"</span>&gt;
  &lt;property name=<span class="code-quote">"dataProvider"</span> ref=<span class="code-quote">"oauthProvider"</span>/&gt;
&lt;/bean&gt;

&lt;bean id=<span class="code-quote">"myApp"</span> class=<span class="code-quote">"org.myapp.MyApp"</span>&gt;
  &lt;property name=<span class="code-quote">"dataProvider"</span> ref=<span class="code-quote">"oauthProvider"</span>/&gt;
&lt;/bean&gt;

&lt;jaxrs:server id=<span class="code-quote">"oauthServer"</span> address=<span class="code-quote">"/myapp"</span>&gt;
   &lt;jaxrs:serviceBeans&gt;
      &lt;ref bean=<span class="code-quote">"myApp"</span>/&gt;
      &lt;ref bean=<span class="code-quote">"authorizationService"</span>/&gt;
  &lt;/jaxrs:serviceBeans&gt;
&lt;/jaxrs:server&gt;
</pre>
</div></div>

<p>AuthorizationRequestService listens on a relative "/authorize" path so in this case its absolute address will be something like "http://localhost:8080/services/myapp/authorize". This address and those of RequestTokenService and AccessTokenService will be used by third-party consumers.</p>

<h1><a name="JAX-RSOAuth-ProtectingresourceswithOAuthfilters"></a>Protecting resources with OAuth filters</h1>

<p><a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/filters/OAuthRequestFilter.java" class="external-link" rel="nofollow">OAuthRequestFilter</a> request handler can be used to protect the resource server when processing the requests from the third-party consumers. Add it as a jaxrs:provider to the endpoint which deal with the consumers requesting the resources.</p>

<p>When checking a request like this:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Address: http://localhost:8080/services/user/calendar
Http-Method: GET
Headers: {
Accept=[application/XML], 
Authorization=[OAuth oauth_signature_method=<span class="code-quote">"HMAC-SHA1"</span>, 
                     oauth_consumer_key=<span class="code-quote">"123456789"</span>, 
                     oauth_token=<span class="code-quote">"abc15aca-2073-4bde-b1be-1a02dc7ccafe"</span>, 
                     oauth_version=<span class="code-quote">"1.0"</span>, 
                     oauth_signature=<span class="code-quote">"dU%2BhXPNFfFpX2sC74IOxzTjdVrY%3D"</span>]
}
</pre>
</div></div> 

<p>the filter will do the following:</p>

<p>1. It will validate the signature and will get Client and AccessToken from OAuthDataProvider.</p>

<p>2. It will check if <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Client.java" class="external-link" rel="nofollow">Client</a> and <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/AccessToken.java" class="external-link" rel="nofollow">AccessToken</a> have a "uris" property set and if yes then it will validate the current request URI against it.</p>

<p>3. If Client or AccessToken have a "scopes" property set then it will ask OAuthDataProvider to convert them into a list of <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthPermission.java" class="external-link" rel="nofollow">OAuthPermissions</a>. For every permission it will:</p>
<ul class="alternate" type="square">
	<li>If it has a uri property set then the current request URI will be checked against it</li>
	<li>If it has an httpVerb property set then the current HTTP verb will be checked against it</li>
</ul>


<p>4. Finally, it will create a CXF <a href="http://svn.apache.org/repos/asf/cxf/trunk/api/src/main/java/org/apache/cxf/security/SecurityContext.java" class="external-link" rel="nofollow">SecurityContext</a> using this list of <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthPermission.java" class="external-link" rel="nofollow">OAuthPermissions</a> and the <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/Client.java" class="external-link" rel="nofollow">Client</a> loginName property.</p>

<p>This loginName property is something that can be optionally associated with the new Client during the registration - if it is not set then the filter will use a Client "applicationName" property instead. The application code checking the user Principal will see the chosen value. Additionally every OAuthPermission may have a list of application-specific roles such as "consumer", etc, which will be added to SecurityContext and will be checked during SecurityContext.isUserInRole(roleName) calls. </p>

<p>This SecurityContext will not necessarily be important for some of OAuth applications. Most of the security checks will be done by OAuth filters and security filters protecting the main application path the end users themselves use. Only if you would like to share the same JAX-RS resource code and access URIs between end users and consumers then it can become handy. More on it below. </p>

<p>Note that <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/filters/OAuthServletFilter.java" class="external-link" rel="nofollow">OAuthServletFilter</a> can be deployed instead. It will need the OAuthDataProvider full class name referenced as an "oauth.data.provider-class" servlet context parameter.</p>

<h1><a name="JAX-RSOAuth-Clientsidesupport"></a>Client-side support</h1>

<p>When developing a third party application which needs to participate in OAuth flows one has to write the code that will redirect users to OAuth AuthorizationRequestService, interact with RequestTokenService and AccessTokenService in order to get request and access tokens as well as correctly build Authorization OAuth headers when accessing the end users' resources. JAX-RS makes it straightforward to support the redirection, while <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/client/OAuthClientUtils.java" class="external-link" rel="nofollow">OAuthClientUtils</a> class makes it possible to encapsulate most of the complexity away from the client application code.   </p>

<p>OAuthClientUtils has utility methods for getting request and access tokens, the consumer is expected to provide a properly initialized WebClient pointing to either RequestTokenService and AccessTokenService, Consumer bean containing the registration key and secret, a callback URI for requesting a request token and the request Token and the verifier for requesting the access token which is all quite straightforward. It also helps to create a proper URI for redirecting to AuthorizationRequestService. A correct Authorization header will also need to be used when accessing the user resources at the resource server and OAuthClientUtils will help with creating this header as well.</p>

<p>For example, the following custom code can be used by the third-party application:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class OAuthClientManager {
	
	<span class="code-keyword">private</span> WebClient accessTokenService;
        <span class="code-keyword">private</span> WebClient requestTokenService;
        <span class="code-keyword">private</span> <span class="code-object">String</span> authorizationServiceURI;
    
        <span class="code-comment">// inject properties...
</span>	
	<span class="code-keyword">public</span> URI getAuthorizationServiceURI(<span class="code-object">String</span> token) {
	    <span class="code-keyword">return</span> OAuthClientUtils.getAuthorizationURI(authorizationServiceURI, token);
	}
	
	<span class="code-keyword">public</span> Token getRequestToken(URI callback) {
	    <span class="code-keyword">try</span> {
	        <span class="code-keyword">return</span> OAuthClientUtils.getRequestToken(requestTokenService, consumer, callback, <span class="code-keyword">null</span>);
	    } <span class="code-keyword">catch</span> (OAuthServiceException ex) {
               <span class="code-keyword">return</span> <span class="code-keyword">null</span>;
            }    
	}
	
	<span class="code-keyword">public</span> Token getAccessToken(Token requestToken, <span class="code-object">String</span> verifier) {
	    <span class="code-keyword">try</span> {
	        <span class="code-keyword">return</span> OAuthClientUtils.getAccessToken(accessTokenService, consumer, requestToken, verifier);
	    } <span class="code-keyword">catch</span> (OAuthServiceException ex) {
	        <span class="code-keyword">return</span> <span class="code-keyword">null</span>;
	    }
	}
	
	<span class="code-keyword">public</span> <span class="code-object">String</span> createAuthorizationHeader(Token token, <span class="code-object">String</span> method, <span class="code-object">String</span> requestURI) {
            <span class="code-keyword">return</span> OAuthClientUtils.createAuthorizationHeader(consumer, token, method, requestURI);
	}
}
</pre>
</div></div>    

<p>The reason such a simple wrapper can be introduced is to minimize the exposure to OAuth of the main application code to the bare minimum, this is why<br/>
in this example OAuthServiceExceptions are caught, presumably logged and null values are returned which will indicate to the main code that the request failed. Obviously, OAuthClientUtils can be used directly as well.</p>

<h1><a name="JAX-RSOAuth-2legOAuthFlow"></a>2-leg OAuth Flow</h1>

<p>The complete 3-leg OAuth flow involves the end user explicitly authorizing the third-party consumer which itself most likely is running as a web server application. In some cases that may not be practical, for example, the end user may just want to let a 3rd party application just keep accessing a given resource it owns until a relevant permission is revoked. This can lead to a simpler so-called 2-leg OAuth flow.</p>

<p>When the consumer is allowed to access the end user resources without seeking an explicit authorization on every request, the following simple Authorization header needs to include only the consumer key and secret obtained during the registration:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
Address: http://localhost:8080/services/user/calendar
Http-Method: GET
Headers: {
Accept=[application/XML], 
Authorization=[OAuth oauth_consumer_key=<span class="code-quote">"123456789"</span>,oauth_consumer_secret=<span class="code-quote">"987654321"</span>] 
                     
}
</pre>
</div></div> 

<p>OAuth filters will validate such a request nearly the same way they validate the requests where access token and signature parameters are included and pass it through only if during the validation it can additionally be asserted that all the <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthPermission.java" class="external-link" rel="nofollow">OAuthPermissions</a> associated with a given Client have an "authorizationKeyRequired" set to false.</p>

<p>What this means is that after a third-party application has been registered, this Client may have got the scopes linking it to such permissions allocated at the very start, or perhaps the resource server application offers an option to registered end users to choose which of the registered third-party applications may access this end user's resources and add scopes to the registered Clients. </p>

<p>For example, a Client may have readCalendar1 and readCalendar2 scopes assigned to it which will be translated during the validation to two OAuthPermission instances with the "authorizationKeyRequired" property set to false and containing /calendar/1 and /calendar/2 relative URIs respectively, with "1" and "2" representing id of the end users which let a particular Client to read their calendars without regular authorization approvals. A single OAuthPermission containing two URIs would do too. </p>

<h1><a name="JAX-RSOAuth-OAuthWithoutaBrowser"></a>OAuth Without a Browser</h1>

<p>When an end user is accessing the 3rd party application and is authorizing it later on, it's usually expected that the user is relying on a browser. <br/>
However, supporting other types of end users is easy enough. Writing the client code that processes the redirection requests from the 3rd party application and AuthorizationRequestService is simple with JAX-RS and additionally CXF can be configured to do auto-redirects on the client side.</p>

<p>Also note that AuthorizationRequestService can return XML or JSON <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthAuthorizationData.java" class="external-link" rel="nofollow">OAuthAuthorizationData</a> representations. That makes it easy for a client code to get OAuthAuthorizationData and offer a pop-up window or get the input from the command-line. Authorizing the third-party application might even be automated in this case - which can lead to a complete 3-leg OAuth flow implemented without a human user being involved.</p>

<h1><a name="JAX-RSOAuth-Designconsiderations"></a>Design considerations</h1>

<p>This section will talk about various design considerations one need to take into account when deploying OAuth-based solutions.</p>

<h2><a name="JAX-RSOAuth-ControllingtheAccesstoResourceServer"></a>Controlling the Access to Resource Server</h2>

<p>One of the most important issues one need to resolve is how to partition a URI space of the resource server application.</p>

<p>We have two different parties trying to access it, the end users which access the resource server to get to the resources which they own and 3rd party consumers which have been authorized by the end users to access some of their resources. </p>

<p>In the former case the way the authentication is managed is completely up to the resource server application: basic authentication, two-way TLS, OpenId (more on it below), you name it.</p>

<p>In the latter case an OAuth filter must enforce that the 3rd party consumer has been registered using the provided consumer key and that it has a valid access token (authorization key in OAuth 2.0) which represents the end user's approval.  It's kind of the authentication and the authorization check at the same time.</p>

<p>Letting both parties access the resource server via the same URI(s) complicates the life for the security filters but all the parties are only aware of the single resource server URI which all of them will use.</p>

<p>Providing different access points to end users and consumers may significantly simplify the authentication process - the possible downside is that multiple access points need to be mantained by the resource server.</p>

<p>Both options are discussed next.</p>

<h3><a name="JAX-RSOAuth-Sharingthesameaccesspathbetweenendusersandconsumers"></a>Sharing the same access path between end users and consumers</h3>

<p>The first problem which needs to be addressed is how to distinguish end users from third-party consumers and get both parties authenticated as required.<br/>
Perhaps the simplest option is to extend a CXF OAuth filter (JAX-RS or servlet one), check Authorization header, if it is OAuth then delegate to the superclass, alternatively - proceed with authenticating the end users:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> class SecurityFilter <span class="code-keyword">extends</span> org.apache.cxf.rs.security.oauth.filters.OAuthRequestFilter {
   @Context
   <span class="code-keyword">private</span> HttpHeaders headers;

   <span class="code-keyword">public</span> Response handleRequest(ClassResourceInfo cri, Message message) {
       <span class="code-object">String</span> header = headers.getRequestHeaders().getFirst(<span class="code-quote">"Authorization"</span>);
       <span class="code-keyword">if</span> (header.startsWith(<span class="code-quote">"OAuth "</span>)) {
           <span class="code-keyword">return</span> <span class="code-keyword">super</span>.handleRequest(cri, message);
       } <span class="code-keyword">else</span> {
           <span class="code-comment">// authenticate the end user
</span>       }
   }

} 
</pre>
</div></div>   

<p>The next issue is how to enforce that the end users can only access the resources they've been authorized to access.<br/>
For example, consider the following JAX-RS resource class:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
@Path(<span class="code-quote">"calendar"</span>)
<span class="code-keyword">public</span> class CalendarResource {

   @GET
   @Path(<span class="code-quote">"{id}"</span>)
   <span class="code-keyword">public</span> Calendar getPublicCalendar(@PathParam(<span class="code-quote">"id"</span>) <span class="code-object">long</span> id) {
       <span class="code-comment">// <span class="code-keyword">return</span> the calendar <span class="code-keyword">for</span> a user identified by 'id'
</span>   }

   @GET
   @Path(<span class="code-quote">"{id}/<span class="code-keyword">private</span>"</span>)
   <span class="code-keyword">public</span> Calendar getPrivateCalendar(@PathParam(<span class="code-quote">"id"</span>) <span class="code-object">long</span> id) {
       <span class="code-comment">// <span class="code-keyword">return</span> the calendar <span class="code-keyword">for</span> a user identified by 'id'
</span>   }

   @PUT
   @Path(<span class="code-quote">"{id}"</span>)
   <span class="code-keyword">public</span> void updateCalendar(@PathParam(<span class="code-quote">"id"</span>) <span class="code-object">long</span> id, Calendar c) {
       <span class="code-comment">// update the calendar <span class="code-keyword">for</span> a user identified by 'id'
</span>   }
}
</pre>
</div></div>

<p>Lets assume that the 3rd party consumer has been allowed to read the public user Calendars at "/calendar/</p>
<div class="error"><span class="error">Unknown macro: {id}</span> <p>" only, how to make sure that the consumer won't try to:<br/>
1. update the calendar available at the same path <br/>
2. read the private Calendars available at "/calendar/</p></div>
<p>/private"</p>

<p>As noted above, Client, AccessToken (in its Token superclass) and <a href="http://svn.apache.org/repos/asf/cxf/trunk/rt/rs/security/oauth-parent/oauth/src/main/java/org/apache/cxf/rs/security/oauth/data/OAuthPermission.java" class="external-link" rel="nofollow">OAuthPermission</a> all have an optional URIs property. Thus one way to solve the problem with the private calendar is to add, say, a uri "/calendar/</p>
<div class="error"><span class="error">Unknown macro: {id}</span> <p>" or "/calendar/1" (etc) property to OAuthPermission (representing a scope like "readCalendar") and the OAuth filter will make sure no subresources beyond "/calendar/</p></div>
<p>" can be accessed. Note, adding a "<b>" at the end of a given URI property, for example, "/a</b>" will let the consumer to access "/a", "/a/b", etc.</p>

<p>Solving the problem with preventing the update can be easily solved by adding an httpVerb property to a given OAuthPermission.</p>

<p>One more option is to rely on the role-based access control and have @RolesAllowed allocated such that only users in roles like "consumer" or "enduser" can invoke the getCalendar() method and let only those in the "enduser" role access getPrivateCalendar() and updateCalendar(). OAuthPermission can help here too as described in the section on using OAuth fiters.</p>

<h3><a name="JAX-RSOAuth-Providingdifferentaccesspointstoendusersandconsumers"></a>Providing different access points to end users and consumers</h3>

<p>Rather than letting both the end users and 3rd party consumers use the same URI such as "http://myapp.com/service/calendars/</p>
<div class="error"><span class="error">Unknown macro: {id}</span> <p>", one may want to introduce two URIs, one for end users and one for third-party consumers, for example, "http://myapp.com/service/calendars/</p></div>
<p>" - for endusers, "http://myapp.com/partners/calendars/</p>
<div class="error"><span class="error">Unknown macro: {id}</span> <p>" - for the 3rd party consumers and deploy 2 jaxrs endpoints, where one is protected by the security filter checking the end users, and the one - by OAuth filters. </p>

<p>Additionally the endpoint managing the 3rd party consumers will deploy a resource which will offer a resticted URI space support. For example, if the application will only allow 3rd party consumers to read calendars then this resource will only have a method supporting @GET and "/calendar/</p></div>
<p>". </p>

<h2><a name="JAX-RSOAuth-SingleSignOn"></a>Single Sign On</h2>

<p>When dealing with authenticating the end users, having an SSO solution in place is very handy. This is because the end user interacts with both the third-party and its resource server web application and is also redirected back and forth. OpenID or say WebBrowser SSO profile can help - CXF may offer some support in this area. </p>

<h1><a name="JAX-RSOAuth-WhatIsNext"></a>What Is Next</h1>

<p>Fine tuning the current OAuth 1.0 will be continued and the feedback from the implementers will be welcomed.<br/>
OAuth 2.0 is going to become a very major specification in the whole RESTful space and CXF will implement the selected OAuth 2.0 profiles. Among other things, OAuth 2.0 will also rely on SAML in one of the extensions and we'll look into it too. Writing a complete OAuth application will most likely require some SSO solution so some support from CXF is likely to come too.</p>

    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action" class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+OAuth">View Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=27830330&revisedVersion=17&originalVersion=16">View Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+OAuth?showComments=true&amp;showCommentArea=true#addcomment">Add Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message