TOMEE-2247 - Initial support for JWK Set.
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/46934a0e Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/46934a0e Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/46934a0e Branch: refs/heads/master Commit: 46934a0e99e0cf0a3306960870345070c7ad3007 Parents: 832ff75 Author: Roberto Cortez <[email protected]> Authored: Tue Sep 25 18:18:26 2018 +0100 Committer: Roberto Cortez <[email protected]> Committed: Fri Dec 7 18:11:18 2018 +0000 ---------------------------------------------------------------------- .../config/ConfigurableJWTAuthContextInfo.java | 65 +++++++++++++++----- .../jwt/MicroProfileJWTTCKArchiveProcessor.java | 2 + 2 files changed, 51 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/46934a0e/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/ConfigurableJWTAuthContextInfo.java ---------------------------------------------------------------------- diff --git a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/ConfigurableJWTAuthContextInfo.java b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/ConfigurableJWTAuthContextInfo.java index ede66b4..3705448 100644 --- a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/ConfigurableJWTAuthContextInfo.java +++ b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/ConfigurableJWTAuthContextInfo.java @@ -18,6 +18,7 @@ package org.apache.tomee.microprofile.jwt.config; import org.eclipse.microprofile.config.Config; import org.jose4j.jwk.JsonWebKey; +import org.jose4j.jwk.JsonWebKeySet; import org.jose4j.lang.JoseException; import javax.enterprise.context.ApplicationScoped; @@ -26,11 +27,12 @@ import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.DeploymentException; import javax.inject.Inject; import javax.json.Json; +import javax.json.JsonArray; import javax.json.JsonObject; +import javax.json.JsonValue; import javax.json.stream.JsonParsingException; import javax.servlet.ServletContext; import java.io.BufferedReader; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -44,19 +46,24 @@ import java.security.NoSuchAlgorithmException; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; import java.util.Base64; +import java.util.List; import java.util.Optional; import java.util.function.Supplier; import java.util.logging.Logger; +import java.util.stream.Collectors; import java.util.stream.Stream; import static org.eclipse.microprofile.jwt.config.Names.ISSUER; import static org.eclipse.microprofile.jwt.config.Names.VERIFIER_PUBLIC_KEY; import static org.eclipse.microprofile.jwt.config.Names.VERIFIER_PUBLIC_KEY_LOCATION; +import static org.jose4j.jwk.JsonWebKeySet.JWK_SET_MEMBER_NAME; @ApplicationScoped public class ConfigurableJWTAuthContextInfo { private static final Logger log = Logger.getLogger(ConfigurableJWTAuthContextInfo.class.getName()); + private static final List<String> JWK_SUPPORTED_KEY_TYPES = Arrays.asList("RSA"); @Inject private Config config; @@ -219,29 +226,55 @@ public class ConfigurableJWTAuthContextInfo { return Optional.empty(); } - final String keyType = jwk.getString("kty"); - if (keyType == null) { - throw new DeploymentException("MicroProfile Public Key JWK kty field is missing."); - } + validateJwk(jwk); - if ("RSA".equals(keyType)) { - try { - return Optional.of((RSAPublicKey) JsonWebKey.Factory.newJwk(publicKey).getKey()); - } catch (final JoseException e) { - throw new DeploymentException("Could not read MicroProfile Public Key JWK.", e); - } + try { + return Optional.of((RSAPublicKey) JsonWebKey.Factory.newJwk(publicKey).getKey()); + } catch (final JoseException e) { + throw new DeploymentException("Could not read MicroProfile Public Key JWK.", e); } - - throw new DeploymentException("MicroProfile Public Key JWK kty not supported: " + keyType); } - private Optional<JsonObject> readEncodedJwk(final String publicKey) { + private Optional<List<RSAPublicKey>> parseJwks(final String publicKey) { + final JsonObject jwks; try { - return Optional.of( - Json.createReader(new ByteArrayInputStream(Base64.getDecoder().decode(publicKey))).readObject()); + jwks = Json.createReader(new StringReader(publicKey)).readObject(); } catch (final JsonParsingException e) { return Optional.empty(); } + + try { + final JsonArray keys = jwks.getJsonArray(JWK_SET_MEMBER_NAME); + for (final JsonValue key : keys) { + validateJwk(key.asJsonObject()); + } + } catch (final Exception e) { + throw new DeploymentException("MicroProfile Public Key JWKS invalid format."); + } + + try { + final JsonWebKeySet keySet = new JsonWebKeySet(publicKey); + final List<RSAPublicKey> keys = + keySet.getJsonWebKeys() + .stream() + .map(JsonWebKey::getKey) + .map(key -> (RSAPublicKey) key) + .collect(Collectors.toList()); + return Optional.of(keys); + } catch (final JoseException e) { + throw new DeploymentException("Could not read MicroProfile Public Key JWK.", e); + } + } + + private void validateJwk(final JsonObject jwk) { + final String keyType = jwk.getString("kty"); + if (keyType == null) { + throw new DeploymentException("MicroProfile Public Key JWK kty field is missing."); + } + + if (!JWK_SUPPORTED_KEY_TYPES.contains(keyType)) { + throw new DeploymentException("MicroProfile Public Key JWK kty not supported: " + keyType); + } } private byte[] normalizeAndDecodePCKS8(final String publicKey) { http://git-wip-us.apache.org/repos/asf/tomee/blob/46934a0e/tck/microprofile-tck/jwt/src/test/java/org/apache/tomee/microprofile/tck/jwt/MicroProfileJWTTCKArchiveProcessor.java ---------------------------------------------------------------------- diff --git a/tck/microprofile-tck/jwt/src/test/java/org/apache/tomee/microprofile/tck/jwt/MicroProfileJWTTCKArchiveProcessor.java b/tck/microprofile-tck/jwt/src/test/java/org/apache/tomee/microprofile/tck/jwt/MicroProfileJWTTCKArchiveProcessor.java index 7be4a05..9725afd 100644 --- a/tck/microprofile-tck/jwt/src/test/java/org/apache/tomee/microprofile/tck/jwt/MicroProfileJWTTCKArchiveProcessor.java +++ b/tck/microprofile-tck/jwt/src/test/java/org/apache/tomee/microprofile/tck/jwt/MicroProfileJWTTCKArchiveProcessor.java @@ -25,6 +25,7 @@ import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsBase64JWKTest; import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsFileLocationURLTest; import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsJWKLocationTest; import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsJWKLocationURLTest; +import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsJWKSTest; import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsJWKTest; import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsPEMLocationTest; import org.eclipse.microprofile.jwt.tck.config.PublicKeyAsPEMTest; @@ -78,6 +79,7 @@ public class MicroProfileJWTTCKArchiveProcessor implements ApplicationArchivePro PublicKeyAsBase64JWKTest.class, PublicKeyAsJWKLocationTest.class, PublicKeyAsJWKLocationURLTest.class, + PublicKeyAsJWKSTest.class, IssValidationTest.class, org.apache.tomee.microprofile.tck.jwt.config.PublicKeyAsPEMLocationTest.class) .filter(c -> c.equals(testClass.getJavaClass()))
