From 4539180b34259b6f8fcc801a661345590cc9bc2c Mon Sep 17 00:00:00 2001 From: Hao Date: Wed, 8 Jan 2025 10:13:43 +0800 Subject: [PATCH] enhance LogoutResource to dynamically resolve OAuth2 client registration --- .../rest/LogoutResource_imperative.java.ejs | 33 +++++++++++++------ .../web/rest/LogoutResource_reactive.java.ejs | 22 +++++++++---- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs index 98916d5a506a..c06047a719f7 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_imperative.java.ejs @@ -19,7 +19,10 @@ package <%= packageName %>.web.rest; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.core.oidc.user.OidcUser; @@ -34,10 +37,10 @@ import java.util.Map; */ @RestController public class LogoutResource { - private final ClientRegistration registration; + private final ClientRegistrationRepository registrationRepository; - public LogoutResource(ClientRegistrationRepository registrations) { - this.registration = registrations.findByRegistrationId("oidc"); + public LogoutResource(ClientRegistrationRepository registrationRepository) { + this.registrationRepository = registrationRepository; } /** @@ -48,16 +51,26 @@ public class LogoutResource { * @return the {@link ResponseEntity} with status {@code 200 (OK)} and a body with a global logout URL. */ @PostMapping("/api/logout") - public ResponseEntity logout(HttpServletRequest request, @AuthenticationPrincipal OidcUser oidcUser) { + public ResponseEntity> logout(HttpServletRequest request, @AuthenticationPrincipal OidcUser oidcUser) { StringBuilder logoutUrl = new StringBuilder(); - - logoutUrl.append(this.registration.getProviderDetails().getConfigurationMetadata().get("end_session_endpoint").toString()); - String originUrl = request.getHeader(HttpHeaders.ORIGIN); - logoutUrl.append("?id_token_hint=").append(oidcUser.getIdToken().getTokenValue()).append("&post_logout_redirect_uri=").append(originUrl); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication instanceof OAuth2AuthenticationToken) { + OAuth2AuthenticationToken oAuth2AuthenticationToken = (OAuth2AuthenticationToken) authentication; + ClientRegistration clientRegistration = registrationRepository.findByRegistrationId( + oAuth2AuthenticationToken.getAuthorizedClientRegistrationId() + ); + logoutUrl + .append(clientRegistration.getProviderDetails().getConfigurationMetadata().get("end_session_endpoint").toString()) + .append("?id_token_hint=") + .append(oidcUser.getIdToken().getTokenValue()) + .append("&post_logout_redirect_uri=") + .append(originUrl); - request.getSession().invalidate(); - return ResponseEntity.ok().body(Map.of("logoutUrl", logoutUrl.toString())); + request.getSession().invalidate(); + return ResponseEntity.ok().body(Map.of("logoutUrl", logoutUrl.toString())); + } + throw new IllegalArgumentException("AuthenticationToken is not OAuth2!"); } } diff --git a/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs b/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs index 9656d717ba4c..a557d5632ef3 100644 --- a/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs +++ b/generators/spring-boot/templates/src/main/java/_package_/web/rest/LogoutResource_reactive.java.ejs @@ -18,7 +18,11 @@ -%> package <%= packageName %>.web.rest; +import java.util.Map; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; import org.springframework.security.oauth2.core.oidc.OidcIdToken; @@ -26,19 +30,17 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.WebSession; -import org.springframework.http.server.reactive.ServerHttpRequest; import reactor.core.publisher.Mono; -import java.util.Map; /** * REST controller for managing global OIDC logout. */ @RestController public class LogoutResource { - private final Mono registration; + private final ReactiveClientRegistrationRepository registrationRepository; - public LogoutResource(ReactiveClientRegistrationRepository registrations) { - this.registration = registrations.findByRegistrationId("oidc"); + public LogoutResource(ReactiveClientRegistrationRepository registrationRepository) { + this.registrationRepository = registrationRepository; } /** @@ -53,9 +55,15 @@ public class LogoutResource { public Mono> logout( @AuthenticationPrincipal OidcUser oidcUser, ServerHttpRequest request, - WebSession session + WebSession session, + AbstractAuthenticationToken authToken ) { - return session.invalidate().then(this.registration.map(oidc -> prepareLogoutUri(request, oidc, oidcUser.getIdToken()))); + if (authToken instanceof OAuth2AuthenticationToken) { + return session.invalidate() + .then(registrationRepository.findByRegistrationId(((OAuth2AuthenticationToken) authToken).getAuthorizedClientRegistrationId()) + .map(oidc -> prepareLogoutUri(request, oidc, oidcUser.getIdToken()))); + } + throw new IllegalArgumentException("AuthenticationToken is not OAuth2!"); } private Map prepareLogoutUri(ServerHttpRequest request, ClientRegistration clientRegistration, OidcIdToken idToken) {