Monday, November 4, 2013

XKMS functionality in Apache CXF

Talend has recently donated an XKMS 2.0 implementation to Apache CXF, which is available from the CXF 2.7.7 release. It is documented on the CXF wiki here. The XKMS implementation consists of two parts. Firstly, an XKMS service is provided that exposes a SOAP interface that allows users to register X.509 certificates, as well as to both locate and validate X.509 certificates. Secondly, an implementation of the WSS4J Crypto interface is provided which allows a (WS-Security based) client to both find and validate certificates via the XKMS service.

This blog post will focus on a simple WS-Security system test in CXF, and how it uses XKMS for certificate location and validation. For more detailed information on XKMS, and how it is implemented in CXF, check out my Talend colleague Andrei Shakirin's excellent blog posts on XKMS.

1) XKMS system test with WS-Security

WS-Security is used to secure SOAP service requests/responses at the message level. How this is done is defined by a WS-SecurityPolicy fragment, which is usually defined in the WSDL of the service. Some additional configuration is required by CXF clients and services, such as what username to use, a CallbackHandler implementation to get passwords, and the location of property files which contain WSS4J Crypto configuration for signing and encrypting. See the following wiki and system tests for more information on using WS-Security and WS-SecurityPolicy in CXF.

The WS-SecurityPolicy specification defines two security "bindings" for use in securing SOAP messages at the message level - the "Symmetric" and "Asymmetric" bindings. With the Symmetric binding, the client creates a secret key to secure the message, and then uses the certificate of the service to encrypt the secret key, so that only the service can decrypt the secured message. The Asymmetric binding assumes that both the client and service have public/private key-pairs, and hence the client signs the request using its private key, and encrypts the request using the service's public key.

In each case, the client (typically) must have access to an X.509 certificate for the service. It must "locate" a certificate for the service on the outbound side for both the Symmetric and Asymmetric bindings, and it must "validate" the certificate used by the service to sign the response in the "Asymmetric" case. Up to now, the default WSS4J Crypto implementation (Merlin) uses a local Java keystore to obtain certificates. However, given that the tasks the client must perform ("locate" and "validate") map directly to XKMS operations, it's possible to use the new XKMS Crypto implementation instead.

The XkmsCryptoProvider is configured with a JAX-WS client proxy which can locate/validate X.509 Certificates from a remote XKMS SOAP service. Additionally, it can be composed with another Crypto implementation from which private keys can be retrieved (for example, when used for the Asymmetric Binding). It can also be configured with a cache to prevent repeated remote calls to the XKMS service to locate or validate a particular certificate. The default cache is based on EhCache.

Aside from the obvious advantages of being able to centralize certificate management by using XKMS, a cool additional advantage is that the client need have no local key information at all for the Symmetric binding, as it only requires the X.509 certificate of the message recipient, and no private key. This could greatly simplify key management in a large deployment.

Let's tie all of the above information on combining WS-Security with XKMS together by looking at some CXF system tests. The tests are available in the CXF WS-Security systests directory. The test source is here and test configuration files are available here. The tests show how to deploy an XKMS Service, and how to configure a JAX-WS client with the XKMS Crypto implementation to locate and validate certificates for a service invocation over both the Symmetric and Asymmetric bindings.

2) The XKMS Service

The XKMS service configuration for the test is available here. It describes a JAX-WS endpoint that can only be accessed over TLS. The endpoint implements the standard XKMS interface. A certificate repository is defined as follows:

<bean id="certificateRepo"
    class="org.apache.cxf.xkms.x509.repo.file.FileCertificateRepo">
    <constructor-arg value="src/test/resources/certs/xkms" />
</bean>

This is a simple file based certificate repository, where certificates are stored in a single directory on the filesystem (see here). A more appropriate implementation for the enterprise is the LDAP certificate repository, which is documented on the wiki. The service defines a single XKMS "locator":

<bean id="x509Locator"
    class="org.apache.cxf.xkms.x509.handlers.X509Locator">
    <constructor-arg ref="certificateRepo" />
</bean>

In other words, any "locate" query will try to find certificates in the file certificate store we have defined above. Similarly, two XKMS "validators" are configured:

<bean id="dateValidator"
    class="org.apache.cxf.xkms.x509.validator.DateValidator" />
<bean id="trustedAuthorityValidator"
    class="org.apache.cxf.xkms.x509.validator.TrustedAuthorityValidator">
    <constructor-arg ref="certificateRepo" />
</bean>

The first will validate that a given certificate is "in date". The second will look for a trusted certificate authority for the certificate in the certificate repo (under the "trusted_cas" subdirectory).

3) The JAX-WS client

Here we will just focus on the configuration for the client for the Symmetric binding use-case. It is configured as follows:

<jaxws:client
    name="{http://www.example.org/contract/DoubleIt}DoubleItSymmetricPort"
    createdFromAPI="true">
    <jaxws:properties>
        <entry key="ws-security.encryption.crypto" value-ref="xkmsCrypto"/>
        <entry key="ws-security.encryption.username" value="CN=bob, OU=eng, O=apache.org"/>
    </jaxws:properties>
</jaxws:client>

The client specifies an encryption username that corresponds to the Subject DN of the message recipient. It can also search for a certificate by the service "{serviceNamespace}serviceName" QName. The encrytion Crypto object is a reference to the XKMSCryptoProvider, which in turn is simply configured with the URL of the XKMS Service:

<bean id="xkmsClient"
    class="org.apache.cxf.xkms.client.XKMSClientFactory"
    factory-method="create">
    <constructor-arg>
        <value>https://localhost:${testutil.ports.XKMSServer}/XKMS</value>
    </constructor-arg>
    <constructor-arg ref="cxf"/>
</bean>

<bean id="xkmsCrypto"
    class="org.apache.cxf.xkms.crypto.impl.XkmsCryptoProvider">
    <constructor-arg>
        <ref bean="xkmsClient" />
    </constructor-arg>
</bean>

Before the service request, the client queries the XKMS service to locate an appropriate certificate using the configured encryption username:

Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:LocateRequest xmlns:ns2="http://www.w3.org/2002/03/xkms#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" xmlns:ns4="http://www.w3.org/2000/09/xmldsig#" xmlns:ns5="http://www.w3.org/2002/03/xkms#wsdl" Id="6a17ae45-21a2-4484-b5ec-c71b04dda0b2" Service="http://cxf.apache.org/services/XKMS/"><ns2:QueryKeyBinding><ns2:UseKeyWith Application="urn:ietf:rfc:2459" Identifier="CN=bob, OU=eng, O=apache.org"/></ns2:QueryKeyBinding></ns2:LocateRequest></soap:Body></soap:Envelope>

The XKMS Service responds with:

Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:LocateResult xmlns:ns2="http://www.w3.org/2002/03/xkms#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" xmlns:ns4="http://www.w3.org/2000/09/xmldsig#" xmlns:ns5="http://www.w3.org/2002/03/xkms#wsdl" ResultMajor="http://www.w3.org/2002/03/xkms#Success" RequestId="6a17ae45-21a2-4484-b5ec-c71b04dda0b2" Id="I-2984733849747242496" Service="http://cxf.apache.org/services/XKMS/"><ns2:UnverifiedKeyBinding><ns4:KeyInfo><ns4:X509Data><ns4:X509Certificate>MIIC...</ns4:X509Certificate></ns4:X509Data></ns4:KeyInfo></ns2:UnverifiedKeyBinding></ns2:LocateResult></soap:Body></soap:Envelope>

This certificate is then used to secure the service request using the Symmetric binding policy. For the Asymmetric testcase, the client also "validates" the certificate used by the service to secure the response.

No comments:

Post a Comment