...
Table of Contents |
---|
Introduction
OAuth 2.0 supports different types of access token grants. The OAuth2 Assertions draft spec "provides a framework for the use of assertions
with OAuth 2.0 " and in the form of a new client authentication mechanism and a new authorization grant type". More specifically, the SAML2 Bearer Assertion Profiles for OAuth2 draft specifically spec provides for the use of SAML2 Bearer assertions, and the JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants spec providers for the use of JWT Bearer tokens.
These assertions can be used as token grants, but also, if needed, for getting 3rd party clients authenticated. Note the clients can use assertions as grants but use for example Basic authentication mechanism, or use say an authorization code grant and the assertion to authenticate, and finally, they can use assertions as a grant and as an authentication token.
Currently CXF supports both SAML2 Bearer and JWT Bearer assertions as grants and authentication tokens.
See the JAX-RS OAuth2 page for information about OAuth 2.0 support in CXF. Please also check the JAX-RS SAML page for more information about SAML support.
SAML2 Bearer
Maven dependencies
Code Block | ||||
---|---|---|---|---|
| ||||
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-rs-security-oauth2-saml</artifactId> <version>2.7.4<<version>${cxf.version}</version> </dependency> |
SAML2 Bearer
Access Token Grant
This section explains how SAML2 Bearer assertions can be used as token grants. The value of grant_type parameter is "urn:ietf:params:oauth:grant-type:saml2-bearer".
It is really just another grant type, but whose actual value is a SAML assertion. The specification provides an example of how such an assertion may look like.
...
This is nearly as simple as using other token grants, the step 2 will often me omitted in more involved cases as it will be the job of Identity Providers to issue OAuth2 SAML2 Bearer assertions. Step 2 needs to be done when testing or when getting client acting on behalf of itself for example.
Instead of using SelfSignInfo utility one can create an empty CXF Message and set required properties on it and passing it to SAMLUtils - see the example on how to use SAML Bearer assertions for the authentication below.
...
Code Block | ||||
---|---|---|---|---|
| ||||
<bean id="dataProvider" class="org.apache.cxf.systest.jaxrs.security.oauth2.OAuthDataProviderImpl"/>
<bean id="samlGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.saml.Saml2BearerGrantHandler">
<property name="dataProvider" ref="dataProvider"/>
</bean>
<bean id="oauthJson" class="org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider"/>
<bean id="serviceBean" class="org.apache.cxf.rs.security.oauth2.services.AccessTokenService">
<property name="dataProvider" ref="dataProvider"/>
<property name="grantHandlers">
<list>
<ref bean="samlGrantHandler"/>
</list>
</property>
</bean>
<jaxrs:server address="https://localhost:${testutil.ports.jaxrs-oauth2}/oauth2">
<jaxrs:serviceBeans>
<ref bean="serviceBean"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="oauthJson"/>
</jaxrs:providers>
<jaxrs:properties>
<entry key="ws-security.signature.properties" value="org/apache/cxf/systest/jaxrs/security/alice.properties"/>
</jaxrs:properties>
</jaxrs:server>
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); Map<String, Object> properties = new HashMap<String, Object>(); properties.put("ws-security.callback-handler", "org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback"); properties.put("ws-security.saml-callback-handler", "org.apache.cxf.systest.jaxrs.security.oauth2.SamlCallbackHandler2"); properties.put("ws-security.signature.username", "alice"); properties.put("ws-security.signature.properties", CRYPTO_RESOURCE_PROPERTIES); properties.put("ws-security.self-sign-saml-assertion", "true"); bean.setProperties(properties); bean.getOutInterceptors().add(new Saml2BearerAuthOutInterceptor()); WebClient wc = bean.createWebClient(); wc.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_JSON); // Use whatever token grant is required AccessTokenGrant accessTokenGrant = ... ClientAccessToken at = OAuthClientUtils.getAccessToken(wc, accessTokenGrant); |
...
Code Block | ||||
---|---|---|---|---|
| ||||
<bean id="dataProvider" class="org.apache.cxf.systest.jaxrs.security.oauth2.OAuthDataProviderImpl"/>
<bean id="oauthJson" class="org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider"/>
<bean id="samlAuthHandler" class="org.apache.cxf.rs.security.oauth2.auth.saml.Saml2BearerAuthHandler"/>
<bean id="serviceBean" class="org.apache.cxf.rs.security.oauth2.services.AccessTokenService">
<property name="dataProvider" ref="dataProvider"/>
<property name="grantHandlers">
<list>
<!-- list of required grant handlers -->
</list>
</property>
</bean>
<jaxrs:server
address="https://localhost:${testutil.ports.jaxrs-oauth2}/oauth2-auth">
<jaxrs:serviceBeans>
<ref bean="serviceBean"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="oauthJson"/>
<ref bean="samlAuthHandler"/>
</jaxrs:providers>
<jaxrs:properties>
<entry key="ws-security.signature.properties"
value="org/apache/cxf/systest/jaxrs/security/alice.properties"/>
</jaxrs:properties>
</jaxrs:server>
|
Client Acting on Behalf of Itself
In the Client Acting on Behalf of Itself use either org.apache.cxf.rs.security.oauth2.grants.saml.Saml2BearerClientCredentialsGrant :
...
Code Block | ||||
---|---|---|---|---|
| ||||
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); Map<String, Object> properties = new HashMap<String, Object>(); properties.put("ws-security.callback-handler", "org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback"); properties.put("ws-security.saml-callback-handler", "org.apache.cxf.systest.jaxrs.security.oauth2.SamlCallbackHandler2"); properties.put("ws-security.signature.username", "alice"); properties.put("ws-security.signature.properties", CRYPTO_RESOURCE_PROPERTIES); properties.put("ws-security.self-sign-saml-assertion", "true"); bean.setProperties(properties); bean.getOutInterceptors().add(new Saml2BearerAuthOutInterceptor()); WebClient wc = bean.createWebClient(); wc.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_JSON); // Use whatever token grant is required AccessTokenGrant accessTokenGrant = new ClientCredentialsGrant(); ClientAccessToken at = OAuthClientUtils.getAccessToken(wc, accessTokenGrant); |
JWT Bearer
...
See this CXF OAuth2 section for the information about the implementation details.
Access Token Grant
This section explains how JWT Bearer tokens can be used as token grants. The value of grant_type parameter is "urn:ietf:params:oauth:grant- type:jwt-bearer".
It is really just another grant type, but whose actual value is a JWT Token. The specification provides an example of how such an assertion may look like.
Here is how a request may look like:
Code Block |
---|
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&
assertion=X.Y.Z
|
Client code
CXF BigQuery demo shows how a so called Google Service Client can prepare a signed JWT token and use JwtBearerGrant in order to issue a JWT Bearer grant request and get a new access token back. CXF WebClient is used in the demo code but OAuthClientUtils can also be used.
Access Token Service
Here is how one may configure the Access Token Service:
Code Block | ||||
---|---|---|---|---|
| ||||
<bean id="dataProvider" class="org.apache.cxf.systest.jaxrs.security.oauth2.OAuthDataProviderImpl"/>
<bean id="jwtGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.jwt.JwtBearerGrantHandler">
<property name="dataProvider" ref="dataProvider"/>
</bean>
<bean id="oauthJson" class="org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider"/>
<bean id="serviceBean" class="org.apache.cxf.rs.security.oauth2.services.AccessTokenService">
<property name="dataProvider" ref="dataProvider"/>
<property name="grantHandlers">
<list>
<ref bean="jwtGrantHandler"/>
</list>
</property>
</bean>
<jaxrs:server address="https://localhost:${testutil.ports.jaxrs-oauth2}/oauth2">
<jaxrs:serviceBeans>
<ref bean="serviceBean"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="oauthJson"/>
</jaxrs:providers>
<jaxrs:properties>
<entry key="rs.security.keystore.type" value="jks" />
<entry key="rs.security.keystore.alias" value="myclientkey"/>
<entry key="rs.security.keystore.password" value="cspass"/>
<entry key="rs.security.keystore.file" value="clientstore.jks" />
<entry key="rs.security.signature.algorithm" value="RS256" />
</jaxrs:properties>
</jaxrs:server>
|
Authentication Token
As noted in the introduction, JWT Bearer tokens may also act as client authentication credentials, when requesting an access token, irrespectively of the actual grant type. For example:
Code Block |
---|
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=12345678
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=X.Y.Z
|
Note "client_assertion_type" with a value "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" indicates that the type of assertion used as an authentication token is "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", while the "client_assertion" parameter carries the actual value of the token.
Client Code
Suppose the client is acting on behalf of itself to request a token, effectively using Client Credentials grant. In this case it will use JwtBearerClientCredentialsGrant.
Access Token Service
Here is how one may configure Access Token Service:
Code Block | ||||
---|---|---|---|---|
| ||||
<bean id="dataProvider" class="org.apache.cxf.systest.jaxrs.security.oauth2.OAuthDataProviderImpl"/>
<bean id="oauthJson" class="org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider"/>
<bean id="jwtAuthHandler" class="org.apache.cxf.rs.security.oauth2.grants.jwt.JwtBearerAuthHandler"/>
<bean id="serviceBean" class="org.apache.cxf.rs.security.oauth2.services.AccessTokenService">
<property name="dataProvider" ref="dataProvider"/>
<property name="grantHandlers">
<list>
<!-- list of required grant handlers -->
</list>
</property>
</bean>
<jaxrs:server
address="https://localhost:${testutil.ports.jaxrs-oauth2}/oauth2-auth">
<jaxrs:serviceBeans>
<ref bean="serviceBean"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="oauthJson"/>
<ref bean="jwtAuthHandler"/>
</jaxrs:providers>
<jaxrs:properties>
<entry key="security.signature.properties"
value="org/apache/cxf/systest/jaxrs/security/alice.properties"/>
</jaxrs:properties>
</jaxrs:server>
|