CXF and Digital Signatures

Some web service interactions may require the use of different technologies that are under the umbrella of WS-Security. One of those requirements is driven by the need for specific parts of the message to contain metadata to ensure that the intended sender actually created that part of the message. This can resolved by applying a Digital Signature. I can create a unique Digital Signature (like our own personal signature) and then I can sign parts of the message (as if you were initialing different parts of a contract). Thomas Erl’s site (What is SOA) defines it as this:

XML-Digital Signatures establishes a standardized format for representing digital signature data. Digital signatures establish credibility within a message, as they assure the recipient that the message was in fact transmitted by the expected partner service. It also provides a means of communicating that the message contents were not altered in transit, as well as support for standard non-repudiation. As with the XML-Encryption standard, XML-Digital Signature also supports binary and textual data.

So I am going to be utilizing functionality provided by CXF to implement Digital Signatures. The details of the properties and features of Digital Signatures sometimes seem hard to find, but luckily CXF (like most Web Service frameworks such as Axis or Spring Web Services Framework) utilizes WSS4J to do much of the actual signature part of the message (as well as Username Token, SAML, etc.). In order to get Digital Signatures to work in CXF, I am going to take advantage of CXF’s Interceptors, as well as Spring’s util namespace for representing properties, and finally some modifications to our startup scripts for WebLogic Server because of issues with jar files that are used.

In this example, I want to go one step further and also provide a Timestamp that is signed, because my service provider only allows Digital Signature requests within a certain timeframe to prevent highjacking of the message (for instance if the message is signed at 11:00 AM and the request isn’t received at the service provider until 11:05 AM, the service provider can read the Timestamp and see that it has been signed…to verify that it wasn’t altered and reject the message because it is outside of the required one minute timeframe for a request). Once I have the Signature piece complete, adding a Timestamp requirement is absolutely simple.

So just as I mentioned in my other post about CXF and 2-way SSL, I will need to create a Java Keystore that is separate from our other keystore since Digital Signatures will allow us to provide the alias for our cert, while 2-way SSL configuration does not. So I will create our keystore and provide a password for it. Unlike the 2-way SSL that requires a Certificate Authority keystore, which I created a custom one and put it as a startup parameter for WebLogic Server, I will not be doing that for this keystore because I have multiple keystores for different security requirements and services.

Much of the source example here is leveraged and taken from David Valeri – CXF with WS* Example.

So first thing I need to do is define a bean for SAAJ and then register that with our JaxWsProxyFactoryBean:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<bean id="saajOutInterceptor" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>

<bean id="secureWebServiceProxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" lazy-init="true">
    <property name="serviceClass" value="com.foo.SecureWebService"/>
    <property name="address" value="${secure.service.url}"/>
    <property name="inInterceptors" ref="logInbound"/>
    <property name="outInterceptors">
        <list>
            <ref bean="saajOutInterceptor"/>
            <ref bean="secureWebServiceWss4jOutInterceptor"/>
            <ref bean="logOutbound"/>
        </list>
    </property>
</bean>

The next part is deciding which actions I am going to do and what type of information I need for those actions. So I will be doing “Timestamp Signature” to signify that I want to Timestamp our outbound request as well as apply a Digital Signature. The Digital Signature needs information such as the certificate alias, how to attach the key (which can be the most complicated piece for me in order to get the Signature correctly received by the provider), which parts of the message I want to sign, I can select the properties file which will provide the necessary information for WSS4J, the signature digest algorithm, and a password callback handler instance. The reason the example I referenced above is so beneficial, is because I really don’t want an external properties file. So as the example shows, I can utilize Spring’s util namespace to represent the properties that are required for WSS4J and I can reference this properties bean via the SignaturePropRefId.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<bean id="secureWebServiceWss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
  <constructor-arg>
        <map>
           <entry key="action" value="Timestamp Signature"/>
           
           <!-- This is the fallback user for sig/enc if the sig/enc specific
            properties are not set.  We shouldn't need this, but the WSS4JOutInterceptor
            (CXF 2.2.2.2) looks for it and fails if it is not set. -->
           <entry key="user" value="${secureWebService.keystore.alias}"/>
           
           <!-- The certificate alias in the signature crypto config to sign
            the message with.  The password is retrieved from the callback handler. -->
           <entry key="signatureUser" value="${secureWebService.keystore.alias}"/>
           
           <!-- Signature key attachment method.  We want to put the token
            directly in the header and not use a reference. -->
           <entry key="signatureKeyIdentifier" value="DirectReference"/>
           <!--entry key="signatureKeyIdentifier" value="X509KeyIdentifier"/-->
           
           <!-- The parts of the response to sign.  Include: Body,
            token, timestamp, and addressing headers. -->
           <entry key="signatureParts" value="{http://schemas.xmlsoap.org/soap/envelope/}Body;{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{http://www.w3.org/2005/08/addressing}MessageID"/>
           
           <!--entry key="signaturePropFile" value="${secureWebService-wss4j.properties}"/-->
           <!-- Defines the property name that contains a Properties object with the desired
             settings in it.  Better than loading a static file from the classpath when using
            Spring. -->
           <entry key="SignaturePropRefId" value="cryptoProperties" />
           
           <!-- The entry that actually contains the Properties object for
            the signature crypto configuration.  See SignaturePropRefId. -->
           <entry key="cryptoProperties" value-ref="secureWebServiceCryptoProperties" />

           <!-- The algorithm used to create the actual signature data. -->
           <!--entry key="signatureAlgorithm" value="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/-->

           <!-- The algorithm used to create digests of message content. -->
           <!-- <entry key="signatureDigestAlgorithm" value="http://www.w3.org/2001/04/xmlenc#sha256"/> -->
           <!--entry key="signatureDigestAlgorithm" value="http://www.w3.org/2000/09/xmldsig#sha1"/-->

           <!-- The reference to the callback handler for retrieving passwords
            for private keys in the signature and encryption crypto configurations. -->
           <entry key="passwordCallbackRef">
                <bean class="com.foo.PasswordCallbackHandler">
                    <property name="password" value="${secureWebService.keystore.password}"/>
                </bean>
            </entry>
        </map>
     </constructor-arg>
  </bean>

<!-- Define a Properties object with the properties required by the
       org.apache.ws.security.components.crypto.Merlin WSS4j Crypto implementation.
       This crypto config is used for signature creation and validation and decryption. -->
  <util:properties id="secureWebServiceCryptoProperties">
    <!-- Defines the implementation class. -->
    <prop key="org.apache.ws.security.crypto.provider">org.apache.ws.security.components.crypto.Merlin</prop>
    <!-- Defines the location, on the classpath, of the keystore file.  Also
         takes URL or file path. Not applicable when using PKCS 11. -->
    <prop key="org.apache.ws.security.crypto.merlin.file">${secureWebService.keystore.file}</prop>
    <!-- The type of the keystore pointed to by org.apache.ws.security.crypto.merlin.file. -->
    <prop key="org.apache.ws.security.crypto.merlin.keystore.type">jks</prop>
    <!-- The crypto provider that can load the keystore. -->
    <!--prop key="org.apache.ws.security.crypto.merlin.keystore.provider"></prop-->
    <!-- The password for the keystore file. -->
    <prop key="org.apache.ws.security.crypto.merlin.keystore.password">${secureWebService.keystore.password}</prop>
    <!-- The alias for the default private key to use.  Not required.
    <prop key="org.apache.ws.security.crypto.merlin.cert.provider"></prop>-->
    <prop key="org.apache.ws.security.crypto.merlin.keystore.alias">${secureWebService.keystore.alias}</prop>
    <!-- If the JVM cacerts file contents should be loaded into the trust chain.
    <prop key="org.apache.ws.security.crypto.merlin.load.cacerts">false</prop> -->
    <!-- If the JVM cacerts file is used, the password for the file.
    <prop key="org.apache.ws.security.crypto.merlin.cacerts.password"></prop> -->
  </util:properties>

So you can see by the signatureParts that I am signing the Body, the Timestamp, and part of the Address. The reason I am signing part of the Address is just like our reasons for the Timestamp, in this case the service provider requires WS-Addressing, and by signing it, I am providing the necessary integrity that the intended client that made the original request is providing the Addressing information without being altered. All of the values in this configuration are provided through a security.properties file that is external to our war (I will talk about this later in utilize WebLogic Optional Packages to create a jar containing our enterprise properties so that the war does not have hard-coded properties per environment).

1
<context:property-placeholder location="classpath*:/enterprise.properties" />

So I wish that this was all that was required, but it is unfortunately not because of the fact that I am running on WebLogic Server. If you have run the latest Hibernate/JPA with WebLogic, you have probably had to make the same types of modification to the startup scripts. Here is some parameters that I had to include, along with adding the saaj jar onto our preclasspath:

1
2
SAAJ_JAVA_OPTIONS="-Djavax.xml.soap.MessageFactory=com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl -Djavax.xml.soap.SOAPConnectionFactory=weblogic.wsee.saaj.SOAPConnectionFactoryImpl"
SAAJ_PRECLASSPATH="$/saaj-impl-1.3.2.jar"

The last piece that really caused me grief was around the version of the JDK I was using and whether or not I needed references to Bouncycastle APIs. And as the following post on CXF’s forum suggests, I no longer need this API because of the features in JDK 6 and therefore I had to remove any references/dependencies on Bouncycastle (as it caused our Digital Signatures) to fail.

http://cxf.547215.n5.nabble.com/java-lang-NoClassDefFoundError-org-bouncycastle-asn1-pkcs-PrivateKeyInfo-td4710843.html

And as I mentioned in the CXF and 2-way SSL thread, I required the additional cryptography libraries in order to digitally sign the message: Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files

Resources related to this subject:

Apache CXF – WS-Security Add Interceptors
Adding X.509 security headers to Apache CXF SOAP calls (WS-SecurityPolicy method)
Adding X.509 security headers to Apache CXF SOAP calls
WSS4J Javadoc – Constants
Java Cryptography Architecture Standard Algorithm Name Documentation
Apache CXF Tutorial – WS-Security with Spring
David Valeri – CXF with WS* Example
JBoss – Turn on WS-Security
Securing your Web services with Spring-WS
Sending WS-Security Signature and Encryption Profiles to Axis2/Rampart Web service
An Overview of the WS-Security Framework

Forum posts related to this subject:

http://cxf.547215.n5.nabble.com/CXF-with-Digital-Signatures-td3408690.html
http://cxf.547215.n5.nabble.com/KeyName-within-a-Digital-Signature-Configurable-td4656619.html
http://cxf.547215.n5.nabble.com/java-lang-NoClassDefFoundError-org-bouncycastle-asn1-pkcs-PrivateKeyInfo-td4710843.html
http://cxf.547215.n5.nabble.com/JaxWsProxyFactoryBean-amp-WS-Addressing-in-Configuration-td4683953.html
http://cxf.547215.n5.nabble.com/Send-X509Certificate-with-request-td564722.html

limo service austin tx

Share and Enjoy