From 80550529c68f72a65aea5bb21058392658ad8772 Mon Sep 17 00:00:00 2001 From: baixinsui Date: Mon, 9 Dec 2024 10:00:23 +0800 Subject: [PATCH] Add retry for JWT auth to avoid application startup failed --- pom.xml | 6 -- .../oauth2/config/Oauth2JwtDecoder.java | 55 +++++++++++++++++++ .../config/Oauth2WebSecurityConfig.java | 21 ++----- .../OauthOpaqueTokenIntrospector.java | 4 +- src/main/resources/application.properties | 1 + 5 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2JwtDecoder.java diff --git a/pom.xml b/pom.xml index a778a71..1345630 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,6 @@ 2.7.0 3.6.0 3.10.0 - 11.20.1 1.18.30 2.8.0 1.1.0 @@ -101,11 +100,6 @@ org.springframework.boot spring-boot-starter-oauth2-resource-server - - com.nimbusds - oauth2-oidc-sdk - ${nimbusds.oidc.sdk.version} - io.opentelemetry.instrumentation opentelemetry-spring-boot-starter diff --git a/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2JwtDecoder.java b/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2JwtDecoder.java new file mode 100644 index 0000000..5acea04 --- /dev/null +++ b/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2JwtDecoder.java @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * SPDX-FileCopyrightText: Huawei Inc. + * + */ + +package org.eclipse.xpanse.tofu.maker.security.oauth2.config; + +import java.time.Duration; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Retryable; +import org.springframework.retry.support.RetrySynchronizationManager; +import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator; +import org.springframework.security.oauth2.core.OAuth2TokenValidator; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.JwtDecoders; +import org.springframework.security.oauth2.jwt.JwtIssuerValidator; +import org.springframework.security.oauth2.jwt.JwtTimestampValidator; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; + +/** + * Beans helper for creating JwtDecoder for OAuth2 JWT authentication. + */ +@Slf4j +@Configuration +public class Oauth2JwtDecoder { + + + /** + * Create JwtDecoder for OAuth2 JWT authentication. + * + * @param issuerUri url of the issuer. + * @return JwtDecoder. + */ + @Retryable(retryFor = Exception.class, + maxAttemptsExpression = "${http.request.retry.max.attempts}", + backoff = @Backoff(delayExpression = "${http.request.retry.delay.milliseconds}")) + public JwtDecoder createJwtDecoder(String issuerUri) { + int retryCount = Objects.isNull(RetrySynchronizationManager.getContext()) + ? 0 : RetrySynchronizationManager.getContext().getRetryCount(); + log.info("Creating Oauth2 JwtDecoder from issuerUri:{}. Retry count:{}", issuerUri, + retryCount); + NimbusJwtDecoder jwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri); + OAuth2TokenValidator withClockSkew = new DelegatingOAuth2TokenValidator<>( + new JwtTimestampValidator(Duration.ofSeconds(60)), + new JwtIssuerValidator(issuerUri)); + jwtDecoder.setJwtValidator(withClockSkew); + return jwtDecoder; + } + +} diff --git a/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2WebSecurityConfig.java b/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2WebSecurityConfig.java index 7fcb2b7..5edde36 100644 --- a/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2WebSecurityConfig.java +++ b/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/config/Oauth2WebSecurityConfig.java @@ -9,9 +9,9 @@ import static org.springframework.web.cors.CorsConfiguration.ALL; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import java.io.PrintWriter; -import java.time.Duration; import java.util.Collections; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -28,14 +28,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator; -import org.springframework.security.oauth2.core.OAuth2TokenValidator; -import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.JwtDecoders; -import org.springframework.security.oauth2.jwt.JwtIssuerValidator; -import org.springframework.security.oauth2.jwt.JwtTimestampValidator; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @@ -70,6 +63,9 @@ public class Oauth2WebSecurityConfig { @Value("${spring.security.oauth2.resourceserver.opaquetoken.client-secret}") private String clientSecret; + @Resource + private Oauth2JwtDecoder oauth2JwtDecoder; + /** * Configures basic security handler per HTTP session. * @@ -145,14 +141,9 @@ CorsConfigurationSource corsConfigurationSource() { } @Bean - @ConditionalOnProperty("authorization.token.type") + @ConditionalOnProperty(name = "authorization.token.type", havingValue = "JWT") JwtDecoder jwtDecoder() { - NimbusJwtDecoder jwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri); - OAuth2TokenValidator withClockSkew = new DelegatingOAuth2TokenValidator<>( - new JwtTimestampValidator(Duration.ofSeconds(60)), - new JwtIssuerValidator(issuerUri)); - jwtDecoder.setJwtValidator(withClockSkew); - return jwtDecoder; + return oauth2JwtDecoder.createJwtDecoder(issuerUri); } } \ No newline at end of file diff --git a/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/introspector/OauthOpaqueTokenIntrospector.java b/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/introspector/OauthOpaqueTokenIntrospector.java index d67689a..a7561c0 100644 --- a/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/introspector/OauthOpaqueTokenIntrospector.java +++ b/src/main/java/org/eclipse/xpanse/tofu/maker/security/oauth2/introspector/OauthOpaqueTokenIntrospector.java @@ -8,8 +8,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; -import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; +import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector; /** * Customize the OAuth2AuthoritiesOpaqueTokenIntrospector implements OpaqueTokenIntrospector. @@ -30,7 +30,7 @@ public OauthOpaqueTokenIntrospector(String introspectionUri, String clientId, String clientSecret) { opaqueTokenIntrospector = - new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret); + new SpringOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret); } /** diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index dd683d9..1a5ab79 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -16,6 +16,7 @@ opentofu.root.module.directory= clean.workspace.after.deployment.enabled=true spring.retry.max-attempts=3 spring.retry.delay-millions=1000 +support.default.opentofu.versions.only=true opentofu.install.dir=/opt/opentofu opentofu.download.base.url=https://github.com/opentofu/opentofu/releases opentofu.versions=1.6.0,1.7.0,1.8.0