Add Modular Spring Security Configuration
Closes gh-16258
This commit is contained in:
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.reactive.configuration.customizerbeanordering;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebFlux
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class CustomizerBeanOrderingConfiguration {
|
||||
|
||||
// tag::sample[]
|
||||
@Bean // <4>
|
||||
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeExchange((exchange) -> exchange
|
||||
.anyExchange().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE) // <2>
|
||||
Customizer<ServerHttpSecurity> userAuthorization() {
|
||||
// @formatter:off
|
||||
return (http) -> http
|
||||
.authorizeExchange((exchange) -> exchange
|
||||
.pathMatchers("/users/**").hasRole("USER")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE) // <1>
|
||||
Customizer<ServerHttpSecurity> adminAuthorization() {
|
||||
// @formatter:off
|
||||
return (http) -> http
|
||||
.authorizeExchange((exchange) -> exchange
|
||||
.pathMatchers("/admins/**").hasRole("ADMIN")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// <3>
|
||||
|
||||
@Bean
|
||||
Customizer<ServerHttpSecurity.HeaderSpec> contentSecurityPolicy() {
|
||||
// @formatter:off
|
||||
return (headers) -> headers
|
||||
.contentSecurityPolicy((csp) -> csp
|
||||
.policyDirectives("object-src 'none'")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
Customizer<ServerHttpSecurity.HeaderSpec> contentTypeOptions() {
|
||||
// @formatter:off
|
||||
return (headers) -> headers
|
||||
.contentTypeOptions(Customizer.withDefaults());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
Customizer<ServerHttpSecurity.HttpsRedirectSpec> httpsRedirect() {
|
||||
// @formatter:off
|
||||
return Customizer.withDefaults();
|
||||
// @formatter:on
|
||||
}
|
||||
// end::sample[]
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.reactive.configuration.customizerbeanordering;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class CustomizerBeanOrderingTests {
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webTest;
|
||||
|
||||
@Test
|
||||
void authorizationOrdered() throws Exception {
|
||||
this.spring.register(
|
||||
CustomizerBeanOrderingConfiguration.class).autowire();
|
||||
// @formatter:off
|
||||
this.webTest.mutateWith(mockUser("admin").roles("ADMIN"))
|
||||
.get()
|
||||
.uri("https://localhost/admins/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
this.webTest.mutateWith(mockUser("user").roles("USER"))
|
||||
.get()
|
||||
.uri("https://localhost/admins/1")
|
||||
.exchange()
|
||||
.expectStatus().isForbidden();
|
||||
this.webTest.mutateWith(mockUser("user").roles("USER"))
|
||||
.get()
|
||||
.uri("https://localhost/users/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
this.webTest.mutateWith(mockUser("user").roles("OTHER"))
|
||||
.get()
|
||||
.uri("https://localhost/users/1")
|
||||
.exchange()
|
||||
.expectStatus().isForbidden();
|
||||
this.webTest.mutateWith(mockUser("authenticated").roles("OTHER"))
|
||||
.get()
|
||||
.uri("https://localhost/other")
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.reactive.configuration.serverhttpsecuritycustomizerbean;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class ServerHttpSecurityCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeExchange((exchange) -> exchange
|
||||
.anyExchange().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// tag::httpSecurityCustomizer[]
|
||||
@Bean
|
||||
Customizer<ServerHttpSecurity> httpSecurityCustomizer() {
|
||||
// @formatter:off
|
||||
return (http) -> http
|
||||
.headers((headers) -> headers
|
||||
.contentSecurityPolicy((csp) -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
)
|
||||
)
|
||||
// <2>
|
||||
.redirectToHttps(Customizer.withDefaults());
|
||||
// @formatter:on
|
||||
}
|
||||
// end::httpSecurityCustomizer[]
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.reactive.configuration.serverhttpsecuritycustomizerbean;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class ServerHttpSecurityCustomizerBeanTests {
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webTest;
|
||||
|
||||
@Test
|
||||
void httpSecurityCustomizer() throws Exception {
|
||||
this.spring.register(
|
||||
ServerHttpSecurityCustomizerBeanConfiguration.class).autowire();
|
||||
// @formatter:off
|
||||
this.webTest
|
||||
.get()
|
||||
.uri("http://localhost/")
|
||||
.exchange()
|
||||
.expectHeader().location("https://localhost/")
|
||||
.expectHeader()
|
||||
.value("Content-Security-Policy", csp ->
|
||||
assertThat(csp).isEqualTo("object-src 'none'")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.reactive.configuration.toplevelcustomizerbean;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class TopLevelCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeExchange((exchange) -> exchange
|
||||
.anyExchange().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// tag::headersCustomizer[]
|
||||
@Bean
|
||||
Customizer<ServerHttpSecurity.HeaderSpec> headersSecurity() {
|
||||
// @formatter:off
|
||||
return (headers) -> headers
|
||||
.contentSecurityPolicy((csp) -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
// end::headersCustomizer[]
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.reactive.configuration.toplevelcustomizerbean;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class TopLevelCustomizerBeanTests {
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private WebTestClient webTest;
|
||||
|
||||
|
||||
@Test
|
||||
void headersCustomizer() throws Exception {
|
||||
this.spring.register(TopLevelCustomizerBeanConfiguration.class).autowire();
|
||||
// @formatter:off
|
||||
this.webTest
|
||||
.get()
|
||||
.uri("http://localhost/")
|
||||
.exchange()
|
||||
.expectHeader()
|
||||
.value("Content-Security-Policy", csp ->
|
||||
assertThat(csp).isEqualTo("object-src 'none'")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static @NotNull ResultMatcher cspIsObjectSrcNone() {
|
||||
return header().string("Content-Security-Policy", "object-src 'none'");
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.configuration.customizerbeanordering;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ThrowingCustomizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HttpsRedirectConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class CustomizerBeanOrderingConfiguration {
|
||||
|
||||
// tag::sample[]
|
||||
@Bean // <4>
|
||||
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE) // <2>
|
||||
ThrowingCustomizer<HttpSecurity> userAuthorization() {
|
||||
// @formatter:off
|
||||
return (http) -> http
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.requestMatchers("/users/**").hasRole("USER")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE) // <1>
|
||||
ThrowingCustomizer<HttpSecurity> adminAuthorization() {
|
||||
// @formatter:off
|
||||
return (http) -> http
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.requestMatchers("/admins/**").hasRole("ADMIN")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// <3>
|
||||
|
||||
@Bean
|
||||
Customizer<HeadersConfigurer<HttpSecurity>> contentSecurityPolicy() {
|
||||
// @formatter:off
|
||||
return (headers) -> headers
|
||||
.contentSecurityPolicy((csp) -> csp
|
||||
.policyDirectives("object-src 'none'")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
Customizer<HeadersConfigurer<HttpSecurity>> contentTypeOptions() {
|
||||
// @formatter:off
|
||||
return (headers) -> headers
|
||||
.contentTypeOptions(Customizer.withDefaults());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
Customizer<HttpsRedirectConfigurer<HttpSecurity>> httpsRedirect() {
|
||||
// @formatter:off
|
||||
return Customizer.withDefaults();
|
||||
// @formatter:on
|
||||
}
|
||||
// end::sample[]
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.configuration.customizerbeanordering;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class CustomizerBeanOrderingTests {
|
||||
public final SpringTestContext spring = new SpringTestContext(this).mockMvcAfterSpringSecurityOk();
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
void authorizationOrdered() throws Exception {
|
||||
this.spring.register(
|
||||
CustomizerBeanOrderingConfiguration.class).autowire();
|
||||
// @formatter:off
|
||||
this.mockMvc
|
||||
.perform(get("https://localhost/admins/1").with(user("admin").roles("ADMIN")))
|
||||
.andExpect(status().isOk());
|
||||
this.mockMvc
|
||||
.perform(get("https://localhost/admins/1").with(user("user").roles("USER")))
|
||||
.andExpect(status().isForbidden());
|
||||
this.mockMvc
|
||||
.perform(get("https://localhost/users/1").with(user("user").roles("USER")))
|
||||
.andExpect(status().isOk());
|
||||
this.mockMvc
|
||||
.perform(get("https://localhost/users/1").with(user("user").roles("OTHER")))
|
||||
.andExpect(status().isForbidden());
|
||||
this.mockMvc
|
||||
.perform(get("https://localhost/other").with(user("authenticated").roles("OTHER")))
|
||||
.andExpect(status().isOk());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.configuration.httpsecuritycustomizerbean;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ThrowingCustomizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class HttpSecurityCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// tag::httpSecurityCustomizer[]
|
||||
@Bean
|
||||
ThrowingCustomizer<HttpSecurity> httpSecurityCustomizer() {
|
||||
// @formatter:off
|
||||
return (http) -> http
|
||||
.headers((headers) -> headers
|
||||
.contentSecurityPolicy((csp) -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
)
|
||||
)
|
||||
// <2>
|
||||
.redirectToHttps(Customizer.withDefaults());
|
||||
// @formatter:on
|
||||
}
|
||||
// end::httpSecurityCustomizer[]
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.configuration.httpsecuritycustomizerbean;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ThrowingCustomizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class HttpSecurityCustomizerBeanTests {
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
void httpSecurityCustomizer() throws Exception {
|
||||
this.spring.register(HttpSecurityCustomizerBeanConfiguration.class).autowire();
|
||||
// @formatter:off
|
||||
this.mockMvc
|
||||
.perform(get("/"))
|
||||
.andExpect(redirectsToHttps());
|
||||
// headers are not sent back as a part of the redirect to https, so a separate request is necessary
|
||||
this.mockMvc.perform(get("https://localhost/"))
|
||||
.andExpect(cspIsObjectSrcNone());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static @NotNull ResultMatcher redirectsToHttps() {
|
||||
return mvcResult -> assertThat(
|
||||
mvcResult.getResponse().getRedirectedUrl()).startsWith("https://");
|
||||
}
|
||||
|
||||
private static @NotNull ResultMatcher cspIsObjectSrcNone() {
|
||||
return header().string("Content-Security-Policy", "object-src 'none'");
|
||||
}
|
||||
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.configuration.toplevelcustomizerbean;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ThrowingCustomizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class TopLevelCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// tag::headersCustomizer[]
|
||||
@Bean
|
||||
Customizer<HeadersConfigurer<HttpSecurity>> headersSecurity() {
|
||||
// @formatter:off
|
||||
return (headers) -> headers
|
||||
.contentSecurityPolicy((csp) -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
// end::headersCustomizer[]
|
||||
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.docs.servlet.configuration.toplevelcustomizerbean;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.ThrowingCustomizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.test.SpringTestContext;
|
||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class TopLevelCustomizerBeanTests {
|
||||
public final SpringTestContext spring = new SpringTestContext(this);
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
|
||||
@Test
|
||||
void headersCustomizer() throws Exception {
|
||||
this.spring.register(TopLevelCustomizerBeanConfiguration.class).autowire();
|
||||
// @formatter:off
|
||||
this.mockMvc
|
||||
.perform(get("/"))
|
||||
.andExpect(cspIsObjectSrcNone());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static @NotNull ResultMatcher cspIsObjectSrcNone() {
|
||||
return header().string("Content-Security-Policy", "object-src 'none'");
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
|
||||
package org.springframework.security.kt.docs.reactive.configuration.customizerbeanordering
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.annotation.Order
|
||||
import org.springframework.security.config.Customizer
|
||||
import org.springframework.security.config.ThrowingCustomizer
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.config.annotation.web.configurers.HttpsRedirectConfigurer
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.anyExchange
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
internal class CustomizerBeanOrderingConfiguration {
|
||||
// tag::sample[]
|
||||
@Bean // <4>
|
||||
fun springSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeExchange({ exchanges -> exchanges
|
||||
.anyExchange().authenticated()
|
||||
})
|
||||
return http.build()
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE) // <2>
|
||||
fun userAuthorization(): Customizer<ServerHttpSecurity> {
|
||||
// @formatter:off
|
||||
return Customizer { http -> http
|
||||
.authorizeExchange { exchanges -> exchanges
|
||||
.pathMatchers("/users/**").hasRole("USER")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE) // <1>
|
||||
fun adminAuthorization(): Customizer<ServerHttpSecurity> {
|
||||
// @formatter:off
|
||||
return ThrowingCustomizer { http -> http
|
||||
.authorizeExchange { exchanges -> exchanges
|
||||
.pathMatchers("/admins/**").hasRole("ADMIN")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// <3>
|
||||
|
||||
@Bean
|
||||
fun contentSecurityPolicy(): Customizer<ServerHttpSecurity.HeaderSpec> {
|
||||
// @formatter:off
|
||||
return Customizer { headers -> headers
|
||||
.contentSecurityPolicy { csp -> csp
|
||||
.policyDirectives("object-src 'none'")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun contentTypeOptions(): Customizer<ServerHttpSecurity.HeaderSpec> {
|
||||
// @formatter:off
|
||||
return Customizer { headers -> headers
|
||||
.contentTypeOptions(Customizer.withDefaults())
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun httpsRedirect(): Customizer<ServerHttpSecurity.HttpsRedirectSpec> {
|
||||
// @formatter:off
|
||||
return Customizer.withDefaults()
|
||||
// @formatter:on
|
||||
}
|
||||
// end::sample[]
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.reactive.configuration.customizerbeanordering
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class CustomizerBeanOrderingTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var webTest: WebTestClient
|
||||
|
||||
@Test
|
||||
fun authorizationOrdered() {
|
||||
this.spring.register(CustomizerBeanOrderingConfiguration::class.java).autowire()
|
||||
// @formatter:off
|
||||
this.webTest.mutateWith(mockUser("admin").roles("ADMIN"))
|
||||
.get()
|
||||
.uri("https://localhost/admins/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
this.webTest.mutateWith(mockUser("user").roles("USER"))
|
||||
.get()
|
||||
.uri("https://localhost/admins/1")
|
||||
.exchange()
|
||||
.expectStatus().isForbidden
|
||||
this.webTest.mutateWith(mockUser("user").roles("USER"))
|
||||
.get()
|
||||
.uri("https://localhost/users/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
this.webTest.mutateWith(mockUser("user").roles("OTHER"))
|
||||
.get()
|
||||
.uri("https://localhost/users/1")
|
||||
.exchange()
|
||||
.expectStatus().isForbidden
|
||||
this.webTest.mutateWith(mockUser("other").roles("OTHER"))
|
||||
.get()
|
||||
.uri("https://localhost/other")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.reactive.configuration.dslbeanordering
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.annotation.Order
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.*
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
internal class DslBeanOrderingConfiguration {
|
||||
// tag::sample[]
|
||||
// All of the Java Modular Configuration is applied first <1>
|
||||
|
||||
@Bean // <5>
|
||||
fun springSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
// @formatter:off
|
||||
return http {
|
||||
authorizeExchange {
|
||||
authorize(anyExchange, authenticated)
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE) // <3>
|
||||
fun userAuthorization(): ServerHttpSecurityDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
authorizeExchange {
|
||||
authorize("/users/**", hasRole("USER"))
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE) // <2>
|
||||
fun adminAuthorization(): ServerHttpSecurityDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
authorizeExchange {
|
||||
authorize("/admins/**", hasRole("ADMIN"))
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// <4>
|
||||
|
||||
@Bean
|
||||
fun contentSecurityPolicy(): ServerHeadersDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
contentSecurityPolicy {
|
||||
policyDirectives = "object-src 'none'"
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun contentTypeOptions(): ServerHeadersDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
contentTypeOptions { }
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun httpsRedirect(): ServerHttpsRedirectDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return { }
|
||||
// @formatter:on
|
||||
}
|
||||
// end::sample[]
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.reactive.configuration.dslbeanordering
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.kt.docs.servlet.configuration.customizerbeanordering.CustomizerBeanOrderingConfiguration
|
||||
import org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.mockUser
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class DslBeanOrderingTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this).mockMvcAfterSpringSecurityOk()
|
||||
|
||||
@Autowired
|
||||
lateinit var webTest: WebTestClient
|
||||
|
||||
@Test
|
||||
fun dslOrdered() {
|
||||
this.spring.register(org.springframework.security.kt.docs.reactive.configuration.customizerbeanordering.CustomizerBeanOrderingConfiguration::class.java).autowire()
|
||||
// @formatter:off
|
||||
this.webTest.mutateWith(mockUser("admin").roles("ADMIN"))
|
||||
.get()
|
||||
.uri("https://localhost/admins/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
this.webTest.mutateWith(mockUser("user").roles("USER"))
|
||||
.get()
|
||||
.uri("https://localhost/admins/1")
|
||||
.exchange()
|
||||
.expectStatus().isForbidden
|
||||
this.webTest.mutateWith(mockUser("user").roles("USER"))
|
||||
.get()
|
||||
.uri("https://localhost/users/1")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
this.webTest.mutateWith(mockUser("user").roles("OTHER"))
|
||||
.get()
|
||||
.uri("https://localhost/users/1")
|
||||
.exchange()
|
||||
.expectStatus().isForbidden
|
||||
this.webTest.mutateWith(mockUser("other").roles("OTHER"))
|
||||
.get()
|
||||
.uri("https://localhost/other")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.serverhttpsecuritycustomizerbean
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.Customizer
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class ServerHttpSecurityCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeExchange({ exchanges -> exchanges
|
||||
.anyExchange().authenticated()
|
||||
})
|
||||
return http.build()
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
// tag::httpSecurityCustomizer[]
|
||||
@Bean
|
||||
fun httpSecurityCustomizer(): Customizer<ServerHttpSecurity> {
|
||||
// @formatter:off
|
||||
return Customizer { http -> http
|
||||
.headers { headers -> headers
|
||||
.contentSecurityPolicy { csp -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
}
|
||||
}
|
||||
// <2>
|
||||
.redirectToHttps(Customizer.withDefaults())
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
// end::httpSecurityCustomizer[]
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.serverhttpsecuritycustomizerbean
|
||||
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import java.util.function.Consumer
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class ServerHttpSecurityCustomizerBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var webTest: WebTestClient
|
||||
|
||||
@Test
|
||||
fun `serverhttpsecurity customizer config`() {
|
||||
this.spring.register(ServerHttpSecurityCustomizerBeanConfiguration::class.java).autowire()
|
||||
// @formatter:off
|
||||
this.webTest
|
||||
.get()
|
||||
.uri("http://localhost/")
|
||||
.exchange()
|
||||
.expectHeader().location("https://localhost/")
|
||||
.expectHeader()
|
||||
.value("Content-Security-Policy", Consumer { csp ->
|
||||
assertThat(csp).isEqualTo("object-src 'none'")
|
||||
})
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.serverhttpsecuritydslbean
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurityDsl
|
||||
import org.springframework.security.config.web.server.invoke
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class ServerHttpSecurityDslBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
return http {
|
||||
authorizeExchange {
|
||||
authorize(anyExchange, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tag::httpSecurityDslBean[]
|
||||
@Bean
|
||||
fun httpSecurityDslBean(): ServerHttpSecurityDsl.() -> Unit {
|
||||
return {
|
||||
headers {
|
||||
contentSecurityPolicy {
|
||||
// <1>
|
||||
policyDirectives = "object-src 'none'"
|
||||
}
|
||||
}
|
||||
// <2>
|
||||
redirectToHttps { }
|
||||
}
|
||||
}
|
||||
// end::httpSecurityDslBean[]
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.serverhttpsecuritydslbean
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import java.util.function.Consumer
|
||||
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class ServerHttpSecurityDslBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var webTest: WebTestClient
|
||||
|
||||
@Test
|
||||
fun `ServerHttpSecurityDslBean`() {
|
||||
this.spring.register(ServerHttpSecurityDslBeanConfiguration::class.java).autowire()
|
||||
|
||||
// @formatter:off
|
||||
this.webTest
|
||||
.get()
|
||||
.uri("http://localhost/")
|
||||
.exchange()
|
||||
.expectHeader().location("https://localhost/")
|
||||
.expectHeader().value("Content-Security-Policy", Consumer { csp ->
|
||||
assertThat(csp).isEqualTo("object-src 'none'")
|
||||
})
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.toplevelcustomizerbean
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.Customizer
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class TopLevelCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeExchange({ exchanges -> exchanges
|
||||
.anyExchange().authenticated()
|
||||
})
|
||||
return http.build()
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// tag::headersCustomizer[]
|
||||
@Bean
|
||||
fun headersSecurity(): Customizer<ServerHttpSecurity.HeaderSpec> {
|
||||
// @formatter:off
|
||||
return Customizer { headers -> headers
|
||||
.contentSecurityPolicy { csp -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
// end::headersCustomizer[]
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.toplevelcustomizerbean
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import java.util.function.Consumer
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class TopLevelCustomizerBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var webTest: WebTestClient
|
||||
|
||||
@Test
|
||||
fun `top level dsl bean`() {
|
||||
this.spring.register(TopLevelCustomizerBeanConfiguration::class.java).autowire()
|
||||
|
||||
// @formatter:off
|
||||
this.webTest
|
||||
.get()
|
||||
.uri("http://localhost/")
|
||||
.exchange()
|
||||
.expectHeader().value("Content-Security-Policy", Consumer { csp ->
|
||||
assertThat(csp).isEqualTo("object-src 'none'")
|
||||
})
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.topleveldslbean
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.web.server.ServerHeadersDsl
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity
|
||||
import org.springframework.security.config.web.server.invoke
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class TopLevelDslBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
return http {
|
||||
authorizeExchange {
|
||||
authorize(anyExchange, authenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tag::headersSecurity[]
|
||||
@Bean
|
||||
fun headersSecurity(): ServerHeadersDsl.() -> Unit {
|
||||
return {
|
||||
contentSecurityPolicy {
|
||||
// <1>
|
||||
policyDirectives = "object-src 'none'"
|
||||
}
|
||||
}
|
||||
}
|
||||
// end::headersSecurity[]
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.springframework.security.kt.docs.reactive.configuration.topleveldslbean
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import java.util.function.Consumer
|
||||
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class TopLevelDslBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var webTest: WebTestClient
|
||||
|
||||
@Test
|
||||
fun `HttpSecurityDslBean`() {
|
||||
this.spring.register(TopLevelDslBeanConfiguration::class.java).autowire()
|
||||
|
||||
// @formatter:off
|
||||
this.webTest
|
||||
.get()
|
||||
.uri("http://localhost/")
|
||||
.exchange()
|
||||
.expectHeader().value("Content-Security-Policy", Consumer { csp ->
|
||||
assertThat(csp).isEqualTo("object-src 'none'")
|
||||
})
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.configuration.customizerbeanordering
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.annotation.Order
|
||||
import org.springframework.security.config.Customizer
|
||||
import org.springframework.security.config.ThrowingCustomizer
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer.AuthorizationManagerRequestMatcherRegistry
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.config.annotation.web.configurers.HttpsRedirectConfigurer
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
internal class CustomizerBeanOrderingConfiguration {
|
||||
// tag::sample[]
|
||||
@Bean // <4>
|
||||
fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests({ requests -> requests
|
||||
.anyRequest().authenticated()
|
||||
})
|
||||
return http.build()
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE) // <2>
|
||||
fun userAuthorization(): ThrowingCustomizer<HttpSecurity> {
|
||||
// @formatter:off
|
||||
return ThrowingCustomizer { http -> http
|
||||
.authorizeHttpRequests { requests -> requests
|
||||
.requestMatchers("/users/**").hasRole("USER")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE) // <1>
|
||||
fun adminAuthorization(): ThrowingCustomizer<HttpSecurity> {
|
||||
// @formatter:off
|
||||
return ThrowingCustomizer { http -> http
|
||||
.authorizeHttpRequests { requests -> requests
|
||||
.requestMatchers("/admins/**").hasRole("ADMIN")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// <3>
|
||||
|
||||
@Bean
|
||||
fun contentSecurityPolicy(): Customizer<HeadersConfigurer<HttpSecurity>> {
|
||||
// @formatter:off
|
||||
return Customizer { headers -> headers
|
||||
.contentSecurityPolicy { csp -> csp
|
||||
.policyDirectives("object-src 'none'")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun contentTypeOptions(): Customizer<HeadersConfigurer<HttpSecurity>> {
|
||||
// @formatter:off
|
||||
return Customizer { headers -> headers
|
||||
.contentTypeOptions(Customizer.withDefaults())
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun httpsRedirect(): Customizer<HttpsRedirectConfigurer<HttpSecurity>> {
|
||||
// @formatter:off
|
||||
return Customizer.withDefaults<HttpsRedirectConfigurer<HttpSecurity>>()
|
||||
// @formatter:on
|
||||
}
|
||||
// end::sample[]
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.configuration.customizerbeanordering
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class CustomizerBeanOrderingTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this).mockMvcAfterSpringSecurityOk()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun authorizationOrdered() {
|
||||
this.spring.register(CustomizerBeanOrderingConfiguration::class.java).autowire()
|
||||
// @formatter:off
|
||||
this.mockMvc.get("https://localhost/admins/1") {
|
||||
with(user("admin").roles("ADMIN"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/admins/1") {
|
||||
with(user("user").roles("USER"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/users/1") {
|
||||
with(user("user").roles("USER"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/users/1") {
|
||||
with(user("noUserRole").roles("OTHER"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/other") {
|
||||
with(user("authenticated").roles("OTHER"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.configuration.dslbeanordering
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.Ordered
|
||||
import org.springframework.core.annotation.Order
|
||||
import org.springframework.security.config.Customizer
|
||||
import org.springframework.security.config.ThrowingCustomizer
|
||||
import org.springframework.security.config.annotation.web.HeadersDsl
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityDsl
|
||||
import org.springframework.security.config.annotation.web.HttpsRedirectDsl
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.config.annotation.web.configurers.HttpsRedirectConfigurer
|
||||
import org.springframework.security.config.annotation.web.invoke
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
internal class DslBeanOrderingConfiguration {
|
||||
// tag::sample[]
|
||||
// All of the Java Modular Configuration is applied first <1>
|
||||
|
||||
@Bean // <5>
|
||||
fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE) // <3>
|
||||
fun userAuthorization(): HttpSecurityDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
authorizeHttpRequests {
|
||||
authorize("/users/**", hasRole("USER"))
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE) // <2>
|
||||
fun adminAuthorization(): HttpSecurityDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
authorizeHttpRequests {
|
||||
authorize("/admins/**", hasRole("ADMIN"))
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// <4>
|
||||
|
||||
@Bean
|
||||
fun contentSecurityPolicy(): HeadersDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
contentSecurityPolicy {
|
||||
policyDirectives = "object-src 'none'"
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun contentTypeOptions(): HeadersDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return {
|
||||
contentTypeOptions { }
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun httpsRedirect(): HttpsRedirectDsl.() -> Unit {
|
||||
// @formatter:off
|
||||
return { }
|
||||
// @formatter:on
|
||||
}
|
||||
// end::sample[]
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
*/
|
||||
package org.springframework.security.kt.docs.servlet.configuration.dslbeanordering
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.kt.docs.servlet.configuration.customizerbeanordering.CustomizerBeanOrderingConfiguration
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class DslBeanOrderingTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this).mockMvcAfterSpringSecurityOk()
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun dslOrdered() {
|
||||
this.spring.register(DslBeanOrderingConfiguration::class.java).autowire()
|
||||
// @formatter:off
|
||||
this.mockMvc.get("https://localhost/admins/1") {
|
||||
with(user("admin").roles("ADMIN"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/admins/1") {
|
||||
with(user("user").roles("USER"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/users/1") {
|
||||
with(user("user").roles("USER"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/users/1") {
|
||||
with(user("noUserRole").roles("OTHER"))
|
||||
}.andExpect {
|
||||
status { isForbidden() }
|
||||
}
|
||||
this.mockMvc.get("https://localhost/other") {
|
||||
with(user("authenticated").roles("OTHER"))
|
||||
}.andExpect {
|
||||
status { isOk() }
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.httpsecuritycustomizerbean
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.Customizer
|
||||
import org.springframework.security.config.ThrowingCustomizer
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.config.annotation.web.invoke
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class HttpSecurityCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
|
||||
// tag::httpSecurityCustomizer[]
|
||||
@Bean
|
||||
fun httpSecurityCustomizer(): ThrowingCustomizer<HttpSecurity> {
|
||||
// @formatter:off
|
||||
return ThrowingCustomizer { http -> http
|
||||
.headers { headers -> headers
|
||||
.contentSecurityPolicy { csp -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
}
|
||||
}
|
||||
// <2>
|
||||
.redirectToHttps(Customizer.withDefaults())
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
// end::httpSecurityCustomizer[]
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.httpsecuritycustomizerbean
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class HttpSecurityCustomizerBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `httpsecurity customizer config`() {
|
||||
this.spring.register(HttpSecurityCustomizerBeanConfiguration::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
redirectedUrl("https://localhost/")
|
||||
}
|
||||
this.mockMvc.get("https://localhost/")
|
||||
.andExpect {
|
||||
header {
|
||||
string("Content-Security-Policy", "object-src 'none'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.httpsecuritydslbean
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.HeadersDsl
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityDsl
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.invoke
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class HttpSecurityDslBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
// tag::httpSecurityDslBean[]
|
||||
@Bean
|
||||
fun httpSecurityDslBean(): HttpSecurityDsl.() -> Unit {
|
||||
return {
|
||||
headers {
|
||||
contentSecurityPolicy {
|
||||
// <1>
|
||||
policyDirectives = "object-src 'none'"
|
||||
}
|
||||
}
|
||||
// <2>
|
||||
redirectToHttps { }
|
||||
}
|
||||
}
|
||||
// end::httpSecurityDslBean[]
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.httpsecuritydslbean
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class HttpSecurityDslBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `HttpSecurityDslBean`() {
|
||||
this.spring.register(HttpSecurityDslBeanConfiguration::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
redirectedUrl("https://localhost/")
|
||||
}
|
||||
|
||||
this.mockMvc.get("https://localhost/")
|
||||
.andExpect {
|
||||
header {
|
||||
string("Content-Security-Policy", "object-src 'none'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.toplevelcustomizerbean
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.Customizer
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
import org.springframework.security.config.annotation.web.invoke
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class TopLevelCustomizerBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
// tag::headersCustomizer[]
|
||||
@Bean
|
||||
fun headersSecurity(): Customizer<HeadersConfigurer<HttpSecurity>> {
|
||||
// @formatter:off
|
||||
return Customizer { headers -> headers
|
||||
.contentSecurityPolicy { csp -> csp
|
||||
// <1>
|
||||
.policyDirectives("object-src 'none'")
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
// end::headersCustomizer[]
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.toplevelcustomizerbean
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class TopLevelCustomizerBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `top level dsl bean`() {
|
||||
this.spring.register(TopLevelCustomizerBeanConfiguration::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header {
|
||||
string("Content-Security-Policy", "object-src 'none'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.topleveldslbean
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.web.HeadersDsl
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityDsl
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.config.annotation.web.invoke
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
|
||||
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class TopLevelDslBeanConfiguration {
|
||||
|
||||
@Bean
|
||||
fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
|
||||
// tag::headersSecurity[]
|
||||
@Bean
|
||||
fun headersSecurity(): HeadersDsl.() -> Unit {
|
||||
return {
|
||||
contentSecurityPolicy {
|
||||
// <1>
|
||||
policyDirectives = "object-src 'none'"
|
||||
}
|
||||
}
|
||||
}
|
||||
// end::headersSecurity[]
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package org.springframework.security.kt.docs.servlet.configuration.topleveldslbean
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.security.config.test.SpringTestContext
|
||||
import org.springframework.security.config.test.SpringTestContextExtension
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
|
||||
|
||||
@ExtendWith(SpringTestContextExtension::class)
|
||||
class TopLevelDslBeanTests {
|
||||
@JvmField
|
||||
val spring = SpringTestContext(this)
|
||||
|
||||
@Autowired
|
||||
lateinit var mockMvc: MockMvc
|
||||
|
||||
@Test
|
||||
fun `HttpSecurityDslBean`() {
|
||||
this.spring.register(TopLevelDslBeanConfiguration::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header {
|
||||
string("Content-Security-Policy", "object-src 'none'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user