Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4fe9d915b6 | |||
| e38c059e7c | |||
| 829af961f0 | |||
| fca704e61f | |||
| ea9dd2728e | |||
| 258aa66f0d | |||
| d5d31a0892 | |||
| 1b3f8435ce | |||
| 22fbbb9365 | |||
| f1622351e5 | |||
| e5c45c9dda | |||
| 82fa658c9b | |||
| 51a703a291 | |||
| ae689cd220 | |||
| 2a3d1340d1 | |||
| 9f40a72f19 | |||
| 470384597c | |||
| c27f7206d9 | |||
| 2cb200079c | |||
| cb515e5c57 | |||
| b56533c13c | |||
| b63a337015 | |||
| 880ba0e1aa | |||
| 9262a8ecc8 | |||
| 4084b70335 | |||
| 59365e9ac5 | |||
| 2a38de48b8 | |||
| 284a32c698 | |||
| 3d028b1c22 | |||
| 126166da1e | |||
| f4387f299a | |||
| 854703cb47 | |||
| b81d894cc8 | |||
| b2f4bf9b74 | |||
| ac7f6260b1 | |||
| ebca0df783 | |||
| 3395e061f0 | |||
| e2f96480a4 | |||
| ba17c3182b | |||
| 1e03085a12 | |||
| c92187a9a7 | |||
| 759736672d | |||
| 64bc37b5d6 | |||
| afc25b1ea3 | |||
| 8461feb028 | |||
| 4f5b17334e | |||
| 3f4ef169f6 | |||
| 192bafe9a5 | |||
| 43042b6724 | |||
| b144c37cad | |||
| 22992afbe8 | |||
| 39b53ee0be | |||
| 23fa7c3047 | |||
| 43e2e53b90 | |||
| 3fec6959b1 | |||
| a8f8fcb046 | |||
| 16956fe01c | |||
| a66efc26f5 |
+9
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,6 +50,7 @@ import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
* @param <O> The object that this builder returns
|
||||
* @param <B> The type of this builder (that is returned by the base class)
|
||||
* @author Rob Winch
|
||||
* @author DingHao
|
||||
* @see WebSecurity
|
||||
*/
|
||||
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
|
||||
@@ -59,7 +60,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
|
||||
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
|
||||
|
||||
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();
|
||||
private List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();
|
||||
|
||||
private final Map<Class<?>, Object> sharedObjects = new HashMap<>();
|
||||
|
||||
@@ -386,8 +387,12 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
for (SecurityConfigurer<O, B> configurer : configurers) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
|
||||
configurer.init((B) this);
|
||||
while (!this.configurersAddedInInitializing.isEmpty()) {
|
||||
List<SecurityConfigurer<O, B>> toInit = this.configurersAddedInInitializing;
|
||||
this.configurersAddedInInitializing = new ArrayList<>();
|
||||
for (SecurityConfigurer<O, B> configurer : toInit) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
@@ -87,6 +87,7 @@ import org.springframework.security.web.authentication.LoginUrlAuthenticationEnt
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
@@ -177,6 +178,8 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
private OAuth2AuthorizedClientRepository authorizedClientRepository;
|
||||
|
||||
private SecurityContextRepository securityContextRepository;
|
||||
|
||||
/**
|
||||
* Sets the repository of client registrations.
|
||||
* @param clientRegistrationRepository the repository of client registrations
|
||||
@@ -230,6 +233,17 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SecurityContextRepository} to use.
|
||||
* @param securityContextRepository the {@link SecurityContextRepository} to use
|
||||
* @return the {@link OAuth2LoginConfigurer} for further configuration
|
||||
*/
|
||||
@Override
|
||||
public OAuth2LoginConfigurer<B> securityContextRepository(SecurityContextRepository securityContextRepository) {
|
||||
this.securityContextRepository = securityContextRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the registry for managing the OIDC client-provider session link
|
||||
* @param oidcSessionRegistry the {@link OidcSessionRegistry} to use
|
||||
@@ -348,6 +362,9 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(
|
||||
this.getClientRegistrationRepository(), this.getAuthorizedClientRepository(), this.loginProcessingUrl);
|
||||
authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
if (this.securityContextRepository != null) {
|
||||
authenticationFilter.setSecurityContextRepository(this.securityContextRepository);
|
||||
}
|
||||
this.setAuthenticationFilter(authenticationFilter);
|
||||
super.loginProcessingUrl(this.loginProcessingUrl);
|
||||
if (this.loginPage != null) {
|
||||
|
||||
+8
-1
@@ -301,6 +301,8 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
|
||||
private static final String CLIENT_INBOUND_CHANNEL_BEAN_ID = "clientInboundChannel";
|
||||
|
||||
private static final String CSRF_CHANNEL_INTERCEPTOR_BEAN_ID = "csrfChannelInterceptor";
|
||||
|
||||
private static final String INTERCEPTORS_PROP = "interceptors";
|
||||
|
||||
private static final String CUSTOM_ARG_RESOLVERS_PROP = "customArgumentResolvers";
|
||||
@@ -364,7 +366,12 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
|
||||
ManagedList<Object> interceptors = new ManagedList();
|
||||
interceptors.add(new RootBeanDefinition(SecurityContextChannelInterceptor.class));
|
||||
if (!this.sameOriginDisabled) {
|
||||
interceptors.add(new RootBeanDefinition(CsrfChannelInterceptor.class));
|
||||
if (!registry.containsBeanDefinition(CSRF_CHANNEL_INTERCEPTOR_BEAN_ID)) {
|
||||
interceptors.add(new RootBeanDefinition(CsrfChannelInterceptor.class));
|
||||
}
|
||||
else {
|
||||
interceptors.add(new RuntimeBeanReference(CSRF_CHANNEL_INTERCEPTOR_BEAN_ID));
|
||||
}
|
||||
}
|
||||
interceptors.add(registry.getBeanDefinition(this.inboundSecurityInterceptorId));
|
||||
BeanDefinition inboundChannel = registry.getBeanDefinition(CLIENT_INBOUND_CHANNEL_BEAN_ID);
|
||||
|
||||
+31
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -163,6 +163,36 @@ public class AbstractConfiguredSecurityBuilderTests {
|
||||
assertThat(this.builder.getConfigurers(TestSecurityConfigurer.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withWhenConfigurerAddInitializing() throws Exception {
|
||||
this.builder.with(new AppliesNestedConfigurer(), Customizer.withDefaults());
|
||||
assertThat(this.builder.build()).isEqualTo("success");
|
||||
}
|
||||
|
||||
private static class AppliesNestedConfigurer
|
||||
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
|
||||
|
||||
@Override
|
||||
public void init(TestConfiguredSecurityBuilder builder) throws Exception {
|
||||
builder.with(new NestedConfigurer(), Customizer.withDefaults());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class NestedConfigurer extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
|
||||
|
||||
@Override
|
||||
public void init(TestConfiguredSecurityBuilder http) throws Exception {
|
||||
http.with(new DoubleNestedConfigurer(), Customizer.withDefaults());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class DoubleNestedConfigurer
|
||||
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
|
||||
|
||||
}
|
||||
|
||||
private static class ApplyAndRemoveSecurityConfigurer
|
||||
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
|
||||
|
||||
|
||||
+26
@@ -101,6 +101,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.context.NullSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.session.HttpSessionDestroyedEvent;
|
||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||
@@ -110,6 +111,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -696,6 +698,12 @@ public class OAuth2LoginConfigurerTests {
|
||||
verifyNoInteractions(clientRegistrationRepository, authorizedClientRepository);
|
||||
}
|
||||
|
||||
// gh-16623
|
||||
@Test
|
||||
public void oauth2LoginWithCustomSecurityContextRepository() {
|
||||
assertThatNoException().isThrownBy(() -> loadConfig(OAuth2LoginConfigSecurityContextRepository.class));
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>... configs) {
|
||||
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
||||
applicationContext.register(configs);
|
||||
@@ -944,6 +952,24 @@ public class OAuth2LoginConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class OAuth2LoginConfigSecurityContextRepository extends CommonSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.oauth2Login((login) -> login
|
||||
.clientRegistrationRepository(
|
||||
new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))
|
||||
.securityContextRepository(new NullSecurityContextRepository()));
|
||||
// @formatter:on
|
||||
return super.configureFilterChain(http);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class OAuth2LoginConfigCustomAuthorizationRequestResolver extends CommonSecurityFilterChainConfig {
|
||||
|
||||
+11
@@ -48,6 +48,7 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.support.ChannelInterceptor;
|
||||
import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.expression.SecurityExpressionOperations;
|
||||
@@ -521,6 +522,16 @@ public class WebSocketMessageBrokerConfigTests {
|
||||
verify(authorizationManager).check(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenCsrfChannelInterceptorBeanThenUses() {
|
||||
this.spring.configLocations(xml("CustomCsrfInterceptor")).autowire();
|
||||
ExecutorSubscribableChannel channel = this.spring.getContext()
|
||||
.getBean("clientInboundChannel", ExecutorSubscribableChannel.class);
|
||||
ChannelInterceptor interceptor = this.spring.getContext()
|
||||
.getBean("csrfChannelInterceptor", ChannelInterceptor.class);
|
||||
assertThat(channel.getInterceptors()).contains(interceptor);
|
||||
}
|
||||
|
||||
private String xml(String configName) {
|
||||
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
|
||||
}
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2002-2018 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ https://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<b:import resource="classpath:org/springframework/security/config/websocket/controllers.xml"/>
|
||||
<b:import resource="classpath:org/springframework/security/config/websocket/websocket.xml"/>
|
||||
|
||||
<b:bean id="csrfChannelInterceptor" class="org.mockito.Mockito" factory-method="mock">
|
||||
<b:constructor-arg value="org.springframework.messaging.support.ChannelInterceptor" type="java.lang.Class"/>
|
||||
</b:bean>
|
||||
|
||||
<websocket-message-broker use-authorization-manager="false">
|
||||
<intercept-message pattern="/**" access="denyNile()"/>
|
||||
</websocket-message-broker>
|
||||
|
||||
</b:beans>
|
||||
+2
-2
@@ -14,8 +14,8 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
springBootVersion=3.3.3
|
||||
version=6.4.8-SNAPSHOT
|
||||
samplesBranch=main
|
||||
version=6.4.8
|
||||
samplesBranch=6.4.x
|
||||
org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[versions]
|
||||
com-squareup-okhttp3 = "3.14.9"
|
||||
io-rsocket = "1.1.5"
|
||||
io-spring-javaformat = "0.0.46"
|
||||
io-spring-javaformat = "0.0.47"
|
||||
io-spring-nohttp = "0.0.11"
|
||||
jakarta-websocket = "2.2.0"
|
||||
org-apache-directory-server = "1.5.5"
|
||||
org-apache-maven-resolver = "1.9.23"
|
||||
org-apache-maven-resolver = "1.9.24"
|
||||
org-aspectj = "1.9.24"
|
||||
org-bouncycastle = "1.79"
|
||||
org-eclipse-jetty = "11.0.25"
|
||||
@@ -14,7 +14,7 @@ org-jetbrains-kotlinx = "1.9.0"
|
||||
org-mockito = "5.14.2"
|
||||
org-opensaml = "4.3.2"
|
||||
org-opensaml5 = "5.1.2"
|
||||
org-springframework = "6.2.7"
|
||||
org-springframework = "6.2.8"
|
||||
|
||||
[libraries]
|
||||
ch-qos-logback-logback-classic = "ch.qos.logback:logback-classic:1.5.18"
|
||||
@@ -70,7 +70,7 @@ org-bouncycastle-bcprov-jdk15on = { module = "org.bouncycastle:bcprov-jdk18on",
|
||||
org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", version.ref = "org-eclipse-jetty" }
|
||||
org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" }
|
||||
org-hamcrest = "org.hamcrest:hamcrest:2.2"
|
||||
org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.17.Final"
|
||||
org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.20.Final"
|
||||
org-hsqldb = "org.hsqldb:hsqldb:2.7.4"
|
||||
org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" }
|
||||
org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25"
|
||||
@@ -88,8 +88,8 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup
|
||||
org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3"
|
||||
org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36"
|
||||
org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.17"
|
||||
org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.6"
|
||||
org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.12"
|
||||
org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2024.1.7"
|
||||
org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:3.2.13"
|
||||
org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" }
|
||||
org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user