You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2015/10/13 12:35:04 UTC
[11/22] cxf git commit: Splitting current jose module into jose-core
+ jose-jaxrs
http://git-wip-us.apache.org/repos/asf/cxf/blob/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java b/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
new file mode 100644
index 0000000..bc5f556
--- /dev/null
+++ b/rt/rs/security/jose/jose-core/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.class.getName());
+ }
+
+ @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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java b/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
new file mode 100644
index 0000000..56cd65a
--- /dev/null
+++ b/rt/rs/security/jose/jose-core/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.class.getName());
+ }
+ @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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeyTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeyTest.java b/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeyTest.java
new file mode 100644
index 0000000..6a60fc9
--- /dev/null
+++ b/rt/rs/security/jose/jose-core/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.class.getName());
+ }
+ }
+ @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.class.getName());
+ }
+ }
+
+ @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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/JwkUtilsTest.java b/rt/rs/security/jose/jose-core/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/jose-core/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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPrivateSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPrivateSet.txt b/rt/rs/security/jose/jose-core/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/jose-core/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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPublicSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkPublicSet.txt b/rt/rs/security/jose/jose-core/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/jose-core/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": [
+ "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
tdEy8W9ViH0Pd"
+ ]
+ }
+
+ ]
+ }
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cxf/blob/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkSecretSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jwk/jwkSecretSet.txt b/rt/rs/security/jose/jose-core/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/jose-core/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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java b/rt/rs/security/jose/jose-core/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/jose-core/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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactReaderWriterTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactReaderWriterTest.java b/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactReaderWriterTest.java
new file mode 100644
index 0000000..64f04ce
--- /dev/null
+++ b/rt/rs/security/jose/jose-core/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.JoseConstants;
+import org.apache.cxf.rs.security.jose.JoseHeaders;
+import org.apache.cxf.rs.security.jose.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.class.getName());
+ }
+ }
+
+ @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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java b/rt/rs/security/jose/jose-core/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/jose-core/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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProducerTest.java b/rt/rs/security/jose/jose-core/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/jose-core/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/66a81773/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/jwkPublicJsonConsumerSet.txt
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/jose-core/src/test/java/org/apache/cxf/rs/security/jose/jws/jwkPublicJsonConsumerSet.txt b/rt/rs/security/jose/jose-core/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/jose-core/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