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)); 
+    }
+}