cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject [10/18] cxf git commit: Renaming jose module
Date Wed, 21 Oct 2015 13:27:50 GMT
http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
new file mode 100644
index 0000000..86c1425
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
@@ -0,0 +1,310 @@
+/**
+ * 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 java.util.LinkedList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.StringUtils;
+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;
+import org.apache.cxf.rt.security.crypto.CryptoUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class JweJsonProducerTest extends Assert {
+    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\":" 
+        + "["
+        + "{\"encrypted_key\":\"b3-M9_CRgT3wEBhhXlpb-BoY7vtA4W_N\"}"
+        + "],"
+        + "\"iv\":\"48V1_ALb6US04U3b\","
+        + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
+        + "\"tag\":\"GxWlwvTPmHi4ZnQgafiHew\""
+        + "}";
+    static final String SINGLE_RECIPIENT_FLAT_OUTPUT = 
+        "{" 
+        + "\"protected\":\"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0\","
+        + "\"encrypted_key\":\"b3-M9_CRgT3wEBhhXlpb-BoY7vtA4W_N\","
+        + "\"iv\":\"48V1_ALb6US04U3b\","
+        + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
+        + "\"tag\":\"GxWlwvTPmHi4ZnQgafiHew\""
+        + "}";
+    static final String SINGLE_RECIPIENT_DIRECT_OUTPUT = 
+        "{" 
+        + "\"protected\":\"eyJlbmMiOiJBMTI4R0NNIn0\","
+        + "\"recipients\":" 
+        + "["
+        + "{}"
+        + "],"
+        + "\"iv\":\"48V1_ALb6US04U3b\","
+        + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
+        + "\"tag\":\"Te59ApbK8wNBDY_1_dgYSw\""
+        + "}";
+    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\""
+        + "}";
+    static final String SINGLE_RECIPIENT_ALL_HEADERS_AAD_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\""
+        + "}";
+    static final String MULTIPLE_RECIPIENTS_OUTPUT = 
+        "{" 
+        + "\"protected\":\"eyJlbmMiOiJBMTI4R0NNIn0\","
+        + "\"unprotected\":{\"jku\":\"https://server.example.com/keys.jwks\",\"alg\":\"A128KW\"},"    
+        + "\"recipients\":" 
+        + "["
+        + "{"
+        + "\"encrypted_key\":\"b3-M9_CRgT3wEBhhXlpb-BoY7vtA4W_N\""
+        + "},"
+        + "{"
+        + "\"encrypted_key\":\"6a_nnEYO45qB_Vp6N2QbFQ7Cv1uecbiE\""
+        + "}"
+        + "],"
+        + "\"aad\":\"WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5keWJ1Y"
+                    + "2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0"
+                    + "IiwiVEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d\","
+        + "\"iv\":\"48V1_ALb6US04U3b\","
+        + "\"ciphertext\":\"KTuJBMk9QG59xPB-c_YLM5-J7VG40_eMPvyHDD7eB-WHj_34YiWgpBOydTBm4RW0zUCJZ09xqorhWJME-DcQ\","
+        + "\"tag\":\"oVUQGS9608D-INq61-vOaA\""
+        + "}";
+    static final String EXTRA_AAD_SOURCE = 
+        "[\"vcard\",["
+        + "[\"version\",{},\"text\",\"4.0\"],"
+        + "[\"fn\",{},\"text\",\"Meriadoc Brandybuck\"],"
+        + "[\"n\",{},\"text\",[\"Brandybuck\",\"Meriadoc\",\"Mr.\",\"\"]],"
+        + "[\"bday\",{},\"text\",\"TA 2982\"],"
+        + "[\"gender\",{},\"text\",\"M\"]"
+        + "]]";
+    static final String SINGLE_RECIPIENT_A128CBCHS256_OUTPUT = 
+        "{" 
+        + "\"protected\":\"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
+        + "\"recipients\":" 
+        + "["
+        + "{\"encrypted_key\":\"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ\"}"
+        + "],"
+        + "\"iv\":\"AxY8DCtDaGlsbGljb3RoZQ\","
+        + "\"ciphertext\":\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
+        + "\"tag\":\"U0m_YmjN04DJvceFICbCVQ\""
+        + "}";
+    static final String SINGLE_RECIPIENT_A128CBCHS256_DIRECT_OUTPUT = 
+        "{" 
+        + "\"protected\":\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
+        + "\"recipients\":" 
+        + "["
+        + "{}"
+        + "],"
+        + "\"iv\":\"AxY8DCtDaGlsbGljb3RoZQ\","
+        + "\"ciphertext\":\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
+        + "\"tag\":\"Mz-VPPyU4RlcuYv1IwIvzw\""
+        + "}";
+    @BeforeClass
+    public static void registerBouncyCastleIfNeeded() throws Exception {
+        try {
+            Cipher.getInstance(AlgorithmUtils.AES_GCM_ALGO_JAVA);
+            Cipher.getInstance(AlgorithmUtils.AES_CBC_ALGO_JAVA);
+        } catch (Throwable t) {
+            Security.addProvider(new BouncyCastleProvider());    
+        }
+    }
+    @AfterClass
+    public static void unregisterBouncyCastleIfNeeded() throws Exception {
+        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);    
+    }
+    
+    @Test
+    public void testSingleRecipientGcm() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        doTestSingleRecipient(text, SINGLE_RECIPIENT_OUTPUT, ContentAlgorithm.A128GCM, 
+                              WRAPPER_BYTES1, JweCompactReaderWriterTest.INIT_VECTOR_A1, 
+                              CEK_BYTES, false);
+    }
+    @Test
+    public void testSingleRecipientDirectGcm() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        doTestSingleRecipient(text, SINGLE_RECIPIENT_DIRECT_OUTPUT, ContentAlgorithm.A128GCM, 
+                              null, JweCompactReaderWriterTest.INIT_VECTOR_A1, 
+                              CEK_BYTES, false);
+    }
+    @Test
+    public void testSingleRecipientDirectFlatGcm() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        doTestSingleRecipient(text, SINGLE_RECIPIENT_DIRECT_FLAT_OUTPUT, ContentAlgorithm.A128GCM, 
+                              null, JweCompactReaderWriterTest.INIT_VECTOR_A1, 
+                              CEK_BYTES, true);
+    }
+    @Test
+    public void testSingleRecipientFlatGcm() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        doTestSingleRecipient(text, SINGLE_RECIPIENT_FLAT_OUTPUT, ContentAlgorithm.A128GCM, 
+                              WRAPPER_BYTES1, JweCompactReaderWriterTest.INIT_VECTOR_A1, 
+                              CEK_BYTES, true);
+    }
+    @Test
+    public void testSingleRecipientA128CBCHS256() throws Exception {
+        String text = "Live long and prosper.";
+        doTestSingleRecipient(text, SINGLE_RECIPIENT_A128CBCHS256_OUTPUT, ContentAlgorithm.A128CBC_HS256, 
+                              Base64UrlUtility.decode(JweCompactReaderWriterTest.KEY_ENCRYPTION_KEY_A3),
+                              JweCompactReaderWriterTest.INIT_VECTOR_A3,
+                              JweCompactReaderWriterTest.CONTENT_ENCRYPTION_KEY_A3,
+                              false);
+    }
+    @Test
+    public void testSingleRecipientDirectA128CBCHS256() throws Exception {
+        String text = "Live long and prosper.";
+        doTestSingleRecipient(text, SINGLE_RECIPIENT_A128CBCHS256_DIRECT_OUTPUT, ContentAlgorithm.A128CBC_HS256, 
+                              null,
+                              JweCompactReaderWriterTest.INIT_VECTOR_A3,
+                              JweCompactReaderWriterTest.CONTENT_ENCRYPTION_KEY_A3,
+                              false);
+    }
+    
+    private String doTestSingleRecipient(String text,
+                                         String expectedOutput, 
+                                         ContentAlgorithm contentEncryptionAlgo,
+                                         final byte[] wrapperKeyBytes,
+                                         final byte[] iv,
+                                         final byte[] cek,
+                                         boolean canBeFlat) throws Exception {
+        JweHeaders headers = new JweHeaders(KeyAlgorithm.A128KW,
+                                            contentEncryptionAlgo);
+        JweEncryptionProvider jwe = null;
+        if (wrapperKeyBytes == null) {
+            headers.asMap().remove("alg");
+            SecretKey cekKey = CryptoUtils.createSecretKeySpec(cek, "AES");
+            jwe = JweUtils.getDirectKeyJweEncryption(cekKey, contentEncryptionAlgo);
+        } else {
+            SecretKey wrapperKey = CryptoUtils.createSecretKeySpec(wrapperKeyBytes, "AES");
+            jwe = JweUtils.createJweEncryptionProvider(wrapperKey, headers);
+        }
+        JweJsonProducer p = new JweJsonProducer(headers, StringUtils.toBytesUTF8(text), canBeFlat) {
+            protected JweEncryptionInput createEncryptionInput(JweHeaders jsonHeaders) {
+                JweEncryptionInput input = super.createEncryptionInput(jsonHeaders);
+                input.setCek(cek);
+                input.setIv(iv);
+                return input;
+            }    
+        };
+        String jweJson = p.encryptWith(jwe);
+        assertEquals(expectedOutput, jweJson);
+        return jweJson;
+    }
+    @Test
+    public void testSingleRecipientAllTypeOfHeadersAndAad() {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        SecretKey wrapperKey = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES1, "AES");
+        
+        JweHeaders protectedHeaders = new JweHeaders(ContentAlgorithm.A128GCM);
+        JweHeaders sharedUnprotectedHeaders = new JweHeaders();
+        sharedUnprotectedHeaders.setJsonWebKeysUrl("https://server.example.com/keys.jwks");
+        
+        JweEncryptionProvider jwe = JweUtils.createJweEncryptionProvider(wrapperKey, 
+                                                                         KeyAlgorithm.A128KW,
+                                                                         ContentAlgorithm.A128GCM,
+                                                                         null);
+        JweJsonProducer p = new JweJsonProducer(protectedHeaders,
+                                                sharedUnprotectedHeaders,
+                                                StringUtils.toBytesUTF8(text),
+                                                StringUtils.toBytesUTF8(EXTRA_AAD_SOURCE),
+                                                false) {
+            protected JweEncryptionInput createEncryptionInput(JweHeaders jsonHeaders) {
+                JweEncryptionInput input = super.createEncryptionInput(jsonHeaders);
+                input.setCek(CEK_BYTES);
+                input.setIv(JweCompactReaderWriterTest.INIT_VECTOR_A1);
+                return input;
+            }
+        };
+        JweHeaders recepientUnprotectedHeaders = new JweHeaders();
+        recepientUnprotectedHeaders.setKeyEncryptionAlgorithm(KeyAlgorithm.A128KW);
+        String jweJson = p.encryptWith(jwe, recepientUnprotectedHeaders);
+        assertEquals(SINGLE_RECIPIENT_ALL_HEADERS_AAD_OUTPUT, jweJson);
+    }
+    @Test
+    public void testMultipleRecipients() {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        SecretKey wrapperKey1 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES1, "AES");
+        SecretKey wrapperKey2 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES2, "AES");
+        
+        JweHeaders protectedHeaders = new JweHeaders(ContentAlgorithm.A128GCM);
+        JweHeaders sharedUnprotectedHeaders = new JweHeaders();
+        sharedUnprotectedHeaders.setJsonWebKeysUrl("https://server.example.com/keys.jwks");
+        sharedUnprotectedHeaders.setKeyEncryptionAlgorithm(KeyAlgorithm.A128KW);
+        
+        List<JweEncryptionProvider> jweList = new LinkedList<JweEncryptionProvider>();
+        
+        KeyEncryptionProvider keyEncryption1 = 
+            JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey1, KeyAlgorithm.A128KW);
+        ContentEncryptionProvider contentEncryption = 
+            JweUtils.getContentEncryptionAlgorithm(AlgorithmUtils.A128GCM_ALGO);
+        JweEncryptionProvider jwe1 = new JweEncryption(keyEncryption1, contentEncryption);
+        KeyEncryptionProvider keyEncryption2 = 
+            JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey2, KeyAlgorithm.A128KW);
+        JweEncryptionProvider jwe2 = new JweEncryption(keyEncryption2, contentEncryption);
+        jweList.add(jwe1);
+        jweList.add(jwe2);
+        
+        JweJsonProducer p = new JweJsonProducer(protectedHeaders,
+                                                sharedUnprotectedHeaders,
+                                                StringUtils.toBytesUTF8(text),
+                                                StringUtils.toBytesUTF8(EXTRA_AAD_SOURCE),
+                                                false) {
+            protected JweEncryptionInput createEncryptionInput(JweHeaders jsonHeaders) {
+                JweEncryptionInput input = super.createEncryptionInput(jsonHeaders);
+                input.setCek(CEK_BYTES);
+                input.setIv(JweCompactReaderWriterTest.INIT_VECTOR_A1);
+                return input;
+            }
+        };
+        
+        String jweJson = p.encryptWith(jweList);
+        assertEquals(MULTIPLE_RECIPIENTS_OUTPUT, jweJson);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
new file mode 100644
index 0000000..8898bf0
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
@@ -0,0 +1,77 @@
+/**
+ * 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 org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
+import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JwePbeHmacAesWrapTest extends Assert {
+    @Before
+    public void registerBouncyCastleIfNeeded() throws Exception {
+        Security.addProvider(new BouncyCastleProvider());    
+    }
+    @After
+    public void unregisterBouncyCastleIfNeeded() throws Exception {
+        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);    
+    }
+    @Test
+    public void testEncryptDecryptPbesHmacAesWrapA128CBCHS256() throws Exception {
+        final String specPlainText = "Live long and prosper.";
+        final String password = "Thus from my lips, by yours, my sin is purged."; 
+        KeyEncryptionProvider keyEncryption = 
+            new PbesHmacAesWrapKeyEncryptionAlgorithm(password, KeyAlgorithm.PBES2_HS256_A128KW);
+        JweEncryptionProvider encryption = new AesCbcHmacJweEncryption(ContentAlgorithm.A128CBC_HS256,
+                                                                       keyEncryption);
+        String jweContent = encryption.encrypt(specPlainText.getBytes("UTF-8"), null);
+        
+        PbesHmacAesWrapKeyDecryptionAlgorithm keyDecryption = new PbesHmacAesWrapKeyDecryptionAlgorithm(password);
+        JweDecryptionProvider decryption = new AesCbcHmacJweDecryption(keyDecryption);
+        String decryptedText = decryption.decrypt(jweContent).getContentText();
+        assertEquals(specPlainText, decryptedText);
+        
+    }
+    @Test
+    public void testEncryptDecryptPbesHmacAesWrapAesGcm() throws Exception {
+        final String specPlainText = "Live long and prosper.";
+        JweHeaders headers = new JweHeaders();
+        headers.setKeyEncryptionAlgorithm(KeyAlgorithm.PBES2_HS256_A128KW);
+        headers.setContentEncryptionAlgorithm(ContentAlgorithm.A128GCM);
+        final String password = "Thus from my lips, by yours, my sin is purged."; 
+        KeyEncryptionProvider keyEncryption = 
+            new PbesHmacAesWrapKeyEncryptionAlgorithm(password, KeyAlgorithm.PBES2_HS256_A128KW);
+        JweEncryptionProvider encryption = new JweEncryption(keyEncryption,
+            new AesGcmContentEncryptionAlgorithm(ContentAlgorithm.A128GCM));
+        String jweContent = encryption.encrypt(specPlainText.getBytes("UTF-8"), null);
+        PbesHmacAesWrapKeyDecryptionAlgorithm keyDecryption = new PbesHmacAesWrapKeyDecryptionAlgorithm(password);
+        JweDecryptionProvider decryption = new JweDecryption(keyDecryption, 
+                                               new AesGcmContentDecryptionAlgorithm(ContentAlgorithm.A128GCM));
+        String decryptedText = decryption.decrypt(jweContent).getContentText();
+        assertEquals(specPlainText, decryptedText);
+        
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeyTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeyTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeyTest.java
new file mode 100644
index 0000000..e647d51
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeyTest.java
@@ -0,0 +1,231 @@
+/**
+ * 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.jwk;
+
+import java.io.InputStream;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.helpers.IOUtils;
+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;
+import org.apache.cxf.rs.security.jose.jwe.JweCompactConsumer;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JsonWebKeyTest extends Assert {
+    private static final String RSA_MODULUS_VALUE = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt"
+        + "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf"
+        + "0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt"
+        + "-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw";
+    private static final String RSA_PUBLIC_EXP_VALUE = "AQAB";
+    private static final String RSA_PRIVATE_EXP_VALUE = "X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7d"
+        + "x5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ4"
+        + "6pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66"
+        + "jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q";
+    private static final String RSA_FIRST_PRIME_FACTOR_VALUE = "83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQ"
+        + "BQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9"
+        + "RzzOGVQzXvNEvn7O0nVbfs";
+    private static final String RSA_SECOND_PRIME_FACTOR_VALUE = "3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3"
+        + "vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfA"
+        + "ITAG9LUnADun4vIcb6yelxk";
+    private static final String RSA_FIRST_PRIME_CRT_VALUE = "G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0o"
+        + "imYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUm"
+        + "s6rY3Ob8YeiKkTiBj0";
+    private static final String RSA_SECOND_PRIME_CRT_VALUE = "s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6hu"
+        + "UUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvW"
+        + "rX-L18txXw494Q_cgk";
+    private static final String RSA_FIRST_CRT_COEFFICIENT_VALUE = "GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfm"
+        + "t0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKF"
+        + "YItdldUKGzO6Ia6zTKhAVRU";
+    private static final String RSA_KID_VALUE = "2011-04-29";
+    private static final String EC_CURVE_VALUE = JsonWebKey.EC_CURVE_P256;
+    private static final String EC_X_COORDINATE_VALUE = "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4";
+    private static final String EC_Y_COORDINATE_VALUE = "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM";
+    private static final String EC_PRIVATE_KEY_VALUE = "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE";
+    private static final String EC_KID_VALUE = "1";
+    private static final String AES_SECRET_VALUE = "GawgguFyGrWKav7AX4VKUg";
+    private static final String AES_KID_VALUE = "AesWrapKey";
+    private static final String HMAC_SECRET_VALUE = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3"
+        + "Yj0iPS4hcgUuTwjAzZr1Z9CAow";
+    private static final String HMAC_KID_VALUE = "HMACKey";
+    
+    @Test
+    public void testPublicSetAsList() throws Exception {
+        JsonWebKeys jwks = readKeySet("jwkPublicSet.txt");
+        List<JsonWebKey> keys = jwks.getKeys();
+        assertEquals(3, keys.size());
+        
+        JsonWebKey ecKey = keys.get(0);
+        assertEquals(6, ecKey.asMap().size());
+        validatePublicEcKey(ecKey);
+        JsonWebKey rsaKey = keys.get(1);
+        assertEquals(5, rsaKey.asMap().size());
+        validatePublicRsaKey(rsaKey);
+        JsonWebKey rsaKeyCert = keys.get(2);
+        assertEquals(3, rsaKeyCert.asMap().size());
+        assertEquals(3, rsaKeyCert.getX509Chain().size());
+        List<X509Certificate> certs = JwkUtils.toX509CertificateChain(rsaKeyCert);
+        assertEquals(3, certs.size());
+    }
+    
+    @Test
+    public void testPublicSetAsMap() throws Exception {
+        JsonWebKeys jwks = readKeySet("jwkPublicSet.txt");
+        Map<String, JsonWebKey> keysMap = jwks.getKeyIdMap();
+        assertEquals(3, keysMap.size());
+        
+        JsonWebKey rsaKey = keysMap.get(RSA_KID_VALUE);
+        assertEquals(5, rsaKey.asMap().size());
+        validatePublicRsaKey(rsaKey);
+        JsonWebKey ecKey = keysMap.get(EC_KID_VALUE);
+        assertEquals(6, ecKey.asMap().size());
+        validatePublicEcKey(ecKey);
+    }
+    
+    @Test
+    public void testPrivateSetAsList() throws Exception {
+        JsonWebKeys jwks = readKeySet("jwkPrivateSet.txt");
+        validatePrivateSet(jwks);
+    }
+    private void validatePrivateSet(JsonWebKeys jwks) throws Exception {
+        List<JsonWebKey> keys = jwks.getKeys();
+        assertEquals(2, keys.size());
+        
+        JsonWebKey ecKey = keys.get(0);
+        assertEquals(7, ecKey.asMap().size());
+        validatePrivateEcKey(ecKey);
+        JsonWebKey rsaKey = keys.get(1);
+        assertEquals(11, rsaKey.asMap().size());
+        validatePrivateRsaKey(rsaKey);
+    }
+    @Test
+    public void testEncryptDecryptPrivateSet() throws Exception {
+        final String password = "Thus from my lips, by yours, my sin is purged.";
+        Security.addProvider(new BouncyCastleProvider());    
+        try {
+            JsonWebKeys jwks = readKeySet("jwkPrivateSet.txt");
+            validatePrivateSet(jwks);
+            String encryptedKeySet = JwkUtils.encryptJwkSet(jwks, password.toCharArray());
+            JweCompactConsumer c = new JweCompactConsumer(encryptedKeySet);
+            assertEquals("jwk-set+json", c.getJweHeaders().getContentType());
+            assertEquals(KeyAlgorithm.PBES2_HS256_A128KW, c.getJweHeaders().getKeyEncryptionAlgorithm());
+            assertEquals(ContentAlgorithm.A128CBC_HS256, c.getJweHeaders().getContentEncryptionAlgorithm());
+            assertNotNull(c.getJweHeaders().getHeader("p2s"));
+            assertNotNull(c.getJweHeaders().getHeader("p2c"));
+            jwks = JwkUtils.decryptJwkSet(encryptedKeySet, password.toCharArray());
+            validatePrivateSet(jwks);
+        } finally {
+            Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+        }
+    }
+    @Test
+    public void testEncryptDecryptPrivateKey() throws Exception {
+        final String password = "Thus from my lips, by yours, my sin is purged.";
+        final String key = "{\"kty\":\"oct\","
+            + "\"alg\":\"A128KW\","
+            + "\"k\":\"GawgguFyGrWKav7AX4VKUg\","
+            + "\"kid\":\"AesWrapKey\"}";
+        Security.addProvider(new BouncyCastleProvider());    
+        try {
+            JsonWebKey jwk = readKey(key);
+            validateSecretAesKey(jwk);
+            String encryptedKey = JwkUtils.encryptJwkKey(jwk, password.toCharArray());
+            JweCompactConsumer c = new JweCompactConsumer(encryptedKey);
+            assertEquals("jwk+json", c.getJweHeaders().getContentType());
+            assertEquals(KeyAlgorithm.PBES2_HS256_A128KW, c.getJweHeaders().getKeyEncryptionAlgorithm());
+            assertEquals(ContentAlgorithm.A128CBC_HS256, c.getJweHeaders().getContentEncryptionAlgorithm());
+            assertNotNull(c.getJweHeaders().getHeader("p2s"));
+            assertNotNull(c.getJweHeaders().getHeader("p2c"));
+            jwk = JwkUtils.decryptJwkKey(encryptedKey, password.toCharArray());
+            validateSecretAesKey(jwk);
+        } finally {
+            Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+        }
+    }
+    
+    @Test
+    public void testSecretSetAsList() throws Exception {
+        JsonWebKeys jwks = readKeySet("jwkSecretSet.txt");
+        List<JsonWebKey> keys = jwks.getKeys();
+        assertEquals(2, keys.size());
+        JsonWebKey aesKey = keys.get(0);
+        assertEquals(4, aesKey.asMap().size());
+        validateSecretAesKey(aesKey);
+        JsonWebKey hmacKey = keys.get(1);
+        assertEquals(4, hmacKey.asMap().size());
+        validateSecretHmacKey(hmacKey);
+    }
+    
+    private void validateSecretAesKey(JsonWebKey key) {
+        assertEquals(AES_SECRET_VALUE, key.getProperty(JsonWebKey.OCTET_KEY_VALUE));
+        assertEquals(AES_KID_VALUE, key.getKeyId());
+        assertEquals(KeyType.OCTET, key.getKeyType());
+        assertEquals(AlgorithmUtils.A128KW_ALGO, key.getAlgorithm());
+    }
+    private void validateSecretHmacKey(JsonWebKey key) {
+        assertEquals(HMAC_SECRET_VALUE, key.getProperty(JsonWebKey.OCTET_KEY_VALUE));
+        assertEquals(HMAC_KID_VALUE, key.getKeyId());
+        assertEquals(KeyType.OCTET, key.getKeyType());
+        assertEquals(AlgorithmUtils.HMAC_SHA_256_ALGO, key.getAlgorithm());
+    }
+    
+    private void validatePublicRsaKey(JsonWebKey key) {
+        assertEquals(RSA_MODULUS_VALUE, key.getProperty(JsonWebKey.RSA_MODULUS));
+        assertEquals(RSA_PUBLIC_EXP_VALUE, key.getProperty(JsonWebKey.RSA_PUBLIC_EXP));
+        assertEquals(RSA_KID_VALUE, key.getKeyId());
+        assertEquals(KeyType.RSA, key.getKeyType());
+        assertEquals(AlgorithmUtils.RS_SHA_256_ALGO, key.getAlgorithm());
+    }
+    private void validatePrivateRsaKey(JsonWebKey key) {
+        validatePublicRsaKey(key);
+        assertEquals(RSA_PRIVATE_EXP_VALUE, key.getProperty(JsonWebKey.RSA_PRIVATE_EXP));
+        assertEquals(RSA_FIRST_PRIME_FACTOR_VALUE, key.getProperty(JsonWebKey.RSA_FIRST_PRIME_FACTOR));
+        assertEquals(RSA_SECOND_PRIME_FACTOR_VALUE, key.getProperty(JsonWebKey.RSA_SECOND_PRIME_FACTOR));
+        assertEquals(RSA_FIRST_PRIME_CRT_VALUE, key.getProperty(JsonWebKey.RSA_FIRST_PRIME_CRT));
+        assertEquals(RSA_SECOND_PRIME_CRT_VALUE, key.getProperty(JsonWebKey.RSA_SECOND_PRIME_CRT));
+        assertEquals(RSA_FIRST_CRT_COEFFICIENT_VALUE, key.getProperty(JsonWebKey.RSA_FIRST_CRT_COEFFICIENT));
+    }
+    private void validatePublicEcKey(JsonWebKey key) {
+        assertEquals(EC_X_COORDINATE_VALUE, key.getProperty(JsonWebKey.EC_X_COORDINATE));
+        assertEquals(EC_Y_COORDINATE_VALUE, key.getProperty(JsonWebKey.EC_Y_COORDINATE));
+        assertEquals(EC_KID_VALUE, key.getKeyId());
+        assertEquals(KeyType.EC, key.getKeyType());
+        assertEquals(EC_CURVE_VALUE, key.getProperty(JsonWebKey.EC_CURVE));
+        assertEquals(PublicKeyUse.ENCRYPT, key.getPublicKeyUse());
+    }
+    private void validatePrivateEcKey(JsonWebKey key) {
+        validatePublicEcKey(key);
+        assertEquals(EC_PRIVATE_KEY_VALUE, key.getProperty(JsonWebKey.EC_PRIVATE_KEY));
+    }
+
+    public JsonWebKeys readKeySet(String fileName) throws Exception {
+        InputStream is = JsonWebKeyTest.class.getResourceAsStream(fileName);
+        String s = IOUtils.readStringFromStream(is);
+        return JwkUtils.readJwkSet(s);
+    }
+    public JsonWebKey readKey(String key) throws Exception {
+        return JwkUtils.readJwkKey(key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
new file mode 100644
index 0000000..3f62f4f
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
@@ -0,0 +1,94 @@
+/**
+ * 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.jwk;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JwkUtilsTest extends Assert {
+    private static final String RSA_KEY = "{"
+      + "\"kty\": \"RSA\","
+      + "\"n\": \"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt"
+      +      "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6"
+      +      "4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD"
+      +      "W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9"
+      +      "1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH"
+      +      "aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\","
+      + "\"e\": \"AQAB\","
+      + "\"alg\": \"RS256\","
+      + "\"kid\": \"2011-04-29\""
+      + "}";
+    private static final String EC_256_KEY = "{"
+        + "\"kty\": \"EC\","
+        + "\"x\": \"CEuRLUISufhcjrj-32N0Bvl3KPMiHH9iSw4ohN9jxrA\","
+        + "\"y\": \"EldWz_iXSK3l_S7n4w_t3baxos7o9yqX0IjzG959vHc\","
+        + "\"crv\": \"P-256\""
+        + "}";
+    private static final String EC_384_KEY = "{"
+        + "\"kty\": \"EC\","
+        + "\"x\": \"2jCG5DmKUql9YPn7F2C-0ljWEbj8O8-vn5Ih1k7Wzb-y3NpBLiG1BiRa392b1kcQ\","
+        + "\"y\": \"7Ragi9rT-5tSzaMbJlH_EIJl6rNFfj4V4RyFM5U2z4j1hesX5JXa8dWOsE-5wPIl\","
+        + "\"crv\": \"P-384\""
+        + "}";
+    private static final String EC_521_KEY = "{"
+        + "\"kty\": \"EC\","
+        + "\"x\": \"Aeq3uMrb3iCQEt0PzSeZMmrmYhsKP5DM1oMP6LQzTFQY9-F3Ab45xiK4AJxltXEI-87g3gRwId88hTyHgq180JDt\","
+        + "\"y\": \"ARA0lIlrZMEzaXyXE4hjEkc50y_JON3qL7HSae9VuWpOv_2kit8p3pyJBiRb468_U5ztLT7FvDvtimyS42trhDTu\","
+        + "\"crv\": \"P-521\""
+        + "}";
+    private static final String OCTET_KEY_1 = "{"
+        + "\"kty\": \"oct\","
+        + "\"k\": \"ZW8Eg8TiwoT2YamLJfC2leYpLgLmUAh_PcMHqRzBnMg\""
+        + "}";
+    private static final String OCTET_KEY_2 = "{"
+        + "\"kty\": \"oct\","
+        + "\"k\": \"NGbwp1rC4n85A1SaNxoHow\""
+        + "}";
+    @Test
+    public void testRsaKeyThumbprint() throws Exception {
+        String thumbprint = JwkUtils.getThumbprint(RSA_KEY);
+        assertEquals("NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs", thumbprint);
+    }
+    @Test
+    public void testOctetKey1Thumbprint() throws Exception {
+        String thumbprint = JwkUtils.getThumbprint(OCTET_KEY_1);
+        assertEquals("7WWD36NF4WCpPaYtK47mM4o0a5CCeOt01JXSuMayv5g", thumbprint);
+    }
+    @Test
+    public void testOctetKey2Thumbprint() throws Exception {
+        String thumbprint = JwkUtils.getThumbprint(OCTET_KEY_2);
+        assertEquals("5_qb56G0OJDw-lb5mkDaWS4MwuY0fatkn9LkNqUHqMk", thumbprint);
+    }
+    @Test
+    public void testEc256KeyThumbprint() throws Exception {
+        String thumbprint = JwkUtils.getThumbprint(EC_256_KEY);
+        assertEquals("j4UYwo9wrtllSHaoLDJNh7MhVCL8t0t8cGPPzChpYDs", thumbprint);
+    }
+    @Test
+    public void testEc384KeyThumbprint() throws Exception {
+        String thumbprint = JwkUtils.getThumbprint(EC_384_KEY);
+        assertEquals("vZtaWIw-zw95JNzzURg1YB7mWNLlm44YZDZzhrPNetM", thumbprint);
+    }
+    @Test
+    public void testEc521KeyThumbprint() throws Exception {
+        String thumbprint = JwkUtils.getThumbprint(EC_521_KEY);
+        assertEquals("rz4Ohmpxg-UOWIWqWKHlOe0bHSjNUFlHW5vwG_M7qYg", thumbprint);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPrivateSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPrivateSet.txt b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPrivateSet.txt
new file mode 100644
index 0000000..cb30c04
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPrivateSet.txt
@@ -0,0 +1,23 @@
+{"keys":
+       [
+         {"kty":"EC",
+          "crv":"P-256",
+          "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
+          "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
+          "d":"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE",
+          "use":"enc",
+          "kid":"1"},
+
+         {"kty":"RSA",
+          "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
+          "e":"AQAB",
+          "d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q",
+          "p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs",
+          "q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk",
+          "dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0",
+          "dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk",
+          "qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU",
+          "alg":"RS256",
+          "kid":"2011-04-29"}
+       ]
+     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPublicSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPublicSet.txt b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPublicSet.txt
new file mode 100644
index 0000000..2fd93f6
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPublicSet.txt
@@ -0,0 +1,27 @@
+{"keys":
+       [
+         {"kty":"EC",
+          "crv":"P-256",
+          "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
+          "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
+          "use":"enc",
+          "kid":"1"},
+
+         {"kty":"RSA",
+          "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
+          "e":"AQAB",
+          "alg":"RS256",
+          "kid":"2011-04-29"},
+          
+          {
+            "kty":"RSA",
+            "kid":"RSACerts",
+            "x5c": [
+             "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYwMTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3HKrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQmVZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpRSgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRTcDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEuMB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDSkdRMEXGzYcs9of7dqGrU4zA
 SBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUHAgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IGOgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMUA2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTXRE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuHqDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWVU+4=",
+             "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoXDTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHUTBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGl
 vbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlvbiBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdvZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUdIAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4OWBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0VmsfSxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==",
+             "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7
 tdEy8W9ViH0Pd"
+            ]
+          } 
+          
+       ]
+     }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkSecretSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkSecretSet.txt b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkSecretSet.txt
new file mode 100644
index 0000000..6520c75
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkSecretSet.txt
@@ -0,0 +1,13 @@
+{"keys":
+       [
+         {"kty":"oct",
+          "alg":"A128KW",
+          "k":"GawgguFyGrWKav7AX4VKUg",
+          "kid":"AesWrapKey"},
+
+         {"kty":"oct",
+          "alg":"HS256",
+          "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
+          "kid":"HMACKey"}
+       ]
+     }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java
new file mode 100644
index 0000000..39c6d3c
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java
@@ -0,0 +1,203 @@
+/**
+ * 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.jws;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JwsCompactHeaderTest extends Assert {
+
+    /**
+     * JWS string, which lacks the "alg" header field.
+     * 
+     * => Must be rejected by verification operation, since the spec declares
+     * that the "alg" header field must be present in the compact serialization.
+     */
+    public static final String MISSING_ALG_HEADER_FIELD_IN_JWS = 
+        "eyAiZ2xhIiA6ICJDQU1IIiB9.eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ"
+        + ".Sqd_AuwlPPqv4L1EV4zPuR-HfFJpe9kOfvc597RlcoE";
+
+    /**
+     * JWS string, which contains two "alg" header fields. Bogus "alg" header
+     * field first.
+     * 
+     * => Must be rejected by verification operation, since the spec declares
+     * that the "alg" header field must be present once in the compact
+     * serialization.
+     */
+    public static final String TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_FIRST = 
+        "eyAiYWxnIjogIkJvZ3VzIiwgImFsZyI6ICJIUzI1NiIgfQ.eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ"
+        + ".FIgpDi1Wp9iIxxXfBw8Zce2kiZ8gmqAaVYPduRFR8kU";
+
+    /**
+     * JWS string, which contains two "alg" header fields. Bogus "alg" header
+     * field last.
+     * 
+     * => Must be rejected by verification operation, since the spec declares
+     * that the "alg" header field must be present once in the compact
+     * serialization.
+     */
+    public static final String TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_LAST = 
+        "eyAiYWxnIjogIkhTMjU2IiwgImFsZyI6ICJCb2d1cyIgfQ.eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ"
+        + ".Ftwla-nAg0Nty8ILVhjlIETOy2Tw1JsD3bBq55AS0PU";
+
+    /**
+     * JWS string, which contains an invalid "alg" header field value.
+     * 
+     * (1): Algorithm not supported/known
+     * 
+     * => Must be rejected by verification operation, since the spec declares
+     * that the signature is not valid if the "alg" value does not represent a
+     * supported algorithm. "alg" values should either be registered in the IANA
+     * JSON Web Signature and Encryption Algorithms registry defined in JWA or
+     * be a value that contains a Collision-Resistant Name.
+     */
+    public static final String INVALID_ALG_HEADER_VALUE_IN_JWS_1 = "tba";
+
+    /**
+     * JWS string, which contains an invalid "alg" header field value.
+     * 
+     * (2): Wrong value encoding
+     * 
+     * => Must be rejected by verification operation, since the spec declares
+     * that the "alg" value is a case-sensitive string containing a StringOrURI
+     * value.
+     */
+    public static final String INVALID_ALG_HEADER_VALUE_IN_JWS_2 = "tba";
+
+    /**
+     * JWS string, which contains a "alg" header field value of "none". The
+     * signature has been generated with "HS256" and the signed JWS has been
+     * altered afterwards to the value "none".
+     * 
+     * => Must be rejected by verification operation, since the "none" algorithm
+     * is considered harmful.
+     */
+    public static final String ALG_HEADER_VALUE_HS256_IN_JWS = 
+        "eyAiYWxnIjogIkhTMjU2IiB9"
+        + ".eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ"
+        + ".as_gclokwAmukh3zVF1X5sUCCfSc8TbjDdhdvk6C5c8";
+    public static final String ALG_HEADER_VALUE_NONE_IN_JWS = 
+        "eyAiYWxnIjogIm5vbmUiIH0"
+        + ".eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ"
+        + ".as_gclokwAmukh3zVF1X5sUCCfSc8TbjDdhdvk6C5c8";
+
+    
+    /**
+     * Support material (keys, etc.)
+     */
+    private static final String ENCODED_MAC_KEY = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75"
+                    + "aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow";
+    
+    // JWS string, which contains crit header field
+    // JWS string, which contains more than three parts
+    // JWS string, which contains less than three parts
+    // JWS string, which contains null bytes padding
+
+    @Test
+    public void verifyJwsWithMissingAlgHeaderField() throws Exception {
+        JwsCompactConsumer jwsConsumer = new JwsCompactConsumer(MISSING_ALG_HEADER_FIELD_IN_JWS);
+
+        assertFalse(jwsConsumer.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, 
+                                                        SignatureAlgorithm.HS256)));
+    }
+
+    @Test
+    public void verifyJwsWithTwoAlgHeaderFieldsBogusFieldFirst() throws Exception {
+        JwsCompactConsumer jwsConsumer = new JwsCompactConsumer(TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_FIRST);
+
+        boolean result = jwsConsumer.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY,
+                                                                     SignatureAlgorithm.HS256));
+        assertFalse(result);
+    }
+
+    @Test
+    public void verifyJwsWithTwoAlgHeaderFieldsBogusFieldLast() throws Exception {
+        JwsCompactConsumer jwsConsumer = new JwsCompactConsumer(TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_LAST);
+
+        assertFalse(jwsConsumer.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY,
+                                                        SignatureAlgorithm.HS256)));
+    }
+    
+    @Test
+    public void verifyJwsWithAlgHeaderValueNone() throws Exception {
+        JwsCompactConsumer jwsConsumerOriginal = new JwsCompactConsumer(ALG_HEADER_VALUE_HS256_IN_JWS);
+        
+        JwsCompactConsumer jwsConsumerAltered = new JwsCompactConsumer(ALG_HEADER_VALUE_NONE_IN_JWS);
+
+        assertTrue(jwsConsumerOriginal.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY,
+                                                           SignatureAlgorithm.HS256)));
+        
+        assertFalse(jwsConsumerAltered.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY,
+                                                           SignatureAlgorithm.HS256)));
+    }
+
+    @Test
+    public void testCriticalHeader() {
+        String payload = "this is a JWS with critical header";
+        String criticalParameter = "criticalParameter";
+        String criticalParameter1 = "criticalParameter1";
+        String criticalParameter2 = "criticalParameter2";
+        String criticalParameter3 = "criticalParameter3";
+        String criticalValue = "criticalValue";
+        String criticalValue1 = "criticalValue1";
+        String criticalValue2 = "criticalValue2";
+        String criticalValue3 = "criticalValue3";
+        JwsCompactProducer producer = new JwsCompactProducer(payload);
+        producer.getJwsHeaders().setSignatureAlgorithm(SignatureAlgorithm.HS512);
+        List<String> criticalHeader = new ArrayList<String>();
+        criticalHeader.add(criticalParameter1);
+        producer.getJwsHeaders().setCritical(criticalHeader);
+        producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256));
+        String signedJws = producer.getSignedEncodedJws();
+        JwsCompactConsumer consumer = new JwsCompactConsumer(signedJws);
+        assertFalse(consumer.validateCriticalHeaders());
+        
+        criticalHeader.add(criticalParameter2);
+        criticalHeader.add(criticalParameter3);
+        producer = new JwsCompactProducer(payload);
+        producer.getJwsHeaders().setSignatureAlgorithm(SignatureAlgorithm.HS512);
+        producer.getJwsHeaders().setCritical(criticalHeader);
+        producer.getJwsHeaders().setHeader(criticalParameter1, criticalValue1);
+        producer.getJwsHeaders().setHeader(criticalParameter2, criticalValue2);
+        producer.getJwsHeaders().setHeader(criticalParameter3, criticalValue3);
+        producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256));
+        signedJws = producer.getSignedEncodedJws();
+        consumer = new JwsCompactConsumer(signedJws);
+        assertTrue(consumer.validateCriticalHeaders());
+    
+        criticalHeader = new ArrayList<String>();
+        criticalHeader.add(criticalParameter);
+        criticalHeader.add(criticalParameter);
+        producer = new JwsCompactProducer(payload);
+        producer.getJwsHeaders().setSignatureAlgorithm(SignatureAlgorithm.HS512);
+        producer.getJwsHeaders().setHeader(criticalParameter, criticalValue);
+        producer.getJwsHeaders().setCritical(criticalHeader);
+        producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256));
+        signedJws = producer.getSignedEncodedJws();
+        consumer = new JwsCompactConsumer(signedJws);
+        assertFalse(consumer.validateCriticalHeaders());
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactReaderWriterTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactReaderWriterTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactReaderWriterTest.java
new file mode 100644
index 0000000..de733c5
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactReaderWriterTest.java
@@ -0,0 +1,307 @@
+/**
+ * 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.jws;
+
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+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.JoseType;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.KeyOperation;
+import org.apache.cxf.rs.security.jose.jwk.KeyType;
+import org.apache.cxf.rs.security.jose.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.jose.jwt.JwtTokenReaderWriter;
+import org.apache.cxf.rt.security.crypto.CryptoUtils;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JwsCompactReaderWriterTest extends Assert {
+    
+    public static final String TOKEN_WITH_DETACHED_UNENCODED_PAYLOAD =
+        "eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2V9..GsyM6AQJbQHY8aQKCbZSPJHzMRWo3HKIlcDuXof7nqs";
+    public static final String UNSIGNED_PLAIN_DOCUMENT = "$.02";
+    
+    public static final String ENCODED_TOKEN_SIGNED_BY_MAC = 
+        "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9"
+        + ".eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
+        + ".dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
+    
+    
+    private static final String ENCODED_MAC_KEY = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75"
+        + "aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow";
+    
+    private static final String ENCODED_TOKEN_WITH_JSON_KEY_SIGNED_BY_MAC = 
+        "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIU"
+        + "zI1NiIsDQogImp3ayI6eyJrdHkiOiJvY3QiLA0KICJrZXlfb3BzIjpbDQogInNpZ24iLA0KICJ2ZXJpZnkiDQogXX19"
+        + ".eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
+        + ".8cFZqb15gEDYRZqSzUu23nQnKNynru1ADByRPvmmOq8";
+    
+    private static final String RSA_MODULUS_ENCODED = "ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddx"
+        + "HmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMs"
+        + "D1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSH"
+        + "SXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdV"
+        + "MTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8"
+        + "NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ";
+    private static final String RSA_PUBLIC_EXPONENT_ENCODED = "AQAB";
+    private static final String RSA_PRIVATE_EXPONENT_ENCODED = 
+        "Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97I"
+        + "jlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0"
+        + "BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn"
+        + "439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYT"
+        + "CBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLh"
+        + "BOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ";
+    private static final String ENCODED_TOKEN_SIGNED_BY_PRIVATE_KEY =
+        "eyJhbGciOiJSUzI1NiJ9"
+        + "."
+        + "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
+        + "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ"
+        + "."
+        + "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7"
+        + "AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4"
+        + "BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K"
+        + "0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv"
+        + "hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB"
+        + "p0igcN_IoypGlUPQGe77Rw";
+     
+    private static final String EC_PRIVATE_KEY_ENCODED = 
+        "jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI";
+    private static final String EC_X_POINT_ENCODED = 
+        "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU";
+    private static final String EC_Y_POINT_ENCODED = 
+        "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0";
+    @Test
+    public void testWriteJwsSignedByMacSpecExample() throws Exception {
+        JwsHeaders headers = new JwsHeaders();
+        headers.setType(JoseType.JWT);
+        headers.setSignatureAlgorithm(SignatureAlgorithm.HS256);
+        JwsCompactProducer jws = initSpecJwtTokenWriter(headers);
+        jws.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256));
+        
+        assertEquals(ENCODED_TOKEN_SIGNED_BY_MAC, jws.getSignedEncodedJws());
+    }
+    @Test
+    public void testWriteReadJwsUnencodedPayload() throws Exception {
+        JwsHeaders headers = new JwsHeaders(SignatureAlgorithm.HS256);
+        headers.setPayloadEncodingStatus(false);
+        JwsCompactProducer producer = new JwsCompactProducer(headers, 
+                                                             UNSIGNED_PLAIN_DOCUMENT, 
+                                                             true);
+        producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256));
+        assertEquals(TOKEN_WITH_DETACHED_UNENCODED_PAYLOAD, producer.getSignedEncodedJws());
+        JwsCompactConsumer consumer = 
+            new JwsCompactConsumer(TOKEN_WITH_DETACHED_UNENCODED_PAYLOAD, UNSIGNED_PLAIN_DOCUMENT);
+        
+        assertTrue(consumer.verifySignatureWith(
+            new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, SignatureAlgorithm.HS256)));
+    }
+    @Test
+    public void testWriteReadJwsUnsigned() throws Exception {
+        JwsHeaders headers = new JwsHeaders(JoseType.JWT);
+        headers.setSignatureAlgorithm(SignatureAlgorithm.NONE);
+        
+        JwtClaims claims = new JwtClaims();
+        claims.setIssuer("https://jwt-idp.example.com");
+        claims.setSubject("mailto:mike@example.com");
+        claims.setAudience("https://jwt-rp.example.net");
+        claims.setNotBefore(1300815780L);
+        claims.setExpiryTime(1300819380L);
+        claims.setClaim("http://claims.example.com/member", true);
+        
+        JwsCompactProducer writer = new JwsJwtCompactProducer(headers, claims);
+        String signed = writer.getSignedEncodedJws();
+        
+        JwsJwtCompactConsumer reader = new JwsJwtCompactConsumer(signed);
+        assertEquals(0, reader.getDecodedSignature().length);
+        
+        JwtToken token = reader.getJwtToken();
+        assertEquals(new JwtToken(headers, claims), token);
+    }
+
+    @Test
+    public void testReadJwsSignedByMacSpecExample() throws Exception {
+        JwsJwtCompactConsumer jws = new JwsJwtCompactConsumer(ENCODED_TOKEN_SIGNED_BY_MAC);
+        assertTrue(jws.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY,
+                                                                        SignatureAlgorithm.HS256)));
+        JwtToken token = jws.getJwtToken();
+        JwsHeaders headers = new JwsHeaders(token.getHeaders());
+        assertEquals(JoseType.JWT, headers.getType());
+        assertEquals(SignatureAlgorithm.HS256, headers.getSignatureAlgorithm());
+        validateSpecClaim(token.getClaims());
+    }
+    
+    @Test
+    public void testWriteJwsWithJwkSignedByMac() throws Exception {
+        JsonWebKey key = new JsonWebKey();
+        key.setKeyType(KeyType.OCTET);
+        key.setKeyOperation(Arrays.asList(
+            new KeyOperation[]{KeyOperation.SIGN, KeyOperation.VERIFY}));
+        doTestWriteJwsWithJwkSignedByMac(key);
+    }
+    
+    @Test
+    public void testWriteJwsWithJwkAsMapSignedByMac() throws Exception {
+        Map<String, Object> map = new LinkedHashMap<String, Object>();
+        map.put(JsonWebKey.KEY_TYPE, JsonWebKey.KEY_TYPE_OCTET);
+        map.put(JsonWebKey.KEY_OPERATIONS,
+                new KeyOperation[]{KeyOperation.SIGN, KeyOperation.VERIFY});
+        doTestWriteJwsWithJwkSignedByMac(map);
+    }
+    
+    private void doTestWriteJwsWithJwkSignedByMac(Object jsonWebKey) throws Exception {
+        JwsHeaders headers = new JwsHeaders();
+        headers.setType(JoseType.JWT);
+        headers.setSignatureAlgorithm(SignatureAlgorithm.HS256);
+        headers.setHeader(JoseConstants.HEADER_JSON_WEB_KEY, jsonWebKey);
+        
+        JwtClaims claims = new JwtClaims();
+        claims.setIssuer("joe");
+        claims.setExpiryTime(1300819380L);
+        claims.setClaim("http://example.com/is_root", Boolean.TRUE);
+        
+        JwtToken token = new JwtToken(headers, claims);
+        JwsCompactProducer jws = new JwsJwtCompactProducer(token, getWriter());
+        jws.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256));
+        
+        assertEquals(ENCODED_TOKEN_WITH_JSON_KEY_SIGNED_BY_MAC, jws.getSignedEncodedJws());
+    }
+    
+    @Test
+    public void testReadJwsWithJwkSignedByMac() throws Exception {
+        JwsJwtCompactConsumer jws = new JwsJwtCompactConsumer(ENCODED_TOKEN_WITH_JSON_KEY_SIGNED_BY_MAC);
+        assertTrue(jws.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY,
+                                                                        SignatureAlgorithm.HS256)));
+        JwtToken token = jws.getJwtToken();
+        JwsHeaders headers = new JwsHeaders(token.getHeaders());
+        assertEquals(JoseType.JWT, headers.getType());
+        assertEquals(SignatureAlgorithm.HS256, headers.getSignatureAlgorithm());
+        
+        JsonWebKey key = headers.getJsonWebKey();
+        assertEquals(KeyType.OCTET, key.getKeyType());
+        List<KeyOperation> keyOps = key.getKeyOperation();
+        assertEquals(2, keyOps.size());
+        assertEquals(KeyOperation.SIGN, keyOps.get(0));
+        assertEquals(KeyOperation.VERIFY, keyOps.get(1));
+        
+        validateSpecClaim(token.getClaims());
+    }
+    
+    private void validateSpecClaim(JwtClaims claims) {
+        assertEquals("joe", claims.getIssuer());
+        assertEquals(Long.valueOf(1300819380), claims.getExpiryTime());
+        assertEquals(Boolean.TRUE, claims.getClaim("http://example.com/is_root"));
+    }
+    
+    @Test
+    public void testWriteJwsSignedByPrivateKey() throws Exception {
+        JwsHeaders headers = new JwsHeaders();
+        headers.setSignatureAlgorithm(SignatureAlgorithm.RS256);
+        JwsCompactProducer jws = initSpecJwtTokenWriter(headers);
+        PrivateKey key = CryptoUtils.getRSAPrivateKey(RSA_MODULUS_ENCODED, RSA_PRIVATE_EXPONENT_ENCODED);
+        jws.signWith(new PrivateKeyJwsSignatureProvider(key, SignatureAlgorithm.RS256));
+        
+        assertEquals(ENCODED_TOKEN_SIGNED_BY_PRIVATE_KEY, jws.getSignedEncodedJws());
+    }
+    @Test
+    public void testJwsPsSha() throws Exception {
+        Security.addProvider(new BouncyCastleProvider());    
+        try {
+            JwsHeaders outHeaders = new JwsHeaders();
+            outHeaders.setSignatureAlgorithm(SignatureAlgorithm.PS256);
+            JwsCompactProducer producer = initSpecJwtTokenWriter(outHeaders);
+            PrivateKey privateKey = CryptoUtils.getRSAPrivateKey(RSA_MODULUS_ENCODED, RSA_PRIVATE_EXPONENT_ENCODED);
+            String signed = producer.signWith(
+                new PrivateKeyJwsSignatureProvider(privateKey, SignatureAlgorithm.PS256));
+            
+            JwsJwtCompactConsumer jws = new JwsJwtCompactConsumer(signed);
+            RSAPublicKey key = CryptoUtils.getRSAPublicKey(RSA_MODULUS_ENCODED, RSA_PUBLIC_EXPONENT_ENCODED);
+            assertTrue(jws.verifySignatureWith(new PublicKeyJwsSignatureVerifier(key, SignatureAlgorithm.PS256)));
+            JwtToken token = jws.getJwtToken();
+            JwsHeaders inHeaders = new JwsHeaders(token.getHeaders());
+            assertEquals(SignatureAlgorithm.PS256, 
+                         inHeaders.getSignatureAlgorithm());
+            validateSpecClaim(token.getClaims());
+        } finally {
+            Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+        }
+    }
+    
+    @Test
+    public void testWriteReadJwsSignedByESPrivateKey() throws Exception {
+        JwsHeaders headers = new JwsHeaders();
+        headers.setSignatureAlgorithm(SignatureAlgorithm.ES256);
+        JwsCompactProducer jws = initSpecJwtTokenWriter(headers);
+        ECPrivateKey privateKey = CryptoUtils.getECPrivateKey(JsonWebKey.EC_CURVE_P256,
+                                                              EC_PRIVATE_KEY_ENCODED);
+        jws.signWith(new EcDsaJwsSignatureProvider(privateKey, SignatureAlgorithm.ES256));
+        String signedJws = jws.getSignedEncodedJws();
+        
+        ECPublicKey publicKey = CryptoUtils.getECPublicKey(JsonWebKey.EC_CURVE_P256,
+                                                           EC_X_POINT_ENCODED, 
+                                                           EC_Y_POINT_ENCODED);
+        JwsJwtCompactConsumer jwsConsumer = new JwsJwtCompactConsumer(signedJws);
+        assertTrue(jwsConsumer.verifySignatureWith(new EcDsaJwsSignatureVerifier(publicKey,
+                                                   SignatureAlgorithm.ES256)));
+        JwtToken token = jwsConsumer.getJwtToken();
+        JwsHeaders headersReceived = new JwsHeaders(token.getHeaders());
+        assertEquals(SignatureAlgorithm.ES256, headersReceived.getSignatureAlgorithm());
+        validateSpecClaim(token.getClaims());
+    }
+    
+    @Test
+    public void testReadJwsSignedByPrivateKey() throws Exception {
+        JwsJwtCompactConsumer jws = new JwsJwtCompactConsumer(ENCODED_TOKEN_SIGNED_BY_PRIVATE_KEY);
+        RSAPublicKey key = CryptoUtils.getRSAPublicKey(RSA_MODULUS_ENCODED, RSA_PUBLIC_EXPONENT_ENCODED);
+        assertTrue(jws.verifySignatureWith(new PublicKeyJwsSignatureVerifier(key, SignatureAlgorithm.RS256)));
+        JwtToken token = jws.getJwtToken();
+        JwsHeaders headers = new JwsHeaders(token.getHeaders());
+        assertEquals(SignatureAlgorithm.RS256, headers.getSignatureAlgorithm());
+        validateSpecClaim(token.getClaims());
+    }
+    
+    private JwsCompactProducer initSpecJwtTokenWriter(JoseHeaders headers) throws Exception {
+        
+        JwtClaims claims = new JwtClaims();
+        claims.setIssuer("joe");
+        claims.setExpiryTime(1300819380L);
+        claims.setClaim("http://example.com/is_root", Boolean.TRUE);
+        
+        JwtToken token = new JwtToken(headers, claims);
+        return new JwsJwtCompactProducer(token, getWriter());
+    }
+
+    
+    private JwtTokenReaderWriter getWriter() {
+        JwtTokenReaderWriter jsonWriter = new JwtTokenReaderWriter();
+        jsonWriter.setFormat(true);
+        return jsonWriter;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
new file mode 100644
index 0000000..0faed8b
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
@@ -0,0 +1,89 @@
+/**
+ * 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.jws;
+
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKeys;
+import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JwsJsonConsumerTest extends Assert {
+    private static final String DUAL_SIGNED_DOCUMENT =                           
+        "{\"payload\":\n"
+        + "\t\"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\",\n"
+        + "\t\"signatures\":[\n"
+        + "\t\t\t{\"protected\":\"eyJhbGciOiJSUzI1NiJ9\",\n"
+        + "\t\t\t \"header\":\n"   
+        + "\t\t\t\t{\"kid\":\"2010-12-29\"},\n"
+        + "\t\t\t \"signature\":\n"
+        + "\t\t\t\t\"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5"
+        +           "jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb"
+        +           "1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOY"
+        +           "EUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw\"},\n"
+        + "\t\t\t{\"protected\":\"eyJhbGciOiJFUzI1NiJ9\",\n"
+        + "\t\t\t \"header\":\n"
+        + "\t\t\t\t{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"},\n"
+        + "\t\t\t \"signature\":\n"
+        + "\t\t\t\t\"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q\"}]\n"
+        + "}";
+    
+    private static final String KID_OF_THE_FIRST_SIGNER = "2010-12-29";
+    private static final String KID_OF_THE_SECOND_SIGNER = "e9bc097a-ce51-4036-9562-d2ade882db0d";
+    
+    @Test
+    public void testVerifySignedWithProtectedHeaderOnlyUnencodedPayload() {
+        JwsJsonConsumer consumer = 
+            new JwsJsonConsumer(JwsJsonProducerTest.SIGNED_JWS_JSON_FLAT_UNENCODED_DOCUMENT);
+        assertEquals(JwsJsonProducerTest.UNSIGNED_PLAIN_DOCUMENT, consumer.getJwsPayload());
+        assertEquals(JwsJsonProducerTest.UNSIGNED_PLAIN_DOCUMENT, consumer.getDecodedJwsPayload());
+        assertTrue(consumer.verifySignatureWith(
+            new HmacJwsSignatureVerifier(JwsJsonProducerTest.ENCODED_MAC_KEY_1, SignatureAlgorithm.HS256)));
+    }
+    
+    @Test
+    public void testVerifyDualSignedDocument() throws Exception {
+        JwsJsonConsumer consumer = new JwsJsonConsumer(DUAL_SIGNED_DOCUMENT); 
+        JsonWebKeys jwks = readKeySet("jwkPublicJsonConsumerSet.txt");
+        
+        List<JwsJsonSignatureEntry> sigEntries = consumer.getSignatureEntries();
+        assertEquals(2, sigEntries.size());
+        // 1st signature
+        String firstKid = (String)sigEntries.get(0).getKeyId();
+        assertEquals(KID_OF_THE_FIRST_SIGNER, firstKid);
+        JsonWebKey rsaKey = jwks.getKey(firstKid);
+        assertNotNull(rsaKey);
+        assertTrue(sigEntries.get(0).verifySignatureWith(rsaKey));
+        // 2nd signature
+        String secondKid = (String)sigEntries.get(1).getKeyId();
+        assertEquals(KID_OF_THE_SECOND_SIGNER, secondKid);
+        JsonWebKey ecKey = jwks.getKey(secondKid);
+        assertNotNull(ecKey);
+        assertTrue(sigEntries.get(1).verifySignatureWith(ecKey));
+    }
+    public JsonWebKeys readKeySet(String fileName) throws Exception {
+        InputStream is = JwsJsonConsumerTest.class.getResourceAsStream(fileName);
+        return JwkUtils.readJwkSet(is);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducerTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducerTest.java
new file mode 100644
index 0000000..5895dcb
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducerTest.java
@@ -0,0 +1,126 @@
+/**
+ * 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.jws;
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JwsJsonProducerTest extends Assert {
+
+    public static final String ENCODED_MAC_KEY_1 = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75"
+                       + "aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow";
+
+    public static final String ENCODED_MAC_KEY_2 = "09Y_RK7l5rAY9QY7EblYQNuYbu9cy1j7ovCbkeIyAKN8LIeRL-3H8g"
+                       + "c8kZSYzAQ1uTRC_egZ_8cgZSZa9T5nmQ";
+
+    public static final String UNSIGNED_PLAIN_JSON_DOCUMENT = "{"
+                       + " \"from\": \"user\"," + " \"to\": \"developer\","
+                       + " \"msg\": \"good job!\" " + "}";
+    
+    public static final String UNSIGNED_PLAIN_DOCUMENT = "$.02";
+
+    public static final String UNSIGNED_PLAIN_JSON_DOCUMENT_AS_B64URL = "eyAiZnJvbSI6ICJ1c2VyIiwgInRvIjogI"
+                       + "mRldmVsb3BlciIsICJtc2ciOiAiZ29vZCBqb2IhIiB9";
+
+       
+    public static final String SIGNED_JWS_JSON_DOCUMENT = "{"
+                       + "\"payload\":\""
+                       + UNSIGNED_PLAIN_JSON_DOCUMENT_AS_B64URL
+                       + "\",\"signatures\":[{\"protected\":\"eyJhbGciOiJIUzI1NiJ9\",\"signature\":"
+                       + "\"NNksREOsFCI1nUQEqzCe6XZFa-bRAge2XXMMAU2Jj2I\"}]}";
+    
+    public static final String SIGNED_JWS_JSON_FLAT_DOCUMENT = "{"
+        + "\"payload\":\""
+        + UNSIGNED_PLAIN_JSON_DOCUMENT_AS_B64URL
+        + "\",\"protected\":\"eyJhbGciOiJIUzI1NiJ9\",\"signature\":"
+        + "\"NNksREOsFCI1nUQEqzCe6XZFa-bRAge2XXMMAU2Jj2I\"}";
+       
+    public static final String SIGNED_JWS_JSON_FLAT_UNENCODED_DOCUMENT = "{"
+        + "\"payload\":\"" + UNSIGNED_PLAIN_DOCUMENT + "\","
+        + "\"protected\":\"eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2V9\","
+        + "\"signature\":" + "\"GsyM6AQJbQHY8aQKCbZSPJHzMRWo3HKIlcDuXof7nqs\"}";
+    
+    public static final String DUAL_SIGNED_JWS_JSON_DOCUMENT = "{"
+                       + "\"payload\":\""
+                       + UNSIGNED_PLAIN_JSON_DOCUMENT_AS_B64URL
+                       + "\",\"signatures\":[{\"protected\":\"eyJhbGciOiJIUzI1NiJ9\","
+                       + "\"signature\":\"NNksREOsFCI1nUQEqzCe6XZFa-bRAge2XXMMAU2Jj2I\"},"
+                       + "{\"protected\":\"eyJhbGciOiJIUzI1NiJ9\","
+                       + "\"signature\":\"KY2r_Gubar7G86fVyrA7I2-69KA7faKDmebfCCmibdI\"}]}";
+
+    @Test
+    public void testSignPlainJsonDocumentPayloadConstruction() {
+        JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_JSON_DOCUMENT);
+
+        assertEquals(UNSIGNED_PLAIN_JSON_DOCUMENT_AS_B64URL,
+                      producer.getUnsignedEncodedPayload());
+    }
+
+       
+    @Test
+    public void testSignWithProtectedHeaderOnly() {
+        JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_JSON_DOCUMENT);
+        JwsHeaders headerEntries = new JwsHeaders();
+        headerEntries.setSignatureAlgorithm(SignatureAlgorithm.HS256);
+               
+        producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY_1, SignatureAlgorithm.HS256),
+                          headerEntries);
+        assertEquals(SIGNED_JWS_JSON_DOCUMENT,
+                     producer.getJwsJsonSignedDocument());
+    }
+    @Test
+    public void testSignWithProtectedHeaderOnlyUnencodedPayload() {
+        JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_DOCUMENT, true);
+        JwsHeaders headers = new JwsHeaders();
+        headers.setSignatureAlgorithm(SignatureAlgorithm.HS256);
+        headers.setPayloadEncodingStatus(false);
+        
+               
+        producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY_1, SignatureAlgorithm.HS256),
+                          headers);
+        assertEquals(SIGNED_JWS_JSON_FLAT_UNENCODED_DOCUMENT,
+                     producer.getJwsJsonSignedDocument());
+    }
+    @Test
+    public void testSignWithProtectedHeaderOnlyFlat() {
+        JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_JSON_DOCUMENT, true);
+        JwsHeaders headerEntries = new JwsHeaders();
+        headerEntries.setSignatureAlgorithm(SignatureAlgorithm.HS256);
+               
+        producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY_1, SignatureAlgorithm.HS256),
+                          headerEntries);
+        assertEquals(SIGNED_JWS_JSON_FLAT_DOCUMENT,
+                     producer.getJwsJsonSignedDocument());
+    }
+    @Test
+    public void testDualSignWithProtectedHeaderOnly() {
+        JwsJsonProducer producer = new JwsJsonProducer(UNSIGNED_PLAIN_JSON_DOCUMENT);
+        JwsHeaders headerEntries = new JwsHeaders();
+        headerEntries.setSignatureAlgorithm(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());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/b33b7d7a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/jwkPublicJsonConsumerSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/jwkPublicJsonConsumerSet.txt b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/jwkPublicJsonConsumerSet.txt
new file mode 100644
index 0000000..ba8e723
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/jwkPublicJsonConsumerSet.txt
@@ -0,0 +1,18 @@
+{"keys":
+       [
+         {"kty":"RSA",
+          "n": "ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ",
+          "e":"AQAB",
+          "alg":"RS256",
+          "kid":"2010-12-29"},       
+          
+         {"kty":"EC",
+          "alg":"ES256",
+          "crv":"P-256",
+      	  "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
+      	  "y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
+          "kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"
+    	  }
+          
+       ]
+     }
\ No newline at end of file


Mime
View raw message