Monday, May 11, 2009

Understanding WS-Trust and configuration in CXF

Apache CXF is a high-performance, extensible, Intuitive & Easy to Use open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS. CXF supports a variety of web service standards including SOAP, the Basic Profile, WSDL, WS-Addressing, WS-Policy, WS-ReliableMessaging, and WS-Security.

Apache CXF 2.2 is the third major release of CXF project. I found this release very interesting as it supports WS-SecurityPolicy and Partially supports WS-Trust. WS-Trust specifically deals with the issuing, renewing, and validating of security tokens, as well as with ways to establish, assess the presence of, and broker trust relationships between participants in a secure message exchange.

WS-SecurityPolicy is a very helpful and easier way of specifying your security requirements in an interoperable way. You can access a secured web service hosted on MS server by just pointing to the wsdl containing embedded WS-SecurityPolicy or a WS-Policy reference to a separate WS-SecurityPolicy file.

In CXF-2.2, WS-Trust is supported on client side, that means that now you can access a web services hosted by any WS vendor who requires you to produce tokens for authentication and authorization. For example, if I host a web service in Metro and configures a Metro STS (Secure Token Service - which provides tokens to clients). My CXF client will talk to Metro STS to acquire a token, once acquired CXF client can then produce this token to the Metro Service as an authentication and authorization token. An STS itself is a web service - a web service that issues security tokens.

Daniel Kulp has done a great job in making WS-Trust support up and working. In future release of CXF, we will come up with full support for WS-Trust. Any one who is interested can join the development I have filed a jira task for it.

How WS-Trust works: Basically on client side, ws-policy engine while parsing and understanding service wsdl, from <issuedtoken><issuer>... <issuer>assertion it learns that the service requires a security token to be produced. gives the WS-Addressing address of the STS service and WS-MEX (Metadata Exchange) address for getting the WSDL location of STS. STS may confirm the authenticity of the client who is requesting for the token. Based on the satisfactory confirmation of the authentication of the client, <issuedtoken> may have an assertion <requestsecuritytokentemplate> in which the service may specify what kind of RST request a client should make to STS, a service may specify it's particular requirements for the Token to be produced to it, the requirements can be KeySize, KeyType, TokenType, etc.

STS issues a RSTR (RequestSecurityTokenResponse) which contains requestedToken and proofkey. A proof key indicates proof of possession of the token associated with the requested security token. There are two types of proof keys: symmetric or asymmetric. A service can specify the proof key in the <keytype> element of <requestsecuritytokentemplate>.

In case of Symmetric key, STS creates and distributes the Symmetric key to both service and client. STS gives the key to the client in the <requestedprooftoken> element. STS gives the exact copy of the key to the service in the <keyinfo> element of the <subjectconfirmation> element in the issued SAML assertion in the RSTR response to the client. Client then forward the issued SAML assertion to the service.

In case of Public Key, client doesn't want to trust STS for issuing the secret key as proof of possession. In the RST (RequestSecurityToken) message client supplies RSA key or X.509 public key to STS. STS just embeds the RSA key or X.509 public key certificate in the <keyinfo> element of the <subjectconfirmation> element in the issued SAML assertion in the RSTR response to the client. Client then forward the issued SAML assertion to the service.

In case of No Proof Key, the issued token in <requestedsecuritytoken> itself works as proof of possession.

After getting RSTR, client composes the web service request as requested by WSDL requirements of the service. It embeds the SAML assertion into the request message to the service. Service and client uses the proof key for authentication and authorization of messages afterwards.

Configuring CXF for WS-Trust

Since currently only Client side support is provided in CXF 2.2 version (as I have discussed at the start of this blog entry), all we require to do is to configure a STSClient java class, org.apache.cxf.ws.security.trust.STSClient with the properties to wsdl location, service name, endpoint name. STSClient will look into wsdl, request for an issue, validate, renewal of the required token from STS and will put into the context of WS call so that finally the ws-request can be send with the required token, proof token and SAML assertion. Usually, you configure STS client in either of below two ways,

You can configure STSClient using code-first by creating a new instance of STSClient and calling setter methods of STSClient and finally setting a property "ws-security.sts.client" oof RequestContext() method on port instance as,

((BindingProvider)port).getRequestContext().put("ws-security.sts.client", stsinstance);

or, else you can configure spring bean as,

<jaxws:client name="{http://cxf.apache.org/}MyService">

<jaxws:properties>

<entry key="ws-security.sts.client">

<!-- direct STSClient config and creation -->

<bean class="org.apache.cxf.ws.security.trust.STSClient">

<constructor-arg ref="cxf"/>

<property name="wsdlLocation" value="target/wsdl/trust.wsdl"/>

<property name="serviceName" value="{http://cxf.apache.org/securitytokenservice}SecurityTokenService"/>

<property name="endpointName" value=""{http://cxf.apache.org/securitytokenservice}SecurityTokenEndpoint"/>

<property name="properties">

<map>

<entry key="ws-security.username" value="joe"/>

<entry key="ws-security.callback-handler" value="interop.client.KeystorePasswordCallback"/>

<entry key="ws-security.signature.properties" value="etc/alice.properties"/>

<entry key="ws-security.encryption.properties" value="etc/bob.properties"/> </map>

</property>

</bean>

</entry>

</jaxws:properties>

</jaxws:client>

1 comment:

shiv said...

Hey Mayank,
I'm a new bee to Web Services and CXF and have been trying out a few examples. They've been working worked out perfectly.
I am currently trying to figure out a way to build a simple STS using CXF and SAML 2.0. From what I have seen so far ... i think this has not been implemented. It would be great of I could get a few pointers on how to do this. I know this can be accomplished on Netbeans using Metro and Glassfish but I'm looking for something using Eclipse, CXF and SAML 2.0 ..
Any kind of help would be greatly appreciated.

Hope to hear from you soon.

Thanks
Shiv