You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2015/02/17 18:43:00 UTC

cxf git commit: [CXF-6085] Prototyping JwsJsonConsumer

Repository: cxf
Updated Branches:
  refs/heads/master 6991bdb7f -> 5ca457f15


[CXF-6085] Prototyping JwsJsonConsumer


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/5ca457f1
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/5ca457f1
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/5ca457f1

Branch: refs/heads/master
Commit: 5ca457f153fc1e461d6d224f9bd27ef9a0874596
Parents: 6991bdb
Author: Sergey Beryozkin <sb...@talend.com>
Authored: Tue Feb 17 17:42:36 2015 +0000
Committer: Sergey Beryozkin <sb...@talend.com>
Committed: Tue Feb 17 17:42:36 2015 +0000

----------------------------------------------------------------------
 .../json/JsonMapObjectReaderWriter.java         |   6 +-
 .../rs/security/jose/jwe/JweJsonConsumer.java   | 181 +++++++++++++++++++
 .../jose/jwe/JweJsonEncryptionEntry.java        |   4 +
 .../cxf/rs/security/jose/jwe/JweUtils.java      |  20 +-
 .../security/jose/jwe/JweJsonConsumerTest.java  | 162 +++++++++++++++++
 .../security/jose/jwe/JweJsonProducerTest.java  |  28 ++-
 6 files changed, 382 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/5ca457f1/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
----------------------------------------------------------------------
diff --git a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
index dac1459..20e0777 100644
--- a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
+++ b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
@@ -115,7 +115,11 @@ public class JsonMapObjectReaderWriter {
             out.append("\r\n ");
         }
     }
-        
+    public JsonMapObject fromJsonToJsonObject(String json) {
+        JsonMapObject obj = new JsonMapObject();
+        fromJson(obj, json);
+        return obj;
+    }    
     public void fromJson(JsonMapObject obj, String json) {
         String theJson = json.trim();
         JsonObjectSettable settable = new JsonObjectSettable(obj);

http://git-wip-us.apache.org/repos/asf/cxf/blob/5ca457f1/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java
new file mode 100644
index 0000000..23a014f
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumer.java
@@ -0,0 +1,181 @@
+/**
+ * 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.
+ */
+package org.apache.cxf.rs.security.jose.jwe;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.jaxrs.provider.json.JsonMapObjectReaderWriter;
+import org.apache.cxf.rs.security.jose.JoseUtils;
+
+public class JweJsonConsumer {
+    private String protectedHeaderJson;
+    private JweHeaders protectedHeaderJwe;
+    private JweHeaders sharedUnprotectedHeader;
+    private List<JweJsonEncryptionEntry> recipients = new LinkedList<JweJsonEncryptionEntry>();
+    private Map<JweJsonEncryptionEntry, JweHeaders> recipientsMap = 
+        new LinkedHashMap<JweJsonEncryptionEntry, JweHeaders>();
+    private byte[] aad;
+    private byte[] iv;
+    private byte[] cipherBytes;
+    private byte[] authTag;
+    
+    private JsonMapObjectReaderWriter reader = new JsonMapObjectReaderWriter();
+    
+    public JweJsonConsumer(String payload) {
+        prepare(payload);
+    }
+
+    public JweDecryptionOutput decryptWith(JweDecryptionProvider jwe) {
+        JweJsonEncryptionEntry entry = getJweDecryptionEntry(jwe);
+        return decryptWith(jwe, entry);
+    }
+    public JweDecryptionOutput decryptWith(JweDecryptionProvider jwe, JweJsonEncryptionEntry entry) {
+        JweDecryptionInput jweDecryptionInput = getJweDecryptionInput(jwe, entry);
+        byte[] content = jwe.decrypt(jweDecryptionInput);
+        return new JweDecryptionOutput(jweDecryptionInput.getJweHeaders(), content);
+    }
+    
+    private JweDecryptionInput getJweDecryptionInput(JweDecryptionProvider jwe, JweJsonEncryptionEntry entry) {
+        if (jwe == null || entry == null) {
+            throw new SecurityException();
+        }
+        JweHeaders unionHeaders = recipientsMap.get(entry);
+        if (unionHeaders == null) {
+            throw new SecurityException();
+        }
+        JweDecryptionInput input = new JweDecryptionInput(entry.getEncryptedKey(),
+                                                          iv,
+                                                          cipherBytes,
+                                                          authTag,
+                                                          aad,
+                                                          protectedHeaderJson,
+                                                          unionHeaders);
+        return input;
+    }
+
+    private JweJsonEncryptionEntry getJweDecryptionEntry(JweDecryptionProvider jwe) {
+        for (Map.Entry<JweJsonEncryptionEntry, JweHeaders> entry : recipientsMap.entrySet()) {
+            String keyAlgo = entry.getValue().getKeyEncryptionAlgorithm();
+            if (keyAlgo != null && keyAlgo.equals(jwe.getKeyAlgorithm())
+                || keyAlgo == null && jwe.getKeyAlgorithm() == null) {
+                return entry.getKey();        
+            }    
+        }
+        return null;
+    }
+
+    private void prepare(String payload) {
+        Map<String, Object> jsonObjectMap = reader.fromJson(payload);
+        String encodedProtectedHeader = (String)jsonObjectMap.get("protected");
+        if (encodedProtectedHeader != null) {
+            protectedHeaderJson = JoseUtils.decodeToString(encodedProtectedHeader);
+            protectedHeaderJwe = 
+                new JweHeaders(reader.fromJson(protectedHeaderJson));
+        }
+        Map<String, Object> unprotectedHeader = CastUtils.cast((Map<?, ?>)jsonObjectMap.get("unprotected"));
+        sharedUnprotectedHeader = unprotectedHeader == null ? null : new JweHeaders(unprotectedHeader);
+        List<Map<String, Object>> encryptionArray = CastUtils.cast((List<?>)jsonObjectMap.get("recipients"));
+        if (encryptionArray != null) {
+            if (jsonObjectMap.containsKey("encryption_key")) {
+                throw new SecurityException("Invalid JWE JSON sequence");
+            }
+            for (Map<String, Object> encryptionEntry : encryptionArray) {
+                this.recipients.add(getEncryptionObject(encryptionEntry));
+            }
+        } else {
+            this.recipients.add(getEncryptionObject(jsonObjectMap));
+        }
+        aad = getDecodedBytes(jsonObjectMap, "aad");
+        cipherBytes = getDecodedBytes(jsonObjectMap, "ciphertext");
+        iv = getDecodedBytes(jsonObjectMap, "iv");
+        authTag = getDecodedBytes(jsonObjectMap, "tag");
+    }
+    protected JweJsonEncryptionEntry getEncryptionObject(Map<String, Object> encryptionEntry) {
+        Map<String, Object> header = CastUtils.cast((Map<?, ?>)encryptionEntry.get("header"));
+        JweHeaders recipientUnprotected = header == null ? null : new JweHeaders(header);
+        String encodedKey = (String)encryptionEntry.get("encrypted_key");
+        JweJsonEncryptionEntry entry = new JweJsonEncryptionEntry(recipientUnprotected, encodedKey);
+        
+        JweHeaders unionHeaders = new JweHeaders();
+        if (protectedHeaderJwe != null) {
+            unionHeaders.asMap().putAll(protectedHeaderJwe.asMap());
+            unionHeaders.setProtectedHeaders(protectedHeaderJwe);
+        }
+        if (sharedUnprotectedHeader != null) {
+            if (!Collections.disjoint(unionHeaders.asMap().keySet(), 
+                                      sharedUnprotectedHeader.asMap().keySet())) {
+                throw new SecurityException("Protected and unprotected headers have duplicate values");
+            }
+            unionHeaders.asMap().putAll(sharedUnprotectedHeader.asMap());
+        }
+        if (recipientUnprotected != null) {
+            if (!Collections.disjoint(unionHeaders.asMap().keySet(), 
+                                      recipientUnprotected.asMap().keySet())) {
+                throw new SecurityException("Protected and unprotected headers have duplicate values");
+            }
+            unionHeaders.asMap().putAll(recipientUnprotected.asMap());
+        }
+        
+        recipientsMap.put(entry, unionHeaders);
+        return entry;
+        
+    }
+    protected byte[] getDecodedBytes(Map<String, Object> map, String name) {
+        String value = (String)map.get(name);
+        if (value != null) {
+            return JoseUtils.decode(value);
+        }
+        return null;
+    }
+
+    public JweHeaders getProtectedHeader() {
+        return protectedHeaderJwe;
+    }
+
+    public JweHeaders getSharedUnprotectedHeader() {
+        return sharedUnprotectedHeader;
+    }
+
+    public byte[] getAad() {
+        return aad;
+    }
+    public String getAadText() {
+        if (aad == null) {
+            return null;
+        }
+        try {
+            return new String(aad, "UTF-8");
+        } catch (UnsupportedEncodingException ex) {
+            throw new SecurityException(ex);
+        }
+    }
+    public List<JweJsonEncryptionEntry> getRecipients() {
+        return recipients;
+    }
+
+    public Map<JweJsonEncryptionEntry, JweHeaders> getRecipientsMap() {
+        return recipientsMap;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/5ca457f1/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
index cdba53e..caa6d9f 100644
--- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweJsonEncryptionEntry.java
@@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 
 import org.apache.cxf.jaxrs.provider.json.JsonMapObjectReaderWriter;
+import org.apache.cxf.rs.security.jose.JoseUtils;
 
 public class JweJsonEncryptionEntry {
     private JweHeaders unprotectedHeader;
@@ -39,6 +40,9 @@ public class JweJsonEncryptionEntry {
     public String getEncodedEncryptedKey() {
         return encodedEncryptedKey;
     }
+    public byte[] getEncryptedKey() {
+        return encodedEncryptedKey == null ? null : JoseUtils.decode(encodedEncryptedKey);
+    }
     public String toJson() {
         JsonMapObjectReaderWriter jsonWriter = new JsonMapObjectReaderWriter();
         Map<String, Object> recipientsEntry = new LinkedHashMap<String, Object>();

http://git-wip-us.apache.org/repos/asf/cxf/blob/5ca457f1/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
index c5aba2a..feba8bc 100644
--- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
@@ -212,8 +212,13 @@ public final class JweUtils {
         return null;
     }
     public static JweEncryption getDirectKeyJweEncryption(JsonWebKey key) {
-        return new JweEncryption(new DirectKeyEncryptionAlgorithm(),
+        if (Algorithm.isAesCbcHmac(key.getAlgorithm())) {
+            return new AesCbcHmacJweEncryption(key.getAlgorithm(), JwkUtils.toSecretKey(key).getEncoded(), 
+                                               null, new DirectKeyEncryptionAlgorithm());
+        } else {
+            return new JweEncryption(new DirectKeyEncryptionAlgorithm(),
                                  getContentEncryptionAlgorithm(key, key.getAlgorithm()));
+        }
     }
     public static JweEncryption getDirectKeyJweEncryption(SecretKey key, String algorithm) {
         if (Algorithm.isAesCbcHmac(algorithm)) {
@@ -225,12 +230,21 @@ public final class JweUtils {
         }
     }
     public static JweDecryption getDirectKeyJweDecryption(SecretKey key, String algorithm) {
-        return new JweDecryption(new DirectKeyDecryptionAlgorithm(key), 
+        if (Algorithm.isAesCbcHmac(algorithm)) { 
+            return new AesCbcHmacJweDecryption(new DirectKeyDecryptionAlgorithm(key), algorithm);
+        } else {
+            return new JweDecryption(new DirectKeyDecryptionAlgorithm(key), 
                                  getContentDecryptionAlgorithm(algorithm));
+        }
     }
     public static JweDecryption getDirectKeyJweDecryption(JsonWebKey key) {
-        return new JweDecryption(new DirectKeyDecryptionAlgorithm(JwkUtils.toSecretKey(key)), 
+        if (Algorithm.isAesCbcHmac(key.getAlgorithm())) { 
+            return new AesCbcHmacJweDecryption(
+                new DirectKeyDecryptionAlgorithm(JwkUtils.toSecretKey(key).getEncoded()), key.getAlgorithm());
+        } else {
+            return new JweDecryption(new DirectKeyDecryptionAlgorithm(JwkUtils.toSecretKey(key)), 
                                  getContentDecryptionAlgorithm(key.getAlgorithm()));
+        }
     }
     public static JweEncryptionProvider loadEncryptionProvider(boolean required) {
         return loadEncryptionProvider(null, required);

http://git-wip-us.apache.org/repos/asf/cxf/blob/5ca457f1/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java
new file mode 100644
index 0000000..0fcdece
--- /dev/null
+++ b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonConsumerTest.java
@@ -0,0 +1,162 @@
+/**
+ * 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.
+ */
+package org.apache.cxf.rs.security.jose.jwe;
+
+import java.security.Security;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.JoseConstants;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class JweJsonConsumerTest extends Assert {
+
+    static final String SINGLE_RECIPIENT_ALL_HEADERS_AAD_MODIFIED_OUTPUT = 
+        "{" 
+        + "\"protected\":\"eyJlbmMiOiJBMTI4R0NNIn0\","
+        + "\"unprotected\":{\"jku\":\"https://server.example.com/keys.jwks\"},"    
+        + "\"recipients\":" 
+        + "["
+        + "{"
+        + "\"header\":{\"alg\":\"A128KW\"},"
+        + "\"encrypted_key\":\"b3-M9_CRgT3wEBhhXlpb-BoY7vtA4W_N\""
+        + "}"
+        + "],"
+        + "\"aad\":\"" + Base64UrlUtility.encode(JweJsonProducerTest.EXTRA_AAD_SOURCE + ".") + "\","
+        + "\"iv\":\"48V1_ALb6US04U3b\","
+        + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
+        + "\"tag\":\"oVUQGS9608D-INq61-vOaA\""
+        + "}";
+    
+    @BeforeClass
+    public static void registerBouncyCastleIfNeeded() throws Exception {
+        try {
+            Cipher.getInstance(Algorithm.AES_GCM_ALGO_JAVA);
+            Cipher.getInstance(Algorithm.AES_CBC_ALGO_JAVA);
+        } catch (Throwable t) {
+            Security.addProvider(new BouncyCastleProvider());    
+        }
+    }
+    @AfterClass
+    public static void unregisterBouncyCastleIfNeeded() throws Exception {
+        Security.removeProvider(BouncyCastleProvider.class.getName());    
+    }
+    
+    @Test
+    public void testSingleRecipientGcm() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        doTestSingleRecipient(text, 
+                              JweJsonProducerTest.SINGLE_RECIPIENT_OUTPUT, 
+                              JoseConstants.A128GCM_ALGO, 
+                              JweJsonProducerTest.WRAPPER_BYTES1,
+                              null);
+    }
+    @Test
+    public void testSingleRecipientFlatGcm() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        doTestSingleRecipient(text, 
+                              JweJsonProducerTest.SINGLE_RECIPIENT_FLAT_OUTPUT, 
+                              JoseConstants.A128GCM_ALGO, 
+                              JweJsonProducerTest.WRAPPER_BYTES1,
+                              null);
+    }
+    @Test
+    public void testSingleRecipientDirectGcm() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        doTestSingleRecipient(text, 
+                              JweJsonProducerTest.SINGLE_RECIPIENT_DIRECT_OUTPUT, 
+                              JoseConstants.A128GCM_ALGO, 
+                              null, 
+                              JweJsonProducerTest.CEK_BYTES);
+    }
+    @Test
+    public void testSingleRecipientDirectA128CBCHS256() throws Exception {
+        String text = "Live long and prosper.";
+        doTestSingleRecipient(text, 
+                              JweJsonProducerTest.SINGLE_RECIPIENT_A128CBCHS256_DIRECT_OUTPUT, 
+                              JoseConstants.A128CBC_HS256_ALGO, 
+                              null,
+                              JweCompactReaderWriterTest.CONTENT_ENCRYPTION_KEY_A3);
+    }
+    @Test
+    public void testSingleRecipientA128CBCHS256() throws Exception {
+        String text = "Live long and prosper.";
+        doTestSingleRecipient(text, 
+                              JweJsonProducerTest.SINGLE_RECIPIENT_A128CBCHS256_OUTPUT, 
+                              JoseConstants.A128CBC_HS256_ALGO, 
+                              Base64UrlUtility.decode(JweCompactReaderWriterTest.KEY_ENCRYPTION_KEY_A3),
+                              null);
+    }
+    @Test
+    public void testSingleRecipientAllTypeOfHeadersAndAad() {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        
+        SecretKey wrapperKey = CryptoUtils.createSecretKeySpec(JweJsonProducerTest.WRAPPER_BYTES1, 
+                                                               "AES");
+        JweDecryptionProvider jwe = JweUtils.createJweDecryptionProvider(wrapperKey, JoseConstants.A128KW_ALGO, 
+                                                                         JoseConstants.A128GCM_ALGO);
+        JweJsonConsumer consumer = new JweJsonConsumer(JweJsonProducerTest.SINGLE_RECIPIENT_ALL_HEADERS_AAD_OUTPUT);
+        JweDecryptionOutput out = consumer.decryptWith(jwe);
+        assertEquals(text, out.getContentText());
+        assertEquals(JweJsonProducerTest.EXTRA_AAD_SOURCE, consumer.getAadText());
+    }
+    @Test
+    public void testSingleRecipientAllTypeOfHeadersAndAadModified() {
+        SecretKey wrapperKey = CryptoUtils.createSecretKeySpec(JweJsonProducerTest.WRAPPER_BYTES1, 
+                                                               "AES");
+        JweDecryptionProvider jwe = JweUtils.createJweDecryptionProvider(wrapperKey, JoseConstants.A128KW_ALGO, 
+                                                                         JoseConstants.A128GCM_ALGO);
+        JweJsonConsumer consumer = new JweJsonConsumer(SINGLE_RECIPIENT_ALL_HEADERS_AAD_MODIFIED_OUTPUT);
+        try {
+            consumer.decryptWith(jwe);
+            fail("AAD check has passed unexpectedly");
+        } catch (SecurityException ex) {
+            // expected
+        }
+        
+    }
+    private void doTestSingleRecipient(String text,
+                                       String input, 
+                                       String contentEncryptionAlgo,
+                                       final byte[] wrapperKeyBytes,
+                                       final byte[] cek) throws Exception {
+        JweDecryptionProvider jwe = null;
+        if (wrapperKeyBytes != null) {
+            SecretKey wrapperKey = CryptoUtils.createSecretKeySpec(wrapperKeyBytes, "AES");
+            jwe = JweUtils.createJweDecryptionProvider(wrapperKey, JoseConstants.A128KW_ALGO, contentEncryptionAlgo);
+        } else {
+            SecretKey cekKey = CryptoUtils.createSecretKeySpec(cek, "AES");
+            jwe = JweUtils.getDirectKeyJweDecryption(cekKey, contentEncryptionAlgo);
+        }
+        JweJsonConsumer consumer = new JweJsonConsumer(input);
+        JweDecryptionOutput out = consumer.decryptWith(jwe);
+        assertEquals(text, out.getContentText());
+    }
+    
+}
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/5ca457f1/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
index 0fdcc97..1fa0c9f 100644
--- a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
+++ b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
@@ -38,10 +38,10 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class JweJsonProducerTest extends Assert {
-    private static final byte[] WRAPPER_BYTES1 = {91, 96, 105, 38, 99, 108, 110, 8, -93, 50, -15, 62, 0, -115, 73, -39};
-    private static final byte[] WRAPPER_BYTES2 = {-39, 96, 105, 38, 99, 108, 110, 8, -93, 50, -15, 62, 0, -115, 73, 91};
-    private static final byte[] CEK_BYTES = {-43, 123, 77, 115, 40, 49, -4, -9, -48, -74, 62, 59, 60, 102, -22, -100};
-    private static final String SINGLE_RECIPIENT_OUTPUT = 
+    static final byte[] WRAPPER_BYTES1 = {91, 96, 105, 38, 99, 108, 110, 8, -93, 50, -15, 62, 0, -115, 73, -39};
+    static final byte[] WRAPPER_BYTES2 = {-39, 96, 105, 38, 99, 108, 110, 8, -93, 50, -15, 62, 0, -115, 73, 91};
+    static final byte[] CEK_BYTES = {-43, 123, 77, 115, 40, 49, -4, -9, -48, -74, 62, 59, 60, 102, -22, -100};
+    static final String SINGLE_RECIPIENT_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0\","
         + "\"recipients\":" 
@@ -52,7 +52,7 @@ public class JweJsonProducerTest extends Assert {
         + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
         + "\"tag\":\"GxWlwvTPmHi4ZnQgafiHew\""
         + "}";
-    private static final String SINGLE_RECIPIENT_FLAT_OUTPUT = 
+    static final String SINGLE_RECIPIENT_FLAT_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0\","
         + "\"encrypted_key\":\"b3-M9_CRgT3wEBhhXlpb-BoY7vtA4W_N\","
@@ -60,7 +60,7 @@ public class JweJsonProducerTest extends Assert {
         + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
         + "\"tag\":\"GxWlwvTPmHi4ZnQgafiHew\""
         + "}";
-    private static final String SINGLE_RECIPIENT_DIRECT_OUTPUT = 
+    static final String SINGLE_RECIPIENT_DIRECT_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJlbmMiOiJBMTI4R0NNIn0\","
         + "\"recipients\":" 
@@ -71,14 +71,14 @@ public class JweJsonProducerTest extends Assert {
         + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
         + "\"tag\":\"Te59ApbK8wNBDY_1_dgYSw\""
         + "}";
-    private static final String SINGLE_RECIPIENT_DIRECT_FLAT_OUTPUT = 
+    static final String SINGLE_RECIPIENT_DIRECT_FLAT_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJlbmMiOiJBMTI4R0NNIn0\","
         + "\"iv\":\"48V1_ALb6US04U3b\","
         + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
         + "\"tag\":\"Te59ApbK8wNBDY_1_dgYSw\""
         + "}";
-    private static final String SINGLE_RECIPIENT_ALL_HEADERS_AAD_OUTPUT = 
+    static final String SINGLE_RECIPIENT_ALL_HEADERS_AAD_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJlbmMiOiJBMTI4R0NNIn0\","
         + "\"unprotected\":{\"jku\":\"https://server.example.com/keys.jwks\"},"    
@@ -89,14 +89,12 @@ public class JweJsonProducerTest extends Assert {
         + "\"encrypted_key\":\"b3-M9_CRgT3wEBhhXlpb-BoY7vtA4W_N\""
         + "}"
         + "],"
-        + "\"aad\":\"WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5keWJ1Y"
-                    + "2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0"
-                    + "IiwiVEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d\","
+        + "\"aad\":\"" + Base64UrlUtility.encode(JweJsonProducerTest.EXTRA_AAD_SOURCE) + "\","
         + "\"iv\":\"48V1_ALb6US04U3b\","
         + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
         + "\"tag\":\"oVUQGS9608D-INq61-vOaA\""
         + "}";
-    private static final String MULTIPLE_RECIPIENTS_OUTPUT = 
+    static final String MULTIPLE_RECIPIENTS_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJlbmMiOiJBMTI4R0NNIn0\","
         + "\"unprotected\":{\"jku\":\"https://server.example.com/keys.jwks\",\"alg\":\"A128KW\"},"    
@@ -116,7 +114,7 @@ public class JweJsonProducerTest extends Assert {
         + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
         + "\"tag\":\"oVUQGS9608D-INq61-vOaA\""
         + "}";
-    private static final String EXTRA_AAD_SOURCE = 
+    static final String EXTRA_AAD_SOURCE = 
         "[\"vcard\",["
         + "[\"version\",{},\"text\",\"4.0\"],"
         + "[\"fn\",{},\"text\",\"Meriadoc Brandybuck\"],"
@@ -124,7 +122,7 @@ public class JweJsonProducerTest extends Assert {
         + "[\"bday\",{},\"text\",\"TA 2982\"],"
         + "[\"gender\",{},\"text\",\"M\"]"
         + "]]";
-    private static final String SINGLE_RECIPIENT_A128CBCHS256_OUTPUT = 
+    static final String SINGLE_RECIPIENT_A128CBCHS256_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
         + "\"recipients\":" 
@@ -135,7 +133,7 @@ public class JweJsonProducerTest extends Assert {
         + "\"ciphertext\":\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
         + "\"tag\":\"U0m_YmjN04DJvceFICbCVQ\""
         + "}";
-    private static final String SINGLE_RECIPIENT_A128CBCHS256_DIRECT_OUTPUT = 
+    static final String SINGLE_RECIPIENT_A128CBCHS256_DIRECT_OUTPUT = 
         "{" 
         + "\"protected\":\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
         + "\"recipients\":"