This is an automated email from the ASF dual-hosted git repository. dblevins pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomee.git
The following commit(s) were added to refs/heads/main by this push: new 81bf08aced Clean dead code and begin TOMEE-4043 Remove support for JWTAuthConfiguration API 81bf08aced is described below commit 81bf08aced1a83440d68012c7711952d49da4f33 Author: David Blevins <dblev...@tomitribe.com> AuthorDate: Mon Sep 12 18:49:57 2022 -0700 Clean dead code and begin TOMEE-4043 Remove support for JWTAuthConfiguration API --- .../microprofile/jwt/JsonWebTokenValidator.java | 175 --------------- .../jwt/config/JWTAuthConfiguration.java | 54 +---- .../jwt/JsonWebTokenValidatorTest.java | 49 ----- .../jwt/bval/ValidationConstraintsTest.java | 244 --------------------- 4 files changed, 1 insertion(+), 521 deletions(-) diff --git a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/JsonWebTokenValidator.java b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/JsonWebTokenValidator.java deleted file mode 100644 index 2178832bc2..0000000000 --- a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/JsonWebTokenValidator.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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.tomee.microprofile.jwt; - -import org.apache.openejb.util.Logger; -import org.apache.tomee.microprofile.jwt.config.JWTAuthConfiguration; -import org.apache.tomee.microprofile.jwt.config.KeyResolver; -import org.apache.tomee.microprofile.jwt.principal.JWTCallerPrincipal; -import org.eclipse.microprofile.jwt.Claims; -import org.eclipse.microprofile.jwt.JsonWebToken; -import org.jose4j.jwa.AlgorithmConstraints; -import org.jose4j.jwk.JsonWebKey; -import org.jose4j.jws.AlgorithmIdentifiers; -import org.jose4j.jwt.JwtClaims; -import org.jose4j.jwt.MalformedClaimException; -import org.jose4j.jwt.NumericDate; -import org.jose4j.jwt.consumer.InvalidJwtException; -import org.jose4j.jwt.consumer.JwtConsumer; -import org.jose4j.jwt.consumer.JwtConsumerBuilder; -import org.jose4j.jwt.consumer.JwtContext; -import org.jose4j.keys.resolvers.JwksVerificationKeyResolver; - -import java.security.Key; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; - -public class JsonWebTokenValidator { - - private static final Logger VALIDATION = Logger.getInstance(JWTLogCategories.CONSTRAINT, JsonWebTokenValidator.class); - - private final Predicate<JsonWebToken> validation; - private final Key verificationKey; - private final Map<String, Key> verificationKeys; - private final String issuer; - private boolean allowNoExpiryClaim = false; - - public JsonWebTokenValidator(final Predicate<JsonWebToken> validation, final Key verificationKey, final String issuer, final Map<String, Key> verificationKeys, final boolean allowNoExpiryClaim) { - this.validation = validation; - this.verificationKey = verificationKey; - this.verificationKeys = verificationKeys; - this.issuer = issuer; - this.allowNoExpiryClaim = allowNoExpiryClaim; - } - - public JsonWebToken validate(final String token) throws ParseException { - final JWTAuthConfiguration authConfiguration = verificationKey != null ? JWTAuthConfiguration.authConfiguration(verificationKey, issuer, allowNoExpiryClaim) : JWTAuthConfiguration.authConfiguration(verificationKeys, issuer, allowNoExpiryClaim); - JWTCallerPrincipal principal; - - try { - final JwtConsumerBuilder builder = new JwtConsumerBuilder() - .setRelaxVerificationKeyValidation() - .setRequireSubject() - .setSkipDefaultAudienceValidation() - .setJwsAlgorithmConstraints( - new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST, - AlgorithmIdentifiers.RSA_USING_SHA256, - AlgorithmIdentifiers.RSA_USING_SHA384, - AlgorithmIdentifiers.RSA_USING_SHA512 - )); - - if (authConfiguration.getIssuer() != null) { - builder.setExpectedIssuer(authConfiguration.getIssuer()); - } - if (authConfiguration.getExpGracePeriodSecs() > 0) { - builder.setAllowedClockSkewInSeconds(authConfiguration.getExpGracePeriodSecs()); - } else { - builder.setEvaluationTime(NumericDate.fromSeconds(0)); - } - - if (authConfiguration.isSingleKey()) { - builder.setVerificationKey(authConfiguration.getPublicKey()); - } else { - builder.setVerificationKeyResolver(new JwksVerificationKeyResolver(authConfiguration.getPublicKeysJwk())); - } - - final JwtConsumer jwtConsumer = builder.build(); - final JwtContext jwtContext = jwtConsumer.process(token); - final String type = jwtContext.getJoseObjects().get(0).getHeader("typ"); - // Validate the JWT and process it to the Claims - jwtConsumer.processContext(jwtContext); - JwtClaims claimsSet = jwtContext.getJwtClaims(); - - // We have to determine the unique name to use as the principal name. It comes from upn, preferred_username, sub in that order - String principalName = claimsSet.getClaimValue("upn", String.class); - if (principalName == null) { - principalName = claimsSet.getClaimValue("preferred_username", String.class); - if (principalName == null) { - principalName = claimsSet.getSubject(); - } - } - claimsSet.setClaim(Claims.raw_token.name(), token); - principal = new JWTCallerPrincipal(token, type, claimsSet, principalName); - - } catch (final InvalidJwtException e) { - VALIDATION.warning(e.getMessage()); - throw new ParseException("Failed to verify token", e); - - } catch (final MalformedClaimException e) { - VALIDATION.warning(e.getMessage()); - throw new ParseException("Failed to verify token claims", e); - } - - return principal; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private Predicate<JsonWebToken> validation = jsonWebToken -> true; - private Key verificationKey; - private List<JsonWebKey> verificationKeys; - private String issuer; - private boolean allowNoExpiryClaim = false; - - public Builder add(final Predicate<JsonWebToken> validation) { - this.validation = validation.and(validation); - return this; - } - - public Builder publicKey(final String keyContent) { - final Map<String, Key> keys = new KeyResolver().readPublicKeys(keyContent); - final Map.Entry<String, Key> key = keys.entrySet().iterator().next(); - return verificationKey(key.getValue()); - } - - public Builder verificationKey(final Key key) { - this.verificationKey = key; - return this; - } - - public Builder verificationKey(final Map<String, Key> key) { - this.verificationKeys = verificationKeys; - return this; - } - - public JsonWebTokenValidator build() { - return new JsonWebTokenValidator(validation, verificationKey, issuer, null, allowNoExpiryClaim); - } - - public Builder verificationKeys(final List<JsonWebKey> keys) { - verificationKeys = keys; - return this; - } - - public Builder issuer(final String iss) { - issuer = iss; - return this; - } - - public Builder allowNoExpiryClaim(final boolean allowNoExpiryClaim) { - this.allowNoExpiryClaim = allowNoExpiryClaim; - return this; - } - - - } -} diff --git a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfiguration.java b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfiguration.java index b41a808a91..96986b2d02 100644 --- a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfiguration.java +++ b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfiguration.java @@ -16,20 +16,14 @@ */ package org.apache.tomee.microprofile.jwt.config; -import org.apache.tomee.microprofile.jwt.MPJWTFilter; -import org.jose4j.jwk.JsonWebKey; - import java.security.Key; import java.util.Collections; -import java.util.List; import java.util.Map; -import java.util.logging.Logger; /** * The public key and expected issuer needed to validate a token. */ public class JWTAuthConfiguration { - private static final Logger logger = Logger.getLogger(JWTAuthConfiguration.class.getName()); public static final String DEFAULT_KEY = "DEFAULT"; private Map<String, Key> publicKeys; @@ -42,13 +36,6 @@ public class JWTAuthConfiguration { private boolean allowNoExpiryClaim = false; private String cookieName = "Bearer"; - private JWTAuthConfiguration(final Key publicKey, final String issuer, final boolean allowNoExpiryClaim, final String[] audiences) { - this.publicKeys = Collections.singletonMap(DEFAULT_KEY, publicKey); - this.issuer = issuer; - this.allowNoExpiryClaim = allowNoExpiryClaim; - this.audiences = audiences; - } - public JWTAuthConfiguration(final Map<String, Key> publicKeys, final String issuer, final boolean allowNoExpiryClaim, final String[] audiences, final Map<String, Key> decryptKeys, final String header, final String cookie) { if (publicKeys == null) { this.publicKeys = Collections.EMPTY_MAP; @@ -64,7 +51,7 @@ public class JWTAuthConfiguration { } else { this.decryptKeys = Collections.unmodifiableMap(decryptKeys); } - + this.issuer = issuer; this.allowNoExpiryClaim = allowNoExpiryClaim; this.audiences = audiences; @@ -72,22 +59,6 @@ public class JWTAuthConfiguration { this.cookieName = cookie; } - public static JWTAuthConfiguration authConfiguration(final Key publicKey, final String issuer, final boolean allowNoExpiryClaim) { - return new JWTAuthConfiguration(publicKey, issuer, allowNoExpiryClaim, new String[0]); - } - - public static JWTAuthConfiguration authConfiguration(final Map<String, Key> publicKeys, final String issuer, final boolean allowNoExpiryClaim) { - return authConfiguration(publicKeys, issuer, allowNoExpiryClaim, new String[0]); - } - - public static JWTAuthConfiguration authConfiguration(final Map<String, Key> publicKeys, final String issuer, final boolean allowNoExpiryClaim, final String[] audiences) { - return authConfiguration(publicKeys, issuer, allowNoExpiryClaim, audiences, null); - } - - public static JWTAuthConfiguration authConfiguration(final Map<String, Key> publicKeys, final String issuer, final boolean allowNoExpiryClaim, final String[] audiences, final Map<String, Key> decryptKeys) { - return new JWTAuthConfiguration(publicKeys, issuer, allowNoExpiryClaim, audiences, decryptKeys, null, null); - } - public String getCookieName() { return cookieName; } @@ -96,10 +67,6 @@ public class JWTAuthConfiguration { return audiences; } - public boolean isSingleKey() { - return publicKeys.size() == 1; - } - public Key getPublicKey() { return publicKeys.get(DEFAULT_KEY); } @@ -112,10 +79,6 @@ public class JWTAuthConfiguration { return decryptKeys; } - public List<JsonWebKey> getPublicKeysJwk() { - return MPJWTFilter.ValidateJSonWebToken.asJwks(publicKeys); - } - public String getIssuer() { return issuer; } @@ -124,31 +87,16 @@ public class JWTAuthConfiguration { return expGracePeriodSecs; } - public void setExpGracePeriodSecs(final int expGracePeriodSecs) { - this.expGracePeriodSecs = expGracePeriodSecs; - } - public String getHeaderName() { return headerName; } - public void setHeaderName(final String headerName) { - this.headerName = headerName; - } - public String getHeaderScheme() { return headerScheme; } - public void setHeaderScheme(final String headerScheme) { - this.headerScheme = headerScheme; - } - public boolean isAllowNoExpiryClaim() { return allowNoExpiryClaim; } - public void setAllowNoExpiryClaim(boolean allowNoExpiryClaim) { - this.allowNoExpiryClaim = allowNoExpiryClaim; - } } diff --git a/mp-jwt/src/test/java/org/apache/tomee/microprofile/jwt/JsonWebTokenValidatorTest.java b/mp-jwt/src/test/java/org/apache/tomee/microprofile/jwt/JsonWebTokenValidatorTest.java deleted file mode 100644 index 1be4da05be..0000000000 --- a/mp-jwt/src/test/java/org/apache/tomee/microprofile/jwt/JsonWebTokenValidatorTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.tomee.microprofile.jwt; - -import org.eclipse.microprofile.jwt.JsonWebToken; -import org.junit.Ignore; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class JsonWebTokenValidatorTest { - - @Test - @Ignore - public void testValidate() throws Exception { - - final JsonWebTokenValidator validator = JsonWebTokenValidator.builder() - .publicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9xnQIDAQAB") - .build(); - - final String claims = "{" + - " \"sub\":\"Jane Awesome\"," + - " \"iss\":\"https://server.example.com\"," + - " \"groups\":[\"manager\",\"user\"]," + - " \"exp\":2552047942" + - "}"; - final String token = Tokens.asToken(claims); - - final JsonWebToken jwt = validator.validate(token); - - assertEquals("Jane Awesome", jwt.getSubject()); - assertEquals("https://server.example.com", jwt.getIssuer()); - assertEquals(2552047942l, jwt.getExpirationTime()); - } -} \ No newline at end of file diff --git a/mp-jwt/src/test/java/org/apache/tomee/microprofile/jwt/bval/ValidationConstraintsTest.java b/mp-jwt/src/test/java/org/apache/tomee/microprofile/jwt/bval/ValidationConstraintsTest.java deleted file mode 100644 index 8b2ff1887a..0000000000 --- a/mp-jwt/src/test/java/org/apache/tomee/microprofile/jwt/bval/ValidationConstraintsTest.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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.tomee.microprofile.jwt.bval; - -import org.apache.tomee.microprofile.jwt.JsonWebTokenValidator; -import org.apache.tomee.microprofile.jwt.Tokens; -import org.apache.tomee.microprofile.jwt.bval.ann.Audience; -import org.apache.tomee.microprofile.jwt.bval.ann.Issuer; -import org.eclipse.microprofile.jwt.JsonWebToken; -import org.junit.Assert; -import org.junit.Test; - -import jakarta.annotation.security.RolesAllowed; -import jakarta.validation.ConstraintValidator; -import jakarta.validation.ConstraintValidatorContext; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -public class ValidationConstraintsTest { - - @Test - public void invalidAudAndIss() throws Exception { - final ValidationConstraints constraints = ValidationConstraints.of(Circle.class); - - final Method red = Circle.class.getMethod("red"); - - - final JsonWebTokenValidator validator = JsonWebTokenValidator.builder() - .publicKey(Tokens.getPublicKey()) - .build(); - - final String claims = "{" + - " \"sub\":\"Jane Awesome\"," + - " \"iss\":\"http://something.com\"," + - " \"groups\":[\"manager\",\"user\"]," + - " \"exp\":2552047942" + - "}"; - final String token = Tokens.asToken(claims); - - final JsonWebToken jwt = validator.validate(token); - - assertViolations(constraints.validate(red, jwt), - "The 'aud' claim is required", - "The 'aud' claim must contain 'bar'", - "The 'iss' claim must be 'http://foo.bar.com'" - ); - } - - @Test - public void invalidIss() throws Exception { - final ValidationConstraints constraints = ValidationConstraints.of(Circle.class); - - final Method red = Circle.class.getMethod("red"); - - - final JsonWebTokenValidator validator = JsonWebTokenValidator.builder() - .publicKey(Tokens.getPublicKey()) - .build(); - - final String claims = "{" + - " \"sub\":\"Jane Awesome\"," + - " \"aud\":[\"bar\",\"user\"]," + - " \"iss\":\"http://something.com\"," + - " \"groups\":[\"manager\",\"user\"]," + - " \"exp\":2552047942" + - "}"; - final String token = Tokens.asToken(claims); - - final JsonWebToken jwt = validator.validate(token); - - assertViolations(constraints.validate(red, jwt), - "The 'iss' claim must be 'http://foo.bar.com'" - ); - } - - @Test - public void invalidAud() throws Exception { - final ValidationConstraints constraints = ValidationConstraints.of(Circle.class); - - final Method red = Circle.class.getMethod("red"); - - - final JsonWebTokenValidator validator = JsonWebTokenValidator.builder() - .publicKey(Tokens.getPublicKey()) - .build(); - - final String claims = "{" + - " \"sub\":\"Jane Awesome\"," + - " \"aud\":[\"foo\",\"user\"]," + - " \"iss\":\"http://foo.bar.com\"," + - " \"groups\":[\"manager\",\"user\"]," + - " \"exp\":2552047942" + - "}"; - final String token = Tokens.asToken(claims); - - final JsonWebToken jwt = validator.validate(token); - - assertViolations(constraints.validate(red, jwt), - "The 'aud' claim must contain 'bar'" - ); - } - - @Test - public void missingAud() throws Exception { - final ValidationConstraints constraints = ValidationConstraints.of(Circle.class); - - final Method red = Circle.class.getMethod("red"); - - - final JsonWebTokenValidator validator = JsonWebTokenValidator.builder() - .publicKey(Tokens.getPublicKey()) - .build(); - - final String claims = "{" + - " \"sub\":\"Jane Awesome\"," + - " \"iss\":\"http://foo.bar.com\"," + - " \"groups\":[\"manager\",\"user\"]," + - " \"exp\":2552047942" + - "}"; - final String token = Tokens.asToken(claims); - - final JsonWebToken jwt = validator.validate(token); - - assertViolations(constraints.validate(red, jwt), - "The 'aud' claim is required", - "The 'aud' claim must contain 'bar'" - ); - } - - @Test - public void valid() throws Exception { - final ValidationConstraints constraints = ValidationConstraints.of(Circle.class); - - final Method red = Circle.class.getMethod("red"); - - - final JsonWebTokenValidator validator = JsonWebTokenValidator.builder() - .publicKey(Tokens.getPublicKey()) - .build(); - - final String claims = "{" + - " \"sub\":\"Jane Awesome\"," + - " \"iss\":\"http://foo.bar.com\"," + - " \"aud\":[\"bar\",\"user\"]," + - " \"groups\":[\"manager\",\"user\"]," + - " \"exp\":2552047942" + - "}"; - final String token = Tokens.asToken(claims); - - final JsonWebToken jwt = validator.validate(token); - - assertViolations(constraints.validate(red, jwt)); - } - - private static void assertViolations(final Set<ConstraintViolation<Object>> constraintViolations, final String... violations) { - final List<String> actual = constraintViolations.stream() - .map(ConstraintViolation::getMessage) - .sorted() - .collect(Collectors.toList()); - - final List<String> expected = Stream.of(violations) - .sorted() - .collect(Collectors.toList()); - - Assert.assertEquals(expected, actual); - } - - public static class Circle { - @Audience("bar") - @Issuer("http://foo.bar.com") - @Crimson() - @RolesAllowed("") // to ensur non bean-validation annotations do not cause errors - public Red red() { - return new Red(); - } - - /** - * To ensure non bean-validation methods do not cause errors - */ - @RolesAllowed("") - public Object green() { - return new Red(); - } - - /** - * To ensure non-public methods do not cause errors - */ - private Object blue() { - return new Red(); - } - } - - public static class Red { - } - - @Documented - @jakarta.validation.Constraint(validatedBy = {Crimson.Constraint.class}) - @Target({METHOD, FIELD, ANNOTATION_TYPE, PARAMETER}) - @Retention(RUNTIME) - public @interface Crimson { - - Class<?>[] groups() default {}; - - String message() default "This will never pass"; - - Class<? extends Payload>[] payload() default {}; - - - class Constraint implements ConstraintValidator<Crimson, Red> { - @Override - public boolean isValid(final Red value, final ConstraintValidatorContext context) { - return false; - } - } - } -} \ No newline at end of file