Authorization Service - 6.1

Talend ESB Service Developer Guide

EnrichVersion
6.1
EnrichProdName
Talend Data Fabric
Talend Data Services Platform
Talend ESB
Talend MDM Platform
Talend Open Studio for ESB
Talend Real-Time Big Data Platform
task
Design and Development
Installation and Upgrade
EnrichPlatform
Talend ESB

The main responsibility of OAuth2 Authorization Service is to present an end user with a form asking the user to allow or deny the client accessing some of the user resources. CXF offers AuthorizationCodeGrantService and ImplicitGrantService for accepting the redirection requests, challenging the end users with the authorization forms, handling the end user decisions and returning the results back to the clients.

One of the differences between the AuthorizationCode and Implicit flows is that in the latter case the grant is the actual access token which is returned as the URI fragment value. The way the end user is asked to authorize the client request is similar between the two flows. In this section we will assume that the Authorization Code flow is being exercised.

A third-party client redirects the current user to AuthorizationCodeGrantService, for example, here is how a redirection may happen:

Response-Code: 303
Headers: {Location=[http://localhost:8080/services/social/authorize?
   client_id=123456789&scope=updateCalendar-7&response_type=code
   &redirect_uri=http%3A//localhost%3A8080/services/reservations/reserve
   /complete&state=1],Date=[Thu, 12 Apr 2012 12:26:21 GMT], 
   Content-Length=[0]}

The client application asks the current user (the browser) to go to a new address provided by the Location header and the follow-up request to AuthorizationCodeGrantService will look like this:

Address: http://localhost:8080/services/social/authorize?client_id=
   123456789&scope=updateCalendar-7&response_type=code&redirect_uri=
   http%3A//localhost%3A8080/services/reservations/reserve/complete&state=1
Http-Method: GET
Headers: {
Accept=[text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8],
Authorization=[Basic YmFycnlAc29jaWFsLmNvbToxMjM0], 
Cookie=[JSESSIONID=suj2wyl54c4g], 
Referer=[http://localhost:8080/services/forms/reservation.jsp]
...
}

Note that the end user needs to authenticate. The Request URI includes the client_id, custom scope value, response_type set to 'code', the current request state and the redirect uri. Note the scope is optional - the Authorization Service will usually allocate a default scope; however even if the client does include an additional custom scope the end user may still not approve it. The redirect uri is also optional, assuming one or more ones redirect URIs have been provided at the client registration time.

AuthorizationCodeGrantService will report a warning is no secure HTTPS transport is used:

12-Apr-2012 13:26:21 
   org.apache.cxf.rs.security.oauth2.services.AbstractOAuthService
   checkTransportSecurity
WARNING: Unsecure HTTP, Transport Layer Security is recommended

It can also be configured to reject the requests over un-secure HTTP transport.

AuthorizationCodeGrantService will retrieve the information about the client application to populate an instance of OAuthAuthorizationData bean and return it. OAuthAuthorizationData contains application name and URI properties, optional list of Permissions and other properties which can be either presented to the user or kept in the hidden form fields in order to uniquely identify the actual authorization request when the end user returns the decision.

One important OAuthAuthorizationData property is "authenticityToken". It is used for validating that the current session has not been hijacked - AuthorizationCodeGrantService generates a random key, stores it in a Servlet HTTPSession instance and expects the returned authenticityToken value to match it - this is a recommended approach and it also implies that the authenticityToken value is hidden from a user, for example, it's kept in a 'hidden' form field. The other properties which are meant to be hidden are clientId, state, redirectUri, proposedScope. The helper "replyTo" property is an absolute URI identifying the AuthorizationCodeGrantService handler processing the user decision and can be used by view handlers when building the forms or by other OAuthAuthorizationData handlers.

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

AuthorizationCodeGrantService supports producing "text/html" and simply relies on a registered RequestDispatcherProvider to set the OAuthAuthorizationData bean as an HttpServletRequest attribute and redirect the response to a view handler (can be JSP or some other servlet) to actually build the form and return it to the user. Alternatively, registering XSLTJaxbProvider would also be a good option for creating HTML views.

Assuming RequestDispatcherProvider is used, the following example log shows the initial response from AuthorizationCodeGrantService:

12-Apr-2012 13:26:21 org.apache.cxf.jaxrs.provider.
    RequestDispatcherProvider logRedirection
INFO: Setting an instance of "org.apache.cxf.rs.security.oauth2.common.
    OAuthAuthorizationData" as HttpServletRequest attribute "data" and 
    redirecting the response to "/forms/oauthAuthorize.jsp".

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 for building the view. Most likely you will want to present a form asking the user to allow or deny the client accessing some of this user's resources. If OAuthAuthorizationData has a list of Permissions set then adding the information about the permissions is needed.

Next the user makes a decision and selects a button allowing or denying the client accessing the resources. The form data are submitted to AuthorizationCodeGrantService:

Address: http://localhost:8080/services/social/authorize/decision
Encoding: ISO-8859-1
Http-Method: POST
Content-Type: application/x-www-form-urlencoded
Headers: {
Authorization=[Basic YmFycnlAc29jaWFsLmNvbToxMjM0],
Content-Type=[application/x-www-form-urlencoded],
...
}
--------------------------------------
12-Apr-2012 15:36:29 org.apache.cxf.jaxrs.utils.FormUtils 
    logRequestParametersIfNeeded
INFO: updateCalendar-7_status=allow&readCalendar_status=allow
&scope=updateCalendar-7+readCalendar
&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fservices%2F
    reservations%2Freserve%2Fcomplete
&session_authenticity_token=4f0005d9-565f-4309-8ffb-c13c72139ebe
    &oauthDecision=allow
&state=1&client_id=123456789

AuthorizationCodeGrantService will use a session_authenticity_token to validate that the session is valid and will process the user decision next.

If the decision is "allow" then it will check the status of the individual scope values. It relies on the "scopename_status" convention, if the form has offered the user a chance to selectively enable individual scopes then name/value pairs such as "updateCalendar-7_status=allow" are submitted. If none of such pairs is coming back then it means the user has approved all the default and additional (if any) scopes. Next it will ask OAuthDataProvider to generate an authorization code grant and return it alongside with the state if any by redirecting the current user back to the redirect URI:

Response-Code: 303
Headers: {
 Location=[http://localhost:8080/services/reservations/reserve/complete
 ?state=1&code=5c993144b910bccd5977131f7d2629ab], 
 Date=[Thu, 12 Apr 2012 14:36:29 GMT], 
 Content-Length=[0]}

Which leads to a browser redirecting the user:

Address: http://localhost:8080/services/reservations/reserve/complete?
state=1&code=5c993144b910bccd5977131f7d2629ab
Http-Method: GET
Headers: {
Accept=[text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8],
Authorization=[Basic YmFycnlAcmVzdGF1cmFudC5jb206NTY3OA==], 
Cookie=[JSESSIONID=1c289vha0cxfe],
}

If a user decision was set to "deny" then the error will be returned to the client. Assuming the decision was "allow", the client has now received back the authorization code grant and is ready to exchange it for a new access token.