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

commit 183e88fd1ee4bb751c5eaea7b358ef7cd7895781
Author: David Blevins <dblev...@tomitribe.com>
AuthorDate: Wed Aug 31 15:43:34 2022 -0700

    TOMEE-3949 Support for JWT audience aud claim
---
 .../apache/tomee/microprofile/jwt/MPJWTFilter.java | 38 ++++++++++++----------
 .../jwt/config/JWTAuthConfiguration.java           | 19 ++++++++---
 .../jwt/config/JWTAuthConfigurationProperties.java | 17 +++++++---
 3 files changed, 49 insertions(+), 25 deletions(-)

diff --git 
a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java 
b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java
index 3ded1ff31b..c9f7c5049c 100644
--- a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java
+++ b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java
@@ -16,7 +16,20 @@
  */
 package org.apache.tomee.microprofile.jwt;
 
-import org.apache.commons.lang3.Validate;
+import jakarta.enterprise.inject.Instance;
+import jakarta.inject.Inject;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ExceptionMapper;
+import jakarta.ws.rs.ext.Provider;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.spi.SecurityService;
 import org.apache.openejb.util.Logger;
@@ -39,21 +52,7 @@ import org.jose4j.jwt.consumer.JwtConsumerBuilder;
 import org.jose4j.jwt.consumer.JwtContext;
 import org.jose4j.keys.resolvers.JwksVerificationKeyResolver;
 
-import jakarta.enterprise.inject.Instance;
-import jakarta.inject.Inject;
 import javax.security.auth.Subject;
-import jakarta.servlet.Filter;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.FilterConfig;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.ServletRequest;
-import jakarta.servlet.ServletResponse;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletRequestWrapper;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.ext.ExceptionMapper;
-import jakarta.ws.rs.ext.Provider;
 import java.io.IOException;
 import java.security.Principal;
 import java.util.Collections;
@@ -294,7 +293,7 @@ public class MPJWTFilter implements Filter {
             }
 
             final String headerScheme = 
(jwtAuthConfiguration.getHeaderScheme() + " ").toLowerCase(Locale.ENGLISH);
-            if (headerScheme.trim().length() > 0 &&  
!authorizationHeader.toLowerCase(Locale.ENGLISH).startsWith(headerScheme)) {
+            if (headerScheme.trim().length() > 0 && 
!authorizationHeader.toLowerCase(Locale.ENGLISH).startsWith(headerScheme)) {
                 throw new BadAuthorizationPrefixException(authorizationHeader);
             }
 
@@ -330,7 +329,6 @@ public class MPJWTFilter implements Filter {
                 final JwtConsumerBuilder builder = new JwtConsumerBuilder()
                         .setRelaxVerificationKeyValidation()
                         .setRequireSubject()
-                        .setSkipDefaultAudienceValidation()
                         .setJwsAlgorithmConstraints(
                                 new 
AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST,
                                         AlgorithmIdentifiers.RSA_USING_SHA256,
@@ -341,6 +339,12 @@ public class MPJWTFilter implements Filter {
                                         
AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512
                                 ));
 
+                if (authContextInfo.getAudiences().length > 0) {
+                    builder.setExpectedAudience(true, 
authContextInfo.getAudiences());
+                } else {
+                    builder.setSkipDefaultAudienceValidation();
+                }
+
                 if (!authContextInfo.isAllowNoExpiryClaim()) {
                     builder.setRequireExpirationTime();
                 }
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 7a9fae68d9..eec7fc4180 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
@@ -34,19 +34,21 @@ public class JWTAuthConfiguration {
     public static final String DEFAULT_KEY = "DEFAULT";
 
     private Map<String, Key> publicKeys;
+    private String[] audiences;
     private String issuer;
     private int expGracePeriodSecs = 60;
     private String headerName = "Authorization";
     private String headerScheme = "Bearer";
     private boolean allowNoExpiryClaim = false;
 
-    private JWTAuthConfiguration(final Key publicKey, final String issuer, 
final boolean allowNoExpiryClaim) {
+    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;
     }
 
-    private JWTAuthConfiguration(final Map<String, Key> publicKeys, final 
String issuer, final boolean allowNoExpiryClaim) {
+    private JWTAuthConfiguration(final Map<String, Key> publicKeys, final 
String issuer, final boolean allowNoExpiryClaim, final String[] audiences) {
         if (publicKeys.size() == 1) {
             final Key singleKey = publicKeys.values().iterator().next();
             this.publicKeys = Collections.singletonMap(DEFAULT_KEY, singleKey);
@@ -55,14 +57,23 @@ public class JWTAuthConfiguration {
         }
         this.issuer = issuer;
         this.allowNoExpiryClaim = allowNoExpiryClaim;
+        this.audiences = audiences;
     }
 
     public static JWTAuthConfiguration authConfiguration(final Key publicKey, 
final String issuer, final boolean allowNoExpiryClaim) {
-        return new JWTAuthConfiguration(publicKey, issuer, 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 new JWTAuthConfiguration(publicKeys, issuer, 
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 new JWTAuthConfiguration(publicKeys, issuer, 
allowNoExpiryClaim, audiences);
+    }
+
+    public String[] getAudiences() {
+        return audiences;
     }
 
     public boolean isSingleKey() {
diff --git 
a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java
 
b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java
index 87a8350d6b..f5255bb428 100644
--- 
a/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java
+++ 
b/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/config/JWTAuthConfigurationProperties.java
@@ -25,9 +25,13 @@ import org.eclipse.microprofile.config.Config;
 import org.eclipse.microprofile.config.ConfigProvider;
 
 import java.security.Key;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
+import static org.eclipse.microprofile.jwt.config.Names.AUDIENCES;
 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;
@@ -69,6 +73,12 @@ public class JWTAuthConfigurationProperties {
         return config.getOptionalValue(ISSUER, String.class);
     }
 
+    private List<String> getAudiences() {
+        final String audiences = config.getOptionalValue(AUDIENCES, 
String.class).orElse(null);
+        if (audiences == null) return Collections.EMPTY_LIST;
+        return Arrays.asList(audiences.split(" *, *"));
+    }
+
     private JWTAuthConfiguration createJWTAuthConfiguration() {
         if (getVerifierPublicKey().isPresent() && 
getPublicKeyLocation().isPresent()) {
             throw new DeploymentException("Both " +
@@ -80,13 +90,12 @@ public class JWTAuthConfigurationProperties {
 
         final Optional<String> publicKeyContents = getVerifierPublicKey();
         final Optional<String> publicKeyLocation = getPublicKeyLocation();
+        final List<String> audiences = getAudiences();
 
-        final Optional<Map<String, Key>> first = new 
PublicKeyResolver().resolve(publicKeyContents, publicKeyLocation);
+        final Map<String, Key> keys = new 
PublicKeyResolver().resolve(publicKeyContents, publicKeyLocation).orElse(null);
         final Boolean allowNoExp = 
config.getOptionalValue("mp.jwt.tomee.allow.no-exp", 
Boolean.class).orElse(false);
 
-        return first
-                .map(keys -> JWTAuthConfiguration.authConfiguration(keys, 
getIssuer().orElse(null), allowNoExp))
-                .orElse(null);
+        return JWTAuthConfiguration.authConfiguration(keys, 
getIssuer().orElse(null), allowNoExp, audiences.toArray(new String[0]));
     }
 
 }

Reply via email to