You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2014/10/06 19:26:00 UTC
[07/10] [CXF-5944] Finalizing the current round of refactorings with
introducing a dedicated rt rs security module, idea from Luigi Lo Iacono
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java
new file mode 100644
index 0000000..c614622
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JsonWebKeys.java
@@ -0,0 +1,131 @@
+/**
+ * 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.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.rs.security.jose.AbstractJoseObject;
+
+public class JsonWebKeys extends AbstractJoseObject {
+ public static final String KEYS_PROPERTY = "keys";
+ public List<JsonWebKey> getKeys() {
+ List<?> list = (List<?>)super.getValue(KEYS_PROPERTY);
+ if (list != null && !list.isEmpty()) {
+ Object first = list.get(0);
+ if (first instanceof JsonWebKey) {
+ return CastUtils.cast(list);
+ } else {
+ List<JsonWebKey> keys = new LinkedList<JsonWebKey>();
+ List<Map<String, Object>> listOfMaps =
+ CastUtils.cast((List<?>)super.getValue(KEYS_PROPERTY));
+ for (Map<String, Object> map : listOfMaps) {
+ keys.add(new JsonWebKey(map));
+ }
+ return keys;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ public void setKeys(List<JsonWebKey> keys) {
+ super.setValue(KEYS_PROPERTY, keys);
+ }
+
+ public Map<String, JsonWebKey> getKeyIdMap() {
+ List<JsonWebKey> keys = getKeys();
+ if (keys == null) {
+ return Collections.emptyMap();
+ }
+ Map<String, JsonWebKey> map = new LinkedHashMap<String, JsonWebKey>();
+ for (JsonWebKey key : keys) {
+ String kid = key.getKid();
+ if (kid != null) {
+ map.put(kid, key);
+ }
+ }
+ return map;
+ }
+ public JsonWebKey getKey(String kid) {
+ return getKeyIdMap().get(kid);
+ }
+ public Map<String, List<JsonWebKey>> getKeyTypeMap() {
+ return getKeyPropertyMap(JsonWebKey.KEY_TYPE);
+ }
+ public Map<String, List<JsonWebKey>> getKeyUseMap() {
+ return getKeyPropertyMap(JsonWebKey.PUBLIC_KEY_USE);
+ }
+ private Map<String, List<JsonWebKey>> getKeyPropertyMap(String propertyName) {
+ List<JsonWebKey> keys = getKeys();
+ if (keys == null) {
+ return Collections.emptyMap();
+ }
+ Map<String, List<JsonWebKey>> map = new LinkedHashMap<String, List<JsonWebKey>>();
+ for (JsonWebKey key : keys) {
+ String propValue = (String)key.getProperty(propertyName);
+ if (propValue != null) {
+ List<JsonWebKey> list = map.get(propValue);
+ if (list == null) {
+ list = new LinkedList<JsonWebKey>();
+ map.put(propValue, list);
+ }
+ list.add(key);
+ }
+ }
+ return map;
+ }
+ public Map<String, List<JsonWebKey>> getKeyOperationMap() {
+ List<JsonWebKey> keys = getKeys();
+ if (keys == null) {
+ return Collections.emptyMap();
+ }
+ Map<String, List<JsonWebKey>> map = new LinkedHashMap<String, List<JsonWebKey>>();
+ for (JsonWebKey key : keys) {
+ List<String> ops = key.getKeyOperation();
+ if (ops != null) {
+ for (String op : ops) {
+ List<JsonWebKey> list = map.get(op);
+ if (list == null) {
+ list = new LinkedList<JsonWebKey>();
+ map.put(op, list);
+ }
+ list.add(key);
+ }
+ }
+ }
+ return map;
+ }
+ public List<JsonWebKey> getKeys(String keyType) {
+ return getKeyTypeMap().get(keyType);
+ }
+ public List<JsonWebKey> getRsaKeys() {
+ return getKeyTypeMap().get(JsonWebKey.KEY_TYPE_RSA);
+ }
+ public List<JsonWebKey> getEllipticKeys() {
+ return getKeyTypeMap().get(JsonWebKey.KEY_TYPE_ELLIPTIC);
+ }
+ public List<JsonWebKey> getSecretKeys() {
+ return getKeyTypeMap().get(JsonWebKey.KEY_TYPE_OCTET);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkReaderWriter.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkReaderWriter.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkReaderWriter.java
new file mode 100644
index 0000000..679b7aa
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkReaderWriter.java
@@ -0,0 +1,27 @@
+/**
+ * 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;
+
+
+public interface JwkReaderWriter {
+ String jwkToJson(JsonWebKey jwk);
+ JsonWebKey jsonToJwk(String jwkJson);
+ String jwkSetToJson(JsonWebKeys jwkSet);
+ JsonWebKeys jsonToJwkSet(String jwkSetJson);
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java
new file mode 100644
index 0000000..c994b1e
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwk/JwkUtils.java
@@ -0,0 +1,280 @@
+/**
+ * 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.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import javax.crypto.SecretKey;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.rs.security.jose.jaxrs.KeyManagementUtils;
+import org.apache.cxf.rs.security.jose.jaxrs.PrivateKeyPasswordProvider;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+import org.apache.cxf.rs.security.jose.jwe.AesCbcHmacJweDecryption;
+import org.apache.cxf.rs.security.jose.jwe.AesCbcHmacJweEncryption;
+import org.apache.cxf.rs.security.jose.jwe.JweDecryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.JweEncryptionProvider;
+import org.apache.cxf.rs.security.jose.jwe.KeyDecryptionAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.KeyEncryptionAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.PbesHmacAesWrapKeyDecryptionAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.PbesHmacAesWrapKeyEncryptionAlgorithm;
+
+public final class JwkUtils {
+ public static final String JWK_KEY_STORE_TYPE = "jwk";
+ public static final String RSSEC_KEY_STORE_JWKSET = "rs.security.keystore.jwkset";
+ public static final String RSSEC_KEY_STORE_JWKKEY = "rs.security.keystore.jwkkey";
+ private JwkUtils() {
+
+ }
+ public static JsonWebKey readJwkKey(InputStream is) throws IOException {
+ return new DefaultJwkReaderWriter().jsonToJwk(IOUtils.readStringFromStream(is));
+ }
+ public static JsonWebKeys readJwkSet(InputStream is) throws IOException {
+ return new DefaultJwkReaderWriter().jsonToJwkSet(IOUtils.readStringFromStream(is));
+ }
+ public static JsonWebKey readJwkKey(String jwkJson) {
+ return new DefaultJwkReaderWriter().jsonToJwk(jwkJson);
+ }
+ public static JsonWebKeys readJwkSet(String jwksJson) {
+ return new DefaultJwkReaderWriter().jsonToJwkSet(jwksJson);
+ }
+ public static String jwkKeyToJson(JsonWebKey jwkKey) {
+ return new DefaultJwkReaderWriter().jwkToJson(jwkKey);
+ }
+ public static String jwkSetToJson(JsonWebKeys jwkSet) {
+ return new DefaultJwkReaderWriter().jwkSetToJson(jwkSet);
+ }
+ public static String encryptJwkSet(JsonWebKeys jwkSet, char[] password) {
+ return encryptJwkSet(jwkSet, password, new DefaultJwkReaderWriter());
+ }
+ public static String encryptJwkSet(JsonWebKeys jwkSet, char[] password, JwkReaderWriter writer) {
+ return encryptJwkSet(jwkSet, createDefaultEncryption(password), writer);
+ }
+ public static String encryptJwkSet(JsonWebKeys jwkSet, JweEncryptionProvider jwe, JwkReaderWriter writer) {
+ return jwe.encrypt(stringToBytes(writer.jwkSetToJson(jwkSet)), "jwk-set+json");
+ }
+ public static JsonWebKeys decryptJwkSet(String jsonJwkSet, char[] password) {
+ return decryptJwkSet(jsonJwkSet, password, new DefaultJwkReaderWriter());
+ }
+ public static JsonWebKeys decryptJwkSet(String jsonJwkSet, char[] password, JwkReaderWriter reader) {
+ return decryptJwkSet(jsonJwkSet, createDefaultDecryption(password), reader);
+ }
+ public static JsonWebKeys decryptJwkSet(String jsonJwkSet, JweDecryptionProvider jwe, JwkReaderWriter reader) {
+ return reader.jsonToJwkSet(jwe.decrypt(jsonJwkSet).getContentText());
+ }
+ public static JsonWebKeys decryptJwkSet(InputStream is, char[] password) throws IOException {
+ return decryptJwkSet(is, password, new DefaultJwkReaderWriter());
+ }
+ public static JsonWebKeys decryptJwkSet(InputStream is, char[] password, JwkReaderWriter reader)
+ throws IOException {
+ return decryptJwkSet(is, createDefaultDecryption(password), reader);
+ }
+ public static JsonWebKeys decryptJwkSet(InputStream is, JweDecryptionProvider jwe, JwkReaderWriter reader)
+ throws IOException {
+ return reader.jsonToJwkSet(jwe.decrypt(IOUtils.readStringFromStream(is)).getContentText());
+ }
+ public static String encryptJwkKey(JsonWebKey jwk, char[] password) {
+ return encryptJwkKey(jwk, password, new DefaultJwkReaderWriter());
+ }
+ public static String encryptJwkKey(JsonWebKey jwkKey, char[] password, JwkReaderWriter writer) {
+ return encryptJwkKey(jwkKey, createDefaultEncryption(password), writer);
+ }
+ public static String encryptJwkKey(JsonWebKey jwkKey, JweEncryptionProvider jwe, JwkReaderWriter writer) {
+ return jwe.encrypt(stringToBytes(writer.jwkToJson(jwkKey)), "jwk+json");
+ }
+ public static JsonWebKey decryptJwkKey(String jsonJwkKey, char[] password) {
+ return decryptJwkKey(jsonJwkKey, password, new DefaultJwkReaderWriter());
+ }
+ public static JsonWebKey decryptJwkKey(String jsonJwkKey, char[] password, JwkReaderWriter reader) {
+ return decryptJwkKey(jsonJwkKey, createDefaultDecryption(password), reader);
+ }
+ public static JsonWebKey decryptJwkKey(String jsonJwkKey, JweDecryptionProvider jwe, JwkReaderWriter reader) {
+ return reader.jsonToJwk(jwe.decrypt(jsonJwkKey).getContentText());
+ }
+ public static JsonWebKey decryptJwkKey(InputStream is, char[] password) throws IOException {
+ return decryptJwkKey(is, password, new DefaultJwkReaderWriter());
+ }
+ public static JsonWebKey decryptJwkKey(InputStream is, char[] password, JwkReaderWriter reader)
+ throws IOException {
+ return decryptJwkKey(is, createDefaultDecryption(password), reader);
+ }
+ public static JsonWebKey decryptJwkKey(InputStream is, JweDecryptionProvider jwe, JwkReaderWriter reader)
+ throws IOException {
+ return reader.jsonToJwk(jwe.decrypt(IOUtils.readStringFromStream(is)).getContentText());
+ }
+ private static JweEncryptionProvider createDefaultEncryption(char[] password) {
+ KeyEncryptionAlgorithm keyEncryption =
+ new PbesHmacAesWrapKeyEncryptionAlgorithm(password, Algorithm.PBES2_HS256_A128KW.getJwtName());
+ return new AesCbcHmacJweEncryption(Algorithm.A128CBC_HS256.getJwtName(), keyEncryption);
+ }
+ private static JweDecryptionProvider createDefaultDecryption(char[] password) {
+ KeyDecryptionAlgorithm keyDecryption = new PbesHmacAesWrapKeyDecryptionAlgorithm(password);
+ return new AesCbcHmacJweDecryption(keyDecryption);
+ }
+ public static JsonWebKeys loadJwkSet(Message m, Properties props, PrivateKeyPasswordProvider cb) {
+ return loadJwkSet(m, props, cb, new DefaultJwkReaderWriter());
+ }
+ public static JsonWebKeys loadJwkSet(Message m, Properties props, PrivateKeyPasswordProvider cb,
+ JwkReaderWriter reader) {
+ JsonWebKeys jwkSet = (JsonWebKeys)m.getExchange().get(props.get(KeyManagementUtils.RSSEC_KEY_STORE_FILE));
+ if (jwkSet == null) {
+ jwkSet = loadJwkSet(props, m.getExchange().getBus(), cb, reader);
+ m.getExchange().put((String)props.get(KeyManagementUtils.RSSEC_KEY_STORE_FILE), jwkSet);
+ }
+ return jwkSet;
+ }
+ public static JsonWebKeys loadJwkSet(Properties props, Bus bus, PrivateKeyPasswordProvider cb) {
+ return loadJwkSet(props, bus, cb, new DefaultJwkReaderWriter());
+ }
+ public static JsonWebKeys loadJwkSet(Properties props, Bus bus, PrivateKeyPasswordProvider cb,
+ JwkReaderWriter reader) {
+ JweDecryptionProvider decryption = cb != null
+ ? new AesCbcHmacJweDecryption(new PbesHmacAesWrapKeyDecryptionAlgorithm(cb.getPassword(props))) : null;
+ return loadJwkSet(props, bus, decryption, reader);
+ }
+ public static JsonWebKeys loadJwkSet(Properties props, Bus bus, JweDecryptionProvider jwe, JwkReaderWriter reader) {
+ String keyContent = null;
+ String keyStoreLoc = props.getProperty(KeyManagementUtils.RSSEC_KEY_STORE_FILE);
+ if (keyStoreLoc != null) {
+ try {
+ InputStream is = ResourceUtils.getResourceStream(keyStoreLoc, bus);
+ keyContent = IOUtils.readStringFromStream(is);
+ } catch (Exception ex) {
+ throw new SecurityException(ex);
+ }
+ } else {
+ keyContent = props.getProperty(RSSEC_KEY_STORE_JWKSET);
+ if (keyContent == null) {
+ keyContent = props.getProperty(RSSEC_KEY_STORE_JWKKEY);
+ }
+ }
+ if (jwe != null) {
+ keyContent = jwe.decrypt(keyContent).getContentText();
+ }
+ if (props.getProperty(RSSEC_KEY_STORE_JWKKEY) == null) {
+ return reader.jsonToJwkSet(keyContent);
+ } else {
+ JsonWebKey key = reader.jsonToJwk(keyContent);
+ JsonWebKeys keys = new JsonWebKeys();
+ keys.setKeys(Collections.singletonList(key));
+ return keys;
+ }
+ }
+ public static JsonWebKey loadJsonWebKey(Message m, Properties props, String keyOper) {
+ return loadJsonWebKey(m, props, keyOper, new DefaultJwkReaderWriter());
+ }
+ public static JsonWebKey loadJsonWebKey(Message m, Properties props, String keyOper, JwkReaderWriter reader) {
+ PrivateKeyPasswordProvider cb =
+ (PrivateKeyPasswordProvider)m.getContextualProperty(KeyManagementUtils.RSSEC_KEY_PSWD_PROVIDER);
+ if (cb == null && keyOper != null) {
+ String propName = keyOper.equals(JsonWebKey.KEY_OPER_SIGN) ? KeyManagementUtils.RSSEC_SIG_KEY_PSWD_PROVIDER
+ : keyOper.equals(JsonWebKey.KEY_OPER_ENCRYPT)
+ ? KeyManagementUtils.RSSEC_DECRYPT_KEY_PSWD_PROVIDER : null;
+ if (propName != null) {
+ cb = (PrivateKeyPasswordProvider)m.getContextualProperty(propName);
+ }
+ }
+ JsonWebKeys jwkSet = loadJwkSet(m, props, cb, reader);
+ String kid = props.getProperty(KeyManagementUtils.RSSEC_KEY_STORE_ALIAS);
+ if (kid == null && keyOper != null) {
+ String keyIdProp = null;
+ if (keyOper.equals(JsonWebKey.KEY_OPER_ENCRYPT)) {
+ keyIdProp = KeyManagementUtils.RSSEC_KEY_STORE_ALIAS + ".jwe";
+ } else if (keyOper.equals(JsonWebKey.KEY_OPER_SIGN)
+ || keyOper.equals(JsonWebKey.KEY_OPER_VERIFY)) {
+ keyIdProp = KeyManagementUtils.RSSEC_KEY_STORE_ALIAS + ".jws";
+ }
+ if (keyIdProp != null) {
+ kid = props.getProperty(keyIdProp);
+ }
+ }
+ if (kid != null) {
+ return jwkSet.getKey(kid);
+ } else if (keyOper != null) {
+ List<JsonWebKey> keys = jwkSet.getKeyUseMap().get(keyOper);
+ if (keys != null && keys.size() == 1) {
+ return keys.get(0);
+ }
+ }
+ return null;
+ }
+ public static RSAPublicKey toRSAPublicKey(JsonWebKey jwk) {
+ String encodedModulus = (String)jwk.getProperty(JsonWebKey.RSA_MODULUS);
+ String encodedPublicExponent = (String)jwk.getProperty(JsonWebKey.RSA_PUBLIC_EXP);
+ return CryptoUtils.getRSAPublicKey(encodedModulus, encodedPublicExponent);
+ }
+ public static RSAPrivateKey toRSAPrivateKey(JsonWebKey jwk) {
+ String encodedModulus = (String)jwk.getProperty(JsonWebKey.RSA_MODULUS);
+ String encodedPrivateExponent = (String)jwk.getProperty(JsonWebKey.RSA_PRIVATE_EXP);
+ String encodedPrimeP = (String)jwk.getProperty(JsonWebKey.RSA_FIRST_PRIME_FACTOR);
+ if (encodedPrimeP == null) {
+ return CryptoUtils.getRSAPrivateKey(encodedModulus, encodedPrivateExponent);
+ } else {
+ String encodedPublicExponent = (String)jwk.getProperty(JsonWebKey.RSA_PUBLIC_EXP);
+ String encodedPrimeQ = (String)jwk.getProperty(JsonWebKey.RSA_SECOND_PRIME_FACTOR);
+ String encodedPrimeExpP = (String)jwk.getProperty(JsonWebKey.RSA_FIRST_PRIME_CRT);
+ String encodedPrimeExpQ = (String)jwk.getProperty(JsonWebKey.RSA_SECOND_PRIME_CRT);
+ String encodedCrtCoefficient = (String)jwk.getProperty(JsonWebKey.RSA_FIRST_CRT_COEFFICIENT);
+ return CryptoUtils.getRSAPrivateKey(encodedModulus,
+ encodedPublicExponent,
+ encodedPrivateExponent,
+ encodedPrimeP,
+ encodedPrimeQ,
+ encodedPrimeExpP,
+ encodedPrimeExpQ,
+ encodedCrtCoefficient);
+ }
+ }
+ public static ECPublicKey toECPublicKey(JsonWebKey jwk) {
+ String eCurve = (String)jwk.getProperty(JsonWebKey.EC_CURVE);
+ String encodedXCoord = (String)jwk.getProperty(JsonWebKey.EC_X_COORDINATE);
+ String encodedYCoord = (String)jwk.getProperty(JsonWebKey.EC_Y_COORDINATE);
+ return CryptoUtils.getECPublicKey(eCurve, encodedXCoord, encodedYCoord);
+ }
+ public static ECPrivateKey toECPrivateKey(JsonWebKey jwk) {
+ String eCurve = (String)jwk.getProperty(JsonWebKey.EC_CURVE);
+ String encodedPrivateKey = (String)jwk.getProperty(JsonWebKey.EC_PRIVATE_KEY);
+ return CryptoUtils.getECPrivateKey(eCurve, encodedPrivateKey);
+ }
+
+ public static SecretKey toSecretKey(JsonWebKey jwk) {
+ return CryptoUtils.createSecretKeySpec((String)jwk.getProperty(JsonWebKey.OCTET_KEY_VALUE),
+ Algorithm.toJavaName(jwk.getAlgorithm()));
+ }
+ private static byte[] stringToBytes(String str) {
+ try {
+ return str.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException ex) {
+ throw new SecurityException(ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/AbstractJwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/AbstractJwsSignatureProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/AbstractJwsSignatureProvider.java
new file mode 100644
index 0000000..fd1a390
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/AbstractJwsSignatureProvider.java
@@ -0,0 +1,59 @@
+/**
+ * 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;
+
+
+public abstract class AbstractJwsSignatureProvider implements JwsSignatureProvider {
+ private String algorithm;
+
+ protected AbstractJwsSignatureProvider(String algo) {
+ this.algorithm = algo;
+ }
+
+ protected JwsHeaders prepareHeaders(JwsHeaders headers) {
+ if (headers == null) {
+ headers = new JwsHeaders();
+ }
+ String algo = headers.getAlgorithm();
+ if (algo != null) {
+ checkAlgorithm(algo);
+ } else {
+ checkAlgorithm(algorithm);
+ headers.setAlgorithm(algorithm);
+ }
+ return headers;
+ }
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+ @Override
+ public JwsSignature createJwsSignature(JwsHeaders headers) {
+ return doCreateJwsSignature(prepareHeaders(headers));
+ }
+
+ protected abstract JwsSignature doCreateJwsSignature(JwsHeaders headers);
+
+ protected void checkAlgorithm(String algo) {
+ if (algo == null) {
+ throw new SecurityException();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureProvider.java
new file mode 100644
index 0000000..b6da904
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureProvider.java
@@ -0,0 +1,42 @@
+/**
+ * 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.SecureRandom;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class EcDsaJwsSignatureProvider extends PrivateKeyJwsSignatureProvider {
+ public EcDsaJwsSignatureProvider(ECPrivateKey key, String algo) {
+ this(key, null, algo);
+ }
+ public EcDsaJwsSignatureProvider(ECPrivateKey key, AlgorithmParameterSpec spec, String algo) {
+ this(key, null, spec, algo);
+ }
+ public EcDsaJwsSignatureProvider(ECPrivateKey key, SecureRandom random, AlgorithmParameterSpec spec,
+ String algo) {
+ super(key, random, spec, algo);
+ }
+ @Override
+ protected boolean isValidAlgorithmFamily(String algo) {
+ return Algorithm.isEcDsaSign(algo);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureVerifier.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureVerifier.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureVerifier.java
new file mode 100644
index 0000000..97a8991
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/EcDsaJwsSignatureVerifier.java
@@ -0,0 +1,40 @@
+/**
+ * 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.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class EcDsaJwsSignatureVerifier extends PublicKeyJwsSignatureVerifier {
+ public EcDsaJwsSignatureVerifier(PublicKey key) {
+ this(key, null);
+ }
+ public EcDsaJwsSignatureVerifier(PublicKey key, String supportedAlgo) {
+ this(key, null, supportedAlgo);
+ }
+ public EcDsaJwsSignatureVerifier(PublicKey key, AlgorithmParameterSpec spec, String supportedAlgo) {
+ super(key, spec, supportedAlgo);
+ }
+ @Override
+ protected boolean isValidAlgorithmFamily(String algo) {
+ return Algorithm.isEcDsaSign(algo);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureProvider.java
new file mode 100644
index 0000000..3808d4e
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureProvider.java
@@ -0,0 +1,75 @@
+/**
+ * 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.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Mac;
+
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.crypto.HmacUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class HmacJwsSignatureProvider extends AbstractJwsSignatureProvider {
+ private byte[] key;
+ private AlgorithmParameterSpec hmacSpec;
+
+ public HmacJwsSignatureProvider(byte[] key, String algo) {
+ this(key, null, algo);
+ }
+ public HmacJwsSignatureProvider(byte[] key, AlgorithmParameterSpec spec, String algo) {
+ super(algo);
+ this.key = key;
+ this.hmacSpec = spec;
+ }
+ public HmacJwsSignatureProvider(String encodedKey, String algo) {
+ super(algo);
+ try {
+ this.key = Base64UrlUtility.decode(encodedKey);
+ } catch (Base64Exception ex) {
+ throw new SecurityException();
+ }
+ }
+
+ protected JwsSignature doCreateJwsSignature(JwsHeaders headers) {
+ final Mac mac = HmacUtils.getInitializedMac(key, Algorithm.toJavaName(headers.getAlgorithm()),
+ hmacSpec);
+ return new JwsSignature() {
+
+ @Override
+ public void update(byte[] src, int off, int len) {
+ mac.update(src, off, len);
+ }
+
+ @Override
+ public byte[] sign() {
+ return mac.doFinal();
+ }
+
+ };
+ }
+ @Override
+ protected void checkAlgorithm(String algo) {
+ super.checkAlgorithm(algo);
+ if (!Algorithm.isHmacSign(algo)) {
+ throw new SecurityException();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureVerifier.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureVerifier.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureVerifier.java
new file mode 100644
index 0000000..4ad9c27
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/HmacJwsSignatureVerifier.java
@@ -0,0 +1,79 @@
+/**
+ * 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.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
+
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.crypto.HmacUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+import org.apache.cxf.rs.security.jose.jwt.JwtHeaders;
+
+public class HmacJwsSignatureVerifier implements JwsSignatureVerifier {
+ private byte[] key;
+ private AlgorithmParameterSpec hmacSpec;
+ private String supportedAlgo;
+
+ public HmacJwsSignatureVerifier(byte[] key) {
+ this(key, null);
+ }
+ public HmacJwsSignatureVerifier(byte[] key, AlgorithmParameterSpec spec) {
+ this(key, spec, null);
+ }
+ public HmacJwsSignatureVerifier(byte[] key, AlgorithmParameterSpec spec, String supportedAlgo) {
+ this.key = key;
+ this.hmacSpec = spec;
+ this.supportedAlgo = supportedAlgo;
+ }
+ public HmacJwsSignatureVerifier(String encodedKey) {
+ this(encodedKey, null);
+ }
+ public HmacJwsSignatureVerifier(String encodedKey, String supportedAlgo) {
+ try {
+ this.key = Base64UrlUtility.decode(encodedKey);
+ } catch (Base64Exception ex) {
+ throw new SecurityException();
+ }
+ this.supportedAlgo = supportedAlgo;
+ }
+
+ @Override
+ public boolean verify(JwtHeaders headers, String unsignedText, byte[] signature) {
+ byte[] expected = computeMac(headers, unsignedText);
+ return Arrays.equals(expected, signature);
+ }
+
+ private byte[] computeMac(JwtHeaders headers, String text) {
+ return HmacUtils.computeHmac(key,
+ Algorithm.toJavaName(checkAlgorithm(headers.getAlgorithm())),
+ hmacSpec,
+ text);
+ }
+
+ protected String checkAlgorithm(String algo) {
+ if (algo == null
+ || !Algorithm.isHmacSign(algo)
+ || supportedAlgo != null && !supportedAlgo.equals(algo)) {
+ throw new SecurityException();
+ }
+ return algo;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactConsumer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactConsumer.java
new file mode 100644
index 0000000..f202c36
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactConsumer.java
@@ -0,0 +1,118 @@
+/**
+ * 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.UnsupportedEncodingException;
+
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.rs.security.jose.JoseHeaders;
+import org.apache.cxf.rs.security.jose.JoseHeadersReader;
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+
+public class JwsCompactConsumer {
+ private JoseHeadersReader reader = new JoseHeadersReaderWriter();
+ private String encodedSequence;
+ private String encodedSignature;
+ private String headersJson;
+ private String jwsPayload;
+ public JwsCompactConsumer(String encodedJws) {
+ this(encodedJws, null);
+ }
+ public JwsCompactConsumer(String encodedJws, JoseHeadersReader r) {
+ if (r != null) {
+ this.reader = r;
+ }
+ String[] parts = encodedJws.split("\\.");
+ if (parts.length != 3) {
+ if (parts.length == 2 && encodedJws.endsWith(".")) {
+ encodedSignature = "";
+ } else {
+ throw new SecurityException("Invalid JWS Compact sequence");
+ }
+ } else {
+ encodedSignature = parts[2];
+ }
+ headersJson = decodeToString(parts[0]);
+ jwsPayload = decodeToString(parts[1]);
+ encodedSequence = parts[0] + "." + parts[1];
+
+ }
+ public String getUnsignedEncodedPayload() {
+ return encodedSequence;
+ }
+ public String getEncodedSignature() {
+ return encodedSignature;
+ }
+ public String getDecodedJsonHeaders() {
+ return headersJson;
+ }
+ public String getDecodedJwsPayload() {
+ return jwsPayload;
+ }
+ public byte[] getDecodedJwsPayloadBytes() {
+ try {
+ return jwsPayload.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException ex) {
+ throw new SecurityException(ex);
+ }
+ }
+ public byte[] getDecodedSignature() {
+ return encodedSignature.isEmpty() ? new byte[]{} : decode(encodedSignature);
+ }
+ public JwsHeaders getJwsHeaders() {
+ JoseHeaders joseHeaders = reader.fromJsonHeaders(headersJson);
+ if (joseHeaders.getHeaderUpdateCount() != null) {
+ throw new SecurityException();
+ }
+ return new JwsHeaders(joseHeaders);
+ }
+ public boolean verifySignatureWith(JwsSignatureVerifier validator) {
+ try {
+ if (validator.verify(getJwsHeaders(), getUnsignedEncodedPayload(), getDecodedSignature())) {
+ return true;
+ }
+ } catch (SecurityException ex) {
+ // ignore
+ }
+ return false;
+ }
+ public boolean verifySignatureWith(JsonWebKey key) {
+ return verifySignatureWith(JwsUtils.getSignatureVerifier(key));
+ }
+ private static String decodeToString(String encoded) {
+ try {
+ return new String(decode(encoded), "UTF-8");
+ } catch (UnsupportedEncodingException ex) {
+ throw new SecurityException(ex);
+ }
+
+ }
+ protected JoseHeadersReader getReader() {
+ return reader;
+ }
+ private static byte[] decode(String encoded) {
+ try {
+ return Base64UrlUtility.decode(encoded);
+ } catch (Base64Exception ex) {
+ throw new SecurityException(ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactProducer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactProducer.java
new file mode 100644
index 0000000..307cf26
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsCompactProducer.java
@@ -0,0 +1,113 @@
+/**
+ * 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.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.rs.security.jose.JoseConstants;
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+import org.apache.cxf.rs.security.jose.JoseHeadersWriter;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+
+public class JwsCompactProducer {
+ private JoseHeadersWriter writer = new JoseHeadersReaderWriter();
+ private JwsHeaders headers;
+ private String plainJwsPayload;
+ private String signature;
+ private String plainRep;
+
+ public JwsCompactProducer(String plainJwsPayload) {
+ this(null, null, plainJwsPayload);
+ }
+ public JwsCompactProducer(JwsHeaders headers, String plainJwsPayload) {
+ this(headers, null, plainJwsPayload);
+ }
+ public JwsCompactProducer(JwsHeaders headers, JoseHeadersWriter w, String plainJwsPayload) {
+ this.headers = headers;
+ if (w != null) {
+ this.writer = w;
+ }
+ this.plainJwsPayload = plainJwsPayload;
+ }
+ public JwsHeaders getHeaders() {
+ if (headers == null) {
+ headers = new JwsHeaders();
+ }
+ return headers;
+ }
+ public String getUnsignedEncodedJws() {
+ checkAlgorithm();
+ if (plainRep == null) {
+ plainRep = Base64UrlUtility.encode(writer.headersToJson(getHeaders()))
+ + "."
+ + Base64UrlUtility.encode(plainJwsPayload);
+ }
+ return plainRep;
+ }
+
+ public String getSignedEncodedJws() {
+ checkAlgorithm();
+ boolean noSignature = StringUtils.isEmpty(signature);
+ if (noSignature && !isPlainText()) {
+ throw new IllegalStateException("Signature is not available");
+ }
+ return getUnsignedEncodedJws() + "." + (noSignature ? "" : signature);
+ }
+
+ public String signWith(JsonWebKey jwk) {
+ return signWith(JwsUtils.getSignatureProvider(jwk));
+ }
+
+ public String signWith(JwsSignatureProvider signer) {
+ JwsSignature worker = signer.createJwsSignature(getHeaders());
+ try {
+ byte[] bytes = getUnsignedEncodedJws().getBytes("UTF-8");
+ worker.update(bytes, 0, bytes.length);
+ signWith(worker.sign());
+ return getSignedEncodedJws();
+ } catch (Exception ex) {
+ throw new SecurityException();
+ }
+ }
+
+ public String signWith(String signatureText) {
+ setEncodedSignature(Base64UrlUtility.encode(signatureText));
+ return getSignedEncodedJws();
+ }
+
+ public String signWith(byte[] signatureOctets) {
+ setEncodedSignature(Base64UrlUtility.encode(signatureOctets));
+ return getSignedEncodedJws();
+ }
+
+ private void setEncodedSignature(String sig) {
+ this.signature = sig;
+ }
+ private boolean isPlainText() {
+ return JoseConstants.PLAIN_TEXT_ALGO.equals(getAlgorithm());
+ }
+ private String getAlgorithm() {
+ return getHeaders().getAlgorithm();
+ }
+ private void checkAlgorithm() {
+ if (getAlgorithm() == null) {
+ throw new IllegalStateException("Algorithm header is not set");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsHeaders.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsHeaders.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsHeaders.java
new file mode 100644
index 0000000..8ef08a6
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsHeaders.java
@@ -0,0 +1,37 @@
+/**
+ * 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.Map;
+
+import org.apache.cxf.rs.security.jose.JoseHeaders;
+import org.apache.cxf.rs.security.jose.jwt.JwtHeaders;
+
+public class JwsHeaders extends JwtHeaders {
+ public JwsHeaders() {
+ }
+
+ public JwsHeaders(JoseHeaders headers) {
+ super(headers.asMap());
+ }
+
+ public JwsHeaders(Map<String, Object> values) {
+ super(values);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java
new file mode 100644
index 0000000..61138af
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactConsumer.java
@@ -0,0 +1,49 @@
+/**
+ * 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.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.jose.jwt.JwtTokenJson;
+import org.apache.cxf.rs.security.jose.jwt.JwtTokenReader;
+import org.apache.cxf.rs.security.jose.jwt.JwtTokenReaderWriter;
+
+public class JwsJwtCompactConsumer extends JwsCompactConsumer {
+ private JwtToken token;
+ public JwsJwtCompactConsumer(String encodedJws) {
+ this(encodedJws, null);
+ }
+ public JwsJwtCompactConsumer(String encodedJws, JwtTokenReader r) {
+ super(encodedJws, r == null ? new JwtTokenReaderWriter() : r);
+ }
+ public JwtTokenJson getDecodedJsonToken() {
+ return new JwtTokenJson(getDecodedJsonHeaders(), getDecodedJwsPayload());
+ }
+ public JwtClaims getJwtClaims() {
+ return getJwtToken().getClaims();
+ }
+ public JwtToken getJwtToken() {
+ if (token == null) {
+ token = ((JwtTokenReaderWriter)getReader()).fromJson(
+ new JwtTokenJson(getDecodedJsonHeaders(), getDecodedJwsPayload()));
+ }
+ return token;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java
new file mode 100644
index 0000000..19c194d
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJwtCompactProducer.java
@@ -0,0 +1,51 @@
+/**
+ * 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.jwt.JwtClaims;
+import org.apache.cxf.rs.security.jose.jwt.JwtHeaders;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+import org.apache.cxf.rs.security.jose.jwt.JwtTokenReaderWriter;
+import org.apache.cxf.rs.security.jose.jwt.JwtTokenWriter;
+
+public class JwsJwtCompactProducer extends JwsCompactProducer {
+
+ public JwsJwtCompactProducer(JwtToken token) {
+ this(token, null);
+ }
+ public JwsJwtCompactProducer(JwtClaims claims) {
+ this(new JwtToken(null, claims), null);
+ }
+ public JwsJwtCompactProducer(JwtHeaders headers, JwtClaims claims) {
+ this(headers, claims, null);
+ }
+ public JwsJwtCompactProducer(JwtHeaders headers, JwtClaims claims, JwtTokenWriter w) {
+ this(new JwtToken(headers, claims), w);
+ }
+ public JwsJwtCompactProducer(JwtToken token, JwtTokenWriter w) {
+ super(new JwsHeaders(token.getHeaders().asMap()), w, serializeClaims(token.getClaims(), w));
+ }
+
+ private static String serializeClaims(JwtClaims claims, JwtTokenWriter writer) {
+ if (writer == null) {
+ writer = new JwtTokenReaderWriter();
+ }
+ return writer.claimsToJson(claims);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.java
new file mode 100644
index 0000000..f10f30c
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsOutputStream.java
@@ -0,0 +1,66 @@
+/**
+ * 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.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+
+public class JwsOutputStream extends FilterOutputStream {
+ private boolean flushed;
+ private JwsSignature signature;
+ public JwsOutputStream(OutputStream out, JwsSignature signature) {
+ super(out);
+ this.signature = signature;
+ }
+
+ @Override
+ public void write(int value) throws IOException {
+ byte[] bytes = ByteBuffer.allocate(Integer.SIZE / 8).putInt(value).array();
+ write(bytes, 0, bytes.length);
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) throws IOException {
+ try {
+ signature.update(b, off, len);
+ } catch (Throwable ex) {
+ throw new SecurityException();
+ }
+ out.write(b, off, len);
+ }
+ @Override
+ public void flush() throws IOException {
+ if (flushed) {
+ return;
+ }
+ try {
+ byte[] finalBytes = signature.sign();
+ out.write(new byte[]{'.'});
+ Base64UrlUtility.encodeAndStream(finalBytes, 0, finalBytes.length, out);
+ } catch (Exception ex) {
+ throw new SecurityException();
+ }
+ flushed = true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java
new file mode 100644
index 0000000..778b5cb
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignature.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+
+public interface JwsSignature {
+ void update(byte[] src, int off, int len);
+ byte[] sign();
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java
new file mode 100644
index 0000000..010c62e
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureProvider.java
@@ -0,0 +1,25 @@
+/**
+ * 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;
+
+
+public interface JwsSignatureProvider {
+ String getAlgorithm();
+ JwsSignature createJwsSignature(JwsHeaders headers);
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java
new file mode 100644
index 0000000..ea4a01f
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsSignatureVerifier.java
@@ -0,0 +1,25 @@
+/**
+ * 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.jwt.JwtHeaders;
+
+public interface JwsSignatureVerifier {
+ boolean verify(JwtHeaders headers, String unsignedText, byte[] signature);
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
new file mode 100644
index 0000000..08c59c1
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsUtils.java
@@ -0,0 +1,67 @@
+/**
+ * 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.Algorithm;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
+
+public final class JwsUtils {
+ private JwsUtils() {
+
+ }
+ public static JwsSignatureProvider getSignatureProvider(JsonWebKey jwk) {
+ return getSignatureProvider(jwk, null);
+ }
+ public static JwsSignatureProvider getSignatureProvider(JsonWebKey jwk, String defaultAlgorithm) {
+ String rsaSignatureAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm : jwk.getAlgorithm();
+ JwsSignatureProvider theSigProvider = null;
+ if (JsonWebKey.KEY_TYPE_RSA.equals(jwk.getKeyType())) {
+ theSigProvider = new PrivateKeyJwsSignatureProvider(JwkUtils.toRSAPrivateKey(jwk),
+ rsaSignatureAlgo);
+ } else if (JsonWebKey.KEY_TYPE_OCTET.equals(jwk.getKeyType())
+ && Algorithm.isHmacSign(rsaSignatureAlgo)) {
+ theSigProvider =
+ new HmacJwsSignatureProvider((String)jwk.getProperty(JsonWebKey.OCTET_KEY_VALUE),
+ rsaSignatureAlgo);
+ } else if (JsonWebKey.KEY_TYPE_ELLIPTIC.equals(jwk.getKeyType())) {
+ theSigProvider = new EcDsaJwsSignatureProvider(JwkUtils.toECPrivateKey(jwk),
+ rsaSignatureAlgo);
+ }
+ return theSigProvider;
+ }
+ public static JwsSignatureVerifier getSignatureVerifier(JsonWebKey jwk) {
+ return getSignatureVerifier(jwk, null);
+ }
+ public static JwsSignatureVerifier getSignatureVerifier(JsonWebKey jwk, String defaultAlgorithm) {
+ String rsaSignatureAlgo = jwk.getAlgorithm() == null ? defaultAlgorithm : jwk.getAlgorithm();
+ JwsSignatureVerifier theVerifier = null;
+ if (JsonWebKey.KEY_TYPE_RSA.equals(jwk.getKeyType())) {
+ theVerifier = new PublicKeyJwsSignatureVerifier(JwkUtils.toRSAPublicKey(jwk), rsaSignatureAlgo);
+ } else if (JsonWebKey.KEY_TYPE_OCTET.equals(jwk.getKeyType())
+ && Algorithm.isHmacSign(rsaSignatureAlgo)) {
+ theVerifier =
+ new HmacJwsSignatureVerifier((String)jwk.getProperty(JsonWebKey.OCTET_KEY_VALUE), rsaSignatureAlgo);
+ } else if (JsonWebKey.KEY_TYPE_ELLIPTIC.equals(jwk.getKeyType())) {
+ theVerifier = new EcDsaJwsSignatureVerifier(JwkUtils.toECPublicKey(jwk), rsaSignatureAlgo);
+ }
+ return theVerifier;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java
new file mode 100644
index 0000000..c2f5a6a
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PrivateKeyJwsSignatureProvider.java
@@ -0,0 +1,87 @@
+/**
+ * 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.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class PrivateKeyJwsSignatureProvider extends AbstractJwsSignatureProvider {
+ private PrivateKey key;
+ private SecureRandom random;
+ private AlgorithmParameterSpec signatureSpec;
+
+ public PrivateKeyJwsSignatureProvider(PrivateKey key, String algo) {
+ this(key, null, algo);
+ }
+ public PrivateKeyJwsSignatureProvider(PrivateKey key, AlgorithmParameterSpec spec, String algo) {
+ this(key, null, spec, algo);
+ }
+ public PrivateKeyJwsSignatureProvider(PrivateKey key, SecureRandom random,
+ AlgorithmParameterSpec spec, String algo) {
+ super(algo);
+ this.key = key;
+ this.random = random;
+ this.signatureSpec = spec;
+ }
+ protected JwsSignature doCreateJwsSignature(JwsHeaders headers) {
+ final Signature s = CryptoUtils.getSignature(key,
+ Algorithm.toJavaName(headers.getAlgorithm()),
+ random,
+ signatureSpec);
+ return new JwsSignature() {
+
+ @Override
+ public void update(byte[] src, int off, int len) {
+ try {
+ s.update(src, off, len);
+ } catch (SignatureException ex) {
+ throw new SecurityException();
+ }
+ }
+
+ @Override
+ public byte[] sign() {
+ try {
+ return s.sign();
+ } catch (SignatureException ex) {
+ throw new SecurityException();
+ }
+ }
+
+ };
+ }
+ @Override
+ protected void checkAlgorithm(String algo) {
+ super.checkAlgorithm(algo);
+ if (!isValidAlgorithmFamily(algo)) {
+ throw new SecurityException();
+ }
+ }
+
+ protected boolean isValidAlgorithmFamily(String algo) {
+ return Algorithm.isRsaShaSign(algo);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java
new file mode 100644
index 0000000..d485256
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/PublicKeyJwsSignatureVerifier.java
@@ -0,0 +1,68 @@
+/**
+ * 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.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+import org.apache.cxf.rs.security.jose.jwt.JwtHeaders;
+
+public class PublicKeyJwsSignatureVerifier implements JwsSignatureVerifier {
+ private PublicKey key;
+ private AlgorithmParameterSpec signatureSpec;
+ private String supportedAlgo;
+
+ public PublicKeyJwsSignatureVerifier(PublicKey key) {
+ this(key, null);
+ }
+ public PublicKeyJwsSignatureVerifier(PublicKey key, String supportedAlgorithm) {
+ this(key, null, supportedAlgorithm);
+ }
+ public PublicKeyJwsSignatureVerifier(PublicKey key, AlgorithmParameterSpec spec, String supportedAlgo) {
+ this.key = key;
+ this.signatureSpec = spec;
+ this.supportedAlgo = supportedAlgo;
+ }
+ @Override
+ public boolean verify(JwtHeaders headers, String unsignedText, byte[] signature) {
+ try {
+ return CryptoUtils.verifySignature(unsignedText.getBytes("UTF-8"),
+ signature,
+ key,
+ Algorithm.toJavaName(checkAlgorithm(headers.getAlgorithm())),
+ signatureSpec);
+ } catch (Exception ex) {
+ throw new SecurityException(ex);
+ }
+ }
+ protected String checkAlgorithm(String algo) {
+ if (algo == null
+ || !isValidAlgorithmFamily(algo)
+ || supportedAlgo != null && !supportedAlgo.equals(algo)) {
+ throw new SecurityException();
+ }
+ return algo;
+ }
+ protected boolean isValidAlgorithmFamily(String algo) {
+ return Algorithm.isRsaShaSign(algo);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java
new file mode 100644
index 0000000..8944e07
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtClaims.java
@@ -0,0 +1,102 @@
+/**
+ * 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.jwt;
+
+import java.util.Map;
+
+import org.apache.cxf.rs.security.jose.AbstractJoseObject;
+
+
+
+
+public class JwtClaims extends AbstractJoseObject {
+
+ public JwtClaims() {
+ }
+
+ public JwtClaims(Map<String, Object> values) {
+ super(values);
+ }
+
+ public void setIssuer(String issuer) {
+ setClaim(JwtConstants.CLAIM_ISSUER, issuer);
+ }
+
+ public String getIssuer() {
+ return (String)getValue(JwtConstants.CLAIM_ISSUER);
+ }
+
+ public void setSubject(String subject) {
+ setClaim(JwtConstants.CLAIM_SUBJECT, subject);
+ }
+
+ public String getSubject() {
+ return (String)getClaim(JwtConstants.CLAIM_SUBJECT);
+ }
+
+ public void setAudience(String audience) {
+ setClaim(JwtConstants.CLAIM_AUDIENCE, audience);
+ }
+
+ public String getAudience() {
+ return (String)getClaim(JwtConstants.CLAIM_AUDIENCE);
+ }
+
+ public void setExpiryTime(Long expiresIn) {
+ setClaim(JwtConstants.CLAIM_EXPIRY, expiresIn);
+ }
+
+ public Long getExpiryTime() {
+ return getLongDate(JwtConstants.CLAIM_EXPIRY);
+ }
+
+ public void setNotBefore(Long notBefore) {
+ setClaim(JwtConstants.CLAIM_NOT_BEFORE, notBefore);
+ }
+
+ public Long getNotBefore() {
+ return getLongDate(JwtConstants.CLAIM_NOT_BEFORE);
+ }
+
+ public void setIssuedAt(Long issuedAt) {
+ setClaim(JwtConstants.CLAIM_ISSUED_AT, issuedAt);
+ }
+
+ public Long getIssuedAt() {
+ return getLongDate(JwtConstants.CLAIM_ISSUED_AT);
+ }
+
+ public void setTokenId(String id) {
+ setValue(JwtConstants.CLAIM_JWT_ID, id);
+ }
+
+ public String getTokenId() {
+ return (String)getClaim(JwtConstants.CLAIM_JWT_ID);
+ }
+
+ public JwtClaims setClaim(String name, Object value) {
+ setValue(name, value);
+ return this;
+ }
+
+ public Object getClaim(String name) {
+ return getValue(name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java
new file mode 100644
index 0000000..2f23e2c
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtConstants.java
@@ -0,0 +1,36 @@
+/**
+ * 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.jwt;
+
+public final class JwtConstants {
+
+ public static final String CLAIM_ISSUER = "iss";
+ public static final String CLAIM_SUBJECT = "sub";
+ public static final String CLAIM_AUDIENCE = "aud";
+ public static final String CLAIM_EXPIRY = "exp";
+ public static final String CLAIM_NOT_BEFORE = "nbf";
+ public static final String CLAIM_ISSUED_AT = "iat";
+ public static final String CLAIM_JWT_ID = "jti";
+
+
+ private JwtConstants() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtHeaders.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtHeaders.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtHeaders.java
new file mode 100644
index 0000000..e4a1891
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtHeaders.java
@@ -0,0 +1,53 @@
+/**
+ * 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.jwt;
+
+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.jwa.Algorithm;
+
+public class JwtHeaders extends JoseHeaders {
+
+ public JwtHeaders() {
+ }
+
+ public JwtHeaders(String algorithm) {
+ init(algorithm);
+ }
+
+ public JwtHeaders(Algorithm algo) {
+ init(algo.getJwtName());
+ }
+
+ public JwtHeaders(Map<String, Object> values) {
+ super(values);
+ }
+
+ public JwtHeaders(JoseHeaders headers) {
+ super(headers.asMap());
+ }
+
+ private void init(String algo) {
+ setType(JoseConstants.TYPE_JWT);
+ setAlgorithm(algo);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java
new file mode 100644
index 0000000..630813c
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtToken.java
@@ -0,0 +1,45 @@
+/**
+ * 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.jwt;
+
+
+
+public class JwtToken {
+ private JwtHeaders headers;
+ private JwtClaims claims;
+ public JwtToken(JwtHeaders headers, JwtClaims claims) {
+ this.headers = headers;
+ this.claims = claims;
+ }
+ public JwtHeaders getHeaders() {
+ return headers;
+ }
+ public JwtClaims getClaims() {
+ return claims;
+ }
+ public int hashCode() {
+ return headers.hashCode() + 37 * claims.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ return obj instanceof JwtToken
+ && ((JwtToken)obj).headers.equals(this.headers)
+ && ((JwtToken)obj).claims.equals(this.claims);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenJson.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenJson.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenJson.java
new file mode 100644
index 0000000..e8e79f0
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenJson.java
@@ -0,0 +1,37 @@
+/**
+ * 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.jwt;
+
+
+
+public class JwtTokenJson {
+ private String headersJson;
+ private String claimsJson;
+ public JwtTokenJson(String headersJson, String claimsJson) {
+ this.headersJson = headersJson;
+ this.claimsJson = claimsJson;
+ }
+ public String getHeadersJson() {
+ return headersJson;
+ }
+ public String getClaimsJson() {
+ return claimsJson;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReader.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReader.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReader.java
new file mode 100644
index 0000000..09a6a5d
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReader.java
@@ -0,0 +1,27 @@
+/**
+ * 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.jwt;
+
+import org.apache.cxf.rs.security.jose.JoseHeadersReader;
+
+
+public interface JwtTokenReader extends JoseHeadersReader {
+ JwtClaims fromJsonClaims(String jsonClaims);
+ JwtToken fromJson(JwtTokenJson jsonPair);
+}
http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReaderWriter.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReaderWriter.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReaderWriter.java
new file mode 100644
index 0000000..d3e7db4
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/JwtTokenReaderWriter.java
@@ -0,0 +1,64 @@
+/**
+ * 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.jwt;
+
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+
+
+
+
+public class JwtTokenReaderWriter extends JoseHeadersReaderWriter
+ implements JwtTokenReader, JwtTokenWriter {
+
+
+ @Override
+ public String claimsToJson(JwtClaims claims) {
+ return toJson(claims);
+ }
+
+ @Override
+ public JwtTokenJson tokenToJson(JwtToken token) {
+ return new JwtTokenJson(toJson(token.getHeaders()),
+ toJson(token.getClaims()));
+ }
+
+ @Override
+ public JwtClaims fromJsonClaims(String claimsJson) {
+ JwtClaims claims = new JwtClaims();
+ fromJsonInternal(claims, claimsJson);
+ return claims;
+
+ }
+
+ private JwtToken fromJson(String headersJson, String claimsJson) {
+ JwtHeaders headers = fromJsonHeaders(headersJson);
+ JwtClaims claims = fromJsonClaims(claimsJson);
+ return new JwtToken(headers, claims);
+ }
+
+ @Override
+ public JwtToken fromJson(JwtTokenJson pair) {
+ return fromJson(pair.getHeadersJson(), pair.getClaimsJson());
+ }
+
+ @Override
+ public JwtHeaders fromJsonHeaders(String jsonHeaders) {
+ return new JwtHeaders(super.fromJsonHeaders(jsonHeaders));
+ }
+}