mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 09:12:14 +00:00
Add with() method to apply SecurityConfigurerAdapter
This method is intended to replace .apply() because it will not be possible to chain configurations when .and() gets removed Closes gh-13204
This commit is contained in:
parent
4855290a76
commit
1ff5eb6b57
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2023 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.
|
||||||
@ -27,6 +27,7 @@ import java.util.Map;
|
|||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||||
@ -139,6 +140,23 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
|||||||
return configurer;
|
return configurer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a {@link SecurityConfigurerAdapter} to this {@link SecurityBuilder} and
|
||||||
|
* invokes {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.
|
||||||
|
* @param configurer
|
||||||
|
* @return the {@link SecurityBuilder} for further customizations
|
||||||
|
* @throws Exception
|
||||||
|
* @since 6.2
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <C extends SecurityConfigurerAdapter<O, B>> B with(C configurer, Customizer<C> customizer) throws Exception {
|
||||||
|
configurer.addObjectPostProcessor(this.objectPostProcessor);
|
||||||
|
configurer.setBuilder((B) this);
|
||||||
|
add(configurer);
|
||||||
|
customizer.customize(configurer);
|
||||||
|
return (B) this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an object that is shared by multiple {@link SecurityConfigurer}.
|
* Sets an object that is shared by multiple {@link SecurityConfigurer}.
|
||||||
* @param sharedType the Class to key the shared object by.
|
* @param sharedType the Class to key the shared object by.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2023 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.
|
||||||
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package org.springframework.security.config.annotation.web
|
package org.springframework.security.config.annotation.web
|
||||||
|
|
||||||
|
import jakarta.servlet.Filter
|
||||||
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import org.checkerframework.checker.units.qual.C
|
||||||
import org.springframework.context.ApplicationContext
|
import org.springframework.context.ApplicationContext
|
||||||
import org.springframework.security.authentication.AuthenticationManager
|
import org.springframework.security.authentication.AuthenticationManager
|
||||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter
|
import org.springframework.security.config.annotation.SecurityConfigurerAdapter
|
||||||
@ -24,9 +27,6 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
|
|||||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository
|
||||||
import org.springframework.security.web.DefaultSecurityFilterChain
|
import org.springframework.security.web.DefaultSecurityFilterChain
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||||
import org.springframework.util.ClassUtils
|
|
||||||
import jakarta.servlet.Filter
|
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures [HttpSecurity] using a [HttpSecurity Kotlin DSL][HttpSecurityDsl].
|
* Configures [HttpSecurity] using a [HttpSecurity Kotlin DSL][HttpSecurityDsl].
|
||||||
@ -107,6 +107,36 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
|||||||
return this.http.apply(configurer).apply(configuration)
|
return this.http.apply(configurer).apply(configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a [SecurityConfigurerAdapter] to this [HttpSecurity]
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* @Configuration
|
||||||
|
* @EnableWebSecurity
|
||||||
|
* class SecurityConfig {
|
||||||
|
*
|
||||||
|
* @Bean
|
||||||
|
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
* http {
|
||||||
|
* with(CustomSecurityConfigurer<HttpSecurity>()) {
|
||||||
|
* customProperty = "..."
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* return http.build()
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param configurer
|
||||||
|
* the [HttpSecurity] for further customizations
|
||||||
|
* @since 6.2
|
||||||
|
*/
|
||||||
|
fun <C : SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> with(configurer: C, configuration: C.() -> Unit = { }): HttpSecurity? {
|
||||||
|
return this.http.with(configurer, configuration)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows configuring the [HttpSecurity] to only be invoked when matching the
|
* Allows configuring the [HttpSecurity] to only be invoked when matching the
|
||||||
* provided pattern.
|
* provided pattern.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2023 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.
|
||||||
@ -21,6 +21,7 @@ import java.util.List;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.SecurityConfigurer;
|
import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||||
@ -149,6 +150,19 @@ public class AbstractConfiguredSecurityBuilderTests {
|
|||||||
assertThat(builder.getConfigurers(DelegateSecurityConfigurer.class)).hasSize(2);
|
assertThat(builder.getConfigurers(DelegateSecurityConfigurer.class)).hasSize(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withWhenConfigurerThenConfigurerAdded() throws Exception {
|
||||||
|
this.builder.with(new TestSecurityConfigurer(), Customizer.withDefaults());
|
||||||
|
assertThat(this.builder.getConfigurers(TestSecurityConfigurer.class)).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void withWhenDuplicateConfigurerAddedThenDuplicateConfigurerRemoved() throws Exception {
|
||||||
|
this.builder.with(new TestSecurityConfigurer(), Customizer.withDefaults());
|
||||||
|
this.builder.with(new TestSecurityConfigurer(), Customizer.withDefaults());
|
||||||
|
assertThat(this.builder.getConfigurers(TestSecurityConfigurer.class)).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
private static class ApplyAndRemoveSecurityConfigurer
|
private static class ApplyAndRemoveSecurityConfigurer
|
||||||
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
|
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
|
|||||||
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
|
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
|
||||||
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
|
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
|
||||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
|
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
@ -63,6 +64,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
|||||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
|
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||||
import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter;
|
import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter;
|
||||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
|
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
|
||||||
@ -90,6 +92,8 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
|
|||||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||||
|
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
|
||||||
|
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
@ -365,6 +369,27 @@ public class HttpSecurityConfigurationTests {
|
|||||||
assertThat(configSource).isInstanceOf(UrlBasedCorsConfigurationSource.class);
|
assertThat(configSource).isInstanceOf(UrlBasedCorsConfigurationSource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configureWhenAddingCustomDslUsingWithThenApplied() throws Exception {
|
||||||
|
this.spring.register(WithCustomDslConfig.class, UserDetailsConfig.class).autowire();
|
||||||
|
SecurityFilterChain filterChain = this.spring.getContext().getBean(SecurityFilterChain.class);
|
||||||
|
List<Filter> filters = filterChain.getFilters();
|
||||||
|
assertThat(filters).hasAtLeastOneElementOfType(UsernamePasswordAuthenticationFilter.class);
|
||||||
|
this.mockMvc.perform(formLogin()).andExpectAll(redirectedUrl("/"), authenticated());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configureWhenCustomDslAddedFromFactoriesAndDisablingUsingWithThenNotApplied() throws Exception {
|
||||||
|
this.springFactoriesLoader.when(
|
||||||
|
() -> SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, getClass().getClassLoader()))
|
||||||
|
.thenReturn(List.of(new WithCustomDsl()));
|
||||||
|
this.spring.register(WithCustomDslDisabledConfig.class, UserDetailsConfig.class).autowire();
|
||||||
|
SecurityFilterChain filterChain = this.spring.getContext().getBean(SecurityFilterChain.class);
|
||||||
|
List<Filter> filters = filterChain.getFilters();
|
||||||
|
assertThat(filters).doesNotHaveAnyElementsOfTypes(UsernamePasswordAuthenticationFilter.class);
|
||||||
|
this.mockMvc.perform(formLogin()).andExpectAll(status().isNotFound(), unauthenticated());
|
||||||
|
}
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
static class NameController {
|
static class NameController {
|
||||||
|
|
||||||
@ -661,4 +686,45 @@ public class HttpSecurityConfigurationTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class WithCustomDslConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.with(new WithCustomDsl(), Customizer.withDefaults())
|
||||||
|
.httpBasic(Customizer.withDefaults());
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class WithCustomDslDisabledConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.with(new WithCustomDsl(), (dsl) -> dsl.disable())
|
||||||
|
.httpBasic(Customizer.withDefaults());
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class WithCustomDsl extends AbstractHttpConfigurer<WithCustomDsl, HttpSecurity> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(HttpSecurity builder) throws Exception {
|
||||||
|
builder.formLogin(Customizer.withDefaults());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2023 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.config.annotation.web
|
|||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockkObject
|
import io.mockk.mockkObject
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
import jakarta.servlet.Filter
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
@ -55,7 +56,6 @@ import org.springframework.test.web.servlet.get
|
|||||||
import org.springframework.test.web.servlet.post
|
import org.springframework.test.web.servlet.post
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||||
import jakarta.servlet.Filter
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for [HttpSecurityDsl]
|
* Tests for [HttpSecurityDsl]
|
||||||
@ -530,6 +530,18 @@ class HttpSecurityDslTests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `HTTP security when apply custom security configurer using with then custom filter added to filter chain`() {
|
||||||
|
this.spring.register(CustomSecurityConfigurerConfig::class.java).autowire()
|
||||||
|
|
||||||
|
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
|
||||||
|
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
|
||||||
|
|
||||||
|
assertThat(filterClasses).contains(
|
||||||
|
CustomFilter::class.java
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
@ -545,6 +557,21 @@ class HttpSecurityDslTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableWebMvc
|
||||||
|
open class CustomSecurityConfigurerUsingWithConfig {
|
||||||
|
@Bean
|
||||||
|
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
http {
|
||||||
|
with(CustomSecurityConfigurer<HttpSecurity>()) {
|
||||||
|
filter = CustomFilter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class CustomSecurityConfigurer<H : HttpSecurityBuilder<H>> : AbstractHttpConfigurer<CustomSecurityConfigurer<H>, H>() {
|
class CustomSecurityConfigurer<H : HttpSecurityBuilder<H>> : AbstractHttpConfigurer<CustomSecurityConfigurer<H>, H>() {
|
||||||
var filter: Filter? = null
|
var filter: Filter? = null
|
||||||
override fun init(builder: H) {
|
override fun init(builder: H) {
|
||||||
@ -555,4 +582,46 @@ class HttpSecurityDslTests {
|
|||||||
builder.addFilterBefore(CustomFilter(), UsernamePasswordAuthenticationFilter::class.java)
|
builder.addFilterBefore(CustomFilter(), UsernamePasswordAuthenticationFilter::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `HTTP security when apply form login using with from custom security configurer then filter added to filter chain`() {
|
||||||
|
this.spring.register(CustomDslUsingWithConfig::class.java).autowire()
|
||||||
|
|
||||||
|
val filterChain = spring.context.getBean(FilterChainProxy::class.java)
|
||||||
|
val filterClasses: List<Class<out Filter>> = filterChain.getFilters("/").map { it.javaClass }
|
||||||
|
|
||||||
|
assertThat(filterClasses).contains(
|
||||||
|
UsernamePasswordAuthenticationFilter::class.java
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableWebMvc
|
||||||
|
open class CustomDslUsingWithConfig {
|
||||||
|
@Bean
|
||||||
|
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
http {
|
||||||
|
with(CustomDslFormLogin()) {
|
||||||
|
formLogin = true
|
||||||
|
}
|
||||||
|
httpBasic { }
|
||||||
|
}
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomDslFormLogin: AbstractHttpConfigurer<CustomDslFormLogin, HttpSecurity>() {
|
||||||
|
|
||||||
|
var formLogin = false
|
||||||
|
|
||||||
|
override fun init(builder: HttpSecurity) {
|
||||||
|
if (formLogin) {
|
||||||
|
builder.formLogin { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,11 @@ This configuration is considered after `apiFilterChain`, since it has an `@Order
|
|||||||
|
|
||||||
You can provide your own custom DSLs in Spring Security:
|
You can provide your own custom DSLs in Spring Security:
|
||||||
|
|
||||||
[source,java]
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
|
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
|
||||||
private boolean flag;
|
private boolean flag;
|
||||||
@ -260,6 +264,38 @@ public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurit
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
class MyCustomDsl : AbstractHttpConfigurer<MyCustomDsl, HttpSecurity>() {
|
||||||
|
var flag: Boolean = false
|
||||||
|
|
||||||
|
override fun init(http: HttpSecurity) {
|
||||||
|
// any method that adds another configurer
|
||||||
|
// must be done in the init method
|
||||||
|
http.csrf().disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configure(http: HttpSecurity) {
|
||||||
|
val context: ApplicationContext = http.getSharedObject(ApplicationContext::class.java)
|
||||||
|
|
||||||
|
// here we lookup from the ApplicationContext. You can also just create a new instance.
|
||||||
|
val myFilter: MyFilter = context.getBean(MyFilter::class.java)
|
||||||
|
myFilter.setFlag(flag)
|
||||||
|
http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun customDsl(): MyCustomDsl {
|
||||||
|
return MyCustomDsl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[NOTE]
|
[NOTE]
|
||||||
====
|
====
|
||||||
This is actually how methods like `HttpSecurity.authorizeRequests()` are implemented.
|
This is actually how methods like `HttpSecurity.authorizeRequests()` are implemented.
|
||||||
@ -267,7 +303,11 @@ This is actually how methods like `HttpSecurity.authorizeRequests()` are impleme
|
|||||||
|
|
||||||
You can then use the custom DSL:
|
You can then use the custom DSL:
|
||||||
|
|
||||||
[source,java]
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@ -275,15 +315,37 @@ public class Config {
|
|||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.apply(customDsl())
|
.with(MyCustomDsl.customDsl(), (dsl) -> dsl
|
||||||
.flag(true)
|
.flag(true)
|
||||||
.and()
|
)
|
||||||
...;
|
// ...
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
class Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
http
|
||||||
|
.with(MyCustomDsl.customDsl()) {
|
||||||
|
flag = true
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
The code is invoked in the following order:
|
The code is invoked in the following order:
|
||||||
|
|
||||||
* Code in the `Config.configure` method is invoked
|
* Code in the `Config.configure` method is invoked
|
||||||
@ -301,21 +363,50 @@ org.springframework.security.config.annotation.web.configurers.AbstractHttpConfi
|
|||||||
|
|
||||||
You can also explicit disable the default:
|
You can also explicit disable the default:
|
||||||
|
|
||||||
[source,java]
|
[tabs]
|
||||||
|
======
|
||||||
|
Java::
|
||||||
|
+
|
||||||
|
[source,java,role="primary"]
|
||||||
----
|
----
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class Config {
|
public class Config {
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.apply(customDsl()).disable()
|
.with(MyCustomDsl.customDsl(), (dsl) -> dsl
|
||||||
|
.disable()
|
||||||
|
)
|
||||||
...;
|
...;
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Kotlin::
|
||||||
|
+
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
class Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
http
|
||||||
|
.with(MyCustomDsl.customDsl()) {
|
||||||
|
disable()
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
----
|
||||||
|
======
|
||||||
|
|
||||||
[[post-processing-configured-objects]]
|
[[post-processing-configured-objects]]
|
||||||
== Post Processing Configured Objects
|
== Post Processing Configured Objects
|
||||||
|
|
||||||
|
@ -7,3 +7,4 @@ Below are the highlights of the release.
|
|||||||
== Configuration
|
== Configuration
|
||||||
|
|
||||||
* https://github.com/spring-projects/spring-security/issues/5011[gh-5011] - xref:servlet/integrations/cors.adoc[(docs)] Automatically enable `.cors()` if `CorsConfigurationSource` bean is present
|
* https://github.com/spring-projects/spring-security/issues/5011[gh-5011] - xref:servlet/integrations/cors.adoc[(docs)] Automatically enable `.cors()` if `CorsConfigurationSource` bean is present
|
||||||
|
* https://github.com/spring-projects/spring-security/issues/13204[gh-13204] - xref:servlet/integrations/cors.adoc[(docs)] Add `AbstractConfiguredSecurityBuilder.with(...)` method to apply configurers returning the builder
|
||||||
|
Loading…
x
Reference in New Issue
Block a user