Thursday, August 18, 2011

Apache WSS4J 1.5.12 and 1.6.2 released

Apache WSS4J 1.5.12 and 1.6.2 have been released.

WSS4J 1.5.12 is a bug-fix release, which fixes some problems relating to future-dated Timestamps, fixes a bug with deriving keys from UsernameTokens, and fixes a concurrency issue with EnvelopeIdResolver, amongst other things.

WSS4J 1.6.2 contains some enhancements for SAML Token creation, fixes a bug with deriving keys from UsernameTokens, adds initial support for the Kerberos Token Profile 1.1, and fixes some problems relating to signature verification in certain containers.

Tuesday, August 16, 2011

SAML token creation in Apache WSS4J 1.6

WSS4J 1.6 uses Opensaml2 to create and parse SAML Assertions. WSS4J ships with a library that wraps the Opensaml API to greatly simplify the process of creating a SAML Assertion. The user implements a CallbackHandler instance which must be able to handle a WSS4J SAMLCallback object. and set certain properties on this object. WSS4J then parses the properties that were set on the object and creates a SAML Assertion accordingly. In this blog post we will examine the process of creating a SAML Assertion by populating a SAMLCallback object in more detail.

1) Obtain a SAMLCallback object

First off, a SAMLCallback object must be obtained in the CallbackHandler implementation, e.g.:

if (callbacks[i] instanceof SAMLCallback) {
    SAMLCallback callback = (SAMLCallback) callbacks[i];
    ....
}

2) Set the SAML Version

The first thing to do is to set the desired SAML Version of the Assertion you want to create on the SAMLCallback object, e.g.:

callback.setSamlVersion(SAMLVersion.VERSION_11);

This method takes an org.opensaml.common.SAMLVersion object. For normal purposes, it will be one of the following:
  • SAMLVersion.VERSION_11
  • SAMLVersion.VERSION_20
The default value in SAMLCallback is VERSION_11.

3) Set the Issuer

The next thing to do is to set the issuer (String) name of the token, e.g.:

callback.setIssuer("sts");

4) Set the Subject

The next thing to do is to set the Subject of the Assertion. WSS4J defines a SubjectBean which encapsulates a SAML Subject. The Subject Name, NameQualifier, NameIDFormat and ConfirmationMethod Strings can be set on the SubjectBean instance. The NameIDFormat and ConfirmationMethod values that can be set are largely defined in the SAML1Constants and SAML2Constants classes. The default value for the SubjectBean NameIDFormat is SAML1Constants.NAMEID_FORMAT_UNSPECIFIED. Both constants classes contain the following values that can be used for the ConfirmationMethod value:
  •  SAML[1|2]Constants.CONF_BEARER
  •  SAML[1|2]Constants.CONF_HOLDER_KEY
  •  SAML[1|2]Constants.CONF_SENDER_VOUCHES
In addition to this, WSS4J defines a KeyInfoBean that can be set on the SubjectBean, which represents a KeyInfo structure that will be embedded in a SAML Subject. There are a number of different ways to set the KeyInfo value:
  • A DOM element can be defined for a pre-existing KeyInfo element
  • A PublicKey object can be used
  • An X.509 Certificate can be used
For the latter two cases, the KeyInfoBean contains a CERT_IDENTIFIER enum which defines how the PublicKey or X.509 Certificate will be output. The following values can be configured:
  • X509_CERT: An X509Certificate element will be output
  • X509_ISSUER_SERIAL: An X509 IssuerSerial element will be output
  • KEY_VALUE: A KeyValue element will be output
The default value in the KeyInfoBean is X509_CERT. Here is a sample that shows how to create a SubjectBean:

SubjectBean subjectBean = new SubjectBean();
subjectBean.setSubjectName("uid=joe");
subjectBean.setSubjectNameQualifier("apache.org");
subjectBean.setSubjectConfirmationMethod(
     SAML1Constants.CONF_SENDER_VOUCHES
);
KeyInfoBean keyInfo = new KeyInfoBean();
keyInfo.setCertificate(cert);
subjectBean.setKeyInfo(keyInfo);

Finally, it remains to store the SubjectBean instance in the SAMLCallback object. A SAML 2.0 Assertion contains a single Subject, and so for this case the SubjectBean instance can be set directly on the SAMLCallback, e.g.:

callback.setSubject(subjectBean);

For a SAML 1.1 Assertion, the Subject can be in a SubjectStatement (in which case it can be set directly on the SAMLCallback), or it can be embedded in one of the other statements which we will cover next.

5) Create and set a Statement

WSS4J contains a number of beans to create Statements for SAML Assertions, that can be set on a SAMLCallback object. They can be used in either SAML 1.1 or SAML 2.0 Assertions, with the caveat that SubjectBean instances are not used with statements in SAML 2.0.

a) Attribute Statements

WSS4J contains an AttributeStatementBean for creating Attribute statements. This contains a SubjectBean (for the SAML 1.1 case), and a list of AttributeBean objects. An attribute simple name, qualified name, and name format Strings can be set on the AttributeBean, as well as a list of attribute value Strings. Here is an example of creating and adding an AttributeStatement to a SAMLCallback object:

AttributeStatementBean attrBean = new AttributeStatementBean();
attrBean.setSubject(subjectBean);
AttributeBean attributeBean = new AttributeBean();
attributeBean.setSimpleName("role");
attributeBean.setAttributeValues(Collections.singletonList("user"));
attrBean.setSamlAttributes(Collections.singletonList(attributeBean));
callback.setAttributeStatementData(Collections.singletonList(attrBean));

b) Authentication Statements

WSS4J contains an AuthenticationStatementBean for creating Authentication statements. For SAML 1.1 a SubjectBean instance can be set on this object. In addition to this, an authentication instant and authentication method can be set, as well as a SubjectLocalityBean object and a session index String. Various authentication method Strings are defined in the SAML1Constants and SAML2Constants given above. Here is an example:

AuthenticationStatementBean authBean = new AuthenticationStatementBean();
authBean.setSubject(subjectBean);
SubjectLocalityBean subjectLocality = new SubjectLocalityBean();
subjectLocality.setIpAddress(subjectLocalityIpAddress);
subjectLocality.setDnsAddress(subjectLocalityDnsAddress);
authBean.setSubjectLocality(subjectLocality);
authBean.setAuthenticationMethod("Password");     callback.setAuthenticationStatementData(Collections.singletonList(authBean));

c) Authorization Decision Statements

WSS4J contains an AuthDecisionStatementBean for creating Authorization Decision Statements. For SAML 1.1 a SubjectBean instance can be set on this object. A Decision enum can be set (PERMIT, INDETERMINATE, DENY), as well as a resource String, evidence Object, and a list of ActionBeans, which in turn contain an action namespace and action contents. Here is an example:

AuthDecisionStatementBean authzBean = new AuthDecisionStatementBean();
authzBean.setSubject(subjectBean);
ActionBean actionBean = new ActionBean();
actionBean.setContents("Read");
authzBean.setActions(Collections.singletonList(actionBean));
authzBean.setResource("endpoint");
authzBean.setDecision(AuthDecisionStatementBean.Decision.PERMIT);
authzBean.setResource(resource);  callback.setAuthDecisionStatementData(Collections.singletonList(authzBean));
 
6) Create a Conditions object

Finally, a ConditionsBean object can be used to specify a set of Conditions on the SAML Assertion. This is optional, as by default a Conditions element will be generated with a NotBefore value of the present instant and a NotOnOrAfter value corresponding to 5 minutes into the future. This can be changed by creating a ConditionsBean and specifying either "notBefore" and "notAfter" dates, or else a token period in minutes in which the token is valid. It is also possible to specify an audience restriction URI on the ConditionsBean object. Here is an example:

ConditionsBean conditions = new ConditionsBean();
conditions.setTokenPeriodMinutes(10);
conditions.setAudienceURI("http://ws.apache.org/wss4j");
callback.setConditions(conditionsBean);

For some examples of CallbackHandlers used to create SAML Assertions, check out the following CallbackHandlers used in the WSS4J unit tests - SAML1AuthnHOKHandler, SAML1CallbackHandler and SAML2CallbackHandler.

Monday, August 15, 2011

WS-Trust 1.4 support in CXF

Apache CXF has had support for sending a WS-Trust 1.4 ActAs element as part of a RequestSecurityToken call to a Security Token Service (STS) since the 2.2.10 release. To quote from the WS-Trust 1.4 specification:
/wst:RequestSecurityToken/wst:ActAs
 
This OTPIONAL (sic) element indicates that the requested token is expected to contain information about the identity represented by the content of this element and the token requestor intends to use the returned token to act as this identity. The identity that the requestor wants to act-as is specified by placing a security token or <wsse:SecurityTokenReference> element within the <wst:ActAs> element.
The object to be placed in an ActAs element can be set by the SecurityConstants tag "STS_TOKEN_ACT_AS" on the Message properties. Prior to Apache CXF 2.4.1 the ActAs object could either be an XML String or else a DOM Element. See the following CXF wiki page for more information.

Several enhancements were made in CXF 2.4.1 as part of this JIRA. First of all, support was added for OnBehalfOf. To quote from the spec again:
/wst:RequestSecurityToken/wst:OnBehalfOf

This OPTIONAL element indicates that the requestor is making the request on behalf of another.  The identity on whose behalf the request is being made is specified by placing a security token, <wsse:SecurityTokenReference> element, or <wsa:EndpointReference> element within the <wst:OnBehalfOf> element. The requestor MAY provide proof of possession of the key associated with the OnBehalfOf identity by including a signature in the RST security header generated using the OnBehalfOf token that signs the primary signature of the RST (i.e. endorsing supporting token concept from WS-SecurityPolicy). Additional signed supporting tokens describing the OnBehalfOf context MAY also be included within the RST security header.
The object to be placed in an OnBehalfOf element can be set by the SecurityConstants tag "STS_TOKEN_ON_BEHALF_OF" on the Message properties. Similar to ActAs, this object can be an XML String or a DOM Element. In addition to this, the object for both ActAs and OnBehalfOf can now be a CallbackHandler instance. The CallbackHandler implementation must be able to process a DelegationCallback object, which has access to the current CXF Message, and returns a DOM Element to the STSClient for insertion into either ActAs or OnBehalfOf.

Two sample CallbackHandler implementations are shipped with CXF 2.4.1 that can be used for either OnBehalfOf or ActAs. The ReceivedTokenCallbackHandler obtains the previously received message from the current message property of the DelegationCallback object, and extracts a token that has been received in that message (SAML Token/UsernameToken/BinarySecurityToken). This token is then used as the delegation token. This CallbackHandler implementation is useful as part of an WS-Trust intermediary scenario. Secondly, the WSSUsernameCallbackHandler obtains a username via the jax-ws property "ws-security.username" (SecurityConstants.USERNAME), and creates a wsse:UsernameToken (with no password) to be used as the delegation token.