1) Test Cases:
Let's start by looking at some practical unit tests on github:
- cxf-jaxrs-jose: This project contains a number of tests that show how to use the JSON Security functionality in Apache CXF to sign and encrypt JSON payloads to/from a JAX-RS service.
For example, here is the output of the "testSignatureCompact" request. The Payload consists of the concatenated (+ separated by a '.') BASE-64 URL encoded JWS header (e.g. containing the signature algorithm, amongst other values), the BASE-64 URL encoded message payload, and the BASE-64 URL encoded signature value.
2) Compact vs. JSON Serialization
The JWS specification defines two different ways of serializing the signatures. Compact serialization is a URL-safe representation that is convenient to use when you only have a single signing entity. JSON serialization resprents the JWS structures as JSON objects, and allows multiple signatures to be included in the request as a result. The JWSSignatureTest includes both examples ("testSignatureListProperties" and "testSignatureCompact"). It's very easy to experiment with both approaches, as you only have to use different providers on both the client + receiving sides:
- JSON Serialization: JwsJsonWriterInterceptor (out) + JwsJsonContainerRequestFilter (in)
- Compact: JwsWriterInterceptor (out) + JwsContainerRequestFilter (in)
As well as adding the desired providers, it is also necessary to specify the security configuration to set the appropriate algorithms, keys, etc. to use. The CXF wiki has an extensive list of all of the different security configuration properties. For signature, we need to first load the signing key (either a JKS keystore or else a JSON Web Key (JWK) is supported).
As well as defining a signing key, we also need to configure the signing algorithm. The list of acceptable signing algorithms for JWS is defined by the JSON Web Algorithms (JWA) spec. For signature, this boils down to a public key signature scheme based on either RSA or EC-DSA, or a symmetric scheme using HMAC.
For example, the tests use the following configuration to load a private key from a Java KeyStore, and to use the signature scheme of RSASSA-PKCS1-v1_5 using SHA-256:
The service side configuration is largely the same, apart from the fact that we don't need to specify the "rs.security.key.password" configuration tag, as we don't need to load the private key. The signature algorithm must be specified to impose a constraint on the acceptable signature algorithm.
4) Signing XML payload
The JWS payload (the content to be signed) can be any binary content and not just a JSON Object. This means that we can use JWS to sign an XML message. This is a really cool feature of the specification in my opinion, as it essentially removes the need to use XML Signature to sign XML payload. An example of this is included in the JWSSignatureTest. The configuration is exactly the same as for the JSON case.
5) Including the signing key
It is possible to include the signing certificate/key in the JWS header by setting one of the following properties:
- rs.security.signature.include.public.key - Include the JWK public key for signature in the "jwk" header.
- rs.security.signature.include.cert - Include the X.509 certificate for signature in the "x5c" header.
- rs.security.signature.include.key.id - Include the JWK key id for signature in the "kid" header.
- rs.security.signature.include.cert.sha1- Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.