Repository: cxf Updated Branches: refs/heads/master de0524a87 -> afa521931
[CXF-6084] Support for validating critical headers, applying a patch on behalf of Daniel Torkian Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/afa52193 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/afa52193 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/afa52193 Branch: refs/heads/master Commit: afa52193148d7b1a6b60266ff73a92c1005f4c38 Parents: de0524a Author: Sergey Beryozkin <[email protected]> Authored: Wed Nov 5 12:55:12 2014 +0000 Committer: Sergey Beryozkin <[email protected]> Committed: Wed Nov 5 12:55:12 2014 +0000 ---------------------------------------------------------------------- .../apache/cxf/rs/security/jose/JoseUtils.java | 23 +++++++++ .../security/jose/jwe/JweCompactConsumer.java | 4 ++ .../cxf/rs/security/jose/jwe/JweUtils.java | 6 +++ .../security/jose/jws/JwsCompactConsumer.java | 4 +- .../jose/jws/JwsJsonSignatureEntry.java | 7 +++ .../cxf/rs/security/jose/jws/JwsUtils.java | 6 +++ .../security/jose/jws/JwsCompactHeaderTest.java | 49 ++++++++++++++++++++ .../provider/ClientSecretHashVerifier.java | 39 ++++++++++++++++ 8 files changed, 137 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/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 b0ba894..23f9936 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 @@ -19,6 +19,9 @@ package org.apache.cxf.rs.security.jose; import java.io.UnsupportedEncodingException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.apache.cxf.common.util.crypto.CryptoUtils; @@ -59,4 +62,24 @@ public final class JoseUtils { public static byte[] decode(String encoded) { return CryptoUtils.decodeSequence(encoded); } + + public static boolean validateCriticalHeaders(JoseHeaders headers) { + List<String> critical = headers.getCritical(); + if (critical == null) { + return true; + } + // The "crit" value MUST NOT be empty "[]" or contain either duplicate values or "crit" + if (critical.isEmpty() + || detectDoubleEntry(critical) + || critical.contains(JoseConstants.HEADER_CRITICAL)) { + return false; + } + + // Check that the headers contain these critical headers + return headers.asMap().keySet().containsAll(critical); + } + private static boolean detectDoubleEntry(List<?> list) { + Set<Object> inputSet = new HashSet<Object>(list); + return list.size() > inputSet.size(); + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweCompactConsumer.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweCompactConsumer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweCompactConsumer.java index 8673d4d..ab4c9b5 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweCompactConsumer.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweCompactConsumer.java @@ -26,6 +26,7 @@ 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.jws.JwsUtils; public class JweCompactConsumer { @@ -113,4 +114,7 @@ public class JweCompactConsumer { throw new SecurityException(ex); } } + public boolean validateCriticalHeaders() { + return JwsUtils.validateCriticalHeaders(getJweHeaders()); + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java index 4158da6..836a284 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java @@ -26,6 +26,8 @@ import javax.crypto.SecretKey; import org.apache.cxf.jaxrs.utils.ResourceUtils; import org.apache.cxf.message.Message; +import org.apache.cxf.rs.security.jose.JoseHeaders; +import org.apache.cxf.rs.security.jose.JoseUtils; import org.apache.cxf.rs.security.jose.jaxrs.KeyManagementUtils; import org.apache.cxf.rs.security.jose.jwa.Algorithm; import org.apache.cxf.rs.security.jose.jwk.JsonWebKey; @@ -38,6 +40,10 @@ public final class JweUtils { private JweUtils() { } + public static boolean validatecriticalheaders(JoseHeaders headers) { + //TODO: Validate JWE specific constraints + return JoseUtils.validateCriticalHeaders(headers); + } public static KeyEncryptionAlgorithm getKeyEncryptionAlgorithm(JsonWebKey jwk) { return getKeyEncryptionAlgorithm(jwk, null); } http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/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 a87bc19..f9c43da 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 @@ -94,7 +94,9 @@ public class JwsCompactConsumer { public boolean verifySignatureWith(JsonWebKey key) { return verifySignatureWith(JwsUtils.getSignatureVerifier(key)); } - + public boolean validateCriticalHeaders() { + return JwsUtils.validateCriticalHeaders(getJoseHeaders()); + } protected JoseHeadersReader getReader() { return reader; } http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/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 index 278aa93..1e75ff9 100644 --- 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 @@ -21,6 +21,7 @@ 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.JoseConstants; import org.apache.cxf.rs.security.jose.JoseHeaders; import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter; import org.apache.cxf.rs.security.jose.JoseUtils; @@ -111,6 +112,12 @@ public class JwsJsonSignatureEntry { public boolean verifySignatureWith(JsonWebKey key) { return verifySignatureWith(JwsUtils.getSignatureVerifier(key)); } + public boolean validateCriticalHeaders() { + if (this.getUnprotectedHeader().getHeader(JoseConstants.HEADER_CRITICAL) != null) { + return false; + } + return JwsUtils.validateCriticalHeaders(getUnionHeader()); + } public String toJson() { StringBuilder sb = new StringBuilder(); sb.append("{"); http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/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 index 93abfd5..7f880cb 100644 --- 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 @@ -30,6 +30,8 @@ import javax.ws.rs.core.MultivaluedMap; import org.apache.cxf.jaxrs.impl.MetadataMap; import org.apache.cxf.jaxrs.utils.ResourceUtils; import org.apache.cxf.message.Message; +import org.apache.cxf.rs.security.jose.JoseHeaders; +import org.apache.cxf.rs.security.jose.JoseUtils; import org.apache.cxf.rs.security.jose.jaxrs.KeyManagementUtils; import org.apache.cxf.rs.security.jose.jwa.Algorithm; import org.apache.cxf.rs.security.jose.jwk.JsonWebKey; @@ -40,6 +42,10 @@ public final class JwsUtils { private JwsUtils() { } + public static boolean validateCriticalHeaders(JoseHeaders headers) { + //TODO: validate JWS specific constraints + return JoseUtils.validateCriticalHeaders(headers); + } public static JwsSignatureProvider getSignatureProvider(JsonWebKey jwk) { return getSignatureProvider(jwk, null); } http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java index 942a856..a6fc066 100644 --- a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java +++ b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsCompactHeaderTest.java @@ -18,6 +18,10 @@ */ package org.apache.cxf.rs.security.jose.jws; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cxf.rs.security.jose.JoseConstants; import org.apache.cxf.rs.security.jose.jwa.Algorithm; import org.junit.Assert; @@ -149,6 +153,51 @@ public class JwsCompactHeaderTest extends Assert { Algorithm.HmacSHA256.getJwtName()))); } + @Test + public void testCriticalHeader() { + String payload = "this is a JWS with critical header"; + String criticalParameter = "criticalParameter"; + String criticalParameter1 = "criticalParameter1"; + String criticalParameter2 = "criticalParameter2"; + String criticalParameter3 = "criticalParameter3"; + String criticalValue = "criticalValue"; + String criticalValue1 = "criticalValue1"; + String criticalValue2 = "criticalValue2"; + String criticalValue3 = "criticalValue3"; + JwsCompactProducer producer = new JwsCompactProducer(payload); + producer.getJoseHeaders().setAlgorithm(JoseConstants.HMAC_SHA_512_ALGO); + List<String> criticalHeader = new ArrayList<String>(); + criticalHeader.add(criticalParameter1); + producer.getJoseHeaders().setCritical(criticalHeader); + producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, Algorithm.HmacSHA256.getJwtName())); + String signedJws = producer.getSignedEncodedJws(); + JwsCompactConsumer consumer = new JwsCompactConsumer(signedJws); + assertFalse(consumer.validateCriticalHeaders()); + + criticalHeader.add(criticalParameter2); + criticalHeader.add(criticalParameter3); + producer = new JwsCompactProducer(payload); + producer.getJoseHeaders().setAlgorithm(JoseConstants.HMAC_SHA_512_ALGO); + producer.getJoseHeaders().setCritical(criticalHeader); + producer.getJoseHeaders().setHeader(criticalParameter1, criticalValue1); + producer.getJoseHeaders().setHeader(criticalParameter2, criticalValue2); + producer.getJoseHeaders().setHeader(criticalParameter3, criticalValue3); + producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, Algorithm.HmacSHA256.getJwtName())); + signedJws = producer.getSignedEncodedJws(); + consumer = new JwsCompactConsumer(signedJws); + assertTrue(consumer.validateCriticalHeaders()); + criticalHeader = new ArrayList<String>(); + criticalHeader.add(criticalParameter); + criticalHeader.add(criticalParameter); + producer = new JwsCompactProducer(payload); + producer.getJoseHeaders().setAlgorithm(JoseConstants.HMAC_SHA_512_ALGO); + producer.getJoseHeaders().setHeader(criticalParameter, criticalValue); + producer.getJoseHeaders().setCritical(criticalHeader); + producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, Algorithm.HmacSHA256.getJwtName())); + signedJws = producer.getSignedEncodedJws(); + consumer = new JwsCompactConsumer(signedJws); + assertFalse(consumer.validateCriticalHeaders()); + } } http://git-wip-us.apache.org/repos/asf/cxf/blob/afa52193/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/ClientSecretHashVerifier.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/ClientSecretHashVerifier.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/ClientSecretHashVerifier.java new file mode 100644 index 0000000..428a818 --- /dev/null +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/ClientSecretHashVerifier.java @@ -0,0 +1,39 @@ +/** + * 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.oauth2.provider; + +import org.apache.cxf.common.util.StringUtils; +import org.apache.cxf.common.util.crypto.MessageDigestUtils; +import org.apache.cxf.rs.security.oauth2.common.Client; + +/** + * ClientSecretVerifier which checks the passwords against hashes + */ +public class ClientSecretHashVerifier implements ClientSecretVerifier { + private String hashAlgorithm = MessageDigestUtils.ALGO_SHA_256; + public boolean validateClientSecret(Client client, String clientSecret) { + String hash = MessageDigestUtils.generate(StringUtils.toBytesUTF8(clientSecret), + hashAlgorithm); + return hash.equals(client.getClientSecret()); + } + public void setHashAlgorithm(String hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; + } +}
