Do Not Wire Default OidcSessionStrategy without OidcLogoutConfigurer
Closes gh-14558
This commit is contained in:
parent
eea4279fae
commit
3ab323663a
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 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.
|
||||||
|
@ -582,6 +582,10 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureOidcSessionRegistry(B http) {
|
private void configureOidcSessionRegistry(B http) {
|
||||||
|
if (http.getConfigurer(OidcLogoutConfigurer.class) == null
|
||||||
|
&& http.getSharedObject(OidcSessionRegistry.class) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
OidcSessionRegistry sessionRegistry = OAuth2ClientConfigurerUtils.getOidcSessionRegistry(http);
|
OidcSessionRegistry sessionRegistry = OAuth2ClientConfigurerUtils.getOidcSessionRegistry(http);
|
||||||
SessionManagementConfigurer<B> sessionConfigurer = http.getConfigurer(SessionManagementConfigurer.class);
|
SessionManagementConfigurer<B> sessionConfigurer = http.getConfigurer(SessionManagementConfigurer.class);
|
||||||
if (sessionConfigurer != null) {
|
if (sessionConfigurer != null) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 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.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 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.
|
||||||
|
@ -3974,8 +3974,10 @@ public class ServerHttpSecurity {
|
||||||
|
|
||||||
ReactiveAuthenticationManager manager = getAuthenticationManager();
|
ReactiveAuthenticationManager manager = getAuthenticationManager();
|
||||||
ReactiveOidcSessionRegistry sessionRegistry = getOidcSessionRegistry();
|
ReactiveOidcSessionRegistry sessionRegistry = getOidcSessionRegistry();
|
||||||
AuthenticationWebFilter authenticationFilter = new OidcSessionRegistryAuthenticationWebFilter(manager,
|
AuthenticationWebFilter authenticationFilter = (sessionRegistry != null)
|
||||||
authorizedClientRepository, sessionRegistry);
|
? new OidcSessionRegistryAuthenticationWebFilter(manager, authorizedClientRepository,
|
||||||
|
sessionRegistry)
|
||||||
|
: new OAuth2LoginAuthenticationWebFilter(manager, authorizedClientRepository);
|
||||||
authenticationFilter.setRequiresAuthenticationMatcher(getAuthenticationMatcher());
|
authenticationFilter.setRequiresAuthenticationMatcher(getAuthenticationMatcher());
|
||||||
authenticationFilter
|
authenticationFilter
|
||||||
.setServerAuthenticationConverter(getAuthenticationConverter(clientRegistrationRepository));
|
.setServerAuthenticationConverter(getAuthenticationConverter(clientRegistrationRepository));
|
||||||
|
@ -3984,8 +3986,10 @@ public class ServerHttpSecurity {
|
||||||
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
|
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
|
||||||
|
|
||||||
setDefaultEntryPoints(http);
|
setDefaultEntryPoints(http);
|
||||||
http.addFilterAfter(new OidcSessionRegistryWebFilter(sessionRegistry),
|
if (sessionRegistry != null) {
|
||||||
SecurityWebFiltersOrder.HTTP_HEADERS_WRITER);
|
http.addFilterAfter(new OidcSessionRegistryWebFilter(sessionRegistry),
|
||||||
|
SecurityWebFiltersOrder.HTTP_HEADERS_WRITER);
|
||||||
|
}
|
||||||
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
|
http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
|
||||||
http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
|
http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
|
||||||
}
|
}
|
||||||
|
@ -4031,6 +4035,9 @@ public class ServerHttpSecurity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReactiveOidcSessionRegistry getOidcSessionRegistry() {
|
private ReactiveOidcSessionRegistry getOidcSessionRegistry() {
|
||||||
|
if (ServerHttpSecurity.this.oidcLogout == null && this.oidcSessionRegistry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (this.oidcSessionRegistry == null) {
|
if (this.oidcSessionRegistry == null) {
|
||||||
this.oidcSessionRegistry = getBeanOrNull(ReactiveOidcSessionRegistry.class);
|
this.oidcSessionRegistry = getBeanOrNull(ReactiveOidcSessionRegistry.class);
|
||||||
}
|
}
|
||||||
|
@ -4269,8 +4276,7 @@ public class ServerHttpSecurity {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class OidcSessionRegistryAuthenticationWebFilter
|
static final class OidcSessionRegistryAuthenticationWebFilter extends OAuth2LoginAuthenticationWebFilter {
|
||||||
extends OAuth2LoginAuthenticationWebFilter {
|
|
||||||
|
|
||||||
private final Log logger = LogFactory.getLog(getClass());
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -22,6 +22,7 @@ import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.http.HttpHeaders;
|
import org.apache.http.HttpHeaders;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
@ -36,6 +37,7 @@ import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.event.SmartApplicationListener;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.mock.web.MockFilterChain;
|
import org.springframework.mock.web.MockFilterChain;
|
||||||
|
@ -48,6 +50,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
|
import org.springframework.security.context.DelegatingApplicationListener;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
@ -55,9 +58,11 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||||
import org.springframework.security.core.context.SecurityContextChangedListener;
|
import org.springframework.security.core.context.SecurityContextChangedListener;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
import org.springframework.security.core.session.SessionDestroyedEvent;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||||
|
import org.springframework.security.oauth2.client.oidc.session.OidcSessionRegistry;
|
||||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||||
import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler;
|
import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
|
@ -95,7 +100,9 @@ import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||||
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||||
import org.springframework.security.web.context.SecurityContextRepository;
|
import org.springframework.security.web.context.SecurityContextRepository;
|
||||||
|
import org.springframework.security.web.session.HttpSessionDestroyedEvent;
|
||||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
|
|
||||||
|
@ -150,10 +157,10 @@ public class OAuth2LoginConfigurerTests {
|
||||||
@Autowired
|
@Autowired
|
||||||
private FilterChainProxy springSecurityFilterChain;
|
private FilterChainProxy springSecurityFilterChain;
|
||||||
|
|
||||||
@Autowired
|
@Autowired(required = false)
|
||||||
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
|
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired(required = false)
|
||||||
SecurityContextRepository securityContextRepository;
|
SecurityContextRepository securityContextRepository;
|
||||||
|
|
||||||
public final SpringTestContext spring = new SpringTestContext(this);
|
public final SpringTestContext spring = new SpringTestContext(this);
|
||||||
|
@ -642,6 +649,26 @@ public class OAuth2LoginConfigurerTests {
|
||||||
.andExpect(redirectedUrl("https://logout?id_token_hint=id-token"));
|
.andExpect(redirectedUrl("https://logout?id_token_hint=id-token"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configureWhenOidcSessionStrategyThenUses() {
|
||||||
|
this.spring.register(OAuth2LoginWithOidcSessionRegistry.class).autowire();
|
||||||
|
OidcSessionRegistry registry = this.spring.getContext().getBean(OidcSessionRegistry.class);
|
||||||
|
this.spring.getContext().publishEvent(new HttpSessionDestroyedEvent(this.request.getSession()));
|
||||||
|
verify(registry).removeSessionInformation(this.request.getSession().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// gh-14558
|
||||||
|
@Test
|
||||||
|
public void oauth2LoginWhenDefaultsThenNoOidcSessionRegistry() {
|
||||||
|
this.spring.register(OAuth2LoginConfig.class).autowire();
|
||||||
|
DelegatingApplicationListener listener = this.spring.getContext().getBean(DelegatingApplicationListener.class);
|
||||||
|
List<SmartApplicationListener> listeners = (List<SmartApplicationListener>) ReflectionTestUtils
|
||||||
|
.getField(listener, "listeners");
|
||||||
|
assertThat(listeners.stream()
|
||||||
|
.filter((l) -> l.supportsEventType(SessionDestroyedEvent.class))
|
||||||
|
.collect(Collectors.toList())).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private void loadConfig(Class<?>... configs) {
|
private void loadConfig(Class<?>... configs) {
|
||||||
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
||||||
applicationContext.register(configs);
|
applicationContext.register(configs);
|
||||||
|
@ -1117,6 +1144,32 @@ public class OAuth2LoginConfigurerTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class OAuth2LoginWithOidcSessionRegistry {
|
||||||
|
|
||||||
|
private final OidcSessionRegistry registry = mock(OidcSessionRegistry.class);
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.oauth2Login((oauth2) -> oauth2
|
||||||
|
.clientRegistrationRepository(
|
||||||
|
new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))
|
||||||
|
.oidcSessionRegistry(this.registry)
|
||||||
|
);
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
OidcSessionRegistry oidcSessionRegistry() {
|
||||||
|
return this.registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class OAuth2LoginWithXHREntryPointConfig extends CommonSecurityFilterChainConfig {
|
static class OAuth2LoginWithXHREntryPointConfig extends CommonSecurityFilterChainConfig {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2021 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.
|
||||||
|
@ -34,11 +34,13 @@ import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||||
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
|
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
|
||||||
|
import org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2LoginSpec.OidcSessionRegistryAuthenticationWebFilter;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
@ -54,10 +56,12 @@ import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuth
|
||||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||||
import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient;
|
import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient;
|
||||||
import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeReactiveAuthenticationManager;
|
import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeReactiveAuthenticationManager;
|
||||||
|
import org.springframework.security.oauth2.client.oidc.server.session.ReactiveOidcSessionRegistry;
|
||||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||||
import org.springframework.security.oauth2.client.oidc.web.server.logout.OidcClientInitiatedServerLogoutSuccessHandler;
|
import org.springframework.security.oauth2.client.oidc.web.server.logout.OidcClientInitiatedServerLogoutSuccessHandler;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
|
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
|
||||||
|
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||||
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
|
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
|
||||||
import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService;
|
import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
|
import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
|
||||||
|
@ -576,6 +580,27 @@ public class OAuth2LoginTests {
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void oauth2LoginWhenOidcSessionRegistryThenUses() {
|
||||||
|
this.spring.register(OAuth2LoginWithOidcSessionRegistry.class).autowire();
|
||||||
|
SecurityWebFilterChain chain = this.spring.getContext().getBean(SecurityWebFilterChain.class);
|
||||||
|
assertThat(chain.getWebFilters()
|
||||||
|
.filter((filter) -> filter instanceof OidcSessionRegistryAuthenticationWebFilter)
|
||||||
|
.collectList()
|
||||||
|
.block()).isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// gh-14558
|
||||||
|
@Test
|
||||||
|
public void oauth2LoginWhenDefaultsThenNoOidcSessionRegistry() {
|
||||||
|
this.spring.register(OAuth2LoginWithSingleClientRegistrations.class, OAuth2LoginConfig.class).autowire();
|
||||||
|
SecurityWebFilterChain chain = this.spring.getContext().getBean(SecurityWebFilterChain.class);
|
||||||
|
assertThat(chain.getWebFilters()
|
||||||
|
.filter((filter) -> filter instanceof OidcSessionRegistryAuthenticationWebFilter)
|
||||||
|
.collectList()
|
||||||
|
.block()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
Mono<SecurityContext> authentication(Authentication authentication) {
|
Mono<SecurityContext> authentication(Authentication authentication) {
|
||||||
SecurityContext context = new SecurityContextImpl();
|
SecurityContext context = new SecurityContextImpl();
|
||||||
context.setAuthentication(authentication);
|
context.setAuthentication(authentication);
|
||||||
|
@ -624,6 +649,21 @@ public class OAuth2LoginTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EnableWebFlux
|
||||||
|
static class OAuth2LoginConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
|
||||||
|
.oauth2Login(Customizer.withDefaults());
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@EnableWebFlux
|
@EnableWebFlux
|
||||||
static class OAuth2AuthorizeWithMockObjectsConfig {
|
static class OAuth2AuthorizeWithMockObjectsConfig {
|
||||||
|
|
||||||
|
@ -892,6 +932,35 @@ public class OAuth2LoginTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebFluxSecurity
|
||||||
|
static class OAuth2LoginWithOidcSessionRegistry {
|
||||||
|
|
||||||
|
private final ReactiveOidcSessionRegistry registry = mock(ReactiveOidcSessionRegistry.class);
|
||||||
|
|
||||||
|
private final ReactiveClientRegistrationRepository clients = new InMemoryReactiveClientRegistrationRepository(
|
||||||
|
TestClientRegistrations.clientRegistration().build());
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
|
||||||
|
.oauth2Login((oauth2) -> oauth2
|
||||||
|
.clientRegistrationRepository(this.clients)
|
||||||
|
.oidcSessionRegistry(this.registry)
|
||||||
|
);
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ReactiveOidcSessionRegistry oidcSessionRegistry() {
|
||||||
|
return this.registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static class GitHubWebFilter implements WebFilter {
|
static class GitHubWebFilter implements WebFilter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -170,6 +170,33 @@ open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
----
|
----
|
||||||
======
|
======
|
||||||
|
|
||||||
|
Then, you need a way listen to events published by Spring Security to remove old `OidcSessionInformation` entries, like so:
|
||||||
|
|
||||||
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source=java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
public HttpSessionEventListener sessionEventListener() {
|
||||||
|
return new HttpSessionEventListener();
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source=kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
open fun sessionEventListener(): HttpSessionEventListener {
|
||||||
|
return HttpSessionEventListener()
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
|
This will make so that if `HttpSession#invalidate` is called, then the session is also removed from memory.
|
||||||
|
|
||||||
And that's it!
|
And that's it!
|
||||||
|
|
||||||
This will stand up the endpoint `+/logout/connect/back-channel/{registrationId}+` which the OIDC Provider can request to invalidate a given session of an end user in your application.
|
This will stand up the endpoint `+/logout/connect/back-channel/{registrationId}+` which the OIDC Provider can request to invalidate a given session of an end user in your application.
|
||||||
|
|
Loading…
Reference in New Issue