...
JAXRS: OAuth2 Assertions
Table of Contents |
---|
Introduction
...
Maven dependencies
Code Block | ||||
---|---|---|---|---|
| ||||
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-security-oauth2-saml</artifactId>
<version>2.7.4</version>
</dependency>
|
...
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%3Asaml2-bearer&
assertion=Base64UrlEncoded-SAML2-Bearer-Assertion
|
...
The following example shows how to use SAML2 Bearer assertion as a grant with CXF OAuth2 client code:
Code Block | ||||
---|---|---|---|---|
| ||||
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.rs.security.common.CryptoLoader;
import org.apache.cxf.rs.security.oauth2.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);
|
...
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="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>
|
...
As noted in the introduction, SAML2 Bearer assertions 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%3Asaml2-bearer
&client_assertion=Base64UrlEncoded-SAML2-Bearer-Assertion
|
...
The following example shows how to use SAML2 Bearer assertion as an authentication token:
Code Block | ||||
---|---|---|---|---|
| ||||
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.rs.security.common.CryptoLoader;
import org.apache.cxf.rs.security.oauth2.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.oauth2.saml.Base64Utility;
import org.apache.cxf.rs.security.oauth2.saml.Constants;
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. Base64Url-encode it
String encodedAssertion = Base64UrlUtility.encode(assertion);
Map<String, String> extraParams = new HashMap<String, String>();
extraParams.put(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER);
extraParams.put(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedAssertion);
// Use whatever token grant is required
AccessTokenGrant accessTokenGrant = ...
ClientAccessToken at = OAuthClientUtils.getAccessToken(wc,
accessTokenGrant,
extraParams);
|
...
A different approach to dealing with the assertion directly in the client code is to use org.apache.cxf.rs.security.oauth2.auth.saml.Saml2BearerAuthOutInterceptor interceptor which will add the assertion to the existing form payload, for example:
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);
|
...
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="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>
|
...
In the Client Acting on Behalf of Itself use either org.apache.cxf.rs.security.oauth2.grants.saml.Saml2BearerClientCredentialsGrant :
Code Block | ||||
---|---|---|---|---|
| ||||
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.rs.security.common.CryptoLoader;
import org.apache.cxf.rs.security.oauth2.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.Saml2BearerClientCredentialsGrant;
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();
AccessTokenGrant accessTokenGrant = new Saml2BearerClientCredentialsGrant(assertion);
ClientAccessToken at = OAuthClientUtils.getAccessToken(wc,
accessTokenGrant,
extraParams);
|
or ClientCredentialsGrant in combination with Saml2BearerAuthOutInterceptor:
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);
|