blob: 1010e6884bf1560eceed07bcff6dd5139c454a76 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<link type="text/css" rel="stylesheet" href="/resources/site.css">
<script src='/resources/space.js'></script>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta name="keywords" content="business integration, EAI, SOA, Service Oriented Architecture, web services, SOAP, JBI, JMS, WSDL, XML, EDI, Electronic Data Interchange, standards support, integration standards, application integration, middleware, software, solutions, services, CXF, open source">
<meta name="description" content="Apache CXF, Services Framework - JAX-RS JOSE">
<link type="text/css" rel="stylesheet" href="/resources/highlighter/styles/shCoreCXF.css">
<link type="text/css" rel="stylesheet" href="/resources/highlighter/styles/shThemeCXF.css">
<script src='/resources/highlighter/scripts/shCore.js'></script>
<script src='/resources/highlighter/scripts/shBrushBash.js'></script>
<script src='/resources/highlighter/scripts/shBrushXml.js'></script>
<script src='/resources/highlighter/scripts/shBrushJava.js'></script>
<script src='/resources/highlighter/scripts/shBrushJScript.js'></script>
<script>
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.all();
</script>
<title>
Apache CXF -- JAX-RS JOSE
</title>
</head>
<body onload="init()">
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td id="cell-0-0" colspan="2">&nbsp;</td>
<td id="cell-0-1">&nbsp;</td>
<td id="cell-0-2" colspan="2">&nbsp;</td>
</tr>
<tr>
<td id="cell-1-0">&nbsp;</td>
<td id="cell-1-1">&nbsp;</td>
<td id="cell-1-2">
<!-- Banner -->
<div class="banner" id="banner"><div><table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td align="left" colspan="1" nowrap>
<a shape="rect" href="http://cxf.apache.org/" title="Apache CXF"><span style="font-weight: bold; font-size: 170%; color: white">Apache CXF</span></a>
</td><td align="right" colspan="1" nowrap>
<a shape="rect" href="http://www.apache.org/" title="The Apache Sofware Foundation"><img border="0" alt="ASF Logo" src="http://cxf.apache.org/images/asf-logo.png"></a>
</td></tr></table></div></div>
<!-- Banner -->
<div id="top-menu">
<table border="0" cellpadding="1" cellspacing="0" width="100%">
<tr>
<td>
<div align="left">
<!-- Breadcrumbs -->
<a href="index.html">Index</a>&nbsp;&gt;&nbsp;<a href="restful-services.html">RESTful Services</a>&nbsp;&gt;&nbsp;<a href="jax-rs.html">JAX-RS</a>&nbsp;&gt;&nbsp;<a href="jax-rs-oauth2.html">JAX-RS OAuth2</a>&nbsp;&gt;&nbsp;<a href="jax-rs-jose.html">JAX-RS JOSE</a>
<!-- Breadcrumbs -->
</div>
</td>
<td>
<div align="right">
<!-- Quicklinks -->
<div id="quicklinks"><p><a shape="rect" href="http://cxf.apache.org/download.html">Download</a> | <a shape="rect" href="http://cxf.apache.org/docs/index.html">Documentation</a></p></div>
<!-- Quicklinks -->
</div>
</td>
</tr>
</table>
</div>
</td>
<td id="cell-1-3">&nbsp;</td>
<td id="cell-1-4">&nbsp;</td>
</tr>
<tr>
<td id="cell-2-0" colspan="2">&nbsp;</td>
<td id="cell-2-1">
<table>
<tr valign="top">
<td height="100%">
<div id="wrapper-menu-page-right">
<div id="wrapper-menu-page-top">
<div id="wrapper-menu-page-bottom">
<div id="menu-page">
<!-- NavigationBar -->
<div id="navigation"><ul class="alternate"><li><a shape="rect" href="overview.html">Overview</a></li><li><a shape="rect" href="how-tos.html">How-Tos</a></li><li><a shape="rect" href="frontends.html">Frontends</a></li><li><a shape="rect" href="databindings.html">DataBindings</a></li><li><a shape="rect" href="transports.html">Transports</a></li><li><a shape="rect" href="configuration.html">Configuration</a></li><li><a shape="rect" href="debugging-and-logging.html">Debugging and Logging</a></li><li><a shape="rect" href="tools.html">Tools</a></li><li><a shape="rect" href="restful-services.html">RESTful Services</a></li><li><a shape="rect" href="wsdl-bindings.html">WSDL Bindings</a></li><li><a shape="rect" href="service-routing.html">Service Routing</a></li><li><a shape="rect" href="dynamic-languages.html">Dynamic Languages</a></li><li><a shape="rect" href="ws-support.html">WS-* Support</a></li><li><a shape="rect" href="advanced-integration.html">Advanced Integration</a></li><li><a shape="rect" href="deployment.html">Deployment</a></li><li><a shape="rect" href="schemas-and-namespaces.html">Use of Schemas and Namespaces</a></li></ul><hr><ul class="alternate"><li><p>Search</p></li></ul><form enctype="application/x-www-form-urlencoded" method="get" id="cse-search-box" action="http://www.google.com/cse">
<div>
<input type="hidden" name="cx" value="002890367768291051730:o99qiwa09y4">
<input type="hidden" name="ie" value="UTF-8">
<input type="text" name="q" size="21">
<input type="submit" name="sa" value="Search">
</div>
</form>
<script type="text/javascript" src="http://www.google.com/cse/brand?form=cse-search-box&amp;lang=en"></script><hr><ul class="alternate"><li><a shape="rect" href="http://cxf.apache.org/javadoc/latest/">API 3.2.x (Javadoc)</a></li><li><a shape="rect" href="http://cxf.apache.org/javadoc/latest-3.1.x/">API 3.1.x (Javadoc)</a></li><li><a shape="rect" href="http://cxf.apache.org/">CXF Website</a></li></ul><p>&#160;</p><p><a shape="rect" class="external-link" href="http://www.apache.org/events/current-event.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://www.apache.org/events/current-event-125x125.png" data-image-src="http://www.apache.org/events/current-event-125x125.png"></span></a></p></div>
<!-- NavigationBar -->
</div>
</div>
</div>
</div>
</td>
<td height="100%">
<!-- Content -->
<div class="wiki-content">
<div id="ConfluenceContent"><p><style type="text/css">/*<![CDATA[*/
div.rbtoc1636141680489 {padding: 0px;}
div.rbtoc1636141680489 ul {list-style: disc;margin-left: 0px;}
div.rbtoc1636141680489 li {margin-left: 0px;padding-left: 0px;}
/*]]>*/</style></p><div class="toc-macro rbtoc1636141680489">
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-Introduction">Introduction</a></li><li><a shape="rect" href="#JAXRSJOSE-MavenDependencies">Maven Dependencies</a></li><li><a shape="rect" href="#JAXRSJOSE-JavaandJCEPolicy">Java and JCE Policy&#160;</a></li><li><a shape="rect" href="#JAXRSJOSE-JOSEOverviewandImplementation">JOSE Overview and Implementation</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-JWAAlgorithms">JWA Algorithms</a></li><li><a shape="rect" href="#JAXRSJOSE-JWKKeys">JWK Keys</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSSignature">JWS Signature</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-SignatureandVerificationProviders">Signature and Verification Providers</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSCompact">JWS Compact</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSJSON">JWS JSON</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSwithDetachedContent">JWS with Detached Content</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSwithUnencodedPayload">JWS with Unencoded Payload</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-JWEEncryption">JWE Encryption</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-KeyandContentEncryptionProviders">Key and Content Encryption Providers</a></li><li><a shape="rect" href="#JAXRSJOSE-JWECompact">JWE Compact</a></li><li><a shape="rect" href="#JAXRSJOSE-JWEJSON">JWE JSON</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-JSONWebToken">JSON Web Token</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSandJWECombined">JWS and JWE Combined</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-JOSEJAX-RSFilters">JOSE JAX-RS Filters</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-JWS">JWS</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-JWSCompact.1">JWS Compact</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSCompactWithUnencodedPayload">JWS Compact With Unencoded Payload</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSJSON.1">JWS JSON</a></li><li><a shape="rect" href="#JAXRSJOSE-JWSJSONwithUnencodedPayload">JWS JSON with Unencoded Payload</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-SigningandVerificationofHTTPAttachments">Signing and Verification of HTTP Attachments</a></li><li><a shape="rect" href="#JAXRSJOSE-JWE">JWE</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-JWECompact.1">JWE Compact</a></li><li><a shape="rect" href="#JAXRSJOSE-JWEJSON.1">JWE JSON</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-LinkingJWTauthenticationstoJWSorJWEcontent">Linking JWT authentications to JWS or JWE content</a></li><li><a shape="rect" href="#JAXRSJOSE-JWTauthorization">JWT authorization</a></li><li><a shape="rect" href="#JAXRSJOSE-OptionalprotectionofHTTPheaders">Optional protection of HTTP headers</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-JOSEinJAX-RSapplicationcode">JOSE in JAX-RS application code</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-Option1:ProcessJOSEdirectly">Option 1:&#160; Process JOSE directly</a></li><li><a shape="rect" href="#JAXRSJOSE-Option2:UseJOSElibraryhelpersandEndpointConfiguration">Option 2:&#160; Use JOSE library helpers and Endpoint Configuration</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-ProduceJOSEdata">Produce JOSE data</a></li><li><a shape="rect" href="#JAXRSJOSE-ConsumeJOSEdata">Consume JOSE data</a></li><li><a shape="rect" href="#JAXRSJOSE-ProduceandConsumeJOSEdata">Produce and Consume JOSE data</a></li><li><a shape="rect" href="#JAXRSJOSE-Configuretheendpoint">Configure the endpoint</a></li></ul>
</li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-Configuration">Configuration</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-ConfigurationPropertyContainers">Configuration Property Containers</a>
<ul class="toc-indentation"><li><a shape="rect" href="#JAXRSJOSE-Signature">Signature</a></li><li><a shape="rect" href="#JAXRSJOSE-Encryption">Encryption</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-Configurationthatappliestobothencryptionandsignature">Configuration that applies to both encryption and signature</a></li><li><a shape="rect" href="#JAXRSJOSE-Configurationthatappliestosignatureonly">Configuration that applies to signature only</a></li><li><a shape="rect" href="#JAXRSJOSE-Configurationthatappliestoencryptiononly">Configuration that applies to encryption only</a></li><li><a shape="rect" href="#JAXRSJOSE-ConfigurationthatappliestoJWTtokensonly">Configuration that applies to JWT tokens only</a></li></ul>
</li><li><a shape="rect" href="#JAXRSJOSE-Interoperability">Interoperability</a></li><li><a shape="rect" href="#JAXRSJOSE-Third-PartyLibraries">Third-Party Libraries</a></li></ul>
</div><h1 id="JAXRSJOSE-Introduction">Introduction</h1><p><a shape="rect" class="external-link" href="https://datatracker.ietf.org/wg/jose/documents/" rel="nofollow">JOSE</a>&#160;is a set of high quality specifications that specify how data payloads can be signed/validated and/or encrypted/decrypted with the cryptographic properties set in the JSON-formatted metadata (headers). The data to be secured can be in JSON or other formats (plain text, XML, binary data).</p><p><a shape="rect" class="external-link" href="https://datatracker.ietf.org/wg/jose/documents/" rel="nofollow">JOSE</a>&#160;is a key piece of advanced OAuth2 and OpenId Connect applications but can also be successfully used for securing the regular HTTP web service communications.</p><p>CXF 3.0.x, 3.1.x and 3.2.0 provide a complete implementation of <a shape="rect" class="external-link" href="https://datatracker.ietf.org/wg/jose/documents/" rel="nofollow">JOSE</a> and offer a comprehensive utility and filter support for protecting JAX-RS services and clients with the help of <a shape="rect" class="external-link" href="https://datatracker.ietf.org/wg/jose/documents/" rel="nofollow">JOSE</a>.</p><p>CXF <a shape="rect" href="http://cxf.apache.org/docs/jax-rs-oauth2.html">OAuth2</a> and <a shape="rect" href="http://cxf.apache.org/docs/jax-rs-oidc.html">OIDC</a> modules are also depending on it.</p><p><strong>New</strong>: Signature and Verification support for multiparts using JWS Detached Content mode.</p><p><strong>New</strong>: Optional HTTP Header protection.</p><h1 id="JAXRSJOSE-MavenDependencies">Maven Dependencies</h1><p>Having the following dependency will let developers write JOSE JWS or JWE code:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">&lt;dependency&gt;
&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;
&lt;artifactId&gt;cxf-rt-rs-security-jose&lt;/artifactId&gt;
&lt;version&gt;3.1.7&lt;/version&gt;
&lt;/dependency&gt;
</pre>
</div></div><p>Having the following dependency will let developers use JAX-RS JOSE filters which will sign and/or encrypt the data streams, and decrypt or/and validate the incoming JOSE sequences and make the original data available for the processing.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">&lt;dependency&gt;
&lt;groupId&gt;org.apache.cxf&lt;/groupId&gt;
&lt;artifactId&gt;cxf-rt-rs-security-jose-jaxrs&lt;/artifactId&gt;
&lt;version&gt;3.1.7&lt;/version&gt;
&lt;/dependency&gt;
</pre>
</div></div><p>You may also need to include BouncyCastle for some of JWE encryption algorithms to be supported:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">&lt;dependency&gt;
&lt;groupId&gt;org.bouncycastle&lt;/groupId&gt;
&lt;artifactId&gt;bcprov-ext-jdk15on&lt;/artifactId&gt;
&lt;version&gt;1.60&lt;/version&gt;
&lt;/dependency&gt;
</pre>
</div></div><p>BouncyCastle provider can be registered and unregistered as follows:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>BouncyCastle Provider</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
private static void registerBouncyCastle() throws Exception {
Security.addProvider(new BouncyCastleProvider());
}
private static void unregisterBouncyCastle() throws Exception {
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
}</pre>
</div></div><p><br clear="none"></p><h1 id="JAXRSJOSE-JavaandJCEPolicy">Java and JCE Policy&#160;</h1><p>Java7 or higher is recommended in most cases.</p><p><strong>JWE</strong></p><p>Java6 does not support JWE AES GCM key wrap and content encryption algorithms (while with BouncyCastle it is not possible to submit JWE Header properties as an extra input to the encryption process to get them integrity protected), however with Java 6 one can use AesCbcHmac content encryption if BouncyCastle is installed.</p><p>Unlimited JCE Policy for Java 7/8/9 needs to be installed if a size of the encryption key is 256 bits (example, JWE A256GCM).</p><p><strong>JWS</strong></p><p>Java 6 should also be fine but note only CXF 3.0.x can be run with Java 6.</p><h1 id="JAXRSJOSE-JOSEOverviewandImplementation">JOSE Overview and Implementation</h1><p>JOSE consists of the following key parts:</p><ul><li><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518" rel="nofollow">JWA</a> - JSON Web Algorithms where all supported signature and encryption algorithms are listed</li><li><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7517" rel="nofollow">JWK</a> - JSON Web Keys - introduces a JSON format for describing the public and private keys used by JWA algorithms</li><li><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515" rel="nofollow">JWS</a> - JSON Web Signature - describes how the data can be signed or validated and introduces compact and JSON JWS formats for representing the signed data</li><li><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7516" rel="nofollow">JWE</a> - JSON Web Encryption - describes how the data can be encrypted or decrypted and introduces compact and JSON JWE formats for representing the encrypted data&#160;&#160;</li></ul><p>Additionally, <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7519" rel="nofollow">JWT</a> (JSON Web Token), while technically being not part of JOSE, is often used as an input material to JWS and JWE processors, especially in OAuth2 flows (example: OAuth2 access tokens can be represented internally as JWT, OpenIdConnect IdToken and UserInfo are effectively JWTs). <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7519" rel="nofollow">JWT</a> describes how a set of claims in JSON format can be JWS-signed and/or JWE-enctypted.&#160;</p><h2 id="JAXRSJOSE-JWAAlgorithms">JWA Algorithms</h2><p>All JOSE signature and encryption algorithms are grouped and described in the <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518" rel="nofollow">JWA</a> (JSON Web Algorithms) specification.</p><p>The algorithms are split into 3 categories: signature algorithms (HMAC, RSA, Elliptic Curve), algorithms for supporting the encryption of content encryption keys (RSA-OAEP, AES Key Wrap, etc), and algorithms for encrypting the actual content (AES GCM or AES CBC HMAC).</p><div>The specification lists all the algorithms that can be used for signing or encrypting the data and also describes how some of these algorithms work in cases</div><div>where Java JCA (or BouncyCastle) does not support them directly, example, AES-CBC-HMAC-SHA2.</div><div>Algorithm name is a type + hint, example: HS256 (HMAC with SHA-256), RSA-OAEP-256 (RSA OAEP key encryption with SHA-256), etc.</div><p>All JWS and JWE algorithms process not only the actual data but also the meta-data (the algorithm properties) thus ensuring they are integrity-protected, additionally JWE algorithms produce authentication tags which ensure the already encrypted content won't be manipulated.</p><p>Please refer to <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518" rel="nofollow">the specification</a> to get all the information needed (with the follow up links to the corresponding RFC when applicable) about a particular signature or encryption algorithm: the properties, recommended key sizes, other security considerations related to all of or some specific algorithms. CXF JOSE code already enforces a number of the recommended constraints.</p><p>CXF offers the utility support for working with JWA algorithms in <a shape="rect" class="external-link" href="https://github.com/apache/cxf/tree/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa" rel="nofollow">this package</a>.</p><p>Typically one would supply an algorithm property in a type-safe way either to JWS or JWE processor, for example,&#160; SignatureAlgorithm.HS256 for JWS,&#160;KeyAlgorithm.A256KW plus ContentAlgorithm.A256GCM for JWE, etc. Each enum has methods for checking a key size, JWA and Java JCA algorithm names.</p><h2 id="JAXRSJOSE-JWKKeys">JWK Keys</h2><p><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7517" rel="nofollow">JWK</a> (JSON Web Key) is a JSON document describing the cryptographic key properties. JWKs are very flexible and one can expect JWKs becoming one of the major mechanisms for representing and storing cryptographic keys. While one does not have to represent the keys as JWK in order to sign or encrypt the document and rely on Java JCA secret and asymmetric keys instead, JWK is a preferred representation of signature or encryption keys in JOSE.</p><p>For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Secret HMAC Key</b></div><div class="codeContent panelContent pdl">
<pre class="brush: js; gutter: false; theme: Default">{
"kty":"oct",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
"kid":"Secret HMAC key"
}</pre>
</div></div><p>or</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Public RSA Key</b></div><div class="codeContent panelContent pdl">
<pre class="brush: js; gutter: false; theme: Default">{
"kty":"RSA",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx
4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs
tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2
QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI
SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb
w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e":"AQAB",
"alg":"RS256",
"kid":"Public RSA Key"
}</pre>
</div></div><p>A 'kid' property can be of special interest as it allows to identify a key but also help with the simple key rotation mechanism realized (ex, <a shape="rect" class="external-link" href="http://openid.net/specs/openid-connect-core-1_0.html#RotateSigKeys" rel="nofollow">OIDC Asymmetric Key Rotation</a>).</p><p>A collection of JWK keys is called a JWK Key Set which is represented as JSON array of JWKs.</p><p>JWK can contain X509 certificates or their thumbprints if preferred.</p><p>CXF offers a utility support for reading and writing JWK keys and key sets and working with the encrypted inlined and standalone JWK stores in <a shape="rect" class="external-link" href="https://github.com/apache/cxf/tree/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk" rel="nofollow">this package</a>.</p><p>For example, a key set containing public JWK keys can be seen <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/certs/jwkPublicSet.txt" rel="nofollow">here</a> and referred to from the <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jws.ec.public.properties#L19" rel="nofollow">configuration properties</a>. The private (test) key set can be represented in a <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/certs/jwkPrivateSet.txt" rel="nofollow">clear form</a>, though most likely you'd want a private key set <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/certs/encryptedJwkPrivateSet.txt" rel="nofollow">encrypted</a> and referred to <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/secret.aescbchmac.properties#L19" rel="nofollow">like this</a>.&#160;</p><p>One can inline the encrypted key or the key set directly in the configuration properties. For example, here is how an encrypted <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/secret.aescbchmac.inlinejwk.properties#L18" rel="nofollow">single JWK key is inlined</a>. Similarly, here is how an encrypted <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/secret.aescbchmac.inlineset.properties#L18" rel="nofollow">collection of keys is inlined</a>.</p><p>CXF assumes that JWK keys have been encrypted if a <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/PrivateKeyPasswordProvider.java" rel="nofollow">password provider</a> is available in a request context, it is typically registered with JAX-RS endpoints. The encryption is done with a password based <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4.8" rel="nofollow">PBES2 algorithm</a>.&#160;</p><p>Support for the pluggable strategies for loading JWKs is on the map.</p><p>For example, here is how you can load a JWK key using its 'kid':</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>JWK examples</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">InputStream is = JsonWebKeyTest.class.getResourceAsStream(fileName);
JsonWebKeys keySet = JwkUtils.readJwkSet(is);
JsonWebKey key = keySet.getKey("Public RSA Key");
String thumbprint = JwkUtils.getThumbprint(key);
assertEquals("NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs", thumbprint);
KeyType keyType = key.getKeyType();
assertEquals(KeyType.RSA, keyType);</pre>
</div></div><p>JsonWebKeys also supports the retrieval of keys by their type (RSA, EC, Octet) and operation (ENCRYPT, SIGN, etc). <br clear="none">Once you have JWK loaded it is typically submitted to JWS or JWE providers.</p><h2 id="JAXRSJOSE-JWSSignature">JWS Signature</h2><p><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515" rel="nofollow">JWS</a> (JSON Web Signature) document describes how a document content can be signed. For example, <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#appendix-A.1" rel="nofollow">Appendix A1</a> shows how the content can be signed with an HMAC key</p><p>CXF ships JWS related classes in <a shape="rect" class="external-link" href="https://github.com/apache/cxf/tree/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws" rel="nofollow">this package</a> and offers a support for all of JWA <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-3" rel="nofollow">signature algorithms</a>.</p><h3 id="JAXRSJOSE-SignatureandVerificationProviders">Signature and Verification Providers</h3><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java" rel="nofollow">JwsSignatureProvider</a> supports signing the content, <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java" rel="nofollow">JwsSignatureVerifier</a> - validating the signatures.</p><p>Note the signature and verification capabilities are represented by 2 different interfaces - it was done to keep the interfaces minimalistic and have the concerns separated which can be appreciated most in the cases where the code only signs or only validates.</p><p>The following table shows the algorithms and the corresponding providers (<span class="pl-smi">org.apache.cxf.rs.security.jose.jws</span> package):</p><div class="table-wrap"><table class="wrapped confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><strong>Algorithm</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>JWS Header 'alg'</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>JwsSignatureProvider</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>JwsSignatureVerifier</strong></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-3.2" rel="nofollow">HMAC</a></td><td colspan="1" rowspan="1" class="confluenceTd">HS256, HS384, HS512</td><td colspan="1" rowspan="1" class="confluenceTd"><p>HmacJwsSignatureProvider</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>HmacJwsSignatureVerifier</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-3.3" rel="nofollow">RSASSA-PKCS1-v1_5</a></td><td colspan="1" rowspan="1" class="confluenceTd">RS256, RS384, RS512</td><td colspan="1" rowspan="1" class="confluenceTd">PrivateKeyJwsSignatureProvider</td><td colspan="1" rowspan="1" class="confluenceTd">PublicKeyJwsSignatureVerifier</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-3.4" rel="nofollow">ECDSA</a></td><td colspan="1" rowspan="1" class="confluenceTd">ES256, ES384, ES512</td><td colspan="1" rowspan="1" class="confluenceTd">EcDsaJwsSignatureProvider</td><td colspan="1" rowspan="1" class="confluenceTd">EcDsaJwsSignatureVerifier</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-3.5" rel="nofollow">RSASSA-PSS</a></td><td colspan="1" rowspan="1" class="confluenceTd">PS256, PS384, PS512</td><td colspan="1" rowspan="1" class="confluenceTd">PrivateKeyJwsSignatureProvider</td><td colspan="1" rowspan="1" class="confluenceTd">PublicKeyJwsSignatureVerifier</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-3.6" rel="nofollow">None</a></td><td colspan="1" rowspan="1" class="confluenceTd">none</td><td colspan="1" rowspan="1" class="confluenceTd">NoneJwsSignatureProvider</td><td colspan="1" rowspan="1" class="confluenceTd">NoneJwsSignatureVerifier</td></tr></tbody></table></div><p>Either of these providers (except for None) can be initialized with the keys loaded from JWK or Java JKS stores or from the in-memory representations.</p><p>RS256/384/512 algorithms are likely to be used most often at the moment due to existing JKS stores being available everywhere and a relatively easy way of making the public validation keys available. 'None' algorithm might be useful when a JWS sequence is subsequently JWE-encrypted or when a 2-way TLS (with client and server certificates) is used.</p><p>Once you have decided which algorithm needs to be supported you can initialize an appropriate pair of JwsSignatureProvider and JwsSignatureVerifier if both signing the data and the verification are needed. If only the signing is needed - select JwsSignatureProvider, only the verification - select JwsSignatureVerifier. The selected providers are submitted to JWS Compact or JWS JSON producers or consumers.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java" rel="nofollow">JwsUtils</a> utility class has a lot of helper methods to load JwsSignatureProvider or JwsSignatureVerifier and to get JWS sequences created and validated.</p><h3 id="JAXRSJOSE-JWSCompact">JWS Compact</h3><p><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#section-3.3" rel="nofollow">JWS Compact representation</a> is the most often used JWS sequence format. It is the concatenation of Base64URL-encoded sequence of JWS headers (algorithm and other properties),&#160; Base64URL-encoded sequence of the actual data being protected and Base64URL-encoded sequence of the signature algorithm output bytes.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactProducer.java" rel="nofollow">JwsCompactProducer</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactConsumer.java" rel="nofollow">JwsCompactConsumer</a> offer a support for producing and consuming compact JWS sequences, protecting the data in JSON or non-JSON formats.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java" rel="nofollow">JwsJwtCompactProducer</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java" rel="nofollow">JwsJwtCompactConsumer</a> are their simple extensions which help with processing typed JWT Tokens.</p><p>&#160;For example, here is how an <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#appendix-A.1" rel="nofollow">Appendix A1</a> example can be done in CXF:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CXF JWS Compact HMac</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">JwtClaims claims = new JwtClaims();
claims.setIssuer("joe");
claims.setExpiryTime(1300819380L);
claims.setClaim("http://example.com/is_root", Boolean.TRUE);
JwsCompactProducer jwsProducer = new JwsJwtCompactProducer(claims);
// Sign
// Load HmacJwsSignatureProvider directly, see the next example for the alternative approach
String jwsSequence = jwsProducer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256));
// Validate
JwsJwtCompactConsumer jwsConsumer = new JwsJwtCompactConsumer(jwsSequence);
// Load HmacJwsSignatureVerifier directly, see the next example for the alternative approach
jwsConsumer.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, SignatureAlgorithm.HS256)));
// Get the data
JwtClaims protectedClaims = jws.getJwtClaims();
</pre>
</div></div><p>In the above example, the data (JwtToken) is submitted to an instance of JwsCompactProducer (JwsJwtCompactProducer) and signed with an HMac key.</p><p>Here is another example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CXF JWS Compact RSA</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">JwsCompactProducer jwsProducer = new JwsCompactProducer("Hello World");
// Load private RSA key from the JWK Key set stored on the disk
InputStream is = JsonWebKeyTest.class.getResourceAsStream(fileName);
JsonWebKeys keySet = JwkUtils.readJwkSet(is);
JsonWebKey jwkPrivateRsaKey = keySet.getKey("Private RSA Key");
// Sign
String jwsSequence = jwsProducer.signWith(jwkPrivateRsaKey);
// Validate
JwsCompactConsumer jwsConsumer = new JwsCompactConsumer(jwsSequence);
// Load Public RSA Key from Java JKS Store
PublicKey publicRsaKey = CryptoUtils.loadPublicKey(keyStoreLocation, keyStorePassword, keyAlias, KeyStore.getDefaultType());
jws.verifySignatureWith(publicRsaKey);
// Get the data
String helloWorldString = jwsConsumer.getDecodedJwsPayload();
</pre>
</div></div><p>In this latest example a plain text sequence is encoded with a private RSA key loaded from the JWK store and validated with a public RSA key loaded from the existing Java JKS store.</p><h3 id="JAXRSJOSE-JWSJSON">JWS JSON</h3><p>While JWS Compact is optimized and represents a concatenation of 3 Base64URL values, JWS JSON is an open JSON container, see <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#appendix-A.6" rel="nofollow">Appendix 6</a>.</p><p>The most interesting feature of JWS JSON is that allows a content be signed for multiple recipients. For example,&#160; the immediate consumer will validate a signature with one key, forward the payload to the next consumer which will also validate the content with another key, etc. &#160;</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducer.java" rel="nofollow">JwsJsonProducer</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumer.java" rel="nofollow">JwsJsonConsumer</a> support producing and consuming JWS JSON sequences.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CXF JWS JSON</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_JSON_DOCUMENT);
JwsHeaders headerEntries = new JwsHeaders(SignatureAlgorithm.HS256);
producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY_1, SignatureAlgorithm.HS256),
headerEntries);
producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY_2, SignatureAlgorithm.HS256),
headerEntries);
assertEquals(DUAL_SIGNED_JWS_JSON_DOCUMENT, producer.getJwsJsonSignedDocument());
JwsJsonConsumer consumer = new JwsJsonConsumer(DUAL_SIGNED_DOCUMENT);
// Validate both signatures, see below how to validate and produce
JsonWebKeys jwks = readKeySet("jwkSet.txt");
List&lt;JwsJsonSignatureEntry&gt; sigEntries = consumer.getSignatureEntries();
assertEquals(2, sigEntries.size());
// 1st signature
String firstKid = (String)sigEntries.get(0).getKeyId();
JsonWebKey firstKey = jwks.getKey(firstKid);
assertTrue(sigEntries.get(0).verifySignatureWith(firstKey));
// 2nd signature
String secondKid = (String)sigEntries.get(1).getKeyId();
JsonWebKey secondKey = jwks.getKey(secondKid);
assertTrue(sigEntries.get(1).verifySignatureWith(secondKey));
// or if you wish to validate (ex with the firstKey loaded above) and forward it to the next consumer, do:
JwsSignatureProvider provider = JwsUtils.getSignatureProvider(firstKey);
String nextJwsJson = consumer.validateAndProduce(Collections.singletonList(provider));
// use WebClient to post nextJwsJson to the next consumer, with nextJwsJson being nearly identical to the original
// double-signed JWS JSON signature, minus the signature which was already validated, in this case nextJwsJson will
// only have a single signature </pre>
</div></div><p>The above code produces a JWS JSON sequence containing two signatures, similarly to <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#appendix-A.6.4" rel="nofollow">this example</a>. If the sequence contains a single signature only then the JWS JSON 'signatures' array will contain a single 'signature' element, or the whole sequence can be <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#appendix-A.6.4" rel="nofollow">flattened</a> instead with the actual 'signatures' array dropped. JwsJsonProducer &#160;does not produce the flattened sequence when only a single signature is used by default because 3rd party JWS JSON consumers may only be able to process the sequences with the 'signatures' array, so pass a 'supportFlattened' flag to JwsJsonProducer if needed.&#160;</p><p>Does it make sense to use JWS JSON if you do not plan to do multiple signatures ? Indeed, if it is only a single signature then using JWS Compact is a good alternative, likely to be used most often.</p><p>However, even if you do a single signature, you may still want to try JWS JSON because is is easier to observe the individual JWS JSON structure parts when, example, checking the logs or TCP-tracing HTTP requests/responses. This is especially true when we start talking about an unencoded payload option, see below.</p><h3 id="JAXRSJOSE-JWSwithDetachedContent">JWS with Detached Content</h3><p><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#appendix-F" rel="nofollow">JWS with Detached Content</a> provides a way to integrity-protect some data without actually having these data included in the resulting JWS sequence.</p><p>For example, if the producer and consumer can both access the same shared piece of data, then the producer can sign these data, post the JWS sequence (without the data) to the consumer. The consumer will validate this JWS sequence and assert the data have not been modified by the time it has received and started validating the sequence. JWS Compact and JWS JSON Producer and Consumer provider constructors accept an optional 'detached' flag in cases were it is required. &#160; &#160; &#160;</p><p>Note the detached content mode is used to support the signing and verification of CXF multipart attachment parts, see below for more information.</p><h3 id="JAXRSJOSE-JWSwithUnencodedPayload">JWS with Unencoded Payload</h3><p>By default, JWS Compact and JWS JSON sequences have the data first Base64Url encoded and then inlined in the resulting sequence. This is useful especially for JWS Compact which is used in OAuth2/OIDC &#160;flows to represent the signed access or id tokens.&#160;</p><p>One concern around the data being inlined is that it takes an extra time to Base64Url encode them which may become noticeable with large payloads, and another one is that one can not see the data while looking at JWS sequences in the logs or trace screens.</p><p>Thus a <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7797" rel="nofollow">JWS with Unencoded Payload</a> option (JWS header 'b64' property set to false) has been introduced to let users configure JWS Signature providers not to encode the actual data payload, see <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7797#page-7" rel="nofollow">this example</a>.</p><p>Both JWS JSON and JWS Compact support 'b64' property for the detached and embedded payloads.</p><p>In CXF you can apply this option to both JWS Compact (embedded payloads - from CXF 3.1.7) and JWS JSON sequences, here is a JWS JSON code fragment:</p><p><br clear="none"></p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>JWS JSON Unencoded</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_JSON_DOCUMENT, true);
JwsHeaders headers = new JwsHeaders(SignatureAlgorithm.HS256);
headers.setPayloadEncodingStatus(false);
producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY_1, SignatureAlgorithm.HS256),
headers);</pre>
</div></div><p>Note that JWS Compact uses a '.' as a separator between its 3 parts. <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7797#section-5" rel="nofollow">JWS with Unencoded Payload</a> recommends that it is the application's responsibility to deal with the unencoded payloads which may have '.' characters. Similarly, JWS JSON unencoded payloads with double quotes will need to be taken care of by the application.&#160;</p><p>Note the the signing and verification of CXF multipart attachment parts does depend on this unencoded payload feature, see below for more information.</p><h2 id="JAXRSJOSE-JWEEncryption">JWE Encryption</h2><p><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7516" rel="nofollow">JWE</a> (JSON Web Encryption) document describes how a document content, and, when applicable, a content encryption key, can be encrypted. For example, <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7516#appendix-A.1" rel="nofollow">Appendix A1</a> shows how the content can be encrypted with a secret key using AesGcm with the actual content encryption key being encrypted using RSA-OAEP.</p><p>CXF ships JWE related classes in <a shape="rect" class="external-link" href="https://github.com/apache/cxf/tree/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe" rel="nofollow">this package</a> and offers a support for all of JWA <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4" rel="nofollow">key encryption</a> and <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-5" rel="nofollow">content encryption</a> algorithms.</p><h3 id="JAXRSJOSE-KeyandContentEncryptionProviders">Key and Content Encryption Providers</h3><p>JWE Encryption process typically involves a content-encryption key being generated with this key being subsequently encrypted/wrapped with a key known to the consumer. Thus CXF offers the providers for supporting the key-encryption algorithms and providers for supporting the content-encryption algorithms. Direct key encryption (where the content-encryption key is established out of band) is also supported.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyEncryptionProvider.java" rel="nofollow">KeyEncryptionProvider</a> supports encrypting a content-encryption key, <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/KeyDecryptionProvider.java" rel="nofollow">KeyDecryptionProvider</a> - decrypting it.</p><p>The following table shows the key encryption algorithms and the corresponding providers (<span class="pl-smi">org.apache.cxf.rs.security.jose.jwe</span> package):</p><div class="table-wrap"><table class="wrapped confluenceTable"><colgroup span="1"><col span="1"><col span="1"><col span="1"><col span="1"></colgroup><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><strong>Algorithm</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>JWE Header 'alg'</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>KeyEncryptionProvider</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>KeyDecryptionProvider</strong></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4.2" rel="nofollow">RSAES-PKCS1-v1_5</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">RSA1_5</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>RSAKeyEncryptionAlgorithm</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>RSAKeyDecryptionAlgorithm</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4.3" rel="nofollow">RSAES OAEP</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">RSA-OAEP, RSA-OAEP-256</p></td><td colspan="1" rowspan="1" class="confluenceTd">RSAKeyEncryptionAlgorithm</td><td colspan="1" rowspan="1" class="confluenceTd">RSAKeyDecryptionAlgorithm</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4.4" rel="nofollow">AES Key Wrap</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">A128KW, A192KW, A256KW</p></td><td colspan="1" rowspan="1" class="confluenceTd">AesKeyWrapEncryptionAlgorithm</td><td colspan="1" rowspan="1" class="confluenceTd">AesKeyWrapDecryptionAlgorithm</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4.5" rel="nofollow">Direct</a></td><td colspan="1" rowspan="1" class="confluenceTd">dir</td><td colspan="1" rowspan="1" class="confluenceTd">DirectKeyEncryptionAlgorithm</td><td colspan="1" rowspan="1" class="confluenceTd">DirectKeyDecryptionAlgorithm</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#page-15" rel="nofollow">ECDH-ES Key Wrap</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">ECDH-ES+A128KW (+A192KW, +256KW)</p></td><td colspan="1" rowspan="1" class="confluenceTd">EcdhAesWrapKeyEncryptionAlgorithm</td><td colspan="1" rowspan="1" class="confluenceTd">EcdhAesWrapKeyDecryptionAlgorithm</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#page-15" rel="nofollow">ECDH-ES Direct</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">ECDH-ES</p></td><td colspan="1" rowspan="1" class="confluenceTd"><span class="pl-en">EcdhDirectKeyJweEncryption</span></td><td colspan="1" rowspan="1" class="confluenceTd"><span class="pl-en">EcdhDirectKeyJweDecryption</span></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4.7" rel="nofollow">AES-GCM Key Wrap</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">A128GCMKW, A192GCMKW, A256GCMKW</p></td><td colspan="1" rowspan="1" class="confluenceTd">AesGcmWrapKeyEncryptionAlgorithm</td><td colspan="1" rowspan="1" class="confluenceTd">AesGcmWrapKeyDecryptionAlgorithm</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-4.8" rel="nofollow">PBES2</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">PBES2-HS256+A128KW</p><p class="newpage">PBES2-HS384+A192KW</p><p class="newpage">PBES2-HS512+A256KW</p></td><td colspan="1" rowspan="1" class="confluenceTd">PbesHmacAesWrapKeyEncryptionAlgorithm</td><td colspan="1" rowspan="1" class="confluenceTd">PbesHmacAesWrapKeyDecryptionAlgorithm</td></tr></tbody></table></div><p><br clear="none"></p><p>RSA-OAEP algorithms are likely to be used most often at the moment due to existing JKS stores being available everywhere and a relatively easy way of making the public validation keys available.</p><p>BouncyCastle is required if you use AES Key or AES-GCM Key Wrap or PBES2 key encryption.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/ContentEncryptionProvider.java" rel="nofollow">ContentEncryptionProvider</a> supports encrypting a generated content-encryption key, <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/ContentDecryptionProvider.java" rel="nofollow">ContentDecryptionProvider</a> - decrypting it.</p><p>The following table shows the content encryption algorithms and the corresponding providers:</p><div class="table-wrap"><table class="wrapped confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><strong>Algorithm</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>JWE Header 'enc'</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>ContentEncryptionProvider</strong></td><td colspan="1" rowspan="1" class="confluenceTd"><strong>ContentDecryptionProvider</strong></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-5.2" rel="nofollow">AES_CBC_HMAC_SHA2</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">A128CBC-HS256(-HS384, -HS512)</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>AesCbcHmacJweEncryption,</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>AesCbcHmacJweDecryption</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-5.3" rel="nofollow">AES-GCM</a></td><td colspan="1" rowspan="1" class="confluenceTd"><p class="newpage">A128GCM, A92GCM, A256GCM</p></td><td colspan="1" rowspan="1" class="confluenceTd">AesGcmContentEncryptionAlgorithm</td><td colspan="1" rowspan="1" class="confluenceTd">AesGcmContentDecryptionAlgorithm</td></tr></tbody></table></div><p>All of the above providers can be initialized with the keys loaded from JWK or Java JKS stores or from the in-memory representations.</p><p>BouncyCastle is required if you use AES_CBC_HMAC content encryption.</p><p>Once you have decided which key and content encryption algorithms need to be supported you can initialize <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweEncryptionProvider.java" rel="nofollow">JwsEncryptionProvider</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweDecryptionProvider.java" rel="nofollow">JwsDecryptionProvider</a> which do the actual JWE encryption/decryption work by coordinating with the key and content encryption providers. CXF ships <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweEncryption.java" rel="nofollow">JweEncryption</a> (JwsEncryptionProvider) and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweDecryption.java" rel="nofollow">JweDecryption</a> (JweDecryptionProvider) helpers, simply pass them the preferred key and content encryption providers and have the content encrypted or decrypted.</p><p>JweEncryption and JweDecryption help with creating and processing JWE Compact sequences (see the next section).&#160; JweEncryption can also help with streaming JWE JSON sequences (see JAX-RS JWE filters section).</p><p>Note that <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java" rel="nofollow">AesCbcHmacJweEncryption</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweDecryption.java" rel="nofollow">AesCbcHmacJweDecryption</a> providers supporting <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-5.2" rel="nofollow">AES_CBC_HMAC_SHA2</a> contet encryption are extending JweEncryption and JweDecryption respectively. They implement <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7518#section-5.2.2" rel="nofollow">the content encryption</a> internally but do accept preferred key encryption/decryption providers.</p><p>Similarly, <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyJweEncryption.java" rel="nofollow">DirectKeyJweEncryption</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/DirectKeyJweDecryption.java" rel="nofollow">DirectKeyJweDecryption</a> are simple&#160;JweEncryption and JweDecryption extensions making it straighforward to do the direct key content encryption/decryption.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java" rel="nofollow">JweUtils</a> utility class has a lot of helper methods to load key and and content encryption providers and get the data encrypted and decrypted.</p><h3 id="JAXRSJOSE-JWECompact">JWE Compact</h3><p><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7516#section-3.3" rel="nofollow">JWE Compact representation</a> is the most often used JWE sequence format. It is the concatenation of 5 parts: Base64URL-encoded sequence of JWE headers (algorithm and other properties),&#160; Base64URL-encoded sequence of JWE encryption key (empty in case of the direct encryption), Base64URL-encoded sequence of JWE Initialization vector,&#160;Base64URL-encoded sequence of the produced ciphertext (encrypted data) and finally&#160;Base64URL-encoded sequence of the authentication tag (integrity protection for the headers and the ciphertext itself).</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweCompactProducer.java" rel="nofollow">JweCompactProducer</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweCompactConsumer.java" rel="nofollow">JweCompactConsumer</a> offer a basic support for creating and consuming compact JWE sequences. In most cases you will likely prefer to use <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweEncryption.java" rel="nofollow">JweEncryption</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweDecryption.java" rel="nofollow">JweDecryption</a> instead: <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweEncryption.java" rel="nofollow">JweEncryption</a> uses JweCompactProducer internally when its <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweEncryptionProvider.java#L27" rel="nofollow">encrypt</a> method is called (<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweEncryptionProvider.java#L32" rel="nofollow">getEncryptedOutput</a> will be discussed in the JAX-RS JWE filters section), and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweDecryption.java" rel="nofollow">JweDecryption</a> accepts only JWE Compact and uses JweCompactConsumer internally.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJwtCompactProducer.java" rel="nofollow">JweJwtCompactProducer</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java" rel="nofollow">JwsJwtCompactConsumer</a> help with directly encrypting typed JWT Tokens.</p><p>Here is the example of doing AES Key Wrap and&#160;AES CBC HMAC in CXF:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CXF Jwe AesWrapAesCbcHMac</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">final String specPlainText = "Live long and prosper.";
AesWrapKeyEncryptionAlgorithm keyEncryption = new AesWrapKeyEncryptionAlgorithm(KEY_ENCRYPTION_KEY_A3, KeyAlgorithm.A128KW);
JweEncryptionProvider encryption = new AesCbcHmacJweEncryption(ContentAlgorithm.A128CBC_HS256,
keyEncryption);
String jweContent = encryption.encrypt(specPlainText.getBytes("UTF-8"), null);
AesWrapKeyDecryptionAlgorithm keyDecryption = new AesWrapKeyDecryptionAlgorithm(cekEncryptionKey);
JweDecryptionProvider decryption = new AesCbcHmacJweDecryption(keyDecryption);
String decryptedText = decryption.decrypt(jweContent).getContentText();
assertEquals(specPlainText, decryptedText);</pre>
</div></div><p><br clear="none"></p><p>Here is another example using RSA-OAEP key encryption and AES-GCM content encryption:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CXF Jwe RsaOaepAesGcm</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">final String content = "Live long and prosper.";
// Load public RSA key from the JWK Key set stored on the disk
InputStream is = JsonWebKeyTest.class.getResourceAsStream(fileName);
JsonWebKeys keySet = JwkUtils.readJwkSet(is);
JsonWebKey jwkPublicRsaKey = keySet.getKey("Public RSA Key");
KeyEncryptionProvider keyEncryptionAlgo = JweUtils.getKeyEncryptionProvider(jwkPublicRsaKey);
ContentEncryptionProvider contentEncryptionAlgo = JweUtils.getContentEncryptionProvider(ContentAlgorithm.A256GCM);
JweEncryptionProvider encryptor = new JweEncryption(keyEncryptionAlgo, contentEncryptionAlgo);
// or simply
// JweEncryptionProvider encryptor = JweUtils.createJweEncryptionProvider(jwkPublicRsaKey, ContentAlgorithm.A256GCM);
String jweOut = encryptor.encrypt(content.getBytes(StandardCharsets.UTF_8), null);
// Load Private RSA Key from Java JKS Store
PrivateKey privateRsaKey =
CryptoUtils.loadPrivateKey(keyStoreLocation, keyStorePassword, privateKeyPassword, keyAlias, KeyStore.getDefaultType());
JweDecryptionProvider decryptor = JweUtils.createJweDecryptionProvider(jwkPrivateRsaKey, ContentAlgorithm.A256GCM);
String decryptedText = decryption.decrypt(jweContent).getContentText();
assertEquals(content, decryptedText);</pre>
</div></div><h3 id="JAXRSJOSE-JWEJSON">JWE JSON</h3><p>While JWE Compact is optimized and represents a concatenation of 5 Base64URL values, JWE JSON is an open JSON container, see <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7516#appendix-A.4" rel="nofollow">Appendix A4</a>.</p><p>The most interesting feature of JWE JSON is that allows a content be encrypted by multiple key encryption keys, with te resulting sequence targeted at multiple recipients. For example,&#160; the immediate consumer will decrypt the content with its own key decryption key, forward the payload to the next consumer, etc. &#160;</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducer.java" rel="nofollow">JweJsonProducer</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java" rel="nofollow">JweJsonConsumer</a> support producing and consuming JWS JSON sequences.</p><p>Here is the code example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>CXF JweJson</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">final String text = "The true sign of intelligence is not knowledge but imagination.";
// Create the secret keys for encrypting the content encryption key:
SecretKey wrapperKey1 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES1, "AES");
SecretKey wrapperKey2 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES2, "AES");
// Create KeyEncryptionProviders initialized with these secret keys:
KeyEncryptionProvider keyEncryption1 = JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey1, KeyAlgorithm.A128KW);
KeyEncryptionProvider keyEncryption2 = JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey2, KeyAlgorithm.A128KW);
// If you work with the public keys do this instead:
// PublicKey publicKey1 = ...;
// KeyEncryptionProvider keyEncryption1 = JweUtils.getPublicKeyEncryptionProvider(publicKey1, KeyAlgorithm.RSA_AEP);
// PublicKey publicKey2 = ...;
// KeyEncryptionProvider keyEncryption2 = JweUtils.getPublicKeyEncryptionProvider(publicKey2, KeyAlgorithm.RSA_AEP);
// Create ContentEncryptionProvider:
// Starting from CXF 3.1.11:
ContentEncryptionProvider contentEncryption = new AesGcmContentEncryptionAlgorithm(ContentAlgorithm.A128GCM, true);
// or
// ContentEncryptionProvider contentEncryption = JweUtils.getContentEncryptionProvider(ContentAlgorithm.A128GCM, true);
// Before CXF 3.1.1 a CEK needs to be pre-generated when dealing with multiple recipients:
//ContentEncryptionProvider contentEncryption = new AesGcmContentEncryptionAlgorithm(CEK_BYTES, ContentAlgorithm.A128GCM);
// If a single recipient then this line is enough:
//ContentEncryptionProvider contentEncryption = JweUtils.getContentEncryptionProvider(ContentAlgorithm.A128GCM);
// Prepare JweEncryptionProviders, one per each recipient.
List&lt;JweEncryptionProvider&gt; jweProviders = new LinkedList&lt;JweEncryptionProvider&gt;();
jweProviders.add(new JweEncryption(keyEncryption1, contentEncryption));
jweProviders.add(new JweEncryption(keyEncryption2, contentEncryption));
// Let the recipients know that the key encryption algorithm is A128KW.
// This step is optional if the recipients support A128KW only.
// Note because these headers are shared A128KW needs to be supported by all the recipients.
// Per-reciepient specific headers can be used instead to note the key encryption algorithm if required.
// One can also consider setting this property in the shared protected headers, same as it is done below
// with the content algorithm
JweHeaders sharedUnprotectedHeaders = new JweHeaders();
sharedUnprotectedHeaders.setKeyEncryptionAlgorithm(KeyAlgorithm.A128KW);
// Set some other custom shared unprotected header
sharedUnprotectedHeaders.setHeader("customHeader", "customValue");
// Let the recipients know that the content encryption algorithm is A128GCM.
// This step is optional if the recipients support A128GCM only.
JweHeaders protectedHeaders = new JweHeaders(ContentAlgorithm.A128GCM);
// Set per-recipient specific headers
List&lt;JweHeaders&gt; perRecipientHeades = new LinkedList&lt;JweHeaders&gt;();
perRecipientHeades.add(new JweHeaders("key1"));
perRecipientHeades.add(new JweHeaders("key2"));
JweJsonProducer p = new JweJsonProducer(protectedHeaders,
sharedUnprotectedHeaders,
StringUtils.toBytesUTF8(text),
StringUtils.toBytesUTF8(EXTRA_AAD_SOURCE),
false);
String jweJsonOut = p.encryptWith(jweProviders, perRecipientHeades);
JweJsonConsumer consumer = new JweJsonConsumer(jweJsonOut);
KeyAlgorithm keyAlgo = consumer.getSharedUnprotectedHeader().getKeyEncryptionAlgorithm();
ContentAlgorithm ctAlgo = consumer.getProtectedHeader().getContentEncryptionAlgorithm();
// first recipient:
JweDecryptionProvider jwe1 = JweUtils.createJweDecryptionProvider(wrapperKey1, keyAlgo, ctAlgo);
// the consumer will iterate over JWE entries and will try to find the one which can be decrypted with this decryptor
// or do consumer.getRecipientsMap() returning a list of entries and their metadata to do a more precise selection.
String content = consumer.decryptWith(jwe1, Collections.singletonMap("kid", "key1")).getContent();
// second recipient:
JweDecryptionProvider jwe2 = JweUtils.createJweDecryptionProvider(wrapperKey2, keyAlgo, ctAlgo);
content = consumer.decryptWith(jwe2, Collections.singletonMap("kid", "key2")).getContent();
</pre>
</div></div><p>If the sequence contains a single recipient entry only then the JWE JSON 'recipients' array will contain a single entry, or the whole sequence can be <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7516#appendix-A.5" rel="nofollow">flattened</a> instead with the actual 'recipients' array dropped. JweJsonProducer &#160;does not produce the flattened sequence when only a single encryption is done by default because 3rd party JWE JSON consumers may only be able to process the sequences with the 'recipients' array, so pass a 'canBeFlat' flag to JwEJsonProducer if needed</p><p>Does it make sense to use JWE JSON if you do not plan to do multiple encryptions ? Most likely you will prefer JWE Compact if only a single recipient is targeted.</p><h2 id="JAXRSJOSE-JSONWebToken">JSON Web Token</h2><p><a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7519" rel="nofollow">JWT</a> (JSON Web Token) is a collection of claims in JSON format. It is simply a regular JSON document where each top elevel property is called a 'claim'.</p><p>JWT can be JWS signed and/or JWE encrypted like any other data structure.</p><p>JWT is mainly used in OAuth2 and OIDC applications to represent self-contained OAuth2 access tokens, OIDC IdToken, UserInfo, but can also be used in other contexts. For example, see the section below on linking JWT authentication tokens to JWS or JWE secured payloads.</p><p>CXF offers a JWT support in <a shape="rect" class="external-link" href="https://github.com/apache/cxf/tree/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt" rel="nofollow">this package</a>. Typically one would create a set of claims and submit them to JWS/JWE JWT processors, for example, see a JWS section above.</p><h2 id="JAXRSJOSE-JWSandJWECombined">JWS and JWE Combined</h2><p>If you have a requirement to sign the data and then encrypt the signed payload then it can be easily achieved by selecting a required JWS Producer and creating a JWS Compact sequence, and next submitting this sequence to a JWE producer, and processing it all in the reverse sequence.</p><h1 id="JAXRSJOSE-JOSEJAX-RSFilters">JOSE JAX-RS Filters</h1><p><br clear="none"></p><p>While working directly with JWS and JWE providers may be needed in the application code, JAX-RS users writing the code like this:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Typical JAX-RS code</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">@Path("/bookstore")
public class BookStore {
public BookStore() {
}
@POST
@Path("/books")
@Produces("text/plain")
@Consumes("text/plain")
public String echoText(String text) {
return text;
}
@POST
@Path("/books")
@Produces("application/json")
@Consumes("application/json")
public Book echoBook(Book book) {
return book;
}
}</pre>
</div></div><p>would expect JWS and/or JWE processing done before the resource method is invoked or after this method returned some response.</p><p>This is what CXF JOSE JAX-RS filters do, they help the client or server code get the application data JWS- or JWE-secured. The filters do it by loadng the configuration properties as described below in the Configuration section, and produce or consume JWS or JWE sequences.</p><p>Note, JWS Compact and JSON, as well as JWE Compact client and server output filters can do the best effort at keeping the <strong>streaming</strong> process going while they are signing or encrypting the payload. JWE JSON client/server output filter and JWS Compact client/server input filters will be enhanced in due time to support the streaming too. Most of CXF JOSE system tests enable the streaming capable filters to stream. &#160;</p><p>JWS and JWE JSON input filters are expected to process JSON containers with the properties set in a random order hence by default they wil not stream the data in. &#160;</p><p>Register both JWS and JWE out filters if the data need to be signed and encrypted (the filters are ordered such that the data are signed first and encrypted next) and JWS and JWE in filters if the signed data need to be decrypted first and then verified.</p><h2 id="JAXRSJOSE-JWS">JWS</h2><h3 id="JAXRSJOSE-JWSCompact.1">JWS Compact</h3><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java" rel="nofollow">JwsWriterInterceptor</a> creates compact JWS sequences on the client or server out directions. For example, if you have the client code posting a Book or the server code returning a Book, with this Book representation expected to be signed, then add&#160;<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java" rel="nofollow">JwsWriterInterceptor</a> and set the signature properties on the JAX-RS client or server.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsClientResponseFilter.java" rel="nofollow">JwsClientResponseFilter</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsContainerRequestFilter.java" rel="nofollow">JwsContainerRequestFilter</a> process the incoming client or server Compact JWS sequences.</p><p>Here is an example of a JSON Book representation being HS256 signed and converted into&#160; Compact JWS and POSTed to the target service:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>Address: https://localhost:9001/jwsjwkhmac/bookstore/books
Http-Method: POST
Content-Type: application/jose
Payload:
eyJhbGciOiJIUzI1NiIsImN0eSI6Impzb24ifQ.
eyJCb29rIjp7ImlkIjoxMjMsIm5hbWUiOiJib29rIn19.
hg1T41ESuX6JvRR--huTA3HnbrsdIZSwkxQdyWj9j6c
org.apache.cxf.rs.security.jose.common.JoseUtils traceHeaders
INFO: JWS Headers:
{"alg":"HS256",
"cty":"json"}</pre>
</div></div><p><br clear="none"></p><p>You can see 3 JWS parts (put on separate lines for the better readibility) separated by dots. The 1st part is Base64Url encoded protected headers, next one - Base64Url encoded Book JSON payload, finally - the signature.</p><p>Note that the protected headers can be traced by enabling a "jose.debug" contextual property: once can see the signature algorithm is "HS256" and the content type of the signed payload is "json" which is a shorcut for a content type "application/json" where "application" is omitted.</p><p>The following client code can be used to set the client JWS Compact interceptors:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Client JWS SetUp</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default"> public void testJwsJwkBookHMac() throws Exception {
String address = "https://localhost:" + PORT + "/jwsjwkhmac";
BookStore bs = createJwsBookStore(address);
Book book = bs.echoBook(new Book("book", 123L));
assertEquals("book", book.getName());
assertEquals(123L, book.getId());
}
private BookStore createJwsBookStore(String address,
List&lt;?&gt; mbProviders) throws Exception {
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
bean.setServiceClass(BookStore.class);
bean.setAddress(address);
List&lt;Object&gt; providers = new LinkedList&lt;Object&gt;();
// JWS Compact Out
&#160;JwsWriterInterceptor jwsWriter = new JwsWriterInterceptor();
// enable streaming
&#160;jwsWriter.setUseJwsOutputStream(true);
// The payload is encoded by default, disable it if required
// jwsWriter.setEncodePayload(false);
&#160;providers.add(jwsWriter);
// JWS Compact In
&#160;providers.add(new JwsClientResponseFilter());
// Book to/from JSON
providers.add(new JacksonJsonProvider());
bean.setProviders(providers);
// point to the JWS security properties
bean.getProperties(true).put("rs.security.signature.properties",
"org/apache/cxf/systest/jaxrs/security/secret.jwk.properties");
// enable the tracing of JWS headers
bean.getProperties(true).put("jose.debug", true);
return bean.create(BookStore.class);
}</pre>
</div></div><p>The above code shows a client proxy code but WebClient can be created instead. The server is configured <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L197" rel="nofollow">here</a>. The client can be configured in Spring/Blueprint too.</p><h3 id="JAXRSJOSE-JWSCompactWithUnencodedPayload">JWS Compact With Unencoded Payload</h3><p>Starting from CXF 3.1.7 it is also possible to produce JWS Compact sequences with the unencoded payload (See JWS With Unencoded Payload above for restrictions).</p><p>Here is an example of a plain text "book" being HS256-signed, converted into JWS Compact and POSTed to the target service:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>Address: https://localhost:9001/jwsjwkhmac/bookstore/books
Http-Method: POST
Content-Type: application/jose
Payload: eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHQvcGxhaW4iLCJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdfQ.
book.
fM7O2IVO3NsQeTGrFiMeLf_TKTsMSqnqmjnK40PwQ88</pre>
</div></div><p>Note that a 2nd part, "book", is not Base64Url encoded. Set an 'encodePayload' option on the request or response JWS Compact filter to 'false'.</p><h3 id="JAXRSJOSE-JWSJSON.1">JWS JSON</h3><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonWriterInterceptor.java" rel="nofollow">JwsJsonWriterInterceptor</a> creates JWS JSON sequences on the client or server out directions.&#160;</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonClientResponseFilter.java" rel="nofollow">JwsJsonClientResponseFilter</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJsonContainerRequestFilter.java" rel="nofollow">JwsJsonContainerRequestFilter</a> process the incoming client or server Compact JWS sequences.</p><p>Here is an example of a plain text "book" being HS256-signed, converted into JWS JSON and POSTed to the target service:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>Http-Method: POST
Content-Type: application/jose+json
Payload:
{
"payload" : "Ym9vaw",
"signatures":
[
{
"protected" : "eyJhbGciOiJIUzI1NiIsImN0eSI6Impzb24ifQ",
"signature" : "dRUibW7F6LyXuOc78DHubUIave0QUSvte5iv6xoJaL4"
}
]
}</pre>
</div></div><p>Note the Base64Url encoded payload goes first, followed by the 'signatures' array, with each element containing the protected headers and the actual signature specific to a given signature key.</p><h3 id="JAXRSJOSE-JWSJSONwithUnencodedPayload">JWS JSON with Unencoded Payload</h3><p>Enabling the unencoded JWS payload option will produce:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>{
"payload" : "book",
"signatures":
[
{
"protected" : "eyJhbGciOiJIUzI1NiIsImN0eSI6InRleHQvcGxhaW4iLCJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdfQ",
"signature" : "fM7O2IVO3NsQeTGrFiMeLf_TKTsMSqnqmjnK40PwQ88"
}
]
}</pre>
</div></div><p>The client code and server configuration is nearly identical to a code/configuration needed to set up JWS Compact filters as shown above, simply replace JwsWriterInterceptor/JwsClientResponseFilter with JwsJsonWriterInterceptor/JwsJsonClientResponseFilter in the client code, and JwsContainerRequestFilter/JwsContainerResponseFilter with JwsJsonContainerRequestFilter/JwsJsonContainerResponseFilter</p><h2 id="JAXRSJOSE-SigningandVerificationofHTTPAttachments">Signing and Verification of HTTP Attachments</h2><p>The signing and verification of HTTP request and response attachments is supported starting from CXF 3.1.12.</p><p>This feature does not buffer the request and response attachment data and is completely streaming-'friendly'.</p><p>Note that in some cases the data may need to be buffered on the receiver end.</p><p>It depends on&#160;<a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7515#appendix-F" rel="nofollow">JWS with Detached Content</a> and&#160; <a shape="rect" class="external-link" href="https://tools.ietf.org/html/rfc7797" rel="nofollow">JWS with Unencoded Payload</a> options as well as on the newly introduced CXF <a shape="rect" href="http://cxf.apache.org/docs/jax-rs-multiparts.html#JAX-RSMultiparts-MultipartFilters">multipart filters</a> and works as follows.</p><p>When request or response attachment parts are about to be submitted to the Multipart serialization provider, JWS Multipart Output Filter (<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartClientRequestFilter.java" rel="nofollow">JwsMultipartClientRequestFilter</a> and/or <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartContainerResponseFilter.java" rel="nofollow">JwsMultipartContainerResponseFilter</a>) initializes a <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java" rel="nofollow">JWSSignature</a> object. Next every parts's output stream is replaced with the filtering output stream which updates the signature object on every write operation. Finally this multipart filter adds one more attachment part to the list of the attachments to be written - this part holds a reference to JWS Signature. When this last part is written, JWSSignature produces the signature bytes which are encoded using either JWS Compact or JWS JSON format, with the detached and unencoded content already being pushed to the output stream.</p><p>When the attachment parts are about to be read by the Multipart deserialization provider, their signature carried over in the last part will need to be verified. Just before the parts are about to be read in order to be made available to the application code, JWS Multipart Input Filter (<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartContainerRequestFilter.java" rel="nofollow">JwsMultipartContainerRequestFilter</a> and/or <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartClientResponseFilter.java" rel="nofollow">JwsMultipartClientResponseFilter</a>) checks the last part and initializes a <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsVerificationSignature.java" rel="nofollow">JWSVerificationSignature</a> object. Next for every attachment but the last one it replaces the input stream with the filtering input stream which updates the signature verification object on every read operation. Once all the data have been read it compares the calculated signature with the received signature.</p><p>Note when the attachments are accessed by the receiving application code, the read process will fail to complete if the validation fails. For example, if the application code copies a given part's InputStream to the disk then this copy operation will fail. For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">@POST
@Path("/books")
@Consumes("multipart/related")
public void uploadBookMultipart(@Multipart(type = "application/xml") Book book) {
// This method will not be even invoked if the data signature verification fails
// causing the construction of Book bean to fail
}
@POST
@Path("/pdf")
@Consumes("multipart/related")
public void uploadStreamMultipart(@Multipart(type = "application/pdf") InputStream is) {
OutputStream os = getTargetOutputStream();
// This copy operation will fail
IOUtils.copy(is, os);
}
</pre>
</div></div><p><br clear="none"></p><p>Note that besides the signature verification process, CXF offers some other indirect support for ensuring the attachment data have not been affected. For example, <a shape="rect" href="http://cxf.apache.org/docs/jax-rs-multiparts.html#JAX-RSMultiparts-Readinglargeattachments">the size of the attachments can be restricted</a>, and if the data stream is converted from XML then the conversion process will be controlled by the secure XML parser.&#160;</p><p>However, if the receiver starts acting immediately on the attachment's InputStream, for example, the attachment data returned from the service to the client are streamed to a UI display which can activate a script then it is important that a '<strong>bufferPayload</strong>' property is enabled on either <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartContainerRequestFilter.java" rel="nofollow">JwsMultipartContainerRequestFilter</a> or <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/multipart/JwsMultipartClientResponseFilter.java" rel="nofollow">JwsMultipartClientResponseFilter</a>. It will ensure that the data streams are validated first before the application gets an access to them.</p><p>The '<strong>bufferPayload</strong>' property may also need be enabled if the multipart payload contains many attachment parts. In this case, if the receiving code is written to consume all the parts in the order different to the one the parts have been ordered in the multipart payload or if the receiver code may optionally skip reading some of the parts, then the '<strong>bufferPayload</strong>' property must be enabled.</p><p>Here is an example showing how a Book object (represented as an XML attachment on the wire) can be secured.</p><p>Given this client code:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">@Test
public void testJwsJwkBookHMacMultipart() throws Exception {
String address = "https://localhost:" + PORT + "/jwsjwkhmacSinglePart";
BookStore bs = createJwsBookStoreHMac(address, true, false);
Book book = bs.echoBookMultipart(new Book("book", 123L));
assertEquals("book", book.getName());
assertEquals(123L, book.getId());
}
private BookStore createJwsBookStoreHMac(String address,
boolean supportSinglePart,
boolean useJwsJsonSignatureFormat) throws Exception {
JAXRSClientFactoryBean bean = createJAXRSClientFactoryBean(address, supportSinglePart,
useJwsJsonSignatureFormat);
bean.getProperties(true).put("rs.security.signature.properties",
"org/apache/cxf/systest/jaxrs/security/secret.jwk.properties");
bean.setServiceClass(BookStore.class);
bean.setAddress(address);
List&lt;Object&gt; providers = new LinkedList&lt;Object&gt;();
JwsMultipartClientRequestFilter outFilter = new JwsMultipartClientRequestFilter();
outFilter.setSupportSinglePartOnly(supportSinglePart);
outFilter.setUseJwsJsonSignatureFormat(useJwsJsonSignatureFormat);
providers.add(outFilter);
JwsMultipartClientResponseFilter inFilter = new JwsMultipartClientResponseFilter();
inFilter.setSupportSinglePartOnly(supportSinglePart);
providers.add(inFilter);
providers.add(new JwsDetachedSignatureProvider());
bean.setProviders(providers);
return bean.create(BookStore.class);
}</pre>
</div></div><p>and the relevant server code:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">@Path("/bookstore")
public class BookStore {
@POST
@Path("/books")
@Produces("multipart/related")
@Consumes("multipart/related")
@Multipart(type = "application/xml")
public Book echoBookMultipart(@Multipart(type = "application/xml") Book book) {
// This method will not be even invoked if the data signature verification fails
&#160;return book;
}
}</pre>
</div></div><p>and server configuration:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default">&lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:jaxrs="http://cxf.apache.org/jaxrs"&gt;
&lt;bean id="serviceBean" class="org.apache.cxf.systest.jaxrs.security.jose.BookStore"/&gt;
&lt;bean id="jwsInMultipartFilter" class="org.apache.cxf.rs.security.jose.jaxrs.multipart.JwsMultipartContainerRequestFilter"/&gt;
&lt;bean id="jwsOutMultipartFilter" class="org.apache.cxf.rs.security.jose.jaxrs.multipart.JwsMultipartContainerResponseFilter"/&gt;
&lt;bean id="jwsDetachedSignatureWriter" class="org.apache.cxf.rs.security.jose.jaxrs.JwsDetachedSignatureProvider"/&gt;
&lt;jaxrs:server address="https://localhost:${testutil.ports.jaxrs-jws-multipart}/jwsjwkhmacSinglePart"&gt;
&lt;jaxrs:serviceBeans&gt;
&lt;ref bean="serviceBean"/&gt;
&lt;/jaxrs:serviceBeans&gt;
&lt;jaxrs:providers&gt;
&lt;ref bean="jwsInMultipartFilter"/&gt;
&lt;ref bean="jwsOutMultipartFilter"/&gt;
&lt;ref bean="jwsDetachedSignatureWriter"/&gt;
&lt;/jaxrs:providers&gt;
&lt;jaxrs:properties&gt;
&lt;entry key="rs.security.signature.properties" value="org/apache/cxf/systest/jaxrs/security/secret.jwk.properties"/&gt;
&lt;/jaxrs:properties&gt;
&lt;/jaxrs:server&gt;
&lt;/beans</pre>
</div></div><p>the following request is produced on the wire:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>ID: 1
Address: https://localhost:9001/jwsjwkhmacSinglePart/bookstore/books
Http-Method: POST
Content-Type: multipart/related; type="application/xml"; boundary="uuid:35b4dd32-470d-4f27-b3c2-2c194f924770"; start="&lt;root.message@cxf.apache.org&gt;"
Headers: {Accept=[multipart/related], Connection=[Keep-Alive]}
Payload:
--uuid:35b4dd32-470d-4f27-b3c2-2c194f924770
Content-Type: application/xml
Content-Transfer-Encoding: binary
Content-ID: &lt;root.message@cxf.apache.org&gt;
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;Book&gt;&lt;id&gt;123&lt;/id&gt;&lt;name&gt;book&lt;/name&gt;&lt;/Book&gt;
--uuid:35b4dd32-470d-4f27-b3c2-2c194f924770
Content-Type: application/jose
Content-Transfer-Encoding: binary
Content-ID: &lt;signature&gt;
eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJIUzI1NiJ9..LWMjPoronjdGmJFAAIuCc_qh9sI2i5Jc2onBd-fHdMM
--uuid:35b4dd32-470d-4f27-b3c2-2c194f924770--</pre>
</div></div><p>with the response being formated identically.</p><p>Enabling a JWS JSON format will produce a flattened JWS JSON signature in the last part:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>ID: 1
Address: https://localhost:9001/jwsjwkhmacSinglePartJwsJson/bookstore/books
Http-Method: POST
Content-Type: multipart/related; type="application/xml"; boundary="uuid:75b37fab-1745-45b7-93ac-15aa9add9b25"; start="&lt;root.message@cxf.apache.org&gt;"
Headers: {Accept=[multipart/related], Connection=[Keep-Alive]}
Payload:
--uuid:75b37fab-1745-45b7-93ac-15aa9add9b25
Content-Type: application/xml
Content-Transfer-Encoding: binary
Content-ID: &lt;root.message@cxf.apache.org&gt;
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;Book&gt;&lt;id&gt;123&lt;/id&gt;&lt;name&gt;book&lt;/name&gt;&lt;/Book&gt;
--uuid:75b37fab-1745-45b7-93ac-15aa9add9b25
Content-Type: application/jose
Content-Transfer-Encoding: binary
Content-ID: &lt;signature&gt;
{"protected":"eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJIUzI1NiJ9","signature":"LWMjPoronjdGmJFAAIuCc_qh9sI2i5Jc2onBd-fHdMM"}
--uuid:75b37fab-1745-45b7-93ac-15aa9add9b25--</pre>
</div></div><h2 id="JAXRSJOSE-JWE">JWE</h2><h3 id="JAXRSJOSE-JWECompact.1">JWE Compact</h3><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java" rel="nofollow">JweWriterInterceptor</a> creates Compact JWE sequences on the client or server out directions. For example, if you have the client code posting a Book or the server code returning a Book, with this Book representation expected to be encrypted, then add&#160;<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java" rel="nofollow">JweWriterInterceptor</a> and set the encryption properties on the JAX-RS client or server.</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweClientResponseFilter.java" rel="nofollow">JweClientResponseFilter</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweContainerRequestFilter.java" rel="nofollow">JweContainerRequestFilter</a> process the incoming client or server Compact JWE sequences.</p><p>Here is an example of a plain text "book" being encrypted with the A128KW key and A128GCM content encryption (see JWE section above), converted into Compact JWE and POSTed to the target service:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>Address: https://localhost:9001/jwejwkaeswrap/bookstore/books
Http-Method: POST
Content-Type: application/jose
Payload:
eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwiY3R5IjoidGV4dC9wbGFpbiJ9.
SQul1USvHmADDLpBvY2Dnqk5GpoowOkJ.
cFuCSzRsl6GZuvHL.
akVT5g.
i8rpTk-v0b1IyE1sVT1IOA
org.apache.cxf.rs.security.jose.common.JoseUtils traceHeaders
INFO: JWE Headers:
{"alg":"A128KW",
"enc":"A128GCM",
"cty":"text/plain"}</pre>
</div></div><p>You can see 5 JWE parts (put on separate lines for the better readibility) separated by dots. The 1st part is Base64Url encoded protected headers, next one - Base64Url encoded content encryption key, next one - Base64Url encoded IV, next one - Base64Url encoded ciphertext, finally - the authentication tag.</p><p>Note that the protected headers can be traced by enabling a "jose.debug" contextual property: once can see the key encryption algorithm is "A128KW", content encryption algorithm is "A128GCM" and the content type of the encrypted payload is "text/plain".</p><p>The following client code can be used to set the client JWE Compact interceptors:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Client JWE SetUp</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default"> public void testJweJwkAesWrap() throws Exception {
String address = "https://localhost:" + PORT + "/jwejwkaeswrap";
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
bean.setServiceClass(BookStore.class);
bean.setAddress(address);
List&lt;Object&gt; providers = new LinkedList&lt;Object&gt;();
JweWriterInterceptor jweWriter = new JweWriterInterceptor();
jweWriter.setUseJweOutputStream(true);
providers.add(jweWriter);
providers.add(new JweClientResponseFilter());
bean.setProviders(providers);
bean.getProperties(true).put("rs.security.encryption.properties",
"org/apache/cxf/systest/jaxrs/security/secret.jwk.properties");
bean.getProperties(true).put("jose.debug", true);
BookStore bs = bean.create(BookStore.class);
String text = bs.echoText("book");
assertEquals("book", text);
}</pre>
</div></div><p>The above code shows a client proxy code but WebClient can be created instead. The server is configured <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L153" rel="nofollow">here</a>. The client can be configured in Spring/Blueprint too.</p><h3 id="JAXRSJOSE-JWEJSON.1">JWE JSON</h3><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweWriterInterceptor.java" rel="nofollow">JweJsonWriterInterceptor</a> creates JWE JSON sequences on the client or server out directions.&#160;</p><p><a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweJsonClientResponseFilter.java" rel="nofollow">JweJsonClientResponseFilter</a> and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JweContainerRequestFilter.java" rel="nofollow">JweContainerRequestFilter</a> process the incoming client or server JWE JSON sequences.</p><p>Here is the same example for encrypting "book" but with JWS JSON interceptors:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>Address: https://localhost:9001/jwejsonhmac/bookstore/books
Http-Method: POST
Content-Type: application/jose+json
Payload:
{
"protected" : "eyJlbmMiOiJBMTI4R0NNIiwiY3R5IjoidGV4dC9wbGFpbiIsImFsZyI6IkExMjhLVyJ9",
"recipients":
[
{
"encrypted_key": "iq1vJBpOHKRkMDoY2GTakWE6M_uPGVsh"
}
],
"iv":"SUpOEf-7Q1tT0JV_",
"ciphertext":"alKm_g",
"tag":"DkW2pZCd7lhR0KqIGQ69-A"
}</pre>
</div></div><p>Note the Base64Url encoded protected headers go first, followed by the 'recipients' array, with each element containing the encrypted content encryption key which can be decrypted by the recipient private key, with the array of recipients followed by the IV, ciphertext and authentication tag Base64Url sequences.</p><h2 id="JAXRSJOSE-LinkingJWTauthenticationstoJWSorJWEcontent">Linking JWT authentications to JWS or JWE content</h2><p>CXF introduced a "JWT" HTTP authentication scheme, with a Base64Url encoded JWT token representing a user authentication against an IDP capable of issuing JWT assertions (or simply JWT tokens). JWT assertion is like SAML assertion except that it is in a JSON format. If you'd like to cryptographically bind this JWT token to a data secured by JWS and/or JWE processors then simply add <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationClientFilter.java" rel="nofollow">JwtAuthenticationClientFilter</a> on the client side and <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose-jaxrs/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwtAuthenticationFilter.java" rel="nofollow">JwtAuthenticationFilter</a> on the server side. These filters link the authentication token with a randomly generated secure value which is added to both the token and the body JWS/JWE protected headers.</p><p>This approach is more effective compared to the ones where the body hash is calculated before it is submitted to a signature creation function, with the signature added as HTTP header.</p><h2 id="JAXRSJOSE-JWTauthorization">JWT authorization</h2><p>CXF supports both role and claims based authorization for JAX-RS endpoints based on information contained in a received JWT. Please see the <a shape="rect" href="jax-rs-token-authorization.html">JAX-RS Token Authorization</a> page for more information.</p><h2 id="JAXRSJOSE-OptionalprotectionofHTTPheaders">Optional protection of HTTP headers</h2><p>Starting from CXF 3.1.12 it is possible to use JWS, JWS JSON, JWE and JWE JSON filters to protect the selected set of HTTP headers. The JOSE payloads produced by these filters guarantee that the JOSE headers are integrity protected. Given this, if one enables a 'protectHttpHeaders' boolean property on the request filters, then, by default, HTTP Content-Type and Accept header values will be registered as JOSE header properties prefixed with "http.", example, "http.Accept":"text/plain". The list of the headers to be protected can be customized using a 'protectedHttpHeaders' set property.</p><p>These properties will be compared against the current HTTP headers on the receiving end.</p><p>This approach does not prevent the streaming of the outgoing data (which will also be protected by the filters) and offers a way to secure the HTTP headers which are really important for the correct processing of the incoming payloads</p><h1 id="JAXRSJOSE-JOSEinJAX-RSapplicationcode">JOSE in JAX-RS application code</h1><p>In some cases you may need to create or process the JOSE data directly in the service or client application code. For example, one of the properties in the request or response payload needs to be JWS signed/verified and/or JWE encrypted/decrypted. The following 2 options can be tried.</p><h2 id="JAXRSJOSE-Option1:ProcessJOSEdirectly">Option 1:&#160; Process JOSE directly</h2><p>This option is about using the CXF JOSE library to sign, encrypt, or/and decrypt and verify the data as <a shape="rect" href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=85460327">documented above</a>. This option should be preferred if one needs to keep a closer control, for example, set the custom JWS or JWE headers, etc.</p><h2 id="JAXRSJOSE-Option2:UseJOSElibraryhelpersandEndpointConfiguration">Option 2:&#160; Use JOSE library helpers and Endpoint Configuration</h2><p>This option makes it straighforward to do JOSE in the application code. One has to extend or delegate to a specific JOSE helper instance and configure the endpoint with the location of the JOSE properties file where the JWS or JWE algorithm and key store properties are set.</p><h3 id="JAXRSJOSE-ProduceJOSEdata">Produce JOSE data</h3><p>If you need to protect some non JWT property - extend or delegate to <strong>JoseProducer</strong>:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">import org.apache.cxf.rs.security.jose.common.JoseProducer;
@Path("service")
public class SecureService extends JoseProducer {
@GET
public String getProtectedValue() {
// encrypt and/or sign the data
return super.processData("some data");
}
}
// or
@Path("service")
public class SecureService extends AbstractSecureService {
private JoseProducer producer = new JoseProducer();
@GET
public String getProtectedValue() {
// encrypt and/or sign the data
return producer.processData("some data");
}
}</pre>
</div></div><p>If you need to protect some JWT property then extend or delegate to <strong>JoseJwtProducer</strong>:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">import org.apache.cxf.rs.security.jose.jwt.JoseJwtProducer;
@Path("service")
public class SecureService extends JoseJwtProducer {
@GET
public String getProtectedToken() {
// encrypt and/or sign JWT
JwtClaims claims = new JwtClaims();
claims.setIssuer("some issuer");
// set other claims
return super.processJwt(new JwtToken(claims));
}
}
// or
@Path("service")
public class SecureService extends AbstractSecureService {
private JoseJwtProducer producer = new JoseJwtProducer();
@GET
public String getProtectedValue() {
// encrypt and/or sign JWT
return producer.processJwt(new JwtToken(new JwtClaims()));
}
}</pre>
</div></div><p>&#160;In both cases the producer helpers will detect the endpoint specific configuration thus they do not need to be preconfigured - however if needed they have the 'encryptionProvider' and 'signatureProvider' setters which can be used to inject JwsSignatureProvider and/or JweEncryptionProvider instances instead.</p><p>The producer helpers require a signature creation only by default. Use their 'setJwsRequired' or 'setJwsRequired' properties to customize it - example, disable JWS but require JWE, or enable JWE to get JWS-protected data encrypted as well.</p><h3 id="JAXRSJOSE-ConsumeJOSEdata">Consume JOSE data</h3><p>If you need to decrypt and/or verify some non-JWT JOSE property - extend or delegate to <strong>JoseConsumer</strong>:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">import org.apache.cxf.rs.security.jose.common.JoseConsumer;
@Path("service")
public class SecureService extends JoseConsumer {
@POST
public void acceptProtectedValue(String joseValue) {
// decrypt the value first if needed, verify the signature
String data = super.getData(joseValue);
}
}
// or
@Path("service")
public class SecureService extends AbstractSecureService {
private JoseConsumer consumer = new JoseConsumer();
@POST
public void acceptProtectedValue(String joseValue) {
// decrypt the value first if needed, verify the signature
String data = consumer.getData(joseValue);
}
}</pre>
</div></div><p>If you need to&#160;decrypt and/or verify some JWT property then extend or delegate to <strong>JoseJwtConsumer</strong>:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">import org.apache.cxf.rs.security.jose.jwt.JoseJwtConsumer;
@Path("service")
public class SecureService extends JoseJwtConsumer {
@POST
public void acceptProtectedToken(String joseValue) {
// decrypt the value first if needed, verify the signature
JwtToken data = super.getJwtToken(joseValue);
}
}
// or
@Path("service")
public class SecureService extends AbstractSecureService {
private JoseJwtConsumer consumer = new JoseJwtConsumer();
@POST
public void acceptProtectedToken(String joseValue) {
// decrypt the value first if needed, verify the signature
JwtToken data = consumer.getJwtToken(joseValue);
}
}</pre>
</div></div><p>&#160;In both cases the producer helpers will detect the endpoint specific configuration thus they do not need to be preconfigured - however if needed they have the 'jweDecryptor' and 'jwsVerifier' setters which can be used to inject JwsSignatureVerifier and/or JweDecryptionProvider instances instead.</p><p>The producer helpers require a signature creation only by default. Use their 'setJwsRequired' or 'setJwsRequired' properties to customize it - example, disable JWS but require JWE, or enable JWE to get JWS-protected data encrypted as well.</p><h3 id="JAXRSJOSE-ProduceandConsumeJOSEdata">Produce and Consume JOSE data</h3><p>If you need to produce and consumer some non-JWT JOSE properties- extend or delegate to <strong>JoseProducerConsumer</strong>:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">import org.apache.cxf.rs.security.jose.common.JoseProducerConsumer;
@Path("service")
public class SecureService extends JoseProducerConsumer {
@POST
public String echoProtectedValue(String joseValue) {
// decrypt the value first if needed, verify the signature
String data = super.getData(joseValue);
// sign and/or encrypt the data
return super.processData(data);
}
}
// or
@Path("service")
public class SecureService extends AbstractSecureService {
private JoseProducerConsumer jose = new JoseProducerConsumer();
@POST
public String echoProtectedValue(String joseValue) {
// decrypt the value first if needed, verify the signature
String data = jose.getData(joseValue);
// sign and/or encrypt the data
return jose.processData(data);
}
}</pre>
</div></div><p>If you need to&#160;decrypt and/or verify some JWT property then extend or delegate to <strong>JoseJwtProducerConsumer</strong>:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">import org.apache.cxf.rs.security.jose.jwt.JoseJwtProducerConsumer;
@Path("service")
public class SecureService extends JoseJwtProducerConsumer {
@POST
public String echoProtectedToken(String joseValue) {
// decrypt the value first if needed, verify the signature
JwtToken data = super.getJwtToken(joseValue);
// sign and/or encrypt the data
return super.processJwt(data);
&#160;}
}
// or
@Path("service")
public class SecureService extends AbstractSecureService {
private JoseJwtProducerConsumer jose = new JoseJwtProducerConsumer();
@POST
public String echoProtectedToken(String joseValue) {
// decrypt the value first if needed, verify the signature
JwtToken data = jose.getJwtToken(joseValue);
// sign and/or encrypt the data
return jose.processJwt(data);
}
}</pre>
</div></div><p>In both cases this composite producer-consumer will use the internal producer and/or consumer helpers which will detect the endpoint specific configuration but which can also be injected with some specific JWE and/or JWS handlers.</p><h3 id="JAXRSJOSE-Configuretheendpoint">Configure the endpoint</h3><p>These properties will contain a location of the key store, signature and/or encryption algorithm properties, etc. See the <a shape="rect" href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=85460327">Configuration section</a> for all the available configuration options.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default">&lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:jaxrs="http://cxf.apache.org/jaxrs"&gt;
&lt;bean id="serviceBean" class="org.apache.cxf.systest.jaxrs.security.jose.SecureService"/&gt;
&lt;jaxrs:server address="/secure"&gt;
&lt;jaxrs:serviceBeans&gt;
&lt;ref bean="serviceBean"/&gt;
&lt;/jaxrs:serviceBeans&gt;
&lt;jaxrs:properties&gt;
&lt;entry key="rs.security.signature.properties" value="org/apache/cxf/systest/jaxrs/security/secret.jwk.properties"/&gt;
&lt;entry key="rs.security.encryption.properties" value="org/apache/cxf/systest/jaxrs/security/secret.jwk.properties"/&gt;
&lt;/jaxrs:properties&gt;
&lt;/jaxrs:server&gt;
&lt;/beans</pre>
</div></div><h1 id="JAXRSJOSE-Configuration">Configuration</h1><p>CXF JOSE configuration provides for loading JWS and JWE keys and supporting various processing options. Configuration properties can be shared between JWS and JWE processors or in/out only JWS and or JWE properties can be set.</p><p>Typically a secure JAX-RS endpoint or client is initialized with JWS and or JWE properties.</p><p>For example, <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L197" rel="nofollow">this endpoint</a> is configured with a <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L207" rel="nofollow">single JWS properties file</a> which will apply to both input (signature verification) and output (signature creation) JWS operations. <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L210" rel="nofollow">This endpoint</a> depends on <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L218" rel="nofollow">two JWS properties files</a>, one - for input JWS, another one - for output JWS. Similarly, <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L153" rel="nofollow">this endpoint</a> uses a <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L162" rel="nofollow">single JWE properties file</a> for encrypting/decrypting the data, while <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L139" rel="nofollow">this endpoint</a> uses <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L139" rel="nofollow">two JWE properties files</a>. <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L178" rel="nofollow">This endpoint</a> support both JWS and JSON with <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L189" rel="nofollow">in/out specific properties</a>. If either JWS or JWE private key needs to be loaded from the password-protected storage (JKS, encryped JWK)&#160; then a&#160;<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/PrivateKeyPasswordProvider.java" rel="nofollow">password provider</a> needs be <a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/server.xml#L194" rel="nofollow">registered</a> as well, it can be shared between JWS or JWS or be in/out specific for either JWS or JWE.</p><p>These configuration propertie are of major help when JAX-RS JOSE filters process the in/out payload without the application service code being aware of it. While filters can be injected with JWS or JWE providers directly, one would usually set the relevant properties as part of the endpoint or client set-up and expect the filters load the required JWS or JWE providers as needed.&#160;</p><p>If you need to do JWS or JWE processing directly in your service or interceptor code then having the properties may also be helpful, for example, the following code works because it is indirectly supported by the properties indicating which signature or encryption algorithm is used, where to get the key if needed, etc:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Loading JWS and JWE Providers </b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">JwsSignatureProvider jwsOut = JwsUtils.loadSignatureProvider(true);
JwsSignatureVerifier jwsIn = JwsUtils.loadSignatureVerifier(true);
JweEncryptionProvider jweOut = JweUtils.loadEncryptionProvider(true);
JweDecryptionProvider jweIn = JweUtils.loadDecryptionProvider(true);</pre>
</div></div><p>The providers may be initialized from a single properties file or each of them may have specific properties allocated to it.</p><p>Sometimes it can be useful to load the properties only and check the signature or encryption algorithm and load a JWS or JWE provider directly as shown in JWS and JWE sections above.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Loading JWS and JWE properties</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default">Properties jwsProps = JweUtils.loadEncryptionProperties("jws.properties", true);
Properties jweProps = JweUtils.loadEncryptionProperties("jwe.properties", true);</pre>
</div></div><p>After loading the properties one can check various property values (signature algorithm, etc) and use it to create a required provider.</p><p>The above code needs to be executed in the context of the current request (in server or client in/out interceptors or server service code) as it expects the current CXF Message be available in order to deduce where to load the configuration properties from. However&#160;<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java" rel="nofollow">JwsUtils</a> and&#160;<a shape="rect" class="external-link" href="https://github.com/apache/cxf/blob/master/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java" rel="nofollow">JweUtils</a> provide a number of utility methods for loading the providers without loading the properties first which can be used when setting up the client code or when no properties are available in the current request context.</p><p>When the code needs to load the configuration properties it first looks for the property 'container' file which contains the specific properties instructing which keys and algorithms need to be used. Singature or encryption properties for in/out operations can be provided. &#160;</p><h2 id="JAXRSJOSE-ConfigurationPropertyContainers">Configuration Property Containers</h2><h3 id="JAXRSJOSE-Signature">Signature</h3><div class="table-wrap"><table class="wrapped confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.out.properties</td><td colspan="1" rowspan="1" class="confluenceTd"><p>The signature properties file for Compact or JSON signature creation. If not specified then it falls back to "rs.security.signature.properties".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.in.properties</td><td colspan="1" rowspan="1" class="confluenceTd"><p>The signature properties file for Compact or JSON signature verification. If not specified then it falls back to "rs.security.signature.properties".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.properties</td><td colspan="1" rowspan="1" class="confluenceTd">The signature properties file for Compact or JSON signature creation/verification.</td></tr></tbody></table></div><h3 id="JAXRSJOSE-Encryption">Encryption</h3><div class="table-wrap"><table class="wrapped confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.out.properties</td><td colspan="1" rowspan="1" class="confluenceTd"><p>The encryption properties file for Compact or JSON encryption creation. If not specified then it falls back to "rs.security.encryption.properties".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.in.properties</td><td colspan="1" rowspan="1" class="confluenceTd"><p>The encryption properties file for Compact or JSON decryption. If not specified then it falls back to "rs.security.encryption.properties".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.properties</td><td colspan="1" rowspan="1" class="confluenceTd">The encryption properties file for encryption/decryption.</td></tr></tbody></table></div><p>Note that these property containers can be used for creating/processing JWS and JWE Compact and JSON sequences. If it is either JWS JSON or JWE JSON and you wish to have more than one signature or encryption be created then let the property value be a commas separated list of locations, with each location pointing to a unique signature or encryption operation property file.</p><p>Once the properties are loaded the runtime proceeds with initializing JWS/JWE providers accordingly. The following section lists the properties, some oif them being common and some - unique to the signature/verification and encryption/decryption processes.</p><p>Note that one can override some of the properties, for example, 'rs.security.store' can be set as a dynamic request property pointing to a preloaded Java KeyStore object.</p><h2 id="JAXRSJOSE-Configurationthatappliestobothencryptionandsignature">Configuration that applies to both encryption and signature</h2><div class="table-wrap"><table class="wrapped confluenceTable"><colgroup span="1"><col span="1"><col span="1"></colgroup><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.keystore</td><td colspan="1" rowspan="1" class="confluenceTd">The Java KeyStore Object to use. This configuration tag is used if you want to pass the KeyStore Object through dynamically.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>rs.security.keystore.type</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>The keystore type. Suitable values are "jks" or "jwk".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.keystore.password</td><td colspan="1" rowspan="1" class="confluenceTd">The password required to access the keystore.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.keystore.alias</td><td colspan="1" rowspan="1" class="confluenceTd">&#160;The keystore alias corresponding to the key to use. You can append one of the following to this tag to get the alias for more specific operations:<br clear="none">&#160;&#160;&#160;&#160; - jwe.out<br clear="none">&#160;&#160;&#160;&#160; - jwe.in<br clear="none">&#160;&#160;&#160;&#160; - jws.out<br clear="none">&#160;&#160;&#160;&#160; - jws.in</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.keystore.aliases</td><td colspan="1" rowspan="1" class="confluenceTd">The keystore aliases corresponding to the keys to use, when using the JSON serialization form. You can append one of the following to this tag to get the alias for more specific operations:<br clear="none">&#160;&#160;&#160;&#160; - jws.out<br clear="none">&#160;&#160;&#160;&#160; - jws.in</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.keystore.file</td><td colspan="1" rowspan="1" class="confluenceTd">The path to the keystore file.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.key.password</td><td colspan="1" rowspan="1" class="confluenceTd">The password required to access the private key (in the keystore).</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.key.password.provider</td><td colspan="1" rowspan="1" class="confluenceTd">A reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.accept.public.key</td><td colspan="1" rowspan="1" class="confluenceTd"><p>Whether to allow using a JWK received in the header for signature validation. The default is "false".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.enable.revocation <strong>CXF 3.4.0</strong></td><td colspan="1" rowspan="1" class="confluenceTd">Whether to enable revocation or not when validating a certificate chain. The default is "false".</td></tr></tbody></table></div><h2 id="JAXRSJOSE-Configurationthatappliestosignatureonly">Configuration that applies to signature only</h2><div class="table-wrap"><table class="wrapped confluenceTable"><colgroup span="1"><col span="1"><col span="1"></colgroup><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>rs.security.signature.key.password.provider</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>A reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys for signature. If this is not specified it falls back to use "rs.security.key.password.provider".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.algorithm</td><td colspan="1" rowspan="1" class="confluenceTd">The signature algorithm to use. The default algorithm if not specified is 'RS256'.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.include.public.key</td><td colspan="1" rowspan="1" class="confluenceTd">Include the JWK public key for signature in the "jwk" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.include.cert</td><td colspan="1" rowspan="1" class="confluenceTd">Include the X.509 certificate for signature in the "x5c" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.include.key.id</td><td colspan="1" rowspan="1" class="confluenceTd">Include the JWK key id for signature in the "kid" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.include.cert.sha1</td><td colspan="1" rowspan="1" class="confluenceTd">Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.signature.include.cert.sha256</td><td colspan="1" rowspan="1" class="confluenceTd">Include the X.509 certificate SHA-256 digest for signature in the "x5t#S256" header.</td></tr></tbody></table></div><h2 id="JAXRSJOSE-Configurationthatappliestoencryptiononly">Configuration that applies to encryption only</h2><div class="table-wrap"><table class="wrapped confluenceTable"><colgroup span="1"><col span="1"><col span="1"></colgroup><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>rs.security.decryption.key.password.provider</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>A reference to a PrivateKeyPasswordProvider instance used to retrieve passwords to access keys for decryption. If this is not specified it falls back to use "rs.security.key.password.provider".</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.content.algorithm</td><td colspan="1" rowspan="1" class="confluenceTd">The encryption content algorithm to use. The default algorithm if not specified is 'A128GCM'.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.key.algorithm</td><td colspan="1" rowspan="1" class="confluenceTd"><p>The encryption key algorithm to use. The default algorithm if not specified is 'RSA-OAEP' if the key is an RSA key, 'ECDH-ES-A128KW'&#160; if the key is an EC key and 'A128GCMKW' if it is an octet sequence.</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.zip.algorithm</td><td colspan="1" rowspan="1" class="confluenceTd">The encryption zip algorithm to use.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.include.public.key</td><td colspan="1" rowspan="1" class="confluenceTd">Include the JWK public key for&#160;encryption in the "jwk" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.include.cert</td><td colspan="1" rowspan="1" class="confluenceTd">Include the X.509 certificate for&#160;encryption in the "x5c" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.include.key.id</td><td colspan="1" rowspan="1" class="confluenceTd">Include the JWK key id for&#160;encryption in the "kid" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.include.cert.sha1</td><td colspan="1" rowspan="1" class="confluenceTd">Include the X.509 certificate SHA-1 digest for&#160;encryption in the "x5t" header.</td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">rs.security.encryption.include.cert.sha256</td><td colspan="1" rowspan="1" class="confluenceTd">Include the X.509 certificate SHA-256 digest for&#160;encryption in the "x5t#S256" header.</td></tr></tbody></table></div><h2 id="JAXRSJOSE-ConfigurationthatappliestoJWTtokensonly">Configuration that applies to JWT tokens only</h2><div class="table-wrap"><table class="wrapped confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>rs.security.enable.unsigned-jwt.principal</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Whether to allow unsigned JWT tokens as SecurityContext Principals. The default is false.</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd">expected.claim.audience</td><td colspan="1" rowspan="1" class="confluenceTd">If this property is defined, the received JWT must have an "aud" claim with a value matching this property.</td></tr></tbody></table></div><h1 id="JAXRSJOSE-Interoperability">Interoperability</h1><p><a shape="rect" class="external-link" href="https://datatracker.ietf.org/wg/jose/documents/" rel="nofollow">JOSE</a> is already widely supported in OAuth2 and OIDC applications. Besides that CXF JOSE client or server will interoperate with a 3rd party client/server able to produce or consume JWS/JWE sequences.&#160; For example, see a <a shape="rect" class="external-link" href="https://www.w3.org/TR/WebCryptoAPI/#jose" rel="nofollow">WebCrypto API use case</a> and&#160; <a shape="rect" class="external-link" href="https://mobilepki.org/WCPPSignatureDemo/home" rel="nofollow">the demo</a> which demonstrates how a JWS sequence produced by a browser-hosted script can be validated by a server application capable of processing JWS, with the demo browser client being tested against a CXF JWS server too.&#160;</p><h1 id="JAXRSJOSE-Third-PartyLibraries">Third-Party Libraries</h1><p><a shape="rect" class="external-link" href="https://bitbucket.org/b_c/jose4j/wiki/Home" rel="nofollow">Jose4J</a></p><p><a shape="rect" class="external-link" href="http://connect2id.com/products/nimbus-jose-jwt" rel="nofollow">Nimbus JOSE</a></p><p><br clear="none"></p></div>
</div>
<!-- Content -->
</td>
</tr>
</table>
</td>
<td id="cell-2-2" colspan="2">&nbsp;</td>
</tr>
<tr>
<td id="cell-3-0">&nbsp;</td>
<td id="cell-3-1">&nbsp;</td>
<td id="cell-3-2">
<div id="footer">
<!-- Footer -->
<div id="site-footer">
<a href="http://cxf.apache.org/privacy-policy.html">Privacy Policy</a> -
(<a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=41812304">edit page</a>)
(<a href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=41812304&amp;showComments=true&amp;showCommentArea=true#addcomment">add comment</a>)<br>
Apache CXF, CXF, Apache, the Apache feather logo are trademarks of The Apache Software Foundation.<br>
All other marks mentioned may be trademarks or registered trademarks of their respective owners.
</div>
<!-- Footer -->
</div>
</td>
<td id="cell-3-3">&nbsp;</td>
<td id="cell-3-4">&nbsp;</td>
</tr>
<tr>
<td id="cell-4-0" colspan="2">&nbsp;</td>
<td id="cell-4-1">&nbsp;</td>
<td id="cell-4-2" colspan="2">&nbsp;</td>
</tr>
</table>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-4458903-1");
pageTracker._trackPageview();
} catch(err) {}</script>
</body>
</html>