JAX-RS XML Security
Introduction
CXF 2.5.0 introduces an initial support for securing JAX-RS clients and endpoints with XML Signature and XML Encryption
.
This is a work in progress and the enhancements will be applied regularly. Support for the alternative signature and encryption technologies will also be provided in due time.
Maven dependencies
XML Signature
XML Signature defines 3 types of signatures: enveloped, enveloping and detached. All the three types are supported by CXF JAX-RS.
Enveloped signatures
Payload:
<Book ID="4bd59819-7b78-47a5-bb61-cc08348e9d48"> <id>126</id> <name>CXF</name> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI="#4bd59819-7b78-47a5-bb61-cc08348e9d48"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>eFduzs6Cg1/Wd6jagUmr8vRYxHY=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>DLD+wU85G+Q+H/SNoMr1I7tOCAZAjd3lYE84sBGU5tuMtzbwxKOIgg10g2F1SUbpujy1CZZ9BPkQNA+gA1CH4FE3uiBzp3DDSVv6o5l6Q76Ci0XI28ylO7O1OCY+q2nbP0WtERFWOn9f9nniVKbduz6YQHjv6cNLd8pf4+k2U3g=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data><ds:X509Certificate>MIICGjCCAYOgAwIBAgIESVRgATANBgkqhkiG9w0BAQUFADAzMRMwEQYDVQQKEwphcGFjaGUub3JnMQwwCgYDVQQLEwNlbmcxDjAMBgNVBAMTBWN4ZmNhMB4XDTcwMDEwMTAwMDAwMFoXDTM4MDExOTAzMTQwN1owMzETMBEGA1UEChMKYXBhY2hlLm9yZzEMMAoGA1UECxMDZW5nMQ4wDAYDVQQDEwVhbGljZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvu747/VShQ85f16DGSc4Ixh9PVpGguyEqrCsK8q9XHOYX9l9/g5wEC6ZcR2FwfNsoaHcKNPjd5sSTzVtBWmQjfBEfIqwTR7vuihOxyNTwEzVwIJzvo7p8/aYxk+VdBtQxq4UweIcf/iFkUbM1cZ1oiXRQzciRBi+C1BQCQE0qzsCAwEAAaM7MDkwIQYDVR0SBBowGIIWTk9UX0ZPUl9QUk9EVUNUSU9OX1VTRTAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQEFBQADgYEAhLwkm+8psKt4gnbikGzV0TgpSWGcWxWKBi+z8tI2n6hFA5v1jVHHa4G9h3s0nxQ2TewzeR/k7gmgV2sI483NgrYHmTmLKaDBWza2pAuZuDhQH8GAEhJakFtKBP++EC9rNNpZnqqHxx3qb2tW25qRtBzDmK921gg9PMomMc7uqRQ=</ds:X509Certificate> </ds:X509Data> <ds:KeyValue> <ds:RSAKeyValue> <ds:Modulus>vu747/VShQ85f16DGSc4Ixh9PVpGguyEqrCsK8q9XHOYX9l9/g5wEC6ZcR2FwfNsoaHcKNPjd5sSTzVtBWmQjfBEfIqwTR7vuihOxyNTwEzVwIJzvo7p8/aYxk+VdBtQxq4UweIcf/iFkUbM1cZ1oiXRQzciRBi+C1BQCQE0qzs=</ds:Modulus> <ds:Exponent>AQAB</ds:Exponent> </ds:RSAKeyValue> </ds:KeyValue> </ds:KeyInfo> </ds:Signature> </Book>
Server Configuration fragment:
<bean id="serviceBean" class="org.apache.cxf.systest.jaxrs.security.BookStore"/> <bean id="xmlSigHandler" class="org.apache.cxf.rs.security.xml.XmlSigInHandler"/> <jaxrs:server address="/xmlsig"> <jaxrs:serviceBeans> <ref bean="serviceBean"/> </jaxrs:serviceBeans> <jaxrs:providers> <ref bean="xmlSigHandler"/> </jaxrs:providers> <jaxrs:properties> <entry key="ws-security.signature.properties" value="org/apache/cxf/systest/jaxrs/security/alice.properties"/> </jaxrs:properties> </jaxrs:server>
Note that org.apache.cxf.rs.security.xml.XmlSigInHandler is capable of processing all 3 types of XML Signature.
Client code:
String address = "https://localhost:8080/xmlsig/bookstore/books"; JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); bean.setAddress(address); // setup properties Map<String, Object> properties = new HashMap<String, Object>(); properties.put("ws-security.callback-handler", "org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback"); properties.put("ws-security.signature.username", "alice"); properties.put("ws-security.signature.properties", "org/apache/cxf/systest/jaxrs/security/alice.properties"); bean.setProperties(properties); // add the interceptor dealing with adding a signature XmlSigOutInterceptor sigInterceptor = new XmlSigOutInterceptor(); bean.getOutInterceptors().add(sigInterceptor); // use WebClient (or proxy) as usual WebClient wc = bean.createWebClient(); Book book = wc.post(new Book("CXF", 126L), Book.class);
Spring configuration can also be used.
Please also check Secure JAX-RS Services on how HTTPS can be configured.
Enveloping signatures
Payload:
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI="#88e688e6-6512-406f-9e88-a58e5d781ff0"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>Cq3zl3t3DqWTvuZ+4EtZgGs4ikk=</ds:DigestValue> </ds:Reference> </ds:SignedInfo><ds:SignatureValue>NvcCS8vx3YJkc8fHMf8bQkC+lwasC6CwiS7HfKSm8t+6TtYdM7TRbYxSuqfCTkF4vBIldWIzl6UngON592FfJdbvrgE2CusCkIybrP7BBmP7zTSV0GjH4/60L6ObkhGPkMNoKzw4V+zgF7Zo+F7ngsz5ZUWZX/GWETmTtYtcfT0=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate><!-- Omitted for brewity--></ds:X509Certificate> </ds:X509Data> <ds:KeyValue> <ds:RSAKeyValue><ds:Modulus>vu747/VShQ85f16DGSc4Ixh9PVpGguyEqrCsK8q9XHOYX9l9/g5wEC6ZcR2FwfNsoaHcKNPjd5sSTzVtBWmQjfBEfIqwTR7vuihOxyNTwEzVwIJzvo7p8/aYxk+VdBtQxq4UweIcf/iFkUbM1cZ1oiXRQzciRBi+C1BQCQE0qzs=</ds:Modulus> <ds:Exponent>AQAB</ds:Exponent> </ds:RSAKeyValue> </ds:KeyValue> </ds:KeyInfo> <ds:Object ID="88e688e6-6512-406f-9e88-a58e5d781ff0"> <Book> <id>126</id> <name>CXF</name> </Book> </ds:Object> </ds:Signature>
Server Configuration fragment is identical to the one shown in the Enveloped signatures section.
Client code is is nearly identical to the one shown in the Enveloped signatures section except that XmlSigOutInterceptor need to have an additional property set:
// add the interceptor dealing with adding a signature XmlSigOutInterceptor sigInterceptor = new XmlSigOutInterceptor(); sigInterceptor.setStyle("enveloping");
Detached signatures
Payload:
<env:Envelope xmlns:env="http://org.apache.cxf/rs/env"> <Book ID="e9836bc2-cb5a-453f-b967-a9ddbaf9a6de"> <id>125</id> <name>CXF</name> </Book> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> <ds:Reference URI="#e9836bc2-cb5a-453f-b967-a9ddbaf9a6de"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>Pxz77Hlg6I/MRsJz4gixkaMFtYI=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>JSwgiVqZT1EtJ9xqtb90juS54pvZguzFMne7cQyGMQDvBW7b65aAAIfVx/PmFB7Tuy4qB4zqNFCzCwHlhDurNP9NYB7PEzFsA3v3vSyEcHnpUhu41xmBvjT5HWEKbuzqX0dHekizuUefbfzG5WpluVPmOgjashrm9DIhfEf+Hyg=</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate><!--Omitted for Brewity--></ds:X509Certificate> </ds:X509Data> <ds:KeyValue> <ds:RSAKeyValue> <ds:Modulus>vu747/VShQ85f16DGSc4Ixh9PVpGguyEqrCsK8q9XHOYX9l9/g5wEC6ZcR2FwfNsoaHcKNPjd5sSTzVtBWmQjfBEfIqwTR7vuihOxyNTwEzVwIJzvo7p8/aYxk+VdBtQxq4UweIcf/iFkUbM1cZ1oiXRQzciRBi+C1BQCQE0qzs=</ds:Modulus> <ds:Exponent>AQAB</ds:Exponent> </ds:RSAKeyValue> </ds:KeyValue> </ds:KeyInfo> </ds:Signature> <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="_E462768C678896CE9913202742137181" IssueInstant="2011-11-02T22:50:13.718Z" Version="2.0" xsi:type="saml2:AssertionType"> <saml2:Issuer>https://idp.example.org/SAML2</saml2:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <!-- Enveloped/embedded SAML Assertion XML Signature is omitted for brewity See the JAX-RS SAML section for more info --> </ds:Signature> <!-- the rest of SAML assertion --> </saml2:Assertion> </env:Envelope>
Note that the whole payload is enveloped by a configurable element wrapper, see the JAX-RS SAML section for more about it. The Book instance is one part of the envelope and it's signed by a detached signature. The envelope also has an embedded SAML assertion which is signed on its own.
The instance of org.apache.cxf.rs.security.xml.XmlSigInHandler will handle a detached XML signature of the Book XML fragment on the server side. See the JAX-RS SAML for more info on how to deal with SAML assertions.
Client code is is nearly identical to the one shown in the Enveloped signatures section except that XmlSigOutInterceptor need to have an additional property set:
// add the interceptor dealing with adding a signature XmlSigOutInterceptor sigInterceptor = new XmlSigOutInterceptor(); sigInterceptor.setStyle("detached");