diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java index d3f42cc9ca..72566bbb73 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurer.java @@ -31,6 +31,7 @@ import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultResourcesFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; @@ -178,6 +179,11 @@ public void configure(H http) { WebAuthnAuthenticationFilter webAuthnAuthnFilter = new WebAuthnAuthenticationFilter(); webAuthnAuthnFilter.setAuthenticationManager( new ProviderManager(new WebAuthnAuthenticationProvider(rpOperations, userDetailsService))); + SessionAuthenticationStrategy sessionAuthenticationStrategy = http + .getSharedObject(SessionAuthenticationStrategy.class); + if (sessionAuthenticationStrategy != null) { + webAuthnAuthnFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy); + } webAuthnAuthnFilter = postProcess(webAuthnAuthnFilter); WebAuthnRegistrationFilter webAuthnRegistrationFilter = new WebAuthnRegistrationFilter(userCredentials, rpOperations); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurerTests.java index 454d069e51..08c8a05207 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/WebAuthnConfigurerTests.java @@ -42,6 +42,8 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy; +import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.authentication.ui.DefaultResourcesFilter; import org.springframework.security.web.webauthn.api.Bytes; import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity; @@ -55,6 +57,7 @@ import org.springframework.security.web.webauthn.management.UserCredentialRepository; import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations; import org.springframework.security.web.webauthn.registration.HttpSessionPublicKeyCredentialCreationOptionsRepository; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; import static org.assertj.core.api.Assertions.assertThat; @@ -408,6 +411,49 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { } + // gh-16685 + @Test + public void webAuthnWhenSessionManagementConfiguredThenSessionAuthenticationStrategyApplied() { + this.spring.register(SessionManagementWebauthnConfiguration.class).autowire(); + FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class); + List filters = filterChain.getFilterChains().get(0).getFilters(); + WebAuthnAuthenticationFilter webAuthnFilter = filters.stream() + .filter(WebAuthnAuthenticationFilter.class::isInstance) + .map(WebAuthnAuthenticationFilter.class::cast) + .findFirst() + .orElseThrow(() -> new AssertionError("WebAuthnAuthenticationFilter not found")); + SessionAuthenticationStrategy strategy = (SessionAuthenticationStrategy) ReflectionTestUtils + .getField(webAuthnFilter, "sessionStrategy"); + assertThat(strategy).isNotNull(); + assertThat(strategy).isInstanceOf(CompositeSessionAuthenticationStrategy.class); + } + + @Configuration + @EnableWebSecurity + static class SessionManagementWebauthnConfiguration { + + @Bean + UserDetailsService userDetailsService() { + return new InMemoryUserDetailsManager(); + } + + @Bean + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .formLogin(Customizer.withDefaults()) + .sessionManagement((session) -> session + .maximumSessions(1) + ) + .webAuthn((authn) -> authn + .rpId("example.com") + ); + // @formatter:on + return http.build(); + } + + } + @Configuration @EnableWebSecurity static class CustomRpNameWebauthnConfiguration {