49 changed files with 3207 additions and 0 deletions
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* 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.config; |
||||||
|
|
||||||
|
/** |
||||||
|
* A {@link Customizer} that allows invocation of code that throws a checked exception. |
||||||
|
* |
||||||
|
* @param <T> The type of input. |
||||||
|
*/ |
||||||
|
@FunctionalInterface |
||||||
|
public interface ThrowingCustomizer<T> extends Customizer<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Default {@link Customizer#customize(Object)} that wraps any thrown checked |
||||||
|
* exceptions (by default in a {@link RuntimeException}). |
||||||
|
* @param t the object to customize |
||||||
|
*/ |
||||||
|
default void customize(T t) { |
||||||
|
try { |
||||||
|
customizeWithException(t); |
||||||
|
} |
||||||
|
catch (RuntimeException ex) { |
||||||
|
throw ex; |
||||||
|
} |
||||||
|
catch (Exception ex) { |
||||||
|
throw new RuntimeException(ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs the customization on the given object, possibly throwing a checked |
||||||
|
* exception. |
||||||
|
* @param t the object to customize |
||||||
|
* @throws Exception on error |
||||||
|
*/ |
||||||
|
void customizeWithException(T t) throws Exception; |
||||||
|
|
||||||
|
} |
||||||
@ -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[]
|
||||||
|
|
||||||
|
} |
||||||
@ -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
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[]
|
||||||
|
|
||||||
|
} |
||||||
@ -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
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[]
|
||||||
|
|
||||||
|
} |
||||||
@ -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'"); |
||||||
|
} |
||||||
|
} |
||||||
@ -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[]
|
||||||
|
|
||||||
|
} |
||||||
@ -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
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[]
|
||||||
|
|
||||||
|
} |
||||||
@ -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'"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[]
|
||||||
|
|
||||||
|
} |
||||||
@ -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'"); |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
|
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[] |
||||||
|
|
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
|
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[] |
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
|
||||||
|
} |
||||||
@ -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'") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[] |
||||||
|
|
||||||
|
} |
||||||
@ -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'") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -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[] |
||||||
|
|
||||||
|
} |
||||||
@ -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'") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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[] |
||||||
|
} |
||||||
@ -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'") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue