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.
Thursday, August 18, 2011
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:
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:
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.
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
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
- 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
- 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
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:
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:
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.
/wst:RequestSecurityToken/wst:ActAsThe 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.
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.
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:
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./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.
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.
Tuesday, June 28, 2011
Custom token validation in Apache CXF 2.4
A previous blog post has covered validators in Apache WSS4J 1.6, why they were introduced, what default implementations ship with WSS4J, etc. It ends with a paragraph on how to use a custom Validator implementation with Apache CXF 2.4. This post expands further on this topic.
1) Use-cases for custom Token Validation
Let's consider first of all the use-cases for specifying a custom Validator implementation in CXF. When a security header is being processed by WSS4J, it delegates each security token to a Processor implementation, depending on the QName of the token. In WSS4J 1.6, Processors do not do any validation of extracted credentials from a token, they merely process it, make sure it meets basic requirements, etc. Validation is delegated to a Validator interface which is associated with that Processor implementation.
However, there are many possible use-cases where a user may wish to replace or remove or extend the default validation behaviour associated with a particular security token. Some examples include:
3) Using Validators with WS-Trust
To see the power and flexibility of the approach of separating processing from validation, consider the STSTokenValidator that ships with CXF 2.4. This validator implementation has the ability to dispatch a received BinarySecurityToken, UsernameToken, or SAML Assertion to an STS (Security Token Service) for validation via WS-Trust. On invocation, it delegates the credential to another validator (STSSamlAssertionValidator). This validator essentially catches an exception caused by a signature validation failure of the SAML Assertion and sets a flag. Only if signature validation is unsuccessful does the STSTokenValidator dispatch the token to the STS for validation.
An example of how to configure the STSTokenValidator to validate a SAML1 Assertion against an STS in spring is as follows:
<jaxws:endpoint ...>
<jaxws:properties>
<entry key="ws-security.saml1.validator">
<bean class="org.apache.cxf.ws.security.trust.STSTokenValidator"/>
</entry>
<entry key="ws-security.sts.client">
<bean class="org.apache.cxf.ws.security.trust.STSClient">
<constructor-arg ref="cxf"/>
<property name="wsdlLocation" value="..."/>
<property name="serviceName" value=".../>
<property name="endpointName" value="..."/>
...
</bean>
</entry>
</jaxws:properties>
</jaxws:endpoint>
The STSTokenValidator also has the ability to obtain a transformed token from the STS and store it in the credential, where it is available as part of the WSSecurityEngineResult under the TAG_TRANSFORMED_TOKEN tag.
1) Use-cases for custom Token Validation
Let's consider first of all the use-cases for specifying a custom Validator implementation in CXF. When a security header is being processed by WSS4J, it delegates each security token to a Processor implementation, depending on the QName of the token. In WSS4J 1.6, Processors do not do any validation of extracted credentials from a token, they merely process it, make sure it meets basic requirements, etc. Validation is delegated to a Validator interface which is associated with that Processor implementation.
However, there are many possible use-cases where a user may wish to replace or remove or extend the default validation behaviour associated with a particular security token. Some examples include:
- Validating a UsernameToken, where the CallbackHandler implementation does not have access to the password.
- Validating a BinarySecurityToken of some custom type.
- Validating the attributes of a received SAML Assertion
- Validating a Timestamp in a more tolerant manner than the default.
- Dispatching a received security token to a third-party security service for validation/authentication.
- "ws-security.ut.validator" - Override UsernameToken validation.
- "ws-security.saml1.validator" - Override SAML1 token validation.
- "ws-security.saml2.validator" - Override SAML2 token validation.
- "ws-security.timestamp.validator" - Override Timestamp validation.
- "ws-security.signature.validator" - Override trust verification on a signature
- "ws-security.bst.validator" - Override BinarySecurityToken validation.
3) Using Validators with WS-Trust
To see the power and flexibility of the approach of separating processing from validation, consider the STSTokenValidator that ships with CXF 2.4. This validator implementation has the ability to dispatch a received BinarySecurityToken, UsernameToken, or SAML Assertion to an STS (Security Token Service) for validation via WS-Trust. On invocation, it delegates the credential to another validator (STSSamlAssertionValidator). This validator essentially catches an exception caused by a signature validation failure of the SAML Assertion and sets a flag. Only if signature validation is unsuccessful does the STSTokenValidator dispatch the token to the STS for validation.
An example of how to configure the STSTokenValidator to validate a SAML1 Assertion against an STS in spring is as follows:
<jaxws:endpoint ...>
<jaxws:properties>
<entry key="ws-security.saml1.validator">
<bean class="org.apache.cxf.ws.security.trust.STSTokenValidator"/>
</entry>
<entry key="ws-security.sts.client">
<bean class="org.apache.cxf.ws.security.trust.STSClient">
<constructor-arg ref="cxf"/>
<property name="wsdlLocation" value="..."/>
<property name="serviceName" value=".../>
<property name="endpointName" value="..."/>
...
</bean>
</entry>
</jaxws:properties>
</jaxws:endpoint>
The STSTokenValidator also has the ability to obtain a transformed token from the STS and store it in the credential, where it is available as part of the WSSecurityEngineResult under the TAG_TRANSFORMED_TOKEN tag.
Friday, June 10, 2011
WS-SecurityPolicy/SAML sample in Talend Service Factory 2.4.0
In this post I will walk through the WS-SecurityPolicy sample that ships with Talend Service Factory 2.4.0. This sample shows how to secure a web service provider using both a UsernameToken and a SAML Assertion. For this post I will concentrate exclusively on the SAML case.
1) Download the artifacts
Go here and download Talend Service Factory 2.4.0. When this is done, go here and download the Talend Service Factory 2.4.0 examples (registration required). Extract the examples into the Talend Service Factory (TSF) install directory ($TSF_HOME). Finally, this sample requires that unlimited strength security policies be installed in the JDK.
2) Build and run the sample
Go to $TSF_HOME/examples/jaxws-ws-secpol and start with the README.txt. Run "mvn eclipse:eclipse" to generate eclipse projects, and "mvn install" to build and install the various modules. There are two options to run the sample.
2.1) Run the sample using maven
To start the service go to the service folder, and run "mvn exec:java". To run the test then go to the client folder and also run "mvn exec:java".
2.2) Run the sample in Karaf
To deploy the service and run the client in an OSGi environment, we can take advantage of the Karaf distribution that ships with TSF. Go to $TSF_HOME/container/bin and run the "karaf" binary. Install the three bundles in Karaf with:
3) The Service Provider
3.1) The Security Policy
The Service endpoint is secured via the following security policy fragment, which is defined in the WSDL ("ws-secpol-wsdl/greeter.wsdl" in the common folder):
<wsp:All>
<sp:AsymmetricBinding xmlns:sp=".../ws-securitypolicy/200702">
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=".../AlwaysToRecipient">
<wsp:Policy>
<sp:RequireThumbprintReference />
<sp:WssX509V3Token10 />
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=".../Never">
<wsp:Policy>
<sp:RequireThumbprintReference />
<sp:WssX509V3Token10 />
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
...
</wsp:Policy>
</sp:AsymmetricBinding>
...
<sp:SignedSupportingTokens xmlns:sp=".../ws-securitypolicy/200702">
<wsp:Policy>
<sp:SamlToken sp:IncludeToken=".../AlwaysToRecipient">
<wsp:Policy>
<sp:WssSamlV20Token11/>
</wsp:Policy>
</sp:SamlToken>
</wsp:Policy>
</sp:SignedSupportingTokens>
</wsp:All>
This Security Policy defines that the Asymmetric Binding is to be used in communication with the service provider, i.e. that the client must sign the request using its private key, and include the corresponding X509 Certificate in the security header of the request, and encrypt the request using the public key of the service provider. Authentication is performed on the basis of trust verification of the client's certificate, as the client illustrates proof-of-possession by signing some part of the request.
In addition to the Asymmetric Binding, the policy requires that a SAML 2.0 Assertion must be included in the service request, and it must be signed by the signature defined by the Asymmetric Binding policy. The (policy-driven) ability to add a SAML Assertion to a SOAP Request is new to Apache CXF 2.4.
Finally, the WSDL defines input and output policies (not included here), which specify that the SOAP Body must be signed and encrypted, and that all of the addressing headers must be signed if present.
3.2) The configuration
The standalone (maven-driven) case is configured entirely in code. The various security configuration items are added as properties to the JAX-WS Endpoint object. The same security configuration items are also used for the case of deploying the service provider in Karaf, except that it is all driven through spring, e.g.:
<jaxws:server id="SAMLGreeter" xmlns:ns1="..."
endpointName="ns1:SAMLGreeterPort"
serviceClass="demo.secure_greeter.server.GreeterImpl">
<jaxws:properties>
<entry key="ws-security.callback-handler" value="..."/>
<entry key="ws-security.encryption.properties" value="..."/>
<entry key="ws-security.signature.properties" value="..."/>
<entry key="ws-security.saml2.validator" value="..."/>
</jaxws:properties>
</jaxws:server>
Four security-related configuration options are used for the service provider. "ws-security.callback-handler" points to a CallbackHandler implementation that is used to supply a password for extracting a private key from a keystore to decrypt the request and sign the response. "ws-security.encryption.properties" refers to a properties file which contains configuration options for loading the keystore used for encryption. Similarly, "ws-security.signature.properties" refers to a properties file for signature creation (and decryption).
"ws-security.saml2.validator" is a configuration tag new to CXF 2.4, and refers to an instance of the WSS4J Validator interface. The Validator interface is used in WSS4J to validate received security tokens. In this case, we are extending the default SAML2 Token Validation with a custom Validator. This Validator does some additional verification on the received token, namely checking who the issuer is, checking that the confirmation method is "sender-vouches", and checking that the Assertion contains an AttributeStatement, with an Attribute "attribute-role" containing a value "authenticated-client".
All of these configuration tags are defined in the SecurityConstants class in CXF.
4) The client
When the client wants to invoke on the service provider, it parses the security policy described above in the WSDL. As with the service provider, the client standalone case is configured entirely in code. For the case of deploying the client in Karaf, it is configured in spring as follows:
<jaxws:client id="samlgreeter" wsdlLocation="..." serviceClass="..."
xmlns:ns1="" serviceName="ns1:SecureGreeterService"
endpointName="ns1:SAMLGreeterPort">
<jaxws:properties>
<entry key="ws-security.signature.username" value="..."/>
<entry key="ws-security.encryption.username" value="..."/>
<entry key="ws-security.callback-handler"><bean class="..."/></entry>
<entry key="ws-security.signature.properties" value="..."/>
<entry key="ws-security.encryption.properties" value="..."/>
<entry key="ws-security.saml-callback-handler" value="..."/>
</jaxws:properties>
</jaxws:client>
"ws-security.callback-handler", "ws-security.signature.properties" and "ws-security.encryption.properties" have been covered in the section on configuring the service provider. "ws-security.signature.username" refers to the keystore alias of the private key to use to sign the request, and "ws-security.encryption.username" refers to the keystore alias to use to encrypt the request.
"ws-security.saml-callback-handler" is a configuration tag new to CXF 2.4, and refers to a CallbackHandler which will supply WSS4J with the information to create a SAML Assertion. This sample ships with a CallbackHandler that creates a simple SAML 2.0 Assertion with a subject confirmation method of "sender-vouches". It adds an Attribute to the Assertion that conveys to the Web Service Provider that the client has authenticated an external user in some way (not shown as part of this sample), and has assigned the attribute role of "authenticated-client" to the external user. The assertion that will be generated from this CallbackHandler instance will be signed by the client, as per the policy definition ("SignedSupportingTokens").
5) The Client Request
The security header of the client request contains a BinarySecurityToken which contains the certificate to use to verify the signature. It also contains a Timestamp, an EncryptedKey which is used to encrypt the SOAP Body, a SAML2 Assertion, and a Signature which signs the Timestamp, Assertion and encrypted SOAP Body. The Assertion looks like this:
<saml2:Assertion xmlns:saml2="..." xmlns:xsi="..." ID="..." IssueInstant="..."
Version="2.0" xsi:type="saml2:AssertionType">
<saml2:Issuer>...</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format=...:unspecified">uid=auth_client</saml2:NameID>
<saml2:SubjectConfirmation Method="...:sender-vouches">
<saml2:SubjectConfirmationData/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="..." NotOnOrAfter="..."/>
<saml2:AttributeStatement>
<saml2:Attribute FriendlyName="attribute-role" NameFormat="...">
<saml2:AttributeValue xsi:type="xs:string">
authenticated-client
</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
The service provider processes the received security header as follows:
1) Download the artifacts
Go here and download Talend Service Factory 2.4.0. When this is done, go here and download the Talend Service Factory 2.4.0 examples (registration required). Extract the examples into the Talend Service Factory (TSF) install directory ($TSF_HOME). Finally, this sample requires that unlimited strength security policies be installed in the JDK.
2) Build and run the sample
Go to $TSF_HOME/examples/jaxws-ws-secpol and start with the README.txt. Run "mvn eclipse:eclipse" to generate eclipse projects, and "mvn install" to build and install the various modules. There are two options to run the sample.
2.1) Run the sample using maven
To start the service go to the service folder, and run "mvn exec:java". To run the test then go to the client folder and also run "mvn exec:java".
2.2) Run the sample in Karaf
To deploy the service and run the client in an OSGi environment, we can take advantage of the Karaf distribution that ships with TSF. Go to $TSF_HOME/container/bin and run the "karaf" binary. Install the three bundles in Karaf with:
- install mvn:com.talend.sf.examples.jaxws-ws-secpol/ws-secpol-common/1.0
- install mvn:com.talend.sf.examples.jaxws-ws-secpol/ws-secpol-server/1.0
- install mvn:com.talend.sf.examples.jaxws-ws-secpol/ws-secpol-client/1.0
3) The Service Provider
3.1) The Security Policy
The Service endpoint is secured via the following security policy fragment, which is defined in the WSDL ("ws-secpol-wsdl/greeter.wsdl" in the common folder):
<wsp:All>
<sp:AsymmetricBinding xmlns:sp=".../ws-securitypolicy/200702">
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=".../AlwaysToRecipient">
<wsp:Policy>
<sp:RequireThumbprintReference />
<sp:WssX509V3Token10 />
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=".../Never">
<wsp:Policy>
<sp:RequireThumbprintReference />
<sp:WssX509V3Token10 />
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
...
</wsp:Policy>
</sp:AsymmetricBinding>
...
<sp:SignedSupportingTokens xmlns:sp=".../ws-securitypolicy/200702">
<wsp:Policy>
<sp:SamlToken sp:IncludeToken=".../AlwaysToRecipient">
<wsp:Policy>
<sp:WssSamlV20Token11/>
</wsp:Policy>
</sp:SamlToken>
</wsp:Policy>
</sp:SignedSupportingTokens>
</wsp:All>
This Security Policy defines that the Asymmetric Binding is to be used in communication with the service provider, i.e. that the client must sign the request using its private key, and include the corresponding X509 Certificate in the security header of the request, and encrypt the request using the public key of the service provider. Authentication is performed on the basis of trust verification of the client's certificate, as the client illustrates proof-of-possession by signing some part of the request.
In addition to the Asymmetric Binding, the policy requires that a SAML 2.0 Assertion must be included in the service request, and it must be signed by the signature defined by the Asymmetric Binding policy. The (policy-driven) ability to add a SAML Assertion to a SOAP Request is new to Apache CXF 2.4.
Finally, the WSDL defines input and output policies (not included here), which specify that the SOAP Body must be signed and encrypted, and that all of the addressing headers must be signed if present.
3.2) The configuration
The standalone (maven-driven) case is configured entirely in code. The various security configuration items are added as properties to the JAX-WS Endpoint object. The same security configuration items are also used for the case of deploying the service provider in Karaf, except that it is all driven through spring, e.g.:
<jaxws:server id="SAMLGreeter" xmlns:ns1="..."
endpointName="ns1:SAMLGreeterPort"
serviceClass="demo.secure_greeter.server.GreeterImpl">
<jaxws:properties>
<entry key="ws-security.callback-handler" value="..."/>
<entry key="ws-security.encryption.properties" value="..."/>
<entry key="ws-security.signature.properties" value="..."/>
<entry key="ws-security.saml2.validator" value="..."/>
</jaxws:properties>
</jaxws:server>
Four security-related configuration options are used for the service provider. "ws-security.callback-handler" points to a CallbackHandler implementation that is used to supply a password for extracting a private key from a keystore to decrypt the request and sign the response. "ws-security.encryption.properties" refers to a properties file which contains configuration options for loading the keystore used for encryption. Similarly, "ws-security.signature.properties" refers to a properties file for signature creation (and decryption).
"ws-security.saml2.validator" is a configuration tag new to CXF 2.4, and refers to an instance of the WSS4J Validator interface. The Validator interface is used in WSS4J to validate received security tokens. In this case, we are extending the default SAML2 Token Validation with a custom Validator. This Validator does some additional verification on the received token, namely checking who the issuer is, checking that the confirmation method is "sender-vouches", and checking that the Assertion contains an AttributeStatement, with an Attribute "attribute-role" containing a value "authenticated-client".
All of these configuration tags are defined in the SecurityConstants class in CXF.
4) The client
When the client wants to invoke on the service provider, it parses the security policy described above in the WSDL. As with the service provider, the client standalone case is configured entirely in code. For the case of deploying the client in Karaf, it is configured in spring as follows:
<jaxws:client id="samlgreeter" wsdlLocation="..." serviceClass="..."
xmlns:ns1="" serviceName="ns1:SecureGreeterService"
endpointName="ns1:SAMLGreeterPort">
<jaxws:properties>
<entry key="ws-security.signature.username" value="..."/>
<entry key="ws-security.encryption.username" value="..."/>
<entry key="ws-security.callback-handler"><bean class="..."/></entry>
<entry key="ws-security.signature.properties" value="..."/>
<entry key="ws-security.encryption.properties" value="..."/>
<entry key="ws-security.saml-callback-handler" value="..."/>
</jaxws:properties>
</jaxws:client>
"ws-security.callback-handler", "ws-security.signature.properties" and "ws-security.encryption.properties" have been covered in the section on configuring the service provider. "ws-security.signature.username" refers to the keystore alias of the private key to use to sign the request, and "ws-security.encryption.username" refers to the keystore alias to use to encrypt the request.
"ws-security.saml-callback-handler" is a configuration tag new to CXF 2.4, and refers to a CallbackHandler which will supply WSS4J with the information to create a SAML Assertion. This sample ships with a CallbackHandler that creates a simple SAML 2.0 Assertion with a subject confirmation method of "sender-vouches". It adds an Attribute to the Assertion that conveys to the Web Service Provider that the client has authenticated an external user in some way (not shown as part of this sample), and has assigned the attribute role of "authenticated-client" to the external user. The assertion that will be generated from this CallbackHandler instance will be signed by the client, as per the policy definition ("SignedSupportingTokens").
5) The Client Request
The security header of the client request contains a BinarySecurityToken which contains the certificate to use to verify the signature. It also contains a Timestamp, an EncryptedKey which is used to encrypt the SOAP Body, a SAML2 Assertion, and a Signature which signs the Timestamp, Assertion and encrypted SOAP Body. The Assertion looks like this:
<saml2:Assertion xmlns:saml2="..." xmlns:xsi="..." ID="..." IssueInstant="..."
Version="2.0" xsi:type="saml2:AssertionType">
<saml2:Issuer>...</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format=...:unspecified">uid=auth_client</saml2:NameID>
<saml2:SubjectConfirmation Method="...:sender-vouches">
<saml2:SubjectConfirmationData/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="..." NotOnOrAfter="..."/>
<saml2:AttributeStatement>
<saml2:Attribute FriendlyName="attribute-role" NameFormat="...">
<saml2:AttributeValue xsi:type="xs:string">
authenticated-client
</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
The service provider processes the received security header as follows:
- It checks that the Timestamp is valid
- It uses its private key to decrypt the EncryptedKey, and then uses the decrypted key to decrypt the SOAP Body.
- It verifies that the Assertion is valid, and passes the Assertion to the custom Validator defined above to validate the contents of the Assertion.
- It verifies that the certificate defined in the BinarySecurityToken can validate the signature, verifies trust in the certificate, and checks that each of the References of the signature produce the correct digest.
Wednesday, June 8, 2011
WSS4J 1.6.1 released
Apache WSS4J 1.6.1 has been released. The distribution can be downloaded here, and the list of issues that have been fixed is here. There are a number of bug fixes to the new functionality introduced in the 1.6.0 release, including some fixes to the SAML Assertion creation code, and a fix to get WSS4J 1.6 working with the IBM JDK. A noteworthy new feature is support for CRLs, as documented by a previous blog post.
In other news, my employer has published a short questionnaire to find out what topics users of open-source integration software are interested in learning about. So for example if you are interested in hearing more from me on enabling security in Apache CXF, navigate to the CXF part of the survey and select the appropriate checkbox for "WS-Security in Apache CXF".
In other news, my employer has published a short questionnaire to find out what topics users of open-source integration software are interested in learning about. So for example if you are interested in hearing more from me on enabling security in Apache CXF, navigate to the CXF part of the survey and select the appropriate checkbox for "WS-Security in Apache CXF".
Monday, May 30, 2011
CRL support in WSS4J 1.6.1
Support for Certificate Revocation Lists (CRLs) has been a long sought feature in WSS4J, and will arrive in the imminent release of WSS4J 1.6.1. This will ensure that the certificate used to validate a signature is not revoked by the issuing Certificate Authority.
Support for CRLs is covered by the task WSS-278. The default behaviour is that certificate revocation is not enabled for backwards compatibility reasons. Two parameters must be configured to enable certificate revocation. The first is that the WSHandlerConstants property "enableRevocation" must be set to "true", if WSS4J is being used in the context of WSHandler. If the handler architecture is not being used, then a new method has been added to the Crypto interface for signature trust validation which explicitly enables certificate revocation:
The second is that the Crypto instance that is used must be supplied with CRL information. This can be done in a number of different ways. The default Crypto instance that ships with WSS4J (Merlin), has a new configuration property:
Update: You can see a test for this feature here.
Support for CRLs is covered by the task WSS-278. The default behaviour is that certificate revocation is not enabled for backwards compatibility reasons. Two parameters must be configured to enable certificate revocation. The first is that the WSHandlerConstants property "enableRevocation" must be set to "true", if WSS4J is being used in the context of WSHandler. If the handler architecture is not being used, then a new method has been added to the Crypto interface for signature trust validation which explicitly enables certificate revocation:
- public boolean verifyTrust(X509Certificate[] certs, boolean enableRevocation) throws WSSecurityException;
The second is that the Crypto instance that is used must be supplied with CRL information. This can be done in a number of different ways. The default Crypto instance that ships with WSS4J (Merlin), has a new configuration property:
- org.apache.ws.security.crypto.merlin.x509crl.file: The location of an (X509) CRL file to be loaded via CertificateFactory.generateCRL(...).
Update: You can see a test for this feature here.
Subscribe to:
Posts (Atom)