cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From serg...@apache.org
Subject git commit: [CXF-6053] Introducing JwsJsonConsumer, applying the first part of the modified patch on behalf of Daniel Torkian and Luigi Lo Iacono
Date Thu, 16 Oct 2014 20:33:54 GMT
Repository: cxf
Updated Branches:
  refs/heads/3.0.x-fixes d951b7efb -> eb7dbc4b3


[CXF-6053] Introducing JwsJsonConsumer, applying the first part of the modified patch on behalf
of Daniel Torkian and Luigi Lo Iacono


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

Branch: refs/heads/3.0.x-fixes
Commit: eb7dbc4b3cca8511e496b2a02ac4bfd8e3e95113
Parents: d951b7e
Author: Sergey Beryozkin <sberyozkin@talend.com>
Authored: Thu Oct 16 21:31:06 2014 +0100
Committer: Sergey Beryozkin <sberyozkin@talend.com>
Committed: Thu Oct 16 21:33:33 2014 +0100

----------------------------------------------------------------------
 .../provider/json/AbstractJsonMapObject.java    |   2 +-
 .../json/JsonMapObjectReaderWriter.java         |   7 +-
 .../cxf/rs/security/jose/JoseHeaders.java       |   4 +
 .../apache/cxf/rs/security/jose/JoseUtils.java  |  16 +++
 .../security/jose/jws/JwsCompactConsumer.java   |  32 ++----
 .../rs/security/jose/jws/JwsJsonConsumer.java   | 101 ++++++++++++++++++
 .../jose/jws/JwsJsonProtectedHeader.java        |  65 ++++++++++++
 .../jose/jws/JwsJsonSignatureEntry.java         | 103 +++++++++++++++++++
 .../jose/jws/JwsJsonUnprotectedHeader.java      |  66 ++++++++++++
 .../security/jose/jws/JwsJsonConsumerTest.java  |  78 ++++++++++++++
 .../jose/jws/jwkPublicJsonConsumerSet.txt       |  18 ++++
 .../jose/jwt/grant/JwtBearerGrantHandler.java   |   2 +-
 12 files changed, 467 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/AbstractJsonMapObject.java
----------------------------------------------------------------------
diff --git a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/AbstractJsonMapObject.java
b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/AbstractJsonMapObject.java
index a518a06..d6eef9d 100644
--- a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/AbstractJsonMapObject.java
+++ b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/AbstractJsonMapObject.java
@@ -42,7 +42,7 @@ public abstract class AbstractJsonMapObject {
     }
 
     public Map<String, Object> asMap() {
-        return new LinkedHashMap<String, Object>(values);
+        return values;
     }
     
     protected Long getLongDate(String name) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
----------------------------------------------------------------------
diff --git a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
index ca30c7d..de382a0 100644
--- a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
+++ b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/json/JsonMapObjectReaderWriter.java
@@ -100,7 +100,12 @@ public class JsonMapObjectReaderWriter {
         readJsonObjectAsSettable(joseObject, theJson.substring(1, theJson.length() - 1));
     }
     
-    
+    public Map<String, Object> fromJson(String json) {
+        String theJson = json.trim();
+        MapSettable nextMap = new MapSettable();
+        readJsonObjectAsSettable(nextMap, theJson.substring(1, theJson.length() - 1));
+        return nextMap.map;
+    }
     
     protected void readJsonObjectAsSettable(Settable values, String json) {
         for (int i = 0; i < json.length(); i++) {

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseHeaders.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseHeaders.java
b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseHeaders.java
index ea1b984..15bff4d 100644
--- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseHeaders.java
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseHeaders.java
@@ -33,6 +33,10 @@ public class JoseHeaders extends AbstractJsonMapObject {
     public JoseHeaders() {
     }
     
+    public JoseHeaders(JoseHeaders headers) {
+        this(headers.asMap());
+    }
+    
     public JoseHeaders(Map<String, Object> values) {
         super(values);
     }

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java
b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java
index 9abbe79..b0ba894 100644
--- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseUtils.java
@@ -18,6 +18,10 @@
  */
 package org.apache.cxf.rs.security.jose;
 
+import java.io.UnsupportedEncodingException;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+
 public final class JoseUtils {
     private JoseUtils() {
         
@@ -43,4 +47,16 @@ public final class JoseUtils {
         }
         return contentType;
     }
+    
+    public static String decodeToString(String encoded) {
+        try {
+            return new String(decode(encoded), "UTF-8");
+        } catch (UnsupportedEncodingException ex) {
+            throw new SecurityException(ex);
+        }
+        
+    }
+    public static byte[] decode(String encoded) {
+        return CryptoUtils.decodeSequence(encoded);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/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
index 1d37dd7..578c049 100644
--- 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
@@ -18,14 +18,11 @@
  */
 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.common.util.StringUtils;
 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.JoseUtils;
 import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
 
 public class JwsCompactConsumer {
@@ -54,12 +51,12 @@ public class JwsCompactConsumer {
         } else {
             encodedSignature = parts[2];
         }
-        headersJson = decodeToString(parts[0]);
-        jwsPayload = decodeToString(parts[1]);
+        headersJson = JoseUtils.decodeToString(parts[0]);
+        jwsPayload = JoseUtils.decodeToString(parts[1]);
         encodedSequence = parts[0] + "." + parts[1];
         
     }
-    public String getUnsignedEncodedPayload() {
+    public String getUnsignedEncodedSequence() {
         return encodedSequence;
     }
     public String getEncodedSignature() {
@@ -75,7 +72,7 @@ public class JwsCompactConsumer {
         return StringUtils.toBytesUTF8(jwsPayload);
     }
     public byte[] getDecodedSignature() {
-        return encodedSignature.isEmpty() ? new byte[]{} : decode(encodedSignature);
+        return encodedSignature.isEmpty() ? new byte[]{} : JoseUtils.decode(encodedSignature);
     }
     public JoseHeaders getJoseHeaders() {
         JoseHeaders joseHeaders = reader.fromJsonHeaders(headersJson);
@@ -86,7 +83,7 @@ public class JwsCompactConsumer {
     }
     public boolean verifySignatureWith(JwsSignatureVerifier validator) {
         try {
-            if (validator.verify(getJoseHeaders(), getUnsignedEncodedPayload(), getDecodedSignature()))
{
+            if (validator.verify(getJoseHeaders(), getUnsignedEncodedSequence(), getDecodedSignature()))
{
                 return true;
             }
         } catch (SecurityException ex) {
@@ -97,22 +94,9 @@ public class JwsCompactConsumer {
     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/eb7dbc4b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumer.java
b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumer.java
new file mode 100644
index 0000000..bbc2ac5
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumer.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.jose.jws;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.jaxrs.provider.json.AbstractJsonMapObject;
+import org.apache.cxf.jaxrs.provider.json.JsonMapObjectReaderWriter;
+import org.apache.cxf.rs.security.jose.JoseUtils;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+
+public class JwsJsonConsumer {
+
+    private String jwsSignedDocument;
+    private String encodedJwsPayload;
+    private List<JwsJsonSignatureEntry> signatureEntries;
+    
+    /**
+     * @param jwsSignedDocument
+     *            signed JWS Document
+     */
+    public JwsJsonConsumer(String jwsSignedDocument) {
+        this.jwsSignedDocument = jwsSignedDocument;
+        prepare();
+    }
+
+    private void prepare() {
+        AbstractJsonMapObject jsonObject = new AbstractJsonMapObject() { };
+        new JsonMapObjectReaderWriter().fromJson(jsonObject, jwsSignedDocument);
+        this.encodedJwsPayload = (String)jsonObject.asMap().get("payload");
+        
+        @SuppressWarnings("unchecked")
+        List<Map<String, Object>> signatureArray = 
+            (List<Map<String, Object>>)jsonObject.asMap().get("signatures");
+        
+        this.signatureEntries = new ArrayList<JwsJsonSignatureEntry>(signatureArray.size());
+        
+        for (Map<String, Object> signatureEntry : signatureArray) {
+            String protectedHeader = (String)signatureEntry.get("protected");
+            @SuppressWarnings("unchecked")
+            Map<String, Object> header = (Map<String, Object>)signatureEntry.get("header");
+            String signature = (String)signatureEntry.get("signature");
+            if (protectedHeader == null && header == null || signature == null) {
+                throw new SecurityException("Invalid security entry");
+            }
+            JwsJsonSignatureEntry signatureObject = 
+                new JwsJsonSignatureEntry(encodedJwsPayload, 
+                                          protectedHeader, 
+                                          signature, 
+                                          new JwsJsonUnprotectedHeader(header));
+            this.signatureEntries.add(signatureObject);
+        }
+    }
+    public String getSignedDocument() {
+        return this.jwsSignedDocument;
+    }
+    public String getEncodedJwsPayload() {
+        return this.encodedJwsPayload;
+    }
+    public String getDecodedJwsPayload() {
+        return JoseUtils.decodeToString(encodedJwsPayload);
+    }
+    public byte[] getDecodedJwsPayloadBytes() {
+        return StringUtils.toBytesUTF8(getDecodedJwsPayload());
+    }
+    public List<JwsJsonSignatureEntry> getSignatureEntries() {
+        return Collections.unmodifiableList(signatureEntries);
+    }
+    public boolean verifySignatureWith(JwsSignatureVerifier validator) {
+        for (JwsJsonSignatureEntry signatureEntry : signatureEntries) {
+            if (signatureEntry.verifySignatureWith(validator)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    public boolean verifySignatureWith(JsonWebKey key) {
+        return verifySignatureWith(JwsUtils.getSignatureVerifier(key));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProtectedHeader.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProtectedHeader.java
b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProtectedHeader.java
new file mode 100644
index 0000000..81b3bf6
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonProtectedHeader.java
@@ -0,0 +1,65 @@
+/**
+ * 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.common.util.Base64UrlUtility;
+import org.apache.cxf.rs.security.jose.JoseHeaders;
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+
+public class JwsJsonProtectedHeader {
+
+    private JoseHeadersReaderWriter writer = new JoseHeadersReaderWriter();
+    private JoseHeaders headerEntries;
+
+    public JwsJsonProtectedHeader() {
+    }
+    public JwsJsonProtectedHeader(JoseHeaders headerEntries) {
+        this.headerEntries = headerEntries;
+    }
+    public JwsJsonProtectedHeader(Map<String, Object> values) {
+        this.headerEntries = new JoseHeaders(values);
+    }
+    public void setHeaderEntries(JoseHeaders headerEntries) {
+        this.headerEntries = headerEntries;
+    }
+    public JoseHeaders getHeaderEntries() {
+        return headerEntries;
+    }
+    public void addHeader(String name, Object value) {
+        headerEntries.setHeader(name, value);
+    }
+    public Object getHeader(String name) {
+        return headerEntries.getHeader(name);
+    }
+    public String toJson() {
+        if (headerEntries == null) {
+            return "";
+        }
+        //The "protected" member MUST be present and contain the value
+        // BASE64URL(UTF8(JWS Protected Header)) when the JWS Protected
+        // Header value is non-empty; otherwise, it MUST be absent. These
+        // Header Parameter values are integrity protected.
+        return "\"protected\":\""
+               + Base64UrlUtility.encode(writer.headersToJson(headerEntries))
+               + "\"";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java
b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java
new file mode 100644
index 0000000..8b73f45
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonSignatureEntry.java
@@ -0,0 +1,103 @@
+/**
+ * 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.Collections;
+
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.rs.security.jose.JoseHeaders;
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+import org.apache.cxf.rs.security.jose.JoseUtils;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+
+
+public class JwsJsonSignatureEntry {
+    private String encodedJwsPayload;
+    private String encodedProtectedHeader;
+    private String encodedSignature;
+    private JwsJsonProtectedHeader protectedHeader;
+    private JwsJsonUnprotectedHeader unprotectedHeader;
+    private JoseHeaders unionHeader;
+      
+    public JwsJsonSignatureEntry(String encodedJwsPayload,
+                                 String encodedProtectedHeader,
+                                 String encodedSignature,
+                                 JwsJsonUnprotectedHeader unprotectedHeader) {
+        this.encodedJwsPayload = encodedJwsPayload;
+        this.encodedProtectedHeader = encodedProtectedHeader;
+        this.encodedSignature = encodedSignature;
+        this.unprotectedHeader = unprotectedHeader;
+        this.protectedHeader = new JwsJsonProtectedHeader(
+            new JoseHeadersReaderWriter().fromJsonHeaders(JoseUtils.decodeToString(encodedProtectedHeader)));
+        prepare();
+    }
+    private void prepare() {
+        JoseHeaders joseProtectedHeader = getProtectedHeader().getHeaderEntries();
+        JoseHeaders joseUnprotectedHeader = getUnprotectedHeader().getHeaderEntries();
+        if (!Collections.disjoint(joseProtectedHeader.asMap().keySet(), 
+                                  joseUnprotectedHeader.asMap().keySet())) {
+            throw new SecurityException("Protected and unprotected headers have duplicate
values");
+        }
+        unionHeader = new JoseHeaders(joseProtectedHeader);
+        unionHeader.asMap().putAll(joseUnprotectedHeader.asMap());
+    }
+    public String getEncodedJwsPayload() {
+        return encodedJwsPayload;
+    }
+    public String getDecodedJwsPayload() {
+        return JoseUtils.decodeToString(encodedJwsPayload);
+    }
+    public byte[] getDecodedJwsPayloadBytes() {
+        return StringUtils.toBytesUTF8(getDecodedJwsPayload());
+    }
+    public String getEncodedProtectedHeader() {
+        return encodedProtectedHeader;
+    }
+    public JwsJsonProtectedHeader getProtectedHeader() {
+        return protectedHeader;
+    }
+    public JwsJsonUnprotectedHeader getUnprotectedHeader() {
+        return unprotectedHeader;
+    }
+    public JoseHeaders getUnionHeader() {
+        return unionHeader;
+    }
+    public String getEncodedSignature() {
+        return encodedSignature;
+    }
+    public byte[] getDecodedSignature() {
+        return JoseUtils.decode(getEncodedSignature());
+    }
+    public String getUnsignedEncodedSequence() {
+        return getEncodedProtectedHeader() + "." + getEncodedJwsPayload();
+    }
+    public boolean verifySignatureWith(JwsSignatureVerifier validator) {
+        try {
+            return validator.verify(getUnionHeader(),
+                                    getUnsignedEncodedSequence(),
+                                    getDecodedSignature());
+        } catch (SecurityException ex) {
+            // ignore
+        }
+        return false;
+    }
+    public boolean verifySignatureWith(JsonWebKey key) {
+        return verifySignatureWith(JwsUtils.getSignatureVerifier(key));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonUnprotectedHeader.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonUnprotectedHeader.java
b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonUnprotectedHeader.java
new file mode 100644
index 0000000..7fdd54a
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsJsonUnprotectedHeader.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.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.JoseHeadersReaderWriter;
+
+public class JwsJsonUnprotectedHeader {
+
+    private JoseHeadersReaderWriter writer = new JoseHeadersReaderWriter();
+    private JoseHeaders headerEntries;
+
+    public JwsJsonUnprotectedHeader() {
+    }
+    public JwsJsonUnprotectedHeader(JoseHeaders headers) {
+        headerEntries = headers;
+    }
+
+    public JwsJsonUnprotectedHeader(Map<String, Object> values) {
+        this(new JoseHeaders(values));
+    }
+
+       
+    public void addHeader(String name, Object value) {
+        if (JoseConstants.HEADER_CRITICAL.equals(name)) {
+            throw new SecurityException();
+        }
+        headerEntries.setHeader(name, value);
+    }
+    public Object getHeader(String name) {
+        return headerEntries.getHeader(name);
+    }
+    public JoseHeaders getHeaderEntries() {
+        return headerEntries;
+    }
+    public String toJson() {
+        // The "header" member MUST be present and contain the value JWS
+        // Unprotected Header when the JWS Unprotected Header value is non-
+        // empty; otherwise, it MUST be absent. This value is represented as
+        // an unencoded JSON object, rather than as a string. These Header
+        // Parameter values are not integrity protected.
+        if (headerEntries == null) {
+            return "";
+        }
+        return "\"header\":" + writer.headersToJson(headerEntries);
+    } 
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
new file mode 100644
index 0000000..a79754a
--- /dev/null
+++ b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsJsonConsumerTest.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.jose.jws;
+
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
+import org.apache.cxf.rs.security.jose.jwk.JsonWebKeys;
+import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JwsJsonConsumerTest extends Assert {
+    private static final String DUAL_SIGNED_DOCUMENT =                           
+        "{\"payload\":\n"
+        + "\t\"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\",\n"
+        + "\t\"signatures\":[\n"
+        + "\t\t\t{\"protected\":\"eyJhbGciOiJSUzI1NiJ9\",\n"
+        + "\t\t\t \"header\":\n"   
+        + "\t\t\t\t{\"kid\":\"2010-12-29\"},\n"
+        + "\t\t\t \"signature\":\n"
+        + "\t\t\t\t\"cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5"
+        +           "jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb"
+        +           "1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOY"
+        +           "EUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw\"},\n"
+        + "\t\t\t{\"protected\":\"eyJhbGciOiJFUzI1NiJ9\",\n"
+        + "\t\t\t \"header\":\n"
+        + "\t\t\t\t{\"kid\":\"e9bc097a-ce51-4036-9562-d2ade882db0d\"},\n"
+        + "\t\t\t \"signature\":\n"
+        + "\t\t\t\t\"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q\"}]\n"
+        + "}";
+    
+    private static final String KID_OF_THE_FIRST_SIGNER = "2010-12-29";
+    private static final String KID_OF_THE_SECOND_SIGNER = "e9bc097a-ce51-4036-9562-d2ade882db0d";
+    
+    @Test
+    public void testVerifyDualSignedDocument() throws Exception {
+        JwsJsonConsumer consumer = new JwsJsonConsumer(DUAL_SIGNED_DOCUMENT); 
+        JsonWebKeys jwks = readKeySet("jwkPublicJsonConsumerSet.txt");
+        
+        List<JwsJsonSignatureEntry> sigEntries = consumer.getSignatureEntries();
+        assertEquals(2, sigEntries.size());
+        // 1st signature
+        String firstKid = (String)sigEntries.get(0).getUnionHeader().getHeader("kid");
+        assertEquals(KID_OF_THE_FIRST_SIGNER, firstKid);
+        JsonWebKey rsaKey = jwks.getKey(firstKid);
+        assertNotNull(rsaKey);
+        assertTrue(sigEntries.get(0).verifySignatureWith(rsaKey));
+        // 2nd signature
+        String secondKid = (String)sigEntries.get(1).getUnionHeader().getHeader("kid");
+        assertEquals(KID_OF_THE_SECOND_SIGNER, secondKid);
+        JsonWebKey ecKey = jwks.getKey(secondKid);
+        assertNotNull(ecKey);
+        //assertTrue(sigEntries.get(1).verifySignatureWith(ecKey));
+    }
+    public JsonWebKeys readKeySet(String fileName) throws Exception {
+        InputStream is = JwsJsonConsumerTest.class.getResourceAsStream(fileName);
+        return JwkUtils.readJwkSet(is);
+    }
+}

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

http://git-wip-us.apache.org/repos/asf/cxf/blob/eb7dbc4b/rt/rs/security/oauth-parent/oauth2-jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/grant/JwtBearerGrantHandler.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2-jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/grant/JwtBearerGrantHandler.java
b/rt/rs/security/oauth-parent/oauth2-jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/grant/JwtBearerGrantHandler.java
index c3a2283..f7b25f8 100644
--- a/rt/rs/security/oauth-parent/oauth2-jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/grant/JwtBearerGrantHandler.java
+++ b/rt/rs/security/oauth-parent/oauth2-jose/src/main/java/org/apache/cxf/rs/security/jose/jwt/grant/JwtBearerGrantHandler.java
@@ -60,7 +60,7 @@ public class JwtBearerGrantHandler extends AbstractJwtHandler {
             JwsJwtCompactConsumer jwsReader = getJwsReader(assertion);
             JwtToken jwtToken = jwsReader.getJwtToken();
             super.validateSignature(jwtToken.getHeaders(),
-                                    jwsReader.getUnsignedEncodedPayload(), 
+                                    jwsReader.getUnsignedEncodedSequence(), 
                                     jwsReader.getDecodedSignature());
             
                    


Mime
View raw message