Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • JCache and JPA2 OAuthDataProviders (as well as Ehcache 2.x prior to CXF 3.3.0) can represent access tokens in JWT
  • Client Certificate Authentication and Token Binding is supported
  • DynamicRegistrationService is enhanced

CXF provides the an implementation of OAuth 2.0. See also the JAX-RS OAuth page for information about OAuth 1.0.

...

Custom grant handlers can be registered.

OAuth2 is a new protocol which offers a complex yet elegant solution toward helping end users (resource owners) authorize third-party providers to access their resources.

The OAuth2 flow which is closely related to the original OAuth 1.0 3-leg flow is called Authorization Code and involves 3 parties: the end user, the third party service (client) and the resource server which is protected by OAuth2 filters. Typically a client offers a service feature that an end user requests and which requires the former to access one or more protected resources on behalf of this user which are located at the resource server. For example, the client 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.

In order to make it this happen, the third-party service application/client needs to register itself with the OAuth2 server. This happens out-of-band and after the registration the client gets back a client key and secret pair. Typically the client is expected to provide the name and description of the application, the application logo URI, one or more redirect URIs, and other information that may help the OAuth2 authorization server to identify this client to the end user at the authorization time.

From then on, the authorization code flow works like this:
1. End User requests the third-party service using a browser.

2. The client redirects the end user to OAuth2 Authorization Service, adding its client id, the state, redirect URI and the optional scope to the target URI. The state parameter represents the current end user's request, redirect URI - where the authorization code is expected to be returned to, and the scope is the list of opaque permissions that the client needs in order to access the protected resources.

3. The Authorization Service will retrieve the information about the client using its client id, build an HTML form and return it to the end user. The form will ask the user if a the given third-party application can be allowed to access some specified resources on behalf of this user.

4. If the user approves it , then the Authorization Service will generate an authorization code and redirect the user back to the redirect uri provided by the client, also adding a state parameter to the redirect URI.

...

6. After getting an access token token, the service finally proceeds with accessing the current user's resources and completes the user's request.

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

Please check the specification as well as other resources available on the WEB web for more information you may need to know about OAuth2.

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

...

Client Registration is typically done out of band, with the the dynamic client registration also being also possible.
The client registration service will offer an HTML form where the clients will enter their details, see a the Client bean for the currently supported properties.

...

CXF offers several JAX-RS service implementations that can be used to create the OAuth2 servers fastquickly: AuthorizationCodeGrantService and ImplicitGrantService for managing the redirection-based flows, as well as AccessTokenService for exchanging the grants for new tokens.

...

Note that some grants that do not require the redirection-based support, such as Client Credentials or SAML2 or JWT assertion grants, and instead may require only require an Access Token Service be operational.

If your OAuth2 server does support either Authorization Code or Implicit flow then either AuthorizationCodeGrantService and ImplicitGrantService need to be registered. If both services need to be supported then simply register two of them, but note each service will have its own @Path segment, "/authorize" and "/authorize-implicit". If you'd like both services listening on the same path then use AuthorizationService and inject inject the AuthorizationCodeGrantService and ImplicitGrantService beans into it.

If no AuthorizationCode redirection flow is supported then implementing OAuthDataProvider is sufficentsufficient.

Writing your own AuthorizationCodeDataProvider or OAuthDataProvider implementation is what is needed to get the OAuth2 server up and running. In many cases all you need to do is to persist or remove the Authorization Code Grant data, use one of the available utility classes to create a new access token and also persist it or remove the expired one, and finally convert the optional opaque scope values (if any are supported) to a more view-able information.

CXF ships several default provider implementations, see the section on wirting writing the providers below.


Authorization Service

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 to access specified resources owned by 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.

...

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 were provided at when the client registration timewas registered with the Authorization Service.

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

...

It can also be configured to reject the requests made over insecure HTTP transport.

The 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. See also "User Session Authenticity" on how SessionAuthenticityTokenProvider can help.

A number of properties which have been submitted to the authorization endpoint with the original user redirect need to be made available after the user has been challenged with the autorization authorization consent form, when the user makes an authorization decision. These are properties such as 'clientId', 'state', 'redirectUri', and other properties, see this class which is extended by OAuthAuthorizationData. One simple approach is to have a view handler preparing prepare an authorization form with OAuthAuthorizationData to have these properties hidden in the form. Another option is to secure them in a session thus making the view creation process much simpler, see "User Session Authenticity" for one example.

The helper "replyTo" property is an absolute URI identifying the AuthorizationCodeGrantService handler processing which processes the user's 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.

The 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. See the section below on other alternatives on how a view can be created.

...

Code Block
xml
xml
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%2Freservations%2Freserve%2Fcomplete
&session_authenticity_token=4f0005d9-565f-4309-8ffb-c13c72139ebe&oauthDecision=allow&state=1&client_id=123456789

The AuthorizationCodeGrantService will use a the 'session_authenticity_token' to validate first check that the session is valid and if so will process the user's decision next.

If the decision is "allow" then it will check the status of the submitted individual scope values. It relies on the "scopename_status" convention (e.g., "updateCalendar-7_status=allow") in name/value pairs, if the form has offered offers 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 are returned then it means the user has approved all the default and any additional (if any) scopes.

Next it will ask the 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:

...

You may want to display a resource owner/end user name in the authorization form this user will be facing, you can get org.apache.cxf.rs.security.oauth2.provider.ResourceOwnerNameProvider registered with either AuthorizationCodeGrantService or ImplicitGrantService.
org.apache.cxf.rs.security.oauth2.provider.DefaultResourceOwnerNameProvider, if registered, will return an actual login name, the custom implementations may choose to return a complete user name instead, etc.

Public Clients (Devices)

The Client can be 'public' if it has been registered as a public client with no client secret if the service itself has a "canSupportPublicClients" property enabled. The same property will also have to be enabled on AccessTokenService (described in the next section) for a public client without a secret be able to exchange a code grant for an access token.

...

Having OOB responses supported is useful when a public client (typically a device which can not keep the client secrets and/or where no redirect URI is supported) needs to get a code grant. What will happen is that a device owner will send a request to the Authorization Service which may look like this:

...

Assuming the 'mobileClient' has been registered as public one with no secret and the service has been set up to support such clients, the end user will get a chance to authorize this client the same way it can do can  confidential clients, and after this user gets back a code (delivered directly in the response HTML page by default) the user will enter the code securely into the device which will then replace it for a time-scoped access token by contacting AccessTokenService.

...

The public (mobile) client generates a 'code_verifier' value and includes a related 'code_challenge' and optional 'code_challenge_method' to the authorization service. The authorization service will save the code_challenge value, with the help of the registered AuthorizationCodeDataProvider into an instance of ServerAuthorizationCodeGrant. The client will next request a token providing the 'code_verifier' - which will be compared by AuthorizationCodeGrantHandler with the original 'code_challenge' value. By default, the 'code_challenge' is expected to be equal to the original 'code_verifier', but the grant handler can be registered with the a custom org.apache.cxf.rs.security.oauth2.grants.code.CodeVerifierTransformer - CXF ships a DigestCodeVerifier which implements a transformation mentioned in the extension.  CXF ships a DigestCodeVerifier which implements a transformation mentioned in the extension.

From CXF 3.5.1/3.4.6, the AuthorizationCodeGrantHandler has a "requireCodeVerifier" property, which when set to "true" requires that all clients must specify a code verifier. This aligns with the OAuth 2.1 specification.

Form Post Response Mode

Form Post Response Mode has been orinially was originally introduced for OpenId Connect but has been generally recomended recommended recently as a possibly safer option of returning OAuth2 Authorization Service response responses to the clients. Starting from CXF 3.1.9, if a client sends a "response_mode=form_post" parameter during the original redirect, CXF AuthorizationCodeService will return  an OOBAuthorizationResponse with its 'redirectUri' property set - which a JSP/etc handler will convert to an HTML form which will re-post the data to the client callback address.

...

This service is available starting from CXF 3.1.8. It supports OAuth2 server configuration queries at ".well-known/oauth-authorization-server".

...

If a 2-way TLS is used to authenticate a client, and the Client has a Base64 encoded representations of its X509Certificates available in its "applicationCertificates" property, then the AccessTokenService will do the additional comparison of these certificates against the ones available in the current TLS session.

New: Mutual TLS Profiles for OAuth2 Clients Also, OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens is completely supported since CXF 3.1.12. Note some parameters used in this draft may changeAfter the client authenticates to the token service, the token service will insert a digest of the client's certificate in the issued (JWT based) access token. On the resource server side, the OAuthRequestFilter will check the digest of the client certificate against the value stored in the token claim, and will throw a 401 exception if they do not match.

User Session Authenticity

...