mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-24 13:02:13 +00:00
Add redirectToHttps DSL Configurer
Closes gh-16679
This commit is contained in:
parent
2d96fba5cf
commit
be23268c37
@ -54,6 +54,7 @@ import org.springframework.security.web.session.ConcurrentSessionFilter;
|
|||||||
import org.springframework.security.web.session.DisableEncodeUrlFilter;
|
import org.springframework.security.web.session.DisableEncodeUrlFilter;
|
||||||
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;
|
||||||
import org.springframework.security.web.session.SessionManagementFilter;
|
import org.springframework.security.web.session.SessionManagementFilter;
|
||||||
|
import org.springframework.security.web.transport.HttpsRedirectFilter;
|
||||||
import org.springframework.web.filter.CorsFilter;
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,6 +79,7 @@ final class FilterOrderRegistration {
|
|||||||
put(DisableEncodeUrlFilter.class, order.next());
|
put(DisableEncodeUrlFilter.class, order.next());
|
||||||
put(ForceEagerSessionCreationFilter.class, order.next());
|
put(ForceEagerSessionCreationFilter.class, order.next());
|
||||||
put(ChannelProcessingFilter.class, order.next());
|
put(ChannelProcessingFilter.class, order.next());
|
||||||
|
put(HttpsRedirectFilter.class, order.next());
|
||||||
order.next(); // gh-8105
|
order.next(); // gh-8105
|
||||||
put(WebAsyncManagerIntegrationFilter.class, order.next());
|
put(WebAsyncManagerIntegrationFilter.class, order.next());
|
||||||
put(SecurityContextHolderFilter.class, order.next());
|
put(SecurityContextHolderFilter.class, order.next());
|
||||||
|
@ -59,6 +59,7 @@ import org.springframework.security.config.annotation.web.configurers.Expression
|
|||||||
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.HttpsRedirectConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.JeeConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.JeeConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
||||||
import org.springframework.security.config.annotation.web.configurers.PasswordManagementConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.PasswordManagementConfigurer;
|
||||||
@ -3145,6 +3146,53 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
|||||||
return HttpSecurity.this;
|
return HttpSecurity.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures channel security. In order for this configuration to be useful at least
|
||||||
|
* one mapping to a required channel must be provided.
|
||||||
|
*
|
||||||
|
* <h2>Example Configuration</h2>
|
||||||
|
*
|
||||||
|
* The example below demonstrates how to require HTTPS for every request. Only
|
||||||
|
* requiring HTTPS for some requests is supported, for example if you need to
|
||||||
|
* differentiate between local and production deployments.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* @Configuration
|
||||||
|
* @EnableWebSecurity
|
||||||
|
* public class RequireHttpsConfig {
|
||||||
|
*
|
||||||
|
* @Bean
|
||||||
|
* public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
* http
|
||||||
|
* .authorizeHttpRequests((authorize) -> authorize
|
||||||
|
* anyRequest().authenticated()
|
||||||
|
* )
|
||||||
|
* .formLogin(withDefaults())
|
||||||
|
* .redirectToHttps(withDefaults());
|
||||||
|
* return http.build();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Bean
|
||||||
|
* public UserDetailsService userDetailsService() {
|
||||||
|
* UserDetails user = User.withDefaultPasswordEncoder()
|
||||||
|
* .username("user")
|
||||||
|
* .password("password")
|
||||||
|
* .roles("USER")
|
||||||
|
* .build();
|
||||||
|
* return new InMemoryUserDetailsManager(user);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
* @param httpsRedirectConfigurerCustomizer the {@link Customizer} to provide more
|
||||||
|
* options for the {@link HttpsRedirectConfigurer}
|
||||||
|
* @return the {@link HttpSecurity} for further customizations
|
||||||
|
*/
|
||||||
|
public HttpSecurity redirectToHttps(
|
||||||
|
Customizer<HttpsRedirectConfigurer<HttpSecurity>> httpsRedirectConfigurerCustomizer) throws Exception {
|
||||||
|
httpsRedirectConfigurerCustomizer.customize(getOrApply(new HttpsRedirectConfigurer<>()));
|
||||||
|
return HttpSecurity.this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures HTTP Basic authentication.
|
* Configures HTTP Basic authentication.
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2025 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* 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.annotation.web.configurers;
|
||||||
|
|
||||||
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
|
import org.springframework.security.web.PortMapper;
|
||||||
|
import org.springframework.security.web.transport.HttpsRedirectFilter;
|
||||||
|
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||||
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies for what requests the application should redirect to HTTPS. When this
|
||||||
|
* configurer is added, it redirects all HTTP requests by default to HTTPS.
|
||||||
|
*
|
||||||
|
* <h2>Security Filters</h2>
|
||||||
|
*
|
||||||
|
* The following Filters are populated
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link HttpsRedirectFilter}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Shared Objects Created</h2>
|
||||||
|
*
|
||||||
|
* No shared objects are created.
|
||||||
|
*
|
||||||
|
* <h2>Shared Objects Used</h2>
|
||||||
|
*
|
||||||
|
* The following shared objects are used:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link PortMapper} is used to configure {@link HttpsRedirectFilter}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
|
||||||
|
* @author Josh Cummings
|
||||||
|
* @since 6.5
|
||||||
|
*/
|
||||||
|
public final class HttpsRedirectConfigurer<H extends HttpSecurityBuilder<H>>
|
||||||
|
extends AbstractHttpConfigurer<HeadersConfigurer<H>, H> {
|
||||||
|
|
||||||
|
private RequestMatcher requestMatcher;
|
||||||
|
|
||||||
|
public HttpsRedirectConfigurer<H> requestMatchers(RequestMatcher... matchers) {
|
||||||
|
this.requestMatcher = new OrRequestMatcher(matchers);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(H http) throws Exception {
|
||||||
|
HttpsRedirectFilter filter = new HttpsRedirectFilter();
|
||||||
|
if (this.requestMatcher != null) {
|
||||||
|
filter.setRequestMatcher(this.requestMatcher);
|
||||||
|
}
|
||||||
|
PortMapper mapper = http.getSharedObject(PortMapper.class);
|
||||||
|
if (mapper != null) {
|
||||||
|
filter.setPortMapper(mapper);
|
||||||
|
}
|
||||||
|
http.addFilter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -533,6 +533,39 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu
|
|||||||
this.http.requiresChannel(requiresChannelCustomizer)
|
this.http.requiresChannel(requiresChannelCustomizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures channel security. In order for this configuration to be useful at least
|
||||||
|
* one mapping to a required channel must be provided.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* The example below demonstrates how to require HTTPS for every request. Only
|
||||||
|
* requiring HTTPS for some requests is supported, for example if you need to differentiate
|
||||||
|
* between local and production deployments.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* @Configuration
|
||||||
|
* @EnableWebSecurity
|
||||||
|
* class RequireHttpsConfig {
|
||||||
|
*
|
||||||
|
* @Bean
|
||||||
|
* fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
* http {
|
||||||
|
* redirectToHttps { }
|
||||||
|
* }
|
||||||
|
* return http.build();
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
* @param httpsRedirectConfiguration custom configuration to apply to HTTPS redirect rules
|
||||||
|
* @see [HttpsRedirectDsl]
|
||||||
|
* @since 6.5
|
||||||
|
*/
|
||||||
|
fun redirectToHttps(httpsRedirectConfiguration: HttpsRedirectDsl.() -> Unit) {
|
||||||
|
val httpsRedirectCustomizer = HttpsRedirectDsl().apply(httpsRedirectConfiguration).get()
|
||||||
|
this.http.redirectToHttps(httpsRedirectCustomizer)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds X509 based pre authentication to an application
|
* Adds X509 based pre authentication to an application
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2020 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.annotation.web
|
||||||
|
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.HttpsRedirectConfigurer
|
||||||
|
import org.springframework.security.web.PortMapper
|
||||||
|
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Kotlin DSL to configure [ServerHttpSecurity] HTTPS redirection rules using idiomatic
|
||||||
|
* Kotlin code.
|
||||||
|
*
|
||||||
|
* @author Eleftheria Stein
|
||||||
|
* @since 5.4
|
||||||
|
* @property portMapper the [PortMapper] that specifies a custom HTTPS port to redirect to.
|
||||||
|
*/
|
||||||
|
@SecurityMarker
|
||||||
|
class HttpsRedirectDsl {
|
||||||
|
var requestMatchers: Array<out RequestMatcher>? = null
|
||||||
|
|
||||||
|
internal fun get(): (HttpsRedirectConfigurer<HttpSecurity>) -> Unit {
|
||||||
|
return { https ->
|
||||||
|
requestMatchers?.also { https.requestMatchers(*requestMatchers!!) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2019 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.annotation.web.configurers;
|
||||||
|
|
||||||
|
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.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
|
import org.springframework.security.config.test.SpringTestContextExtension;
|
||||||
|
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;
|
||||||
|
import org.springframework.security.web.PortMapper;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
|
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link HttpsRedirectConfigurerTests}
|
||||||
|
*
|
||||||
|
* @author Josh Cummings
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringTestContextExtension.class)
|
||||||
|
public class HttpsRedirectConfigurerTests {
|
||||||
|
|
||||||
|
public final SpringTestContext spring = new SpringTestContext(this);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mvc;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWhenSecureThenDoesNotRedirect() throws Exception {
|
||||||
|
this.spring.register(RedirectToHttpConfig.class).autowire();
|
||||||
|
// @formatter:off
|
||||||
|
this.mvc.perform(get("https://localhost"))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWhenInsecureThenRespondsWithRedirectToSecure() throws Exception {
|
||||||
|
this.spring.register(RedirectToHttpConfig.class).autowire();
|
||||||
|
// @formatter:off
|
||||||
|
this.mvc.perform(get("http://localhost"))
|
||||||
|
.andExpect(status().isFound())
|
||||||
|
.andExpect(redirectedUrl("https://localhost"));
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWhenInsecureAndPathRequiresTransportSecurityThenRedirects() throws Exception {
|
||||||
|
this.spring.register(SometimesRedirectToHttpsConfig.class, UsePathPatternConfig.class).autowire();
|
||||||
|
// @formatter:off
|
||||||
|
this.mvc.perform(get("http://localhost:8080"))
|
||||||
|
.andExpect(status().isNotFound());
|
||||||
|
this.mvc.perform(get("http://localhost:8080/secure"))
|
||||||
|
.andExpect(status().isFound())
|
||||||
|
.andExpect(redirectedUrl("https://localhost:8443/secure"));
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getWhenInsecureAndUsingCustomPortMapperThenRespondsWithRedirectToSecurePort() throws Exception {
|
||||||
|
this.spring.register(RedirectToHttpsViaCustomPortsConfig.class).autowire();
|
||||||
|
PortMapper portMapper = this.spring.getContext().getBean(PortMapper.class);
|
||||||
|
given(portMapper.lookupHttpsPort(4080)).willReturn(4443);
|
||||||
|
// @formatter:off
|
||||||
|
this.mvc.perform(get("http://localhost:4080"))
|
||||||
|
.andExpect(status().isFound())
|
||||||
|
.andExpect(redirectedUrl("https://localhost:4443"));
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvc
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class RedirectToHttpConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.redirectToHttps(withDefaults());
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvc
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class SometimesRedirectToHttpsConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain springSecurity(HttpSecurity http, PathPatternRequestMatcher.Builder path) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.redirectToHttps((https) -> https.requestMatchers(path.matcher("/secure")));
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
|
||||||
|
return new PathPatternRequestMatcherBuilderFactoryBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvc
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class RedirectToHttpsViaCustomPortsConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
http
|
||||||
|
.portMapper((p) -> p.portMapper(portMapper()))
|
||||||
|
.redirectToHttps(withDefaults());
|
||||||
|
|
||||||
|
// @formatter:on
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
PortMapper portMapper() {
|
||||||
|
return mock(PortMapper.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class UsePathPatternConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
|
||||||
|
return new PathPatternRequestMatcherBuilderFactoryBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2020 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.annotation.web
|
||||||
|
|
||||||
|
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.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.http.HttpHeaders
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
|
import org.springframework.security.config.test.SpringTestContext
|
||||||
|
import org.springframework.security.config.test.SpringTestContextExtension
|
||||||
|
import org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean
|
||||||
|
import org.springframework.security.web.PortMapperImpl
|
||||||
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
|
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.get
|
||||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||||
|
import java.net.URI
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for [HttpsRedirectDsl]
|
||||||
|
*
|
||||||
|
* @author Eleftheria Stein
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringTestContextExtension::class)
|
||||||
|
class HttpsRedirectDslTests {
|
||||||
|
@JvmField
|
||||||
|
val spring = SpringTestContext(this)
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
lateinit var mockMvc: MockMvc
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `request when matches redirect to HTTPS matcher then redirects to HTTPS`() {
|
||||||
|
this.spring.register(HttpRedirectMatcherConfig::class.java, UsePathPatternConfig::class.java).autowire()
|
||||||
|
|
||||||
|
val result = this.mockMvc.get("/secure")
|
||||||
|
.andExpect {
|
||||||
|
status { is3xxRedirection() }
|
||||||
|
}.andReturn()
|
||||||
|
|
||||||
|
val location = result.response.getHeader(HttpHeaders.LOCATION)?.let { URI.create(it) }
|
||||||
|
assertThat(location?.scheme).isEqualTo("https")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `request when does not match redirect to HTTPS matcher then does not redirect`() {
|
||||||
|
this.spring.register(HttpRedirectMatcherConfig::class.java, UsePathPatternConfig::class.java).autowire()
|
||||||
|
|
||||||
|
this.mockMvc.get("/")
|
||||||
|
.andExpect {
|
||||||
|
status { isNotFound() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableWebMvc
|
||||||
|
open class HttpRedirectMatcherConfig {
|
||||||
|
@Bean
|
||||||
|
open fun springFilterChain(http: HttpSecurity, path: PathPatternRequestMatcher.Builder): SecurityFilterChain {
|
||||||
|
http {
|
||||||
|
redirectToHttps {
|
||||||
|
requestMatchers = arrayOf(path.matcher("/secure"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
open class UsePathPatternConfig {
|
||||||
|
@Bean
|
||||||
|
open fun requestMatcherBuilder() = PathPatternRequestMatcherBuilderFactoryBean()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `request when port mapper configured then redirected to HTTPS port`() {
|
||||||
|
this.spring.register(PortMapperConfig::class.java).autowire()
|
||||||
|
|
||||||
|
val result = this.mockMvc.get("http://localhost:543")
|
||||||
|
.andExpect {
|
||||||
|
status {
|
||||||
|
is3xxRedirection()
|
||||||
|
}
|
||||||
|
}.andReturn()
|
||||||
|
|
||||||
|
val location = result.response.getHeader(HttpHeaders.LOCATION)?.let { URI.create(it) }
|
||||||
|
assertThat(location?.scheme).isEqualTo("https")
|
||||||
|
assertThat(location?.port).isEqualTo(123)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableWebMvc
|
||||||
|
open class PortMapperConfig {
|
||||||
|
@Bean
|
||||||
|
open fun springFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
|
val customPortMapper = PortMapperImpl()
|
||||||
|
customPortMapper.setPortMappings(Collections.singletonMap("543", "123"))
|
||||||
|
http {
|
||||||
|
portMapper {
|
||||||
|
portMapper = customPortMapper
|
||||||
|
}
|
||||||
|
redirectToHttps { }
|
||||||
|
}
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,9 +27,7 @@ public class WebSecurityConfig {
|
|||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
// ...
|
// ...
|
||||||
.requiresChannel(channel -> channel
|
.redirectToHttps(withDefaults());
|
||||||
.anyRequest().requiresSecure()
|
|
||||||
);
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,9 +45,7 @@ class SecurityConfig {
|
|||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
||||||
http {
|
http {
|
||||||
// ...
|
// ...
|
||||||
requiresChannel {
|
redirectToHttps { }
|
||||||
secure(AnyRequestMatcher.INSTANCE, "REQUIRES_SECURE_CHANNEL")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return http.build()
|
return http.build()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user