diff --git a/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceConfig.java b/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceConfig.java index f0b618869b..e8e899bb66 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceConfig.java +++ b/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceConfig.java @@ -59,6 +59,7 @@ public class IdentityServiceConfig implements InitializingBean private String clientKeystorePassword; private String clientKeyPassword; private String realmKey; + private int publicKeyCacheTtl; public void setGlobalProperties(Properties globalProperties) { @@ -240,4 +241,14 @@ public class IdentityServiceConfig implements InitializingBean { return realmKey; } + + public void setPublicKeyCacheTtl(int publicKeyCacheTtl) + { + this.publicKeyCacheTtl = publicKeyCacheTtl; + } + + public int getPublicKeyCacheTtl() + { + return publicKeyCacheTtl; + } } diff --git a/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceFacadeFactoryBean.java b/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceFacadeFactoryBean.java index b1fbca113b..c391c83357 100644 --- a/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceFacadeFactoryBean.java +++ b/repository/src/main/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceFacadeFactoryBean.java @@ -33,6 +33,7 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStream; import java.net.URI; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.interfaces.RSAPublicKey; import java.time.Duration; @@ -42,11 +43,20 @@ import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.jwk.source.DefaultJWKSetCache; +import com.nimbusds.jose.jwk.source.JWKSource; +import com.nimbusds.jose.jwk.source.RemoteJWKSet; +import com.nimbusds.jose.proc.JWSVerificationKeySelector; +import com.nimbusds.jose.proc.SecurityContext; +import com.nimbusds.jose.util.ResourceRetriever; +import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata; import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacade.IdentityServiceFacadeException; @@ -253,8 +263,8 @@ public class IdentityServiceFacadeFactoryBean implements FactoryBean jwtProcessor) + { + final Optional> jwkSource = ofNullable(jwtProcessor) + .map(ConfigurableJWTProcessor::getJWSKeySelector) + .filter(JWSVerificationKeySelector.class::isInstance).map(o -> (JWSVerificationKeySelector)o) + .map(JWSVerificationKeySelector::getJWKSource) + .filter(RemoteJWKSet.class::isInstance).map(o -> (RemoteJWKSet)o); + if (jwkSource.isEmpty()) + { + LOGGER.warn("Not able to reconfigure the JWK Cache. Unexpected JWKSource."); + return; + } + + final Optional jwkSetUrl = jwkSource.map(RemoteJWKSet::getJWKSetURL); + if (jwkSetUrl.isEmpty()) + { + LOGGER.warn("Not able to reconfigure the JWK Cache. Unknown JWKSetURL."); + return; + } + + final Optional resourceRetriever = jwkSource.map(RemoteJWKSet::getResourceRetriever); + if (resourceRetriever.isEmpty()) + { + LOGGER.warn("Not able to reconfigure the JWK Cache. Unknown ResourceRetriever."); + return; + } + + final DefaultJWKSetCache cache = new DefaultJWKSetCache(config.getPublicKeyCacheTtl(), -1, TimeUnit.SECONDS); + final JWKSource cachingJWKSource = new RemoteJWKSet<>(jwkSetUrl.get(), resourceRetriever.get(), cache); + + jwtProcessor.setJWSKeySelector(new JWSVerificationKeySelector<>( + JWSAlgorithm.parse(SIGNATURE_ALGORITHM.getName()), + cachingJWKSource)); + } + private OAuth2TokenValidator createJwtTokenValidator(ProviderDetails providerDetails) { return new DelegatingOAuth2TokenValidator<>( diff --git a/repository/src/main/resources/alfresco/subsystems/Authentication/identity-service/identity-service-authentication-context.xml b/repository/src/main/resources/alfresco/subsystems/Authentication/identity-service/identity-service-authentication-context.xml index d60420109f..bafa6a126b 100644 --- a/repository/src/main/resources/alfresco/subsystems/Authentication/identity-service/identity-service-authentication-context.xml +++ b/repository/src/main/resources/alfresco/subsystems/Authentication/identity-service/identity-service-authentication-context.xml @@ -131,6 +131,9 @@ ${identity-service.realm-public-key:#{null}} + + ${identity-service.public-key-cache-ttl:86400} +