Versions Compared

Key

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

...

SAML2 Bearer

Maven dependencies

 

Code Block
xml
xml
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-security-oauth2-saml</artifactId>
  <version>${cxf.version}</version>
</dependency>

 

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.

...

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
java
java
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();

Map<String, Object> properties = new HashMap<String, Object>();
properties.put("security.callback-handler", 
               "org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback");
properties.put("security.saml-callback-handler", 
               "org.apache.cxf.systest.jaxrs.security.oauth2.SamlCallbackHandler2");
properties.put("security.signature.username", "alice");
properties.put("security.signature.properties", CRYPTO_RESOURCE_PROPERTIES);
properties.put("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 SAML2 JWT Bearer assertions tokens can be used as token grants. The value of grant_type parameter is "urn:ietf:params:oauth:grant- type:saml2jwt-bearer".

It is really just another grant type, but whose actual value is a SAML assertionJWT Token. The specification provides an example of how such an assertion may look like.

The additional restriction is that the assertions have to be encoded using Base64Url encoding.
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%3Asaml2type%3Ajwt-bearer&
assertion=Base64UrlEncoded-SAML2-Bearer-AssertionX.Y.Z

Client code

The following example CXF BigQuery demo shows how to use SAML2 Bearer assertion as a grant with CXF OAuth2 client codea 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
javaxmljava
xml
<bean id="dataProvider" class="import org.apache.cxf.systest.jaxrs.client.WebClient;
import org.apache.cxf.rs.security.common.CryptoLoader;
import security.oauth2.OAuthDataProviderImpl"/>
<bean id="jwtGrantHandler" class="org.apache.cxf.rs.security.oauth2.grants.client.OAuthClientUtils;
import org.apache.cxf.rs.security.oauth2.common.AccessTokenGrant;
import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken;
import org.apache.cxf.rs.security.oauth2.grants.saml.Saml2BearerGrant;
import org.apache.cxf.rs.security.saml.SAMLUtils;
import org.apache.cxf.rs.security.saml.SAMLUtils.SelfSignInfo;
import org.apache.ws.security.components.crypto.Crypto;

//1: create web client
String address = "https://localhost:8080/oauth2/token";
WebClient wc = WebClient.create(address);
wc.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_JSON);

//2. Create and self-sign SAML assertion        
Crypto crypto = new CryptoLoader().loadCrypto(CRYPTO_RESOURCE_PROPERTIES);
SelfSignInfo signInfo = new SelfSignInfo(crypto, "alice", "password"); 
        
String assertion =  SAMLUtils.createAssertion(new SamlCallbackHandler(),
                                              signInfo).assertionToString();

//3. Send it as a token grant to Access Token Service and get some access token back
AccessTokenGrant grant = new Saml2BearerGrant(assertion);
ClientAccessToken at = OAuthClientUtils.getAccessToken(wc, 
                                                       new OAuthClientUtils.Consumer("alice", "alice"), 
                                                       grant,
                                                       false);

The code above prepares an info for a new SAML assertion be self-signed, loading a Crypto instance with crypto properties, and uses SAMLUtils to create and sign the assertion (using Crypto, plus user alias and password). Saml2BearerGrant will get the assertion Base64Url-encoded - unless the assertion has already been encoded with CXF Base64UrlUtility or came encoded from IP - in this case Saml2BearerGrant constructor accepting an 'encoded' property will have to be used, with the value set to "true".

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.

When doing step 2, the main effort is to do with getting a SAML assertion populated - use a SAML callback handler like this one, it is actually quite easy to build the assertion.

Access Token Service

Here is how one may configure Access Token Service:

Code Block
xmlxml
<bean id="dataProviderjwt.JwtBearerGrantHandler">
  <property name="dataProvider" ref="dataProvider"/>
</bean>
<bean id="oauthJson" class="org.apache.cxf.systest.jaxrsrs.security.oauth2.OAuthDataProviderImplprovider.OAuthJSONProvider"/>

<bean id="samlGrantHandlerserviceBean" class="org.apache.cxf.rs.security.oauth2.grantsservices.saml.Saml2BearerGrantHandlerAccessTokenService">
  <property name="dataProvider" ref="dataProvider"/>
  <property name="grantHandlers">
     <list>
       <ref bean="jwtGrantHandler"/>
     </list>
  </property>
</bean>

<bean<jaxrs:server 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="dataProvideraddress="https://localhost:${testutil.ports.jaxrs-oauth2}/oauth2">
   <jaxrs:serviceBeans>
      <ref bean="serviceBean"/>
  <property name="grantHandlers"> </jaxrs:serviceBeans>
     <list>
 <jaxrs:providers>
      <ref bean="samlGrantHandleroauthJson"/>
     </list>jaxrs:providers>
   </property>
</bean>

<jaxrs:server address="https://localhost:${testutil.ports.jaxrs-oauth2}/oauth2"<jaxrs:properties>
      <entry key="rs.security.keystore.type" value="jks" />
   <jaxrs:serviceBeans>
   <entry   <ref bean="serviceBeankey="rs.security.keystore.alias" value="myclientkey"/>
    </jaxrs:serviceBeans>
   <jaxrs:providers><entry key="rs.security.keystore.password" value="cspass"/>
      <ref bean="oauthJson"/>
   </jaxrs:providers>
   <jaxrs:properties>
<entry key="rs.security.keystore.file" value="clientstore.jks" />
      <entry key="rs.security.signature.propertiesalgorithm" value="org/apache/cxf/systest/jaxrs/security/alice.properties"RS256" />
   </jaxrs:properties>
</jaxrs:server>

...

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

The following example shows how to use JWT Bearer tokens as an authentication token: TODO

 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:

...