This is an automated email from the ASF dual-hosted git repository.
more pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 06f05b499 KNOX-3040 - Followup patch. Support for multiple JWKS
endpoints + code cleanup (#924)
06f05b499 is described below
commit 06f05b499d5ca71411f9dd79f1782eed58f61bd9
Author: Sandeep Moré <[email protected]>
AuthorDate: Tue Jul 30 10:30:39 2024 -0400
KNOX-3040 - Followup patch. Support for multiple JWKS endpoints + code
cleanup (#924)
* KNOX-3040 - Followup patch. Support for multiple JWKS endpoints + code
cleanup
* Review changes
* Update main.yml
Bumping github actions for checkout and setup-java to v4
* Update main.yml
added distribution and cache attributes
* Update main.yml
simplify mvn cmd
* KNOX-3053 - Fix DefaultTopologyService - Mock setup moved before method
call (#927)
* KNOX-3040-1 - Fix unit test
---------
Co-authored-by: lmccay <[email protected]>
Co-authored-by: hanicz <[email protected]>
---
.../hadoopauth/filter/HadoopAuthFilterTest.java | 1 +
.../provider/federation/jwt/JWTMessages.java | 3 ++
.../federation/jwt/filter/AbstractJWTFilter.java | 7 ++--
.../federation/jwt/filter/JWTFederationFilter.java | 37 +++++++++++++++++++++-
.../provider/federation/AbstractJWTFilterTest.java | 7 ++++
.../gateway/config/impl/GatewayConfigImpl.java | 10 +++++-
.../token/impl/DefaultTokenAuthorityService.java | 29 +++++++++++++++--
.../token/impl/TokenAuthorityServiceMessages.java | 3 ++
.../service/knoxsso/WebSSOResourceTest.java | 6 ++++
.../knoxtoken/TokenServiceResourceTest.java | 7 ++++
.../org/apache/knox/gateway/GatewayTestConfig.java | 7 ++++
.../apache/knox/gateway/config/GatewayConfig.java | 5 +++
.../services/security/token/JWTokenAuthority.java | 4 +++
.../services/security/token/impl/JWTToken.java | 34 ++++++++++----------
.../services/security/token/impl/JWTTokenTest.java | 8 ++---
pom.xml | 2 +-
16 files changed, 140 insertions(+), 30 deletions(-)
diff --git
a/gateway-provider-security-hadoopauth/src/test/java/org/apache/knox/gateway/hadoopauth/filter/HadoopAuthFilterTest.java
b/gateway-provider-security-hadoopauth/src/test/java/org/apache/knox/gateway/hadoopauth/filter/HadoopAuthFilterTest.java
index 8b1755fd7..c06876524 100644
---
a/gateway-provider-security-hadoopauth/src/test/java/org/apache/knox/gateway/hadoopauth/filter/HadoopAuthFilterTest.java
+++
b/gateway-provider-security-hadoopauth/src/test/java/org/apache/knox/gateway/hadoopauth/filter/HadoopAuthFilterTest.java
@@ -582,6 +582,7 @@ public class HadoopAuthFilterTest {
expect(filterConfig.getInitParameter(JWTFederationFilter.KNOX_TOKEN_AUDIENCES)).andReturn(null).anyTimes();
expect(filterConfig.getInitParameter(JWTFederationFilter.KNOX_TOKEN_QUERY_PARAM_NAME)).andReturn(null).anyTimes();
expect(filterConfig.getInitParameter(JWTFederationFilter.JWKS_URL)).andReturn(null).anyTimes();
+
expect(filterConfig.getInitParameter(JWTFederationFilter.JWKS_URLS)).andReturn(null).anyTimes();
expect(filterConfig.getInitParameter(JWTFederationFilter.TOKEN_PRINCIPAL_CLAIM)).andReturn(null).anyTimes();
expect(filterConfig.getInitParameter(JWTFederationFilter.TOKEN_VERIFICATION_PEM)).andReturn(null).anyTimes();
expect(filterConfig.getInitParameter(JWTFederationFilter.JWT_UNAUTHENTICATED_PATHS_PARAM)).andReturn(null).anyTimes();
diff --git
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/JWTMessages.java
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/JWTMessages.java
index d41ca2d0a..b5ba653f3 100644
---
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/JWTMessages.java
+++
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/JWTMessages.java
@@ -123,4 +123,7 @@ public interface JWTMessages {
@Message( level = MessageLevel.INFO, text = "Token verification result using
knox signing cert, verified: {0}" )
void signingKeyVerificationResultMessage(boolean verified);
+
+ @Message(level = MessageLevel.ERROR, text = "Invalid URL ignored. Not a
valid JWKS url {0}")
+ void invalidJwksUrl(String jwksUrl);
}
diff --git
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
index e9daff9b1..fb1517a73 100644
---
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
+++
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java
@@ -20,6 +20,7 @@ package
org.apache.knox.gateway.provider.federation.jwt.filter;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
+import java.net.URI;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@@ -115,7 +116,7 @@ public abstract class AbstractJWTFilter implements Filter {
private String expectedIssuer;
private String expectedSigAlg;
protected String expectedPrincipalClaim;
- protected String expectedJWKSUrl;
+ protected Set<URI> expectedJWKSUrls = new HashSet();
protected Set<JOSEObjectType> allowedJwsTypes;
private TokenStateService tokenStateService;
@@ -516,8 +517,8 @@ public abstract class AbstractJWTFilter implements Filter {
log.pemVerificationResultMessage(verified);
}
- if (!verified && expectedJWKSUrl != null) {
- verified = authority.verifyToken(token, expectedJWKSUrl,
expectedSigAlg, allowedJwsTypes);
+ if (!verified && expectedJWKSUrls != null &&
!expectedJWKSUrls.isEmpty()) {
+ verified = authority.verifyToken(token, expectedJWKSUrls,
expectedSigAlg, allowedJwsTypes);
log.jwksVerificationResultMessage(verified);
}
diff --git
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
index a58622a0e..e3ac3967e 100644
---
a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
+++
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
@@ -23,14 +23,18 @@ import static
org.apache.knox.gateway.util.AuthFilterUtils.DEFAULT_AUTH_UNAUTHEN
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
+import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.security.auth.Subject;
@@ -76,6 +80,7 @@ public class JWTFederationFilter extends AbstractJWTFilter {
public static final String KNOX_TOKEN_QUERY_PARAM_NAME =
"knox.token.query.param.name";
public static final String TOKEN_PRINCIPAL_CLAIM =
"knox.token.principal.claim";
public static final String JWKS_URL = "knox.token.jwks.url";
+ public static final String JWKS_URLS = "knox.token.jwks.urls";
public static final String ALLOWED_JWS_TYPES =
"knox.token.allowed.jws.types";
public static final String BEARER = "Bearer ";
public static final String BASIC = "Basic";
@@ -110,7 +115,13 @@ public class JWTFederationFilter extends AbstractJWTFilter
{
// JWKSUrl
String oidcjwksurl = filterConfig.getInitParameter(JWKS_URL);
if (oidcjwksurl != null) {
- expectedJWKSUrl = oidcjwksurl;
+ expectedJWKSUrls = parseJwksUrlsFromConfig(oidcjwksurl);
+ }
+
+ /* in case knox.token.jwks.urls property is defined use it */
+ final String oidcjwksurls = filterConfig.getInitParameter(JWKS_URLS);
+ if (oidcjwksurls != null) {
+ expectedJWKSUrls.addAll(parseJwksUrlsFromConfig(oidcjwksurls));
}
allowedJwsTypes = new HashSet<>();
@@ -149,6 +160,30 @@ public class JWTFederationFilter extends AbstractJWTFilter
{
configureExpectedParameters(filterConfig);
}
+ /**
+ * Helper function to extract URLs from given string
+ * in the form of https://url:port/contxt/.wellknown,
https://url2:port/contxt/.wellknown
+ * into expectedJWKSUrl URL set.
+ * @param oidcjwksurls
+ */
+ private Set<URI> parseJwksUrlsFromConfig(final String oidcjwksurls) {
+ final Set<URI> jwksUrlSet = new HashSet<>();
+ final Set<String> jwksurls = Arrays.stream(
+ oidcjwksurls.split(","))
+ .map(String::trim)
+ .collect(Collectors.toSet());
+
+ for (final String jwksurl : jwksurls) {
+ try {
+ jwksUrlSet.add(new URI(jwksurl));
+ } catch (URISyntaxException e) {
+ /* Not valid JWKS url, log and move on */
+ log.invalidJwksUrl(jwksurl);
+ }
+ }
+ return jwksUrlSet;
+ }
+
@Override
public void destroy() {
}
diff --git
a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
index 384468a3a..bb255a19c 100644
---
a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
+++
b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
@@ -33,6 +33,7 @@ import
org.apache.knox.gateway.provider.federation.jwt.filter.SignatureVerificat
import org.apache.knox.gateway.security.PrimaryPrincipal;
import org.apache.knox.gateway.services.security.token.JWTokenAttributes;
import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
+import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.impl.JWT;
import org.apache.knox.gateway.services.security.token.impl.JWTToken;
import org.apache.knox.gateway.util.X509CertificateUtil;
@@ -55,6 +56,7 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetAddress;
+import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.AccessController;
import java.security.KeyPair;
@@ -1180,6 +1182,11 @@ public abstract class AbstractJWTFilterTest {
public boolean verifyToken(JWT token, String jwksurl, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) {
return false;
}
+
+ @Override
+ public boolean verifyToken(JWT token, Set<URI> jwksurls, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) throws TokenServiceException {
+ return false;
+ }
}
protected static class TestFilterChain implements FilterChain {
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index 1b6e967a7..5f35ff8e7 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -166,7 +166,7 @@ public class GatewayConfigImpl extends Configuration
implements GatewayConfig {
public static final String WEBSHELL_READ_BUFFER_SIZE =
GATEWAY_CONFIG_FILE_PREFIX + ".webshell.read.buffer.size";
/**
- * Properties for for gateway port mapping feature
+ * Properties for gateway port mapping feature
*/
public static final String GATEWAY_PORT_MAPPING_PREFIX =
GATEWAY_CONFIG_FILE_PREFIX + ".port.mapping.";
public static final String GATEWAY_PORT_MAPPING_REGEX =
GATEWAY_CONFIG_FILE_PREFIX + "\\.port\\.mapping\\..*";
@@ -354,6 +354,9 @@ public class GatewayConfigImpl extends Configuration
implements GatewayConfig {
private static final String GATEWAY_HEALTH_CHECK_TOPOLOGIES =
GATEWAY_CONFIG_FILE_PREFIX + ".health.check.topologies";
+ private static final String JWKS_OUTAGE_CACHE_TTL =
GATEWAY_CONFIG_FILE_PREFIX + ".jwks.outage.cache.ttl";;
+ private static final long JWKS_OUTAGE_CACHE_TTL_DEFAULT =
TimeUnit.HOURS.toMillis(2);
+
public GatewayConfigImpl() {
init();
}
@@ -1590,4 +1593,9 @@ public class GatewayConfigImpl extends Configuration
implements GatewayConfig {
return get(UI_BANNER_TEXT, "");
}
+ @Override
+ public long getJwksOutageCacheTTL() {
+ return getLong(JWKS_OUTAGE_CACHE_TTL, JWKS_OUTAGE_CACHE_TTL_DEFAULT);
+ }
+
}
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
index 275e2ec97..08cc297cf 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenAuthorityService.java
@@ -18,6 +18,7 @@
package org.apache.knox.gateway.services.token.impl;
import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.Key;
@@ -47,7 +48,7 @@ import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.source.JWKSource;
-import com.nimbusds.jose.jwk.source.RemoteJWKSet;
+import com.nimbusds.jose.jwk.source.JWKSourceBuilder;
import com.nimbusds.jose.proc.BadJOSEException;
import com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier;
import com.nimbusds.jose.proc.JOSEObjectTypeVerifier;
@@ -226,7 +227,12 @@ public class DefaultTokenAuthorityService implements
JWTokenAuthority, Service {
try {
if (algorithm != null && jwksurl != null) {
JWSAlgorithm expectedJWSAlg = JWSAlgorithm.parse(algorithm);
- JWKSource<SecurityContext> keySource = new RemoteJWKSet<>(new
URL(jwksurl));
+ /* Retry one time in case of failure and cache JWKS in case there is
outage, TTL is OUTAGE_TTL */
+ long outageTTL = config.getJwksOutageCacheTTL();
+ JWKSource<SecurityContext> keySource = JWKSourceBuilder.create(new
URL(jwksurl))
+ .retrying(true)
+ .outageTolerant(outageTTL)
+ .build();
JWSKeySelector<SecurityContext> keySelector = new
JWSVerificationKeySelector<>(expectedJWSAlg, keySource);
// Create a JWT processor for the access tokens
@@ -248,6 +254,25 @@ public class DefaultTokenAuthorityService implements
JWTokenAuthority, Service {
return verified;
}
+ @Override
+ public boolean verifyToken(JWT token, Set<URI> jwksurls, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) throws TokenServiceException {
+ boolean verified = false;
+ for(final URI url : jwksurls) {
+ try {
+ verified = this.verifyToken(token, url.toString(), algorithm,
allowedJwsTypes);
+ /* if token is verified no need to check further return result */
+ if(verified) {
+ return verified;
+ }
+ } catch (TokenServiceException e) {
+ /* failed to verify token, log and move on */
+ LOG.jwksVerificationFailed(url.toString(), e.toString());
+ }
+ }
+ return verified;
+ }
+
+
@Override
public void init(GatewayConfig config, Map<String, String> options)
throws ServiceLifecycleException {
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenAuthorityServiceMessages.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenAuthorityServiceMessages.java
index f93c95287..4ade199e0 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenAuthorityServiceMessages.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/TokenAuthorityServiceMessages.java
@@ -25,4 +25,7 @@ import org.apache.knox.gateway.i18n.messages.Messages;
public interface TokenAuthorityServiceMessages {
@Message(level = MessageLevel.ERROR, text = "There was an error getting kid,
cause: {0}")
void errorGettingKid(String message);
+
+ @Message(level = MessageLevel.ERROR, text = "Failed to verify token using
JWKS endpoint {0}, reason: {1}")
+ void jwksVerificationFailed(String jwksUrl, String reason);
}
diff --git
a/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
b/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
index ecf7463ba..991af4117 100644
---
a/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
+++
b/gateway-service-knoxsso/src/test/java/org/apache/knox/gateway/service/knoxsso/WebSSOResourceTest.java
@@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
import java.net.HttpCookie;
import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
@@ -1005,5 +1006,10 @@ public class WebSSOResourceTest {
public boolean verifyToken(JWT token, String jwksurl, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) {
return false;
}
+
+ @Override
+ public boolean verifyToken(JWT token, Set<URI> jwksurls, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) throws TokenServiceException {
+ return false;
+ }
}
}
diff --git
a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
index 9ef8523cf..b3798bdd7 100644
---
a/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
+++
b/gateway-service-knoxtoken/src/test/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceResourceTest.java
@@ -33,6 +33,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
+import java.net.URI;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Principal;
@@ -95,6 +96,7 @@ import
org.apache.knox.gateway.services.security.token.JWTokenAuthority;
import org.apache.knox.gateway.services.security.token.KnoxToken;
import
org.apache.knox.gateway.services.security.token.PersistentTokenStateService;
import org.apache.knox.gateway.services.security.token.TokenMetadata;
+import org.apache.knox.gateway.services.security.token.TokenServiceException;
import org.apache.knox.gateway.services.security.token.TokenStateService;
import org.apache.knox.gateway.services.security.token.TokenUtils;
import org.apache.knox.gateway.services.security.token.UnknownTokenException;
@@ -1899,5 +1901,10 @@ public class TokenServiceResourceTest {
public boolean verifyToken(JWT token, String jwksurl, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) {
return false;
}
+
+ @Override
+ public boolean verifyToken(JWT token, Set<URI> jwksurls, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) throws TokenServiceException {
+ return false;
+ }
}
}
diff --git
a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index e3f2ddab5..fd26c0f2a 100644
---
a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++
b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -32,6 +32,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;
@@ -1126,4 +1127,10 @@ public class GatewayTestConfig extends Configuration
implements GatewayConfig {
return null;
}
+ @Override
+ public long getJwksOutageCacheTTL() {
+ return TimeUnit.HOURS.toMillis(2);
+ }
+
+
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index 352aabbe5..bdb10adf9 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -956,4 +956,9 @@ public interface GatewayConfig {
*/
String getBannerText();
+ /**
+ * The time to live of the cached JWK set to cover outages, in milliseconds.
+ * @return jwks outage cache TTL
+ */
+ long getJwksOutageCacheTTL();
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
index ccd74c714..7c1e503c6 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/JWTokenAuthority.java
@@ -17,6 +17,7 @@
*/
package org.apache.knox.gateway.services.security.token;
+import java.net.URI;
import java.security.interfaces.RSAPublicKey;
import java.util.Set;
@@ -33,4 +34,7 @@ public interface JWTokenAuthority {
boolean verifyToken(JWT token, RSAPublicKey publicKey) throws
TokenServiceException;
boolean verifyToken(JWT token, String jwksurl, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) throws TokenServiceException;
+
+ boolean verifyToken(JWT token, Set<URI> jwksurls, String algorithm,
Set<JOSEObjectType> allowedJwsTypes) throws TokenServiceException;
+
}
diff --git
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
index 7920bfcf5..cd9ccc5b2 100644
---
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
+++
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/token/impl/JWTToken.java
@@ -63,26 +63,26 @@ public class JWTToken implements JWT {
try {
header = new JWSHeader(new JWSAlgorithm(jwtAttributes.getAlgorithm()),
jwtAttributes.getType() == null ? null : new
JOSEObjectType(jwtAttributes.getType()),
- null,
- null,
- jwtAttributes.getJkuUri(),
- null,
- null,
- null,
- null,
- null,
- jwtAttributes.getKid(),
- null,
- null);
+ null,
+ null,
+ jwtAttributes.getJkuUri(),
+ null,
+ null,
+ null,
+ null,
+ null,
+ jwtAttributes.getKid(),
+ null,
+ null);
} catch (URISyntaxException e) {
/* in event of bad URI exception fall back to using just algo in header
*/
header = new JWSHeader(new JWSAlgorithm(jwtAttributes.getAlgorithm()));
}
JWTClaimsSet claims;
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder()
- .issuer(jwtAttributes.getIssuer())
- .subject(jwtAttributes.getUserName())
- .audience(jwtAttributes.getAudiences());
+ .issuer(jwtAttributes.getIssuer())
+ .subject(jwtAttributes.getUserName())
+ .audience(jwtAttributes.getAudiences());
if(jwtAttributes.getExpiresDate() != null) {
builder = builder.expirationTime(jwtAttributes.getExpiresDate());
}
@@ -127,7 +127,7 @@ public class JWTToken implements JWT {
JWTClaimsSet claims;
try {
claims = jwt.getJWTClaimsSet();
- c = claims.toJSONObject().toJSONString();
+ c = claims.toJSONObject().toString();
} catch (ParseException e) {
log.unableToParseToken(e);
}
@@ -195,7 +195,7 @@ public class JWTToken implements JWT {
String c = null;
claim = getAudienceClaims();
- if (claim != null) {
+ if (claim != null && claim.length > 0) {
c = claim[0];
}
@@ -217,7 +217,7 @@ public class JWTToken implements JWT {
@Override
public String getExpires() {
- Date expires = getExpiresDate();
+ Date expires = getExpiresDate();
if (expires != null) {
return String.valueOf(expires.getTime());
}
diff --git
a/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
b/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
index ff0df7af4..c3099a898 100644
---
a/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
+++
b/gateway-spi/src/test/java/org/apache/knox/gateway/services/security/token/impl/JWTTokenTest.java
@@ -19,7 +19,6 @@ package org.apache.knox.gateway.services.security.token.impl;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -143,7 +142,7 @@ public class JWTTokenTest {
assertEquals("KNOXSSO", token.getIssuer());
assertEquals("[email protected]", token.getSubject());
assertNull(token.getAudience());
- assertArrayEquals(null, token.getAudienceClaims());
+ assertEquals(0, token.getAudienceClaims().length);
}
@Test
@@ -205,15 +204,14 @@ public class JWTTokenTest {
@Test
public void testUnsignedToken() throws Exception {
String unsignedToken =
"eyJhbGciOiJub25lIn0.eyJzdWIiOiJhbGljZSIsImp0aSI6ImY2YmNj"
- +
"MDVjLWI4MTktNGM0Mi1iMGMyLWJlYmY1MDE4YWFiZiJ9.";
+ + "MDVjLWI4MTktNGM0Mi1iMGMyLWJlYmY1MDE4YWFiZiJ9.";
try {
new JWTToken(unsignedToken);
fail("Failure expected on an unsigned token");
} catch (ParseException ex) {
// expected
- assertEquals("Invalid JWS header: The algorithm \"alg\" header parameter
must be for signatures",
- ex.getMessage());
+ assertEquals("Invalid JWS header: Not a JWS header", ex.getMessage());
}
}
diff --git a/pom.xml b/pom.xml
index 673384b39..03dfbb0d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -252,7 +252,7 @@
<mina.version>2.0.22</mina.version>
<mockito.version>4.8.1</mockito.version>
<netty.version>4.1.77.Final</netty.version>
- <nimbus-jose-jwt.version>8.14.1</nimbus-jose-jwt.version>
+ <nimbus-jose-jwt.version>9.37.3</nimbus-jose-jwt.version>
<nodejs.version>v14.15.0</nodejs.version>
<okhttp.version>2.7.5</okhttp.version>
<opensaml.version>3.4.5</opensaml.version>