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/16 22:31:31 UTC
git commit: [CXF-6053] Introducing JwsJsonConsumer,
applying the first part of the modified patch on behalf of Daniel
Torkian and Luigi Lo Iacono
Repository: cxf
Updated Branches:
refs/heads/master 2b4fe9966 -> e97552774
[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/e9755277
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/e9755277
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/e9755277
Branch: refs/heads/master
Commit: e975527748e6de7de34baf5768ebc8b0ea7448aa
Parents: 2b4fe99
Author: Sergey Beryozkin <sb...@talend.com>
Authored: Thu Oct 16 21:31:06 2014 +0100
Committer: Sergey Beryozkin <sb...@talend.com>
Committed: Thu Oct 16 21:31:06 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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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/e9755277/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());