You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2017/11/17 17:01:59 UTC

[cxf] branch master updated: CXF-7568 - Support JWE PBES encryption

This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/master by this push:
     new eeae043  CXF-7568 - Support JWE PBES encryption
eeae043 is described below

commit eeae04330ebd610be9cb46891e9f05851afad2a4
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Fri Nov 17 17:01:19 2017 +0000

    CXF-7568 - Support JWE PBES encryption
---
 .../cxf/rs/security/jose/common/JoseConstants.java |  9 +-
 .../security/jose/common/KeyManagementUtils.java   |  4 +-
 .../apache/cxf/rs/security/jose/jwe/JweUtils.java  | 99 ++++++++++++++--------
 .../security/jose/jwejws/JweJwsAlgorithmTest.java  | 61 +++++++++++++
 .../security/jose/jwejws/algorithms-server.xml     | 19 +++++
 5 files changed, 155 insertions(+), 37 deletions(-)

diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
index 9fb4bdf..a6897a9 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
@@ -173,7 +173,7 @@ public final class JoseConstants {
      * Include the X.509 certificate SHA-1 digest for signature in the "x5t" header.
      */
     public static final String RSSEC_SIGNATURE_INCLUDE_CERT_SHA1 = "rs.security.signature.include.cert.sha1";
-    
+
     /**
      * Include the X.509 certificate SHA-256 digest for signature in the "x5t#S256" header.
      */
@@ -241,12 +241,17 @@ public final class JoseConstants {
      * Include the X.509 certificate SHA-1 digest for encryption in the "x5t" header.
      */
     public static final String RSSEC_ENCRYPTION_INCLUDE_CERT_SHA1 = "rs.security.encryption.include.cert.sha1";
-    
+
     /**
      * Include the X.509 certificate SHA-256 digest for encryption in the "x5t#S256" header.
      */
     public static final String RSSEC_ENCRYPTION_INCLUDE_CERT_SHA256 = "rs.security.encryption.include.cert.sha256";
 
+    /**
+     * The value to be used for the "p2c" (PBES2 count) Header Parameter. The default is 4096.
+     */
+    public static final String RSSEC_ENCRYPTION_PBES2_COUNT = "rs.security.encryption.pbes2.count";
+
     //
     // JWT specific configuration
     //
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
index 3063971..5a7942b 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/KeyManagementUtils.java
@@ -439,7 +439,7 @@ public final class KeyManagementUtils {
         if (props == null) {
             if (required) {
                 LOG.warning("Properties resource is not identified");
-                throw new JoseException();
+                throw new JoseException("Properties resource is not identified");
             }
             props = new Properties();
         }
@@ -509,7 +509,7 @@ public final class KeyManagementUtils {
 
         return null;
     }
-    
+
     public static void setSha1DigestHeader(JoseHeaders headers, Message m, Properties props) {
         String digest = loadDigestAndEncodeX509Certificate(m, props, MessageDigestUtils.ALGO_SHA_1);
         if (digest != null) {
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
index d45ada7..8447a59 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
@@ -44,11 +44,13 @@ import javax.crypto.SecretKey;
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.phase.PhaseInterceptorChain;
 import org.apache.cxf.rs.security.jose.common.JoseConstants;
 import org.apache.cxf.rs.security.jose.common.JoseHeaders;
 import org.apache.cxf.rs.security.jose.common.JoseUtils;
 import org.apache.cxf.rs.security.jose.common.KeyManagementUtils;
+import org.apache.cxf.rs.security.jose.common.PrivateKeyPasswordProvider;
 import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
 import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
 import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
@@ -270,7 +272,7 @@ public final class JweUtils {
     public static ContentEncryptionProvider getContentEncryptionProvider(ContentAlgorithm algorithm) {
         return getContentEncryptionProvider(algorithm, false);
     }
-    public static ContentEncryptionProvider getContentEncryptionProvider(ContentAlgorithm algorithm, 
+    public static ContentEncryptionProvider getContentEncryptionProvider(ContentAlgorithm algorithm,
                                                                          boolean generateCekOnce) {
         if (AlgorithmUtils.isAesGcm(algorithm.getJwaName())) {
             return new AesGcmContentEncryptionAlgorithm(algorithm, generateCekOnce);
@@ -367,9 +369,9 @@ public final class JweUtils {
         Message m = PhaseInterceptorChain.getCurrentMessage();
         return loadEncryptionProvider(props, m, headers);
     }
-    
+
     public static JweEncryptionProvider loadEncryptionProvider(Properties props, Message m, JweHeaders headers) {
-    
+
         KeyEncryptionProvider keyEncryptionProvider = loadKeyEncryptionProvider(props, m, headers);
         ContentAlgorithm contentAlgo = getContentEncryptionAlgorithm(m, props, null, ContentAlgorithm.A128GCM);
         if (m != null) {
@@ -383,7 +385,7 @@ public final class JweUtils {
                     jwk.getAlgorithm() != null ? ContentAlgorithm.getAlgorithm(jwk.getAlgorithm()) : null,
                     contentAlgo);
                 ctEncryptionProvider = getContentEncryptionProvider(jwk, contentAlgo);
-            }         
+            }
         }
         String compression = props.getProperty(JoseConstants.RSSEC_ENCRYPTION_ZIP_ALGORITHM);
         return createJweEncryptionProvider(keyEncryptionProvider,
@@ -392,21 +394,31 @@ public final class JweUtils {
                                     compression,
                                     headers);
     }
-    
+
     public static KeyEncryptionProvider loadKeyEncryptionProvider(Properties props, Message m, JweHeaders headers) {
-        
+
         KeyEncryptionProvider keyEncryptionProvider = null;
         KeyAlgorithm keyAlgo = getKeyEncryptionAlgorithm(m, props, null, null);
+
         if (KeyAlgorithm.DIRECT == keyAlgo) {
-            keyEncryptionProvider = new DirectKeyEncryptionAlgorithm();    
+            keyEncryptionProvider = new DirectKeyEncryptionAlgorithm();
+        } else if (keyAlgo != null && AlgorithmUtils.PBES_HS_SET.contains(keyAlgo.getJwaName())) {
+            PrivateKeyPasswordProvider provider =
+                KeyManagementUtils.loadPasswordProvider(m, props, KeyOperation.ENCRYPT);
+            char[] password = provider != null ? provider.getPassword(props) : null;
+            if (password == null) {
+                throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE);
+            }
+            int pbes2Count = MessageUtils.getContextualInteger(m, JoseConstants.RSSEC_ENCRYPTION_PBES2_COUNT, 4096);
+            return new PbesHmacAesWrapKeyEncryptionAlgorithm(new String(password), pbes2Count, keyAlgo, false);
         } else {
-            boolean includeCert = 
+            boolean includeCert =
                 JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT);
-            boolean includeCertSha1 = 
+            boolean includeCertSha1 =
                 JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA1);
-            boolean includeCertSha256 =  
+            boolean includeCertSha256 =
                 JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_CERT_SHA256);
-            boolean includeKeyId = 
+            boolean includeKeyId =
                 JoseUtils.checkBooleanProperty(headers, props, m, JoseConstants.RSSEC_ENCRYPTION_INCLUDE_KEY_ID);
 
             if (JoseConstants.HEADER_JSON_WEB_KEY.equals(props.get(JoseConstants.RSSEC_KEY_STORE_TYPE))) {
@@ -416,9 +428,9 @@ public final class JweUtils {
                                                         KeyAlgorithm.getAlgorithm(jwk.getAlgorithm()),
                                                         getDefaultKeyAlgorithm(jwk));
                     keyEncryptionProvider = getKeyEncryptionProvider(jwk, keyAlgo);
-    
-                    boolean includePublicKey = 
-                        JoseUtils.checkBooleanProperty(headers, props, m, 
+
+                    boolean includePublicKey =
+                        JoseUtils.checkBooleanProperty(headers, props, m,
                                                        JoseConstants.RSSEC_ENCRYPTION_INCLUDE_PUBLIC_KEY);
                     if (includeCert) {
                         JwkUtils.includeCertChain(jwk, headers, keyAlgo.getJwaName());
@@ -458,10 +470,10 @@ public final class JweUtils {
         }
         headers.setKeyEncryptionAlgorithm(keyEncryptionProvider.getAlgorithm());
         return keyEncryptionProvider;
-        
+
     }
-    
-    
+
+
     public static JweDecryptionProvider loadDecryptionProvider(boolean required) {
         return loadDecryptionProvider(null, required);
     }
@@ -494,7 +506,7 @@ public final class JweUtils {
                 keyAlgo = getDefaultPrivateKeyAlgorithm(privateKey);
             }
             contentAlgo = inHeaders.getContentEncryptionAlgorithm();
-            
+
             keyDecryptionProvider = getPrivateKeyDecryptionProvider(privateKey, keyAlgo);
         } else if (inHeaders != null && inHeaders.getHeader(JoseConstants.HEADER_X509_THUMBPRINT) != null) {
             X509Certificate foundCert =
@@ -543,6 +555,14 @@ public final class JweUtils {
                                                         getDefaultKeyAlgorithm(jwk));
                     keyDecryptionProvider = getKeyDecryptionProvider(jwk, keyAlgo);
                 }
+            } else if (keyAlgo != null && AlgorithmUtils.PBES_HS_SET.contains(keyAlgo.getJwaName())) {
+                PrivateKeyPasswordProvider provider =
+                    KeyManagementUtils.loadPasswordProvider(m, props, KeyOperation.DECRYPT);
+                char[] password = provider != null ? provider.getPassword(props) : null;
+                if (password == null) {
+                    throw new JweException(JweException.Error.KEY_DECRYPTION_FAILURE);
+                }
+                keyDecryptionProvider = new PbesHmacAesWrapKeyDecryptionAlgorithm(new String(password));
             } else {
                 PrivateKey privateKey = KeyManagementUtils.loadPrivateKey(m, props, KeyOperation.DECRYPT);
                 if (keyAlgo == null) {
@@ -554,7 +574,7 @@ public final class JweUtils {
         return createJweDecryptionProvider(keyDecryptionProvider, ctDecryptionKey,
                                            contentAlgo);
     }
-    
+
     public static JweEncryptionProvider createJweEncryptionProvider(PublicKey key,
                                                                     KeyAlgorithm keyAlgo,
                                                                     ContentAlgorithm contentEncryptionAlgo) {
@@ -611,7 +631,7 @@ public final class JweUtils {
                 contentEncryptionAlgo.getJwaName(), compression, null);
         return createJweEncryptionProvider(keyEncryptionProvider, headers);
     }
-    
+
     public static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider,
                                                                     JweHeaders headers) {
         return createJweEncryptionProvider(keyEncryptionProvider, headers, false);
@@ -662,7 +682,7 @@ public final class JweUtils {
                           JwkUtils.toECPublicKey(peerPublicKey),
                           partyUInfo, partyVInfo, algoName, algoKeyBitLen);
     }
-    
+
     public static byte[] getECDHKey(ECPrivateKey privateKey,
                                     ECPublicKey peerPublicKey,
                                     byte[] partyUInfo,
@@ -670,17 +690,17 @@ public final class JweUtils {
                                     String algoName,
                                     int algoKeyBitLen) {
         // Validate the peerPublicKey first
-        
-        // Credits: 
+
+        // Credits:
         // https://neilmadden.wordpress.com/2017/05/17/so-how-do-you-validate-nist-ecdh-public-keys/
-        // https://blogs.adobe.com/security/2017/03/critical-vulnerability-uncovered-in-json-encryption.html 
-        
-        // Step 1: Verify public key is not point at infinity. 
+        // https://blogs.adobe.com/security/2017/03/critical-vulnerability-uncovered-in-json-encryption.html
+
+        // Step 1: Verify public key is not point at infinity.
         if (ECPoint.POINT_INFINITY.equals(peerPublicKey.getW())) {
             throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE);
         }
         EllipticCurve curve = peerPublicKey.getParams().getCurve();
-        
+
         final BigInteger x = peerPublicKey.getW().getAffineX();
         final BigInteger y = peerPublicKey.getW().getAffineY();
         final BigInteger p = ((ECFieldFp) curve.getField()).getP();
@@ -699,7 +719,7 @@ public final class JweUtils {
         if (!ySquared.equals(xCubedPlusAXPlusB)) {
             throw new JweException(JweException.Error.KEY_ENCRYPTION_FAILURE);
         }
-        
+
         // Step 4: Verify that nQ = 0, where n is the order of the curve and Q is the public key.
         // As per http://www.secg.org/sec1-v2.pdf section 3.2.2:
         // "In Step 4, it may not be necessary to compute the point nQ. For example, if h = 1, then nQ = O is implied
@@ -710,7 +730,7 @@ public final class JweUtils {
         }
 
         // Finally calculate the derived key
-        
+
         byte[] keyZ = generateKeyZ(privateKey, peerPublicKey);
         return calculateDerivedKey(keyZ, algoName, partyUInfo, partyVInfo, algoKeyBitLen);
     }
@@ -800,7 +820,7 @@ public final class JweUtils {
         }
         return headers;
     }
-    
+
     private static JweEncryptionProvider createJweEncryptionProvider(KeyEncryptionProvider keyEncryptionProvider,
                                                                      ContentEncryptionProvider ctEncryptionProvider,
                                                                      ContentAlgorithm contentEncryptionAlgo,
@@ -840,7 +860,7 @@ public final class JweUtils {
     public static KeyAlgorithm getKeyEncryptionAlgorithm(Properties props, KeyAlgorithm defaultAlgo) {
         return getKeyEncryptionAlgorithm(PhaseInterceptorChain.getCurrentMessage(), props, defaultAlgo);
     }
-    public static KeyAlgorithm getKeyEncryptionAlgorithm(Message m, Properties props, KeyAlgorithm defaultAlgo) {    
+    public static KeyAlgorithm getKeyEncryptionAlgorithm(Message m, Properties props, KeyAlgorithm defaultAlgo) {
         String algo = KeyManagementUtils.getKeyAlgorithm(m,
                                                   props,
                                                   JoseConstants.RSSEC_ENCRYPTION_KEY_ALGORITHM,
@@ -867,7 +887,7 @@ public final class JweUtils {
         return algo;
     }
     public static ContentAlgorithm getContentEncryptionAlgorithm(Properties props) {
-        return getContentEncryptionAlgorithm(PhaseInterceptorChain.getCurrentMessage(), props, null); 
+        return getContentEncryptionAlgorithm(PhaseInterceptorChain.getCurrentMessage(), props, null);
     }
     public static ContentAlgorithm getContentEncryptionAlgorithm(Properties props,
                                                                  ContentAlgorithm defaultAlgo) {
@@ -901,6 +921,12 @@ public final class JweUtils {
     }
     public static Properties loadEncryptionInProperties(boolean required) {
         Message m = PhaseInterceptorChain.getCurrentMessage();
+        String keyEncryptionAlgorithm =
+            (String)m.getContextualProperty(JoseConstants.RSSEC_ENCRYPTION_KEY_ALGORITHM);
+        if (keyEncryptionAlgorithm != null && AlgorithmUtils.PBES_HS_SET.contains(keyEncryptionAlgorithm)) {
+            // We don't need to load the keystore properties for the PBES case
+            required = false;
+        }
         return KeyManagementUtils.loadStoreProperties(m, required,
                                                       JoseConstants.RSSEC_ENCRYPTION_IN_PROPS,
                                                       JoseConstants.RSSEC_ENCRYPTION_PROPS);
@@ -908,6 +934,13 @@ public final class JweUtils {
     }
     public static Properties loadEncryptionOutProperties(boolean required) {
         Message m = PhaseInterceptorChain.getCurrentMessage();
+        String keyEncryptionAlgorithm =
+            (String)m.getContextualProperty(JoseConstants.RSSEC_ENCRYPTION_KEY_ALGORITHM);
+        if (keyEncryptionAlgorithm != null && AlgorithmUtils.PBES_HS_SET.contains(keyEncryptionAlgorithm)) {
+            // We don't need to load the keystore properties for the PBES case
+            required = false;
+        }
+
         return KeyManagementUtils.loadStoreProperties(m, required,
                                                       JoseConstants.RSSEC_ENCRYPTION_OUT_PROPS,
                                                       JoseConstants.RSSEC_ENCRYPTION_PROPS);
@@ -936,7 +969,7 @@ public final class JweUtils {
         JsonWebKey jwk = JwkUtils.fromPublicKey(key, props, JoseConstants.RSSEC_ENCRYPTION_KEY_ALGORITHM);
         return new JsonWebKeys(jwk);
     }
-    
+
     public static Properties loadJweProperties(Message m, String propLoc) {
         try {
             return JoseUtils.loadProperties(propLoc, m.getExchange().getBus());
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JweJwsAlgorithmTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JweJwsAlgorithmTest.java
index 2ca1dcb..d96b1db 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JweJwsAlgorithmTest.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/jose/jwejws/JweJwsAlgorithmTest.java
@@ -313,9 +313,70 @@ public class JweJwsAlgorithmTest extends AbstractBusClientServerTestBase {
         assertNotEquals(response.getStatus(), 200);
     }
 
+    @org.junit.Test
+    public void testEncryptionPBES() throws Exception {
+
+        URL busFile = JweJwsAlgorithmTest.class.getResource("client.xml");
+
+        List<Object> providers = new ArrayList<>();
+        providers.add(new JacksonJsonProvider());
+        providers.add(new JweWriterInterceptor());
+
+        String address = "http://localhost:" + PORT + "/jwepbes/bookstore/books";
+        WebClient client =
+            WebClient.create(address, providers, busFile.toString());
+        client.type("application/json").accept("application/json");
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("rs.security.encryption.content.algorithm", "A128GCM");
+        properties.put("rs.security.encryption.key.algorithm", "PBES2-HS256+A128KW");
+        String password = "123456789123456789";
+        properties.put("rs.security.key.password.provider", new PrivateKeyPasswordProviderImpl(password));
+        WebClient.getConfig(client).getRequestContext().putAll(properties);
+
+        Response response = client.post(new Book("book", 123L));
+        assertEquals(response.getStatus(), 200);
+
+        Book returnedBook = response.readEntity(Book.class);
+        assertEquals(returnedBook.getName(), "book");
+        assertEquals(returnedBook.getId(), 123L);
+    }
+
+    @org.junit.Test
+    public void testEncryptionPBESDifferentCount() throws Exception {
+
+        URL busFile = JweJwsAlgorithmTest.class.getResource("client.xml");
+
+        List<Object> providers = new ArrayList<>();
+        providers.add(new JacksonJsonProvider());
+        providers.add(new JweWriterInterceptor());
+
+        String address = "http://localhost:" + PORT + "/jwepbes/bookstore/books";
+        WebClient client =
+            WebClient.create(address, providers, busFile.toString());
+        client.type("application/json").accept("application/json");
+
+        Map<String, Object> properties = new HashMap<>();
+        String password = "123456789123456789";
+        properties.put("rs.security.encryption.content.algorithm", "A128GCM");
+        properties.put("rs.security.encryption.key.algorithm", "PBES2-HS256+A128KW");
+        properties.put("rs.security.key.password.provider", new PrivateKeyPasswordProviderImpl(password));
+        properties.put("rs.security.encryption.pbes2.count", "1000");
+        WebClient.getConfig(client).getRequestContext().putAll(properties);
+
+        Response response = client.post(new Book("book", 123L));
+        assertEquals(response.getStatus(), 200);
+
+        Book returnedBook = response.readEntity(Book.class);
+        assertEquals(returnedBook.getName(), "book");
+        assertEquals(returnedBook.getId(), 123L);
+    }
+
+
     //
     // Signature tests
     //
+
     @org.junit.Test
     public void testSignatureProperties() throws Exception {
 
diff --git a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/algorithms-server.xml b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/algorithms-server.xml
index c1cfebc..7d33348 100644
--- a/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/algorithms-server.xml
+++ b/systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/jose/jwejws/algorithms-server.xml
@@ -61,6 +61,25 @@ under the License.
        </jaxrs:properties>
    </jaxrs:server>
    
+   <bean id="pbesKeyProvider" class="org.apache.cxf.systest.jaxrs.security.jose.jwejws.PrivateKeyPasswordProviderImpl">
+       <constructor-arg>
+           <value>123456789123456789</value> 
+       </constructor-arg>
+   </bean>
+   
+   <jaxrs:server address="http://localhost:${testutil.ports.jaxrs-jwejws-algorithms}/jwepbes">
+       <jaxrs:serviceBeans>
+          <ref bean="serviceBean"/>
+       </jaxrs:serviceBeans>
+       <jaxrs:providers>
+          <ref bean="jweInFilter"/>
+       </jaxrs:providers>
+       <jaxrs:properties>
+            <entry key="rs.security.encryption.key.algorithm" value="PBES2-HS256+A128KW"/>
+            <entry key="rs.security.key.password.provider" value-ref="pbesKeyProvider"/>
+       </jaxrs:properties>
+   </jaxrs:server>
+   
     <bean id="jwsInFilter" class="org.apache.cxf.rs.security.jose.jaxrs.JwsContainerRequestFilter"/>
     
     <jaxrs:server address="http://localhost:${testutil.ports.jaxrs-jwejws-algorithms}/jws">

-- 
To stop receiving notification emails like this one, please contact
['"commits@cxf.apache.org" <co...@cxf.apache.org>'].