You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2022/09/10 02:35:54 UTC
[tomee] branch main updated: TOMEE-3950 Support for JWT token cookies
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 f53be6f4fb TOMEE-3950 Support for JWT token cookies
new e07945cb7f Merge branch 'main' of github.com:apache/tomee into main
f53be6f4fb is described below
commit f53be6f4fb6d0b26ad84a50ab4c00d609fcf72a6
Author: David Blevins <db...@tomitribe.com>
AuthorDate: Fri Sep 9 19:32:14 2022 -0700
TOMEE-3950 Support for JWT token cookies
---
.../apache/tomee/microprofile/jwt/MPJWTFilter.java | 63 ++++++++++++++++++----
.../jwt/config/JWTAuthConfiguration.java | 11 +++-
.../jwt/config/JWTAuthConfigurationProperties.java | 11 +++-
3 files changed, 72 insertions(+), 13 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 adee42c135..23b086f3e0 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
@@ -25,6 +25,7 @@ import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
@@ -71,6 +72,7 @@ import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
// async is supported because we only need to do work on the way in
//@WebFilter(asyncSupported = true, urlPatterns = "/*")
@@ -243,6 +245,25 @@ public class MPJWTFilter implements Filter {
}
}
+ private static class MissingTokenCookieException extends MPJWTException {
+
+ private final String cookieName;
+
+ public MissingTokenCookieException(final String authorizationHeader) {
+ this.cookieName = authorizationHeader;
+ }
+
+ @Override
+ public int getStatus() {
+ return HttpServletResponse.SC_UNAUTHORIZED;
+ }
+
+ @Override
+ public String getMessage() {
+ return String.format("Cookie of name '%s' holding a JWT was not found.", cookieName);
+ }
+ }
+
private static class InvalidTokenException extends MPJWTException {
private final String token;
@@ -293,17 +314,39 @@ public class MPJWTFilter implements Filter {
}
final String headerName = jwtAuthConfiguration.getHeaderName();
- final String authorizationHeader = httpServletRequest.getHeader(headerName);
- if (authorizationHeader == null || authorizationHeader.isEmpty()) {
- throw new MissingAuthorizationHeaderException();
- }
+ final String token;
+
+ if ("cookie".equals(headerName)) {
+ final String cookieName = jwtAuthConfiguration.getCookieName();
+
+ if (httpServletRequest.getCookies() == null) {
+ throw new MissingTokenCookieException(cookieName);
+ }
+
+ final Cookie tokenCookie = Stream.of(httpServletRequest.getCookies())
+ .filter(cookie -> cookieName.equals(cookie.getName().toLowerCase()))
+ .findFirst()
+ .orElse(null);
+
+ if (tokenCookie == null) {
+ throw new MissingTokenCookieException(cookieName);
+ }
- final String headerScheme = (jwtAuthConfiguration.getHeaderScheme() + " ").toLowerCase(Locale.ENGLISH);
- if (headerScheme.trim().length() > 0 && !authorizationHeader.toLowerCase(Locale.ENGLISH).startsWith(headerScheme)) {
- throw new BadAuthorizationPrefixException(authorizationHeader);
+ token = tokenCookie.getValue();
+ } else {
+ final String authorizationHeader = httpServletRequest.getHeader(headerName);
+ if (authorizationHeader == null || authorizationHeader.isEmpty()) {
+ throw new MissingAuthorizationHeaderException();
+ }
+
+ final String headerScheme = (jwtAuthConfiguration.getHeaderScheme() + " ").toLowerCase(Locale.ENGLISH);
+ if (headerScheme.trim().length() > 0 && !authorizationHeader.toLowerCase(Locale.ENGLISH).startsWith(headerScheme)) {
+ throw new BadAuthorizationPrefixException(authorizationHeader);
+ }
+
+ token = authorizationHeader.substring(headerScheme.length());
}
- final String token = authorizationHeader.substring(headerScheme.length());
try {
jsonWebToken = parse(token, jwtAuthConfiguration);
@@ -369,13 +412,13 @@ public class MPJWTFilter implements Filter {
builder.setVerificationKeyResolver(new JwksVerificationKeyResolver(asJwks(authContextInfo.getPublicKeys())));
}
- if (authContextInfo.getDecryptKeys().size() == 1){
+ if (authContextInfo.getDecryptKeys().size() == 1) {
final Key decryptionKey = authContextInfo.getDecryptKeys().values().iterator().next();
builder.setDecryptionKey(decryptionKey);
} else if (authContextInfo.getDecryptKeys().size() > 1) {
builder.setDecryptionKeyResolver(new JwksDecryptionKeyResolver(asJwks(authContextInfo.getDecryptKeys())));
}
-
+
final JwtConsumer jwtConsumer = builder.build();
final JwtContext jwtContext = jwtConsumer.process(token);
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 cd66709355..b41a808a91 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
@@ -40,6 +40,7 @@ public class JWTAuthConfiguration {
private String headerName = "Authorization";
private String headerScheme = "Bearer";
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);
@@ -48,7 +49,7 @@ public class JWTAuthConfiguration {
this.audiences = audiences;
}
- private JWTAuthConfiguration(final Map<String, Key> publicKeys, final String issuer, final boolean allowNoExpiryClaim, final String[] audiences, final Map<String, Key> decryptKeys) {
+ 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;
} else if (publicKeys.size() == 1) {
@@ -67,6 +68,8 @@ public class JWTAuthConfiguration {
this.issuer = issuer;
this.allowNoExpiryClaim = allowNoExpiryClaim;
this.audiences = audiences;
+ this.headerName = header;
+ this.cookieName = cookie;
}
public static JWTAuthConfiguration authConfiguration(final Key publicKey, final String issuer, final boolean allowNoExpiryClaim) {
@@ -82,7 +85,11 @@ public class JWTAuthConfiguration {
}
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);
+ return new JWTAuthConfiguration(publicKeys, issuer, allowNoExpiryClaim, audiences, decryptKeys, null, null);
+ }
+
+ public String getCookieName() {
+ return cookieName;
}
public String[] getAudiences() {
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 76ad9c9003..cf204b7aaf 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
@@ -34,6 +34,8 @@ import java.util.Optional;
import static org.eclipse.microprofile.jwt.config.Names.AUDIENCES;
import static org.eclipse.microprofile.jwt.config.Names.DECRYPTOR_KEY_LOCATION;
import static org.eclipse.microprofile.jwt.config.Names.ISSUER;
+import static org.eclipse.microprofile.jwt.config.Names.TOKEN_COOKIE;
+import static org.eclipse.microprofile.jwt.config.Names.TOKEN_HEADER;
import static org.eclipse.microprofile.jwt.config.Names.VERIFIER_PUBLIC_KEY;
import static org.eclipse.microprofile.jwt.config.Names.VERIFIER_PUBLIC_KEY_LOCATION;
@@ -101,7 +103,14 @@ public class JWTAuthConfigurationProperties {
final Boolean allowNoExp = config.getOptionalValue("mp.jwt.tomee.allow.no-exp", Boolean.class).orElse(false);
- return JWTAuthConfiguration.authConfiguration(publicKeys, getIssuer().orElse(null), allowNoExp, audiences.toArray(new String[0]), decryptkeys);
+ return new JWTAuthConfiguration(
+ publicKeys,
+ getIssuer().orElse(null),
+ allowNoExp,
+ audiences.toArray(new String[0]),
+ decryptkeys,
+ config.getOptionalValue(TOKEN_HEADER, String.class).map(String::toLowerCase).orElse("authorization"),
+ config.getOptionalValue(TOKEN_COOKIE, String.class).map(String::toLowerCase).orElse("bearer"));
}
}