Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public abstract class AbstractHTTPJwtAuthenticator implements HTTPAuthenticator
private final String jwtUrlParameter;
private final String subjectKey;
private final String rolesKey;
private final String requiredAudience;
private final String requiredIssuer;

public static final int DEFAULT_CLOCK_SKEW_TOLERANCE_SECONDS = 30;
private final int clockSkewToleranceSeconds ;
Expand All @@ -66,10 +68,12 @@ public AbstractHTTPJwtAuthenticator(Settings settings, Path configPath) {
rolesKey = settings.get("roles_key");
subjectKey = settings.get("subject_key");
clockSkewToleranceSeconds = settings.getAsInt("jwt_clock_skew_tolerance_seconds", DEFAULT_CLOCK_SKEW_TOLERANCE_SECONDS);
requiredAudience = settings.get("required_audience");
requiredIssuer = settings.get("required_issuer");

try {
this.keyProvider = this.initKeyProvider(settings, configPath);
jwtVerifier = new JwtVerifier(keyProvider, clockSkewToleranceSeconds );
jwtVerifier = new JwtVerifier(keyProvider, clockSkewToleranceSeconds, requiredIssuer, requiredAudience);

} catch (Exception e) {
log.error("Error creating JWT authenticator. JWT authentication will not work", e);
Expand Down Expand Up @@ -233,4 +237,12 @@ public boolean reRequestAuthentication(RestChannel channel, AuthCredentials auth
return true;
}

public String getRequiredAudience() {
return requiredAudience;
}

public String getRequiredIssuer() {
return requiredIssuer;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ protected KeyProvider initKeyProvider(Settings settings, Path configPath) throws

int refreshRateLimitTimeWindowMs = settings.getAsInt("refresh_rate_limit_time_window_ms", 10000);
int refreshRateLimitCount = settings.getAsInt("refresh_rate_limit_count", 10);

KeySetRetriever keySetRetriever = new KeySetRetriever(settings.get("openid_connect_url"),
getSSLConfig(settings, configPath), settings.getAsBoolean("cache_jwks_endpoint", false));
String jwksUri = settings.get("jwks_uri");

KeySetRetriever keySetRetriever;
if(jwksUri != null && !jwksUri.isBlank()) {
keySetRetriever =
new KeySetRetriever(getSSLConfig(settings, configPath), settings.getAsBoolean("cache_jwks_endpoint", false), jwksUri);
} else {
keySetRetriever = new KeySetRetriever(settings.get("openid_connect_url"), getSSLConfig(settings, configPath), settings.getAsBoolean("cache_jwks_endpoint", false));
}

keySetRetriever.setRequestTimeoutMs(idpRequestTimeoutMs);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ public class JwtVerifier {

private final KeyProvider keyProvider;
private final int clockSkewToleranceSeconds;

public JwtVerifier(KeyProvider keyProvider, int clockSkewToleranceSeconds ) {
private final String requiredIssuer;
private final String requiredAudience;

public JwtVerifier(KeyProvider keyProvider, int clockSkewToleranceSeconds, String requiredIssuer, String requiredAudience) {
this.keyProvider = keyProvider;
this.clockSkewToleranceSeconds = clockSkewToleranceSeconds;
this.requiredIssuer = requiredIssuer;
this.requiredAudience = requiredAudience;
}

public JwtToken getVerifiedJwtToken(String encodedJwt) throws BadCredentialsException {
Expand Down Expand Up @@ -106,12 +110,26 @@ private JwsSignatureVerifier getInitializedSignatureVerifier(JsonWebKey key, Jwt
}
}

private void validateClaims(JwtToken jwt) throws BadCredentialsException, JwtException {
private void validateClaims(JwtToken jwt) throws JwtException {
JwtClaims claims = jwt.getClaims();

if (claims != null) {
JwtUtils.validateJwtExpiry(claims, clockSkewToleranceSeconds, false);
JwtUtils.validateJwtNotBefore(claims, clockSkewToleranceSeconds, false);
validateRequiredAudienceAndIssuer(claims);
}
}

private void validateRequiredAudienceAndIssuer(JwtClaims claims) {
String audience = claims.getAudience();
String issuer = claims.getIssuer();

if (!Strings.isNullOrEmpty(requiredAudience) && !requiredAudience.equals(audience)) {
throw new JwtException("Invalid audience");
}

if (!Strings.isNullOrEmpty(requiredIssuer) && !requiredIssuer.equals(issuer)) {
throw new JwtException("Invalid issuer");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import joptsimple.internal.Strings;
import org.apache.cxf.rs.security.jose.jwk.JsonWebKeys;
import org.apache.cxf.rs.security.jose.jwk.JwkUtils;
import org.apache.hc.client5.http.cache.HttpCacheContext;
Expand Down Expand Up @@ -54,15 +55,20 @@ public class KeySetRetriever implements KeySetProvider {
private int oidcCacheModuleResponses = 0;
private long oidcRequests = 0;
private long lastCacheStatusLog = 0;
private String jwksUri;

KeySetRetriever(String openIdConnectEndpoint, SSLConfig sslConfig, boolean useCacheForOidConnectEndpoint) {
this.openIdConnectEndpoint = openIdConnectEndpoint;
this.sslConfig = sslConfig;

if (useCacheForOidConnectEndpoint) {
cacheConfig = CacheConfig.custom().setMaxCacheEntries(10).setMaxObjectSize(1024L * 1024L).build();
oidcHttpCacheStorage = new BasicHttpCacheStorage(cacheConfig);
}
configureCache(useCacheForOidConnectEndpoint);
}

KeySetRetriever(SSLConfig sslConfig, boolean useCacheForOidConnectEndpoint, String jwksUri) {
this.jwksUri = jwksUri;
this.sslConfig = sslConfig;

configureCache(useCacheForOidConnectEndpoint);
}

public JsonWebKeys get() throws AuthenticatorUnavailableException {
Expand Down Expand Up @@ -101,6 +107,14 @@ public JsonWebKeys get() throws AuthenticatorUnavailableException {

String getJwksUri() throws AuthenticatorUnavailableException {

if (!Strings.isNullOrEmpty(jwksUri)) {
return jwksUri;
}

if (Strings.isNullOrEmpty(openIdConnectEndpoint)) {
throw new AuthenticatorUnavailableException("Either openid_connect_url or jwks_uri must be configured for OIDC Authentication backend");
}

try (CloseableHttpClient httpClient = createHttpClient(oidcHttpCacheStorage)) {

HttpGet httpGet = new HttpGet(openIdConnectEndpoint);
Expand Down Expand Up @@ -204,6 +218,13 @@ private CloseableHttpClient createHttpClient(HttpCacheStorage httpCacheStorage)
return builder.build();
}

private void configureCache(boolean useCacheForOidConnectEndpoint) {
if (useCacheForOidConnectEndpoint) {
cacheConfig = CacheConfig.custom().setMaxCacheEntries(10).setMaxObjectSize(1024L * 1024L).build();
oidcHttpCacheStorage = new BasicHttpCacheStorage(cacheConfig);
}
}

public int getOidcCacheHits() {
return oidcCacheHits;
}
Expand Down
Loading