parent
4c44de7db2
commit
663946806c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -23,6 +23,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||||
|
@ -35,6 +36,7 @@ import org.springframework.security.web.server.WebFilterExchange;
|
||||||
import org.springframework.security.web.server.authentication.logout.RedirectServerLogoutSuccessHandler;
|
import org.springframework.security.web.server.authentication.logout.RedirectServerLogoutSuccessHandler;
|
||||||
import org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler;
|
import org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import org.springframework.web.util.UriComponents;
|
import org.springframework.web.util.UriComponents;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
@ -57,6 +59,8 @@ public class OidcClientInitiatedServerLogoutSuccessHandler implements ServerLogo
|
||||||
|
|
||||||
private String postLogoutRedirectUri;
|
private String postLogoutRedirectUri;
|
||||||
|
|
||||||
|
private Converter<RedirectUriParameters, Mono<String>> redirectUriResolver = new DefaultRedirectUriResolver();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an {@link OidcClientInitiatedServerLogoutSuccessHandler} with the
|
* Constructs an {@link OidcClientInitiatedServerLogoutSuccessHandler} with the
|
||||||
* provided parameters
|
* provided parameters
|
||||||
|
@ -79,15 +83,10 @@ public class OidcClientInitiatedServerLogoutSuccessHandler implements ServerLogo
|
||||||
.map(OAuth2AuthenticationToken.class::cast)
|
.map(OAuth2AuthenticationToken.class::cast)
|
||||||
.map(OAuth2AuthenticationToken::getAuthorizedClientRegistrationId)
|
.map(OAuth2AuthenticationToken::getAuthorizedClientRegistrationId)
|
||||||
.flatMap(this.clientRegistrationRepository::findByRegistrationId)
|
.flatMap(this.clientRegistrationRepository::findByRegistrationId)
|
||||||
.flatMap((clientRegistration) -> {
|
.flatMap((clientRegistration) ->
|
||||||
URI endSessionEndpoint = endSessionEndpoint(clientRegistration);
|
this.redirectUriResolver.convert(
|
||||||
if (endSessionEndpoint == null) {
|
new RedirectUriParameters(exchange.getExchange(), authentication, clientRegistration))
|
||||||
return Mono.empty();
|
)
|
||||||
}
|
|
||||||
String idToken = idToken(authentication);
|
|
||||||
String postLogoutRedirectUri = postLogoutRedirectUri(exchange.getExchange().getRequest(), clientRegistration);
|
|
||||||
return Mono.just(endpointUri(endSessionEndpoint, idToken, postLogoutRedirectUri));
|
|
||||||
})
|
|
||||||
.switchIfEmpty(
|
.switchIfEmpty(
|
||||||
this.serverLogoutSuccessHandler.onLogoutSuccess(exchange, authentication).then(Mono.empty())
|
this.serverLogoutSuccessHandler.onLogoutSuccess(exchange, authentication).then(Mono.empty())
|
||||||
)
|
)
|
||||||
|
@ -189,4 +188,79 @@ public class OidcClientInitiatedServerLogoutSuccessHandler implements ServerLogo
|
||||||
this.serverLogoutSuccessHandler.setLogoutSuccessUrl(logoutSuccessUrl);
|
this.serverLogoutSuccessHandler.setLogoutSuccessUrl(logoutSuccessUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link Converter} that converts {@link RedirectUriParameters} to redirect
|
||||||
|
* URI
|
||||||
|
* @param redirectUriResolver {@link Converter}
|
||||||
|
* @since 6.4
|
||||||
|
*/
|
||||||
|
public void setRedirectUriResolver(Converter<RedirectUriParameters, Mono<String>> redirectUriResolver) {
|
||||||
|
Assert.notNull(redirectUriResolver, "redirectUriResolver cannot be null");
|
||||||
|
this.redirectUriResolver = redirectUriResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters, required for redirect URI resolving.
|
||||||
|
*
|
||||||
|
* @author Max Batischev
|
||||||
|
* @since 6.4
|
||||||
|
*/
|
||||||
|
public static final class RedirectUriParameters {
|
||||||
|
|
||||||
|
private final ServerWebExchange serverWebExchange;
|
||||||
|
|
||||||
|
private final Authentication authentication;
|
||||||
|
|
||||||
|
private final ClientRegistration clientRegistration;
|
||||||
|
|
||||||
|
public RedirectUriParameters(ServerWebExchange serverWebExchange, Authentication authentication,
|
||||||
|
ClientRegistration clientRegistration) {
|
||||||
|
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
|
||||||
|
Assert.notNull(serverWebExchange, "serverWebExchange cannot be null");
|
||||||
|
Assert.notNull(authentication, "authentication cannot be null");
|
||||||
|
this.serverWebExchange = serverWebExchange;
|
||||||
|
this.authentication = authentication;
|
||||||
|
this.clientRegistration = clientRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerWebExchange getServerWebExchange() {
|
||||||
|
return this.serverWebExchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Authentication getAuthentication() {
|
||||||
|
return this.authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistration getClientRegistration() {
|
||||||
|
return this.clientRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default {@link Converter} for redirect uri resolving.
|
||||||
|
*
|
||||||
|
* @since 6.4
|
||||||
|
*/
|
||||||
|
private final class DefaultRedirectUriResolver implements Converter<RedirectUriParameters, Mono<String>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<String> convert(RedirectUriParameters redirectUriParameters) {
|
||||||
|
// @formatter:off
|
||||||
|
return Mono.just(redirectUriParameters.authentication)
|
||||||
|
.flatMap((authentication) -> {
|
||||||
|
URI endSessionEndpoint = endSessionEndpoint(redirectUriParameters.clientRegistration);
|
||||||
|
if (endSessionEndpoint == null) {
|
||||||
|
return Mono.empty();
|
||||||
|
}
|
||||||
|
String idToken = idToken(authentication);
|
||||||
|
String postLogoutRedirectUri = postLogoutRedirectUri(
|
||||||
|
redirectUriParameters.serverWebExchange.getRequest(), redirectUriParameters.clientRegistration);
|
||||||
|
return Mono.just(endpointUri(endSessionEndpoint, idToken, postLogoutRedirectUri));
|
||||||
|
});
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,6 +19,7 @@ package org.springframework.security.oauth2.client.oidc.web.server.logout;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -199,6 +200,25 @@ public class OidcClientInitiatedServerLogoutSuccessHandlerTests {
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.setPostLogoutRedirectUri((String) null));
|
assertThatIllegalArgumentException().isThrownBy(() -> this.handler.setPostLogoutRedirectUri((String) null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void logoutWhenCustomRedirectUriResolverSetThenRedirects() {
|
||||||
|
OAuth2AuthenticationToken token = new OAuth2AuthenticationToken(TestOidcUsers.create(),
|
||||||
|
AuthorityUtils.NO_AUTHORITIES, this.registration.getRegistrationId());
|
||||||
|
WebFilterExchange filterExchange = new WebFilterExchange(this.exchange, this.chain);
|
||||||
|
given(this.exchange.getRequest())
|
||||||
|
.willReturn(MockServerHttpRequest.get("/").queryParam("location", "https://test.com").build());
|
||||||
|
// @formatter:off
|
||||||
|
this.handler.setRedirectUriResolver((params) -> Mono.just(
|
||||||
|
Objects.requireNonNull(params.getServerWebExchange()
|
||||||
|
.getRequest()
|
||||||
|
.getQueryParams()
|
||||||
|
.getFirst("location"))));
|
||||||
|
// @formatter:on
|
||||||
|
this.handler.onLogoutSuccess(filterExchange, token).block();
|
||||||
|
|
||||||
|
assertThat(redirectedUrl(this.exchange)).isEqualTo("https://test.com");
|
||||||
|
}
|
||||||
|
|
||||||
private String redirectedUrl(ServerWebExchange exchange) {
|
private String redirectedUrl(ServerWebExchange exchange) {
|
||||||
return exchange.getResponse().getHeaders().getFirst("Location");
|
return exchange.getResponse().getHeaders().getFirst("Location");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue