Glen Mazza's Weblog

« Using UsernameToken... | Main | Deploying and Using... »

https://web-gmazza.rhcloud.com/blog/date/20170409 Sunday April 09, 2017

Using X.509 security with Apache CXF

This tutorial shows how to modify the earlier DoubleIt web service tutorial to include WS-Security (WSS) with X.509 public key certificates. This method differs over the perhaps more common UsernameToken-over-SSL strategy in that with X.509 only the contents of the SOAP body and certain elements (depending on configuration) of the SOAP header are encrypted whereas with UT-over-SSL the entire SOAP message is encrypted.

As with the UsernameToken method, CXF provides two main options for adding certificate-based security: WS-SecurityPolicy and the standard CXF interceptor method. The WS-SecurityPolicy method involves placing WS-SecurityPolicy statements in your WSDL to activate secure handling of SOAP requests and responses by both the web service provider and client. It is recommended to use WS-SecurityPolicy because Apache CXF automatically codes in additional security checks (here for example) that you would otherwise have to manually take care of if with the Interceptor approach. But if the WSDL you're working with has no security policy statements, the CXF interceptor approach can be used instead. This tutorial is configured to use WS-SecurityPolicy by default but includes instructions on modifying the sample to use the interceptor approach.

The finished tutorial source code can be obtained from GitHub by using either the download ZIP button or git clone -v git://github.com/gmazza/blog-samples.git command. Note the tutorial inadvertently may have errors within it, so make sure any production work is carefully tested by experienced security engineers. (I should also mention out of caution for newbie coders reading this article not to use the tutorial's provided sample keystores in production work, be sure to use your own with different credentials.)

Steps involved for enhancing DoubleIt with certificate-based security:

  1. Include additional Maven dependencies to handle security processing. This is the same as Step #2 of the CXF UsernameToken tutorial.

  2. Update the WSDL to add in the WS-SecurityPolicy statements. This has already been done in the DoubleIt.wsdl in the source code download, using WS-SecurityPolicy statements generated by NetBeans. If using the CXF interceptor method, you'll need a policy-free WSDL, so remove this file and rename the policy-free DoubleItInterceptorMethod.txt found in the same resources folder to DoubleIt.wsdl (it's the same WSDL from the original web service tutorial.)

    If you'd like to use NetBeans to generate your own WS-SecurityPolicy statements, follow Step #4 of the UsernameToken tutorial, with the exception of the "Edit Web Service Attributes" section--for X.509, you'll want to choose "Mutual Certificates Security" as your security mechanism (see illustration below), pressing the configure button to provide additional customization based on your project's needs.

    Activating X.509 profile using NetBeans

    Some notes:

    • Important: From any resultant NetBeans-generated WSDL, remove the xmlns:sc namespace and sc:KeyStore element as those are specific to the Metro Web Services stack (not used by CXF), and would be publicly visible when viewing the WSDL from a browser (Metro normally suppresses the KeyStore element when viewing the WSDL, but CXF doesn't know about the element and would display it, creating a problem if one were to erroneously think that security credentials need to be placed in that element.)

    • Using the stronger 256-bit encryption as shown in the illustration will require downloading and installing the Java Cryptography Extension's unlimited strength files.

  3. Create key pairs for the client and the web service provider. We'll be creating two key pairs using Java keytool--one for the web service provider and the other for the client. From the project folder root, run the following commands to create these keys:

    keytool -genkey -keyalg RSA -sigalg SHA1withRSA -validity 1461 -alias myservicekey -keypass skpass -storepass sspass -keystore serviceKeystore.jks -dname "cn=localhost"
    keytool -genkey -keyalg RSA -sigalg SHA1withRSA -validity 1461 -alias myclientkey  -keypass ckpass -storepass cspass -keystore clientKeystore.jks -dname "cn=clientuser"
    

    Note these keys are self-signed so should not be used in actual production, and of course the passwords used should be different in your production work. (You may also wish to have the keys expire sooner than the 1461 days, or four years, given above.) Also I've found the case sensitivity of key aliases to vary depending on the tool generating and/or processing them; for that reason I've kept the aliases all lowercase here.

    Next, we'll be setting up two-way trust between the SOAP client and web service provider, which involves each one's public key being loaded into the keystore of the other. The following commands will accomplish this:

    keytool -export -rfc -keystore clientKeystore.jks -storepass cspass -alias myclientkey -file MyClient.cer
    keytool -import -trustcacerts -keystore serviceKeystore.jks -storepass sspass -alias myclientkey -file MyClient.cer -noprompt
    
    keytool -export -rfc -keystore serviceKeystore.jks -storepass sspass -alias myservicekey -file MyService.cer
    keytool -import -trustcacerts -keystore clientKeystore.jks -storepass cspass -alias myservicekey -file MyService.cer -noprompt
    

    Once done, delete the temporary .cer files created and place the serviceKeystore.jks file in service/src/main/resources and clientKeystore.jks in client/src/main/resources, creating either directory first if necessary.

    Note: For simplicity with the various operating and file systems available, this tutorial will be placing the serviceKeystore.jks file inside the deployable WAR (it will end up getting wrapped inside the DoubleIt JAR in the WEB-INF/lib folder). Alternatively, you may wish to place this file into some specific directory outside of your Maven project and provide the full path to this file in the serviceKeystore.properties file discussed below. At any rate, make sure it is not in a location that can be viewed externally from a browser (per the Servlet specification anything under the WAR's expanded WEB-INF/ is shielded from external access.)

  4. Configure the SOAP client to encrypt and sign the SOAP request, and decrypt and verify the signature of the SOAP response. A few files will need to be created for this step:

    1. Create the following Spring cxf.xml file and place it in the client/src/main/resources folder. It's configured for the WS-SecurityPolicy approach by providing additional information beyond that provided by the WSDL as property elements under the jaxws:client element. If you're using the CXF interceptor approach, make the changes given in the comments in this source file. Note the CXF interceptor approach, both here and later with the service-side configuration, uses a DefaultCoverageCryptoChecker to ensure necessary elements are signed; see CXF's WS-Security sign_encryption sample to see how the DefaultCoverageCryptoChecker can be further customized via Java API.

    2. Create a WSS4J properties file for the client's combination keystore/truststore and place it in the same folder:

      clientKeystore.properties:

      org.apache.ws.security.crypto.merlin.keystore.file=clientKeystore.jks
      org.apache.ws.security.crypto.merlin.keystore.password=cspass
      org.apache.ws.security.crypto.merlin.keystore.type=jks
      org.apache.ws.security.crypto.merlin.keystore.alias=myclientkey
      
    3. Add the keystore callback handler in order to obtain the key password for the private key. Place the following ClientKeystorePasswordCallback.java file into the same package as the client's WSClient class:

  5. Configure the server to decrypt and verify the signature of the SOAP request, and encrypt and sign the SOAP response. For this process we'll need to modify the WEB-INF/cxf-servlet.xml from Step #5 of the WSDL-first tutorial to declare security configuration. Replace that file with the following, and make the changes listed within the file if you're using the CXF interceptor approach:

    Of special note is the useReqSigCert value for the encryptionUser parameter in the WSS4JOutInterceptor above. When this value is used instead of a specific client key alias, it tells the service to use the same key that was used to sign the SOAP request. This allows the service to handle any client whose public key is in the service's truststore. (See this WSO2 article for more information on handling multiple clients.)

    Next, create the following WSS4J properties file for the service's keystore/truststore and place it in the service/src/main/resources folder:

    serviceKeystore.properties:

    org.apache.ws.security.crypto.merlin.keystore.file=serviceKeystore.jks
    org.apache.ws.security.crypto.merlin.keystore.password=sspass
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
    

    Finally, we'll need to add the service's keystore callback handler in order to obtain the key password for the private key. Place the following ServiceKeystorePasswordCallback.java file into the same package as the service's DoubleItPortTypeImpl class:

  6. Test the client. After deploying the web service provider as described in Step #7 of the WSDL-first tutorial, run the client as shown in Step #9 and make sure you see the same output. Next, you may wish to reconfigure the client to use another client key not trusted by the service to make sure the calls will not succeed.

    Prior to optionally activating transport-layer encryption (next step), it would be wise to check the SOAP messages to make sure they are being properly signed and encrypted at the message level. The logging activated in the SOAP client should accomplish that (using Wireshark is another option.) Here is the SOAP request and response for one call (with the encrypted SOAP body being shortened):

    Apr 02, 2017 6:10:48 PM org.apache.cxf.services.DoubleItService.DoubleItPort.DoubleItPortType
    INFO: Outbound Message
    ---------------------------
    ID: 1
    Address: http://localhost:8080/doubleit/services/doubleit
    Encoding: UTF-8
    Http-Method: POST
    Content-Type: text/xml
    Headers: {Accept=[*/*], SOAPAction=[""]}
    Payload: 
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Header>
            <Action xmlns="http://www.w3.org/2005/08/addressing"
                    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                    wsu:Id="_70375a09-82fb-4200-88f5-705294f9f549">
                http://www.example.org/contract/DoubleIt/DoubleItPortType/DoubleItRequest
            </Action>
            <MessageID xmlns="http://www.w3.org/2005/08/addressing"
                       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                       wsu:Id="_182bd88b-e404-43f0-ab1b-94707b272b77">urn:uuid:46ffa094-5ca5-4c53-90f5-5fbe0ca0501f
            </MessageID>
            <To xmlns="http://www.w3.org/2005/08/addressing"
                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                wsu:Id="_91a976d1-df5c-4c6b-9259-aaa345d2bfcb">http://localhost:8080/doubleit/services/doubleit
            </To>
            <ReplyTo xmlns="http://www.w3.org/2005/08/addressing"
                     xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                     wsu:Id="_759542e3-30d2-4d3a-8e83-32f4856dab58">
                <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
            </ReplyTo>
            <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                           xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                           soap:mustUnderstand="1">
                <wsu:Timestamp wsu:Id="TS-ea90ce64-d962-4812-aea9-babf280033ad">
                    <wsu:Created>2017-04-02T22:10:47.600Z</wsu:Created>
                    <wsu:Expires>2017-04-02T22:15:47.600Z</wsu:Expires>
                </wsu:Timestamp>
                <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
                                   Id="EK-b2cb6937-11e7-4787-afd4-09eb32cfa738">
                    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
                    <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                        <wsse:SecurityTokenReference>
                            <ds:X509Data>
                                <ds:X509IssuerSerial>
                                    <ds:X509IssuerName>CN=localhost</ds:X509IssuerName>
                                    <ds:X509SerialNumber>756426887</ds:X509SerialNumber>
                                </ds:X509IssuerSerial>
                            </ds:X509Data>
                        </wsse:SecurityTokenReference>
                    </ds:KeyInfo>
                    <xenc:CipherData>
                        <xenc:CipherValue>
                            edpa8cT0qZePPTIRQwHx/kCk6x7PxxQxlFqmq90Hkn9tkY3VMn4b5+4Ac9nUnTc1vI3NySadfIfeymAK4afZZMhpcPY50LPdgOxRX76DA5lOizGqZwki0AQdYPVTJTkD5eDGNN9uLHEruEIUIe3ycsuvabXKqG4oQjOQkQalKh6xzRv/PsRkvINIrCjcNr/HvgJd3NbYnQAv9Byp+fhz2R8QZR1pWKxgcOaiMrLpOg4uqlDxzV0DP+fDuG14tQgigZV+u2ni4nImIEEdM+D9vapuYsq+SrnVCPf0223J1x+mvGAF9lSjwpb0iV1utJM1k4sVi96NeeDlVBuIOYdjDg==
                        </xenc:CipherValue>
                    </xenc:CipherData>
                    <xenc:ReferenceList>
                        <xenc:DataReference URI="#ED-84ec8013-06da-4275-97cc-abf272686d77"/>
                        <xenc:DataReference URI="#ED-30ddcad5-f1f5-43a4-842d-ce66e178f180"/>
                    </xenc:ReferenceList>
                </xenc:EncryptedKey>
                <wsse:BinarySecurityToken
                        EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
                        ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"
                        wsu:Id="X509-984cc422-21bf-4668-8f31-97660bb7a3a0">
                    MIICyTCCAbGgAwIBAgIEXX/dtDANBgkqhkiG9w0BAQUFADAVMRMwEQYDVQQDEwpjbGllbnR1c2VyMB4XDTE3MDQwMjIxMDkzOVoXDTIxMDQwMjIxMDkzOVowFTETMBEGA1UEAxMKY2xpZW50dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAILLJ1HMzwG9FJrA8CyIF0G63kcMfiI6PERmB8Fz+nRxmQRcvUtWusaOntI0EJKRjQu0MukQ23ENuRyfsKBuzKTHxdfxRU0M/as2qcPir96XLd+/e7u/DhUhhVRKkv0VN7ZpKl1M+5Xoz/+pTvczNV1rNSuc0dGgHznhR3qPK3KNvFV16z5hh75oXhWWD49KrbGd36PWMTiF2XqiJoyqaDT63wLH5EUX0GnY/augxoShg4PKv97k/R9uRpeAZGf6bUe46/ww6ytGE60GGg8dLoQMWXCUmn/NaHO2Cq4DyCdh2wo+jS+pG4G8+olwh/6Z/i0OdbzdaTbjG9tezuPFhh0CAwEAAaMhMB8wHQYDVR0OBBYEFND/3YMixA8Jo9yZI1yww2B0nFltMA0GCSqGSIb3DQEBBQUAA4IBAQBZJBHoMrg/5atPGJzk9H4utW0qPWMmHGz9ubSKknfW3Asv1U49j3TN6EKcacRNWqUTG64rJjF3Q+foJrcTSb5s0iuOY3GD0HUm7ykTJLuBkVTNLiLypCUL08l/PX3DLjBnDRfUXxlqghLGmdbl+VQZQw1rHN4fQ58a6D/197XNhERBBSe+uVFYeVaVT77CBbzEb8B9czF3cIgGiIzqT3820P+MZczHioPoqac+NCq3SYbrpr8UPkejctHk6HOzv9DYkTDOsbKR7r7/px4lbGOwb7stR03bdvMQ8pBfPiCAa8j1+LB+IM3vlJXyja3hlo7ZZ7WJMsMImkCfFFjVmWjK
                </wsse:BinarySecurityToken>
                <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
                                    Id="ED-30ddcad5-f1f5-43a4-842d-ce66e178f180"
                                    Type="http://www.w3.org/2001/04/xmlenc#Element">
                    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
                    <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                        <wsse:SecurityTokenReference
                                xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                                xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"
                                wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
                            <wsse:Reference URI="#EK-b2cb6937-11e7-4787-afd4-09eb32cfa738"/>
                        </wsse:SecurityTokenReference>
                    </ds:KeyInfo>
                    <xenc:CipherData>
                        <xenc:CipherValue>
                            NDWTMvk+VrwYtw4CYyZmpEqnfw3fZTyQVLFnI1XnHCjc48l3IjiR3TmronosZeVBqiVuOthykIb953XH5VaEmU9WWRfXgznOz3oQwY2vL6ChSo+bM6FevJyniGPxFdKurJQF6LcpO0Fcq8XmADOEA/EBEt0cgRbIf3ETU+vvfBY9s3l5efvJqWyqWYR7IPuZyn6ifvByV96PM4YSJEe+XoOVzFn+Q/aZIfYii0XhMGnR7kF/mBe0cc192aMY1Hn4kSSE23FponeGbBxbJnyECqYlVJAFyUVMH2YWaBwfRSaWj3Tx5x0sgFbl7bI0k/Lpn0r3wq/GJi+CEw6wYmyjzWWWh3100ka+0L41Z4l8nIn5t/3VoZJmlRF
                            ...truncated...
                            e5vWJz6CPdbsXzXL7XzL8owL027NSLtnoprlBsNVyeYN3w61Vt0i8rK1bCbKqRsd3ScrOVDl4ROtRjIEDE/3kokqAooLrC917PCHAFajM9Z45+hHOMrGD0HuFi5VY5+lOgTtgkX9DC6aVF0x3+x6CVa9cLWXQwFDiqXsXaQVjWpAX2TpWdicIR81qP/HOoWt4oVbd2c1TF+oSC8fh3jBHn
                        </xenc:CipherValue>
                    </xenc:CipherData>
                </xenc:EncryptedData>
            </wsse:Security>
        </soap:Header>
        <soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                   wsu:Id="_46ca1278-9faf-462d-9ca6-e650d2929588">
            <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-84ec8013-06da-4275-97cc-abf272686d77"
                                Type="http://www.w3.org/2001/04/xmlenc#Content">
                <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <wsse:SecurityTokenReference
                            xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                            xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"
                            wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
                        <wsse:Reference URI="#EK-b2cb6937-11e7-4787-afd4-09eb32cfa738"/>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
                <xenc:CipherData>
                    <xenc:CipherValue>
                        +qwPCZs/msFEIr5eqjKvYB4BfHtfsRQlPx0jUeoL+0t424R/CZzsHME3WSK6OG65WXL1jJzU5GXM1yPYnLms+qKm6seqxLKfYWHMNJQqOizfQBrZHlolv+uc8EMFeVBIaZN+u3IFLq1ls17K0lqctnv9Q5Zj5CrKS8+o9ERm/PGEUR/mfncxXTN91S7qmCXJ
                    </xenc:CipherValue>
                </xenc:CipherData>
            </xenc:EncryptedData>
        </soap:Body>
    </soap:Envelope>
    --------------------------------------
    Apr 02, 2017 6:10:54 PM org.apache.cxf.services.DoubleItService.DoubleItPort.DoubleItPortType
    INFO: Inbound Message
    ----------------------------
    ID: 1
    Response-Code: 200
    Encoding: UTF-8
    Content-Type: text/xml;charset=UTF-8
    Headers: {content-type=[text/xml;charset=UTF-8], Date=[Sun, 02 Apr 2017 22:10:54 GMT], transfer-encoding=[chunked]}
    Payload: 
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <Action xmlns="http://www.w3.org/2005/08/addressing"
                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                wsu:Id="_f8ded96f-0238-4fc2-a269-c76144f6dae2">
            http://www.example.org/contract/DoubleIt/DoubleItPortType/DoubleItResponse
        </Action>
        <MessageID xmlns="http://www.w3.org/2005/08/addressing"
                   xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                   wsu:Id="_695c2c09-e01c-462f-9be5-2c8ce277da91">urn:uuid:5bc246fa-f198-48ec-854f-25a0dcbf0eda
        </MessageID>
        <To xmlns="http://www.w3.org/2005/08/addressing"
            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
            wsu:Id="_757af7d3-af2c-4b30-9a98-c776d4fc0af9">http://www.w3.org/2005/08/addressing/anonymous
        </To>
        <RelatesTo xmlns="http://www.w3.org/2005/08/addressing"
                   xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                   wsu:Id="_4d7ee9fe-5cbc-4b92-a3a0-271947650ef5">urn:uuid:46ffa094-5ca5-4c53-90f5-5fbe0ca0501f
        </RelatesTo>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                       soap:mustUnderstand="1">
            <wsu:Timestamp wsu:Id="TS-ba5cc274-19c8-41bd-8855-60b334248025">
                <wsu:Created>2017-04-02T22:10:54.042Z</wsu:Created>
                <wsu:Expires>2017-04-02T22:15:54.042Z</wsu:Expires>
            </wsu:Timestamp>
            <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
                               Id="EK-e8b468d5-95e6-4889-b62a-9aa43670f506">
                <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <wsse:SecurityTokenReference>
                        <ds:X509Data>
                            <ds:X509IssuerSerial>
                                <ds:X509IssuerName>CN=clientuser</ds:X509IssuerName>
                                <ds:X509SerialNumber>1568660916</ds:X509SerialNumber>
                            </ds:X509IssuerSerial>
                        </ds:X509Data>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
                <xenc:CipherData>
                    <xenc:CipherValue>
                        Mqk1/81Ez0pggpe9iYo1ZmXovjV3cq0gwsxPQ5vN2AzCJgy9izfjQH+3/IoHzyLbvR3Krwe91yNctHEJwzBNBFEO+Yt0+NsbCW5Q5vy5TkRwJN3wuPyKiIgm8i7fcULnvkITtNLIx3HN58kI4zWsOMucvw+JZqSDvbrTHxK1/+wHebLpjSCZOUG4r7Y5seXBcqQcaXwpVCNB7cxr/GI66bFQp4tm/gjc5KgS372dT4OLU687feZv60YA/Wi8q5nxlGZAupC0hncp4P7YlMwLCQ866+ShZsKguUvwWjxoPaH5gbOSuVypXnLsxIAvRy53QkpoqeHbxjfVGc+puwMJKQ==
                    </xenc:CipherValue>
                </xenc:CipherData>
                <xenc:ReferenceList>
                    <xenc:DataReference URI="#ED-22de4ca9-1ecb-4981-9740-09a1b07c40f8"/>
                    <xenc:DataReference URI="#ED-b1664128-1268-4f11-b1ce-434079adbe12"/>
                </xenc:ReferenceList>
            </xenc:EncryptedKey>
            <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
                                Id="ED-b1664128-1268-4f11-b1ce-434079adbe12"
                                Type="http://www.w3.org/2001/04/xmlenc#Element">
                <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <wsse:SecurityTokenReference
                            xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                            xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"
                            wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
                        <wsse:Reference URI="#EK-e8b468d5-95e6-4889-b62a-9aa43670f506"/>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
                <xenc:CipherData>
                    <xenc:CipherValue>
                        v7bPvwUhhHVe1Sinoo1HxSyGtOAeBb1UNXcAfK8WbfGdPyME9BYFJeT/9SDzpyQCCeWUd8TV6xuKV62+cYTIzLcQdAPIsHvqvWelApAZs1jKCovfjApVKMWVa+dm/NTZ+VzrG6uM89XVdkBU2n3KrrfaYMGONFfacgT87bd4wxSVXZdbYr7zrSTJmhP6MP7Qcj2IiCKkfM1L5YY5pkI5AEO7VKdRaZODyoVXQswYkva2UFfrpovdRiZrdaqGXl/MZuK3QZQw6RyIebHaUMae7exvdRORWqyxlHowqzZwPY+/fQvTrgp9pJOdXk+DtqkhUGQ2jPoNREAA9Lt7CO+ygqlk3maAYAisBr8VWLXtlA3kn9Q
                        ...truncated...
                        mFOAo2pSd6bvuDQW2+sC1Sq+lyYY2Ks8MWt9FrL1UJI8CwDyxvponwiRZbGQkV93Cc9wD9oZqEU3BiU3iTvYsIH8PNPb4qSj/n1soH0G1T4wUYoTY+mmgbJANEtZAS4Cbb/5ArfFl1dVdvO2flMVPIFhiY+AWeTV+sdczeqqvIOPQXKOtjwp3HFVf7PDIBOyUowd+08G90/vWQOB1eHGwauZGfoTA8=
                    </xenc:CipherValue>
                </xenc:CipherData>
            </xenc:EncryptedData>
        </wsse:Security>
    </soap:Header>
    <soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
               wsu:Id="_581ed46d-86a5-44a6-8232-23178031b8ae">
        <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-22de4ca9-1ecb-4981-9740-09a1b07c40f8"
                            Type="http://www.w3.org/2001/04/xmlenc#Content">
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <wsse:SecurityTokenReference
                        xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                        xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"
                        wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
                    <wsse:Reference URI="#EK-e8b468d5-95e6-4889-b62a-9aa43670f506"/>
                </wsse:SecurityTokenReference>
            </ds:KeyInfo>
            <xenc:CipherData>
                <xenc:CipherValue>
                    tdnZEkympcFwTjp+XlljyjY5Kp/lmjJ16dqJNMltz1cnSyasSqml4hKHLEHy6r1aUZgPfgOZ3DqHPD1OjWHRTK6HJxKmiMMeqQyOg/e5y9kwQceVCNdCAgkmMWo6ywKpMZXAPCqydmf8JhZ4jec1O/Sk44ggOV5X1IkVJ2nhYiiH1LOopbJY175YJFsmJ87OK3jtJ+VzRs43HdwG7xPqOA==
                </xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedData>
    </soap:Body>
    </soap:Envelope>
    --------------------------------------
    The number 10 doubled is 20
    
  7. (Optional) Activate transport-layer security (i.e., HTTPS/SSL) for the web service provider. While message-layer encryption should in theory be sufficient, transport-layer encryption provides an additional layer of security that some projects may wish to consider. Modifying the project to add SSL can be done as follows:

    1. In the web service provider's DoubleIt.wsdl file update the SOAP endpoint URL to https://localhost:8443/doubleit/services/doubleit (in the soap:address element under the wsdl:port).
    2. Make the same modification to the service provider's web.xml file listed in Step #1 of the CXF UsernameToken tutorial.
    3. If necessary, create and configure the application server key as described in Steps #1 and #2 of the SSL tutorial.
    4. Redeploy the web service provider and make a SOAP client call. While the log output activated by the SOAP client above will still be readable, using Wireshark will confirm that transport-layer encryption has been activated (the entire SOAP envelope, including element tags, will be encrypted.)

Troubleshooting:

  • If client calls aren't working, first confirm you can access the web service provider's WSDL (for this tutorial, on localhost Tomcat without SSL, the WSDL would be located at http://localhost:8080/doubleit/services/doubleit?wsdl.) Absent the WSDL being viewable, i.e., the web service provider working, no SOAP call will work. Check the Tomcat (or other servlet container) logs for troubleshooting the web service provider.

  • If you're getting an "java.security.InvalidKeyException: Illegal key size" error when running the client with a 256-bit encryption requirement, make sure you've installed the JCE unlimited strength policy files and restart Tomcat.

  • If the SOAP response back to the client is "A security error was encountered when verifying the message", again, check the Tomcat logs for additional errors that the server logs but hides from the client for security reasons.

Notes:

  • For the interceptor approach, many of the values chosen for the client and service configuration mirror the test values given in a CXF test case. See the CXF documentation for more information on interceptor configuration.
  • As shown in the client.xml and server.xml of other test cases, CXF also provides an option to place WS-SecurityPolicy statements within your Spring configuration instead of within the WSDL. I haven't tried this method but would recommend if you go this route to avoid also placing policy statements within the WSDL, as the configuration in one would probably cause the configuration in the other to get ignored.
  • For certain encryption and signature algorithms not provided by the JDK and JCE you may need to import the BouncyCastle encryption library, see its documentation for more details.

Comments:

Great tutorial. I took your example without the spring part and used Java EE instead. Works as a charm.

Posted by ojothepojo on April 07, 2017 at 05:39 AM EDT #

This is really very helpful tutorial. Thank you Very much.

Posted by subbueng on May 24, 2017 at 10:47 AM EDT #

Post a Comment:
  • HTML Syntax: NOT allowed

Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.