Skip to content

Commit

Permalink
enhance LogoutResource to dynamically resolve OAuth2 client registration
Browse files Browse the repository at this point in the history
  • Loading branch information
yhao3 committed Jan 8, 2025
1 parent 2d01f84 commit 4539180
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

/**
Expand All @@ -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<Map<String, String>> 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!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,29 @@
-%>
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;
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<ClientRegistration> registration;
private final ReactiveClientRegistrationRepository registrationRepository;

public LogoutResource(ReactiveClientRegistrationRepository registrations) {
this.registration = registrations.findByRegistrationId("oidc");
public LogoutResource(ReactiveClientRegistrationRepository registrationRepository) {
this.registrationRepository = registrationRepository;
}

/**
Expand All @@ -53,9 +55,15 @@ public class LogoutResource {
public Mono<Map<String, String>> 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<String, String> prepareLogoutUri(ServerHttpRequest request, ClientRegistration clientRegistration, OidcIdToken idToken) {
Expand Down

0 comments on commit 4539180

Please sign in to comment.