Skip to content

Commit e6008b6

Browse files
committed
Add RedirectToHttps to XML
Closes gh-16775
1 parent 989aee2 commit e6008b6

File tree

8 files changed

+94
-4
lines changed

8 files changed

+94
-4
lines changed

config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -82,6 +82,7 @@
8282
import org.springframework.security.web.session.SessionManagementFilter;
8383
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
8484
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;
85+
import org.springframework.security.web.transport.HttpsRedirectFilter;
8586
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
8687
import org.springframework.util.Assert;
8788
import org.springframework.util.ClassUtils;
@@ -176,6 +177,8 @@ class HttpConfigurationBuilder {
176177

177178
private BeanDefinition cpf;
178179

180+
private BeanDefinition httpsRedirectFilter;
181+
179182
private BeanDefinition securityContextPersistenceFilter;
180183

181184
private BeanDefinition forceEagerSessionCreationFilter;
@@ -252,6 +255,7 @@ class HttpConfigurationBuilder {
252255
createServletApiFilter(authenticationManager);
253256
createJaasApiFilter();
254257
createChannelProcessingFilter();
258+
createHttpsRedirectFilter();
255259
createFilterSecurity(authenticationManager);
256260
createAddHeadersFilter();
257261
createCorsFilter();
@@ -656,6 +660,19 @@ private void createJaasApiFilter() {
656660
}
657661
}
658662

663+
private void createHttpsRedirectFilter() {
664+
String ref = this.httpElt
665+
.getAttribute(HttpSecurityBeanDefinitionParser.ATT_REDIRECT_TO_HTTPS_REQUEST_MATCHER_REF);
666+
if (!StringUtils.hasText(ref)) {
667+
return;
668+
}
669+
RootBeanDefinition channelFilter = new RootBeanDefinition(HttpsRedirectFilter.class);
670+
channelFilter.getPropertyValues().addPropertyValue("requestMatcher", new RuntimeBeanReference(ref));
671+
channelFilter.getPropertyValues().addPropertyValue("portMapper", this.portMapper);
672+
this.httpsRedirectFilter = channelFilter;
673+
}
674+
675+
@Deprecated
659676
private void createChannelProcessingFilter() {
660677
ManagedMap<BeanMetadataElement, BeanDefinition> channelRequestMap = parseInterceptUrlsForChannelSecurity();
661678
if (channelRequestMap.isEmpty()) {
@@ -691,7 +708,9 @@ private void createChannelProcessingFilter() {
691708
* Parses the intercept-url elements to obtain the map used by channel security. This
692709
* will be empty unless the <tt>requires-channel</tt> attribute has been used on a URL
693710
* path.
711+
* @deprecated please use {@link #createHttpsRedirectFilter} instead
694712
*/
713+
@Deprecated
695714
private ManagedMap<BeanMetadataElement, BeanDefinition> parseInterceptUrlsForChannelSecurity() {
696715
ManagedMap<BeanMetadataElement, BeanDefinition> channelRequestMap = new ManagedMap<>();
697716
for (Element urlElt : this.interceptUrls) {
@@ -897,6 +916,9 @@ List<OrderDecorator> getFilters() {
897916
if (this.disableUrlRewriteFilter != null) {
898917
filters.add(new OrderDecorator(this.disableUrlRewriteFilter, SecurityFilters.DISABLE_ENCODE_URL_FILTER));
899918
}
919+
if (this.httpsRedirectFilter != null) {
920+
filters.add(new OrderDecorator(this.httpsRedirectFilter, SecurityFilters.HTTPS_REDIRECT_FILTER));
921+
}
900922
if (this.cpf != null) {
901923
filters.add(new OrderDecorator(this.cpf, SecurityFilters.CHANNEL_FILTER));
902924
}

config/src/main/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -81,6 +81,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
8181

8282
static final String ATT_REQUEST_MATCHER_REF = "request-matcher-ref";
8383

84+
static final String ATT_REDIRECT_TO_HTTPS_REQUEST_MATCHER_REF = "redirect-to-https-request-matcher-ref";
85+
8486
static final String ATT_PATH_PATTERN = "pattern";
8587

8688
static final String ATT_HTTP_METHOD = "method";

config/src/main/java/org/springframework/security/config/http/SecurityFilters.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,8 +33,11 @@ enum SecurityFilters {
3333

3434
FORCE_EAGER_SESSION_FILTER,
3535

36+
@Deprecated
3637
CHANNEL_FILTER,
3738

39+
HTTPS_REDIRECT_FILTER,
40+
3841
SECURITY_CONTEXT_FILTER,
3942

4043
CONCURRENT_SESSION_FILTER,

config/src/main/resources/org/springframework/security/config/spring-security-6.5.rnc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,8 @@ http.attlist &=
345345
http.attlist &=
346346
## Allows a RequestMatcher instance to be used, as an alternative to pattern-matching.
347347
attribute request-matcher-ref { xsd:token }?
348+
http.attlist &=
349+
attribute redirect-to-https-request-matcher-ref { xsd:token }?
348350
http.attlist &=
349351
## A legacy attribute which automatically registers a login form, BASIC authentication and a logout URL and logout services. If unspecified, defaults to "false". We'd recommend you avoid using this and instead explicitly configure the services you require.
350352
attribute auto-config {xsd:boolean}?

config/src/main/resources/org/springframework/security/config/spring-security-6.5.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,7 @@
12421242
</xs:documentation>
12431243
</xs:annotation>
12441244
</xs:attribute>
1245+
<xs:attribute name="redirect-to-https-request-matcher-ref" type="xs:token"/>
12451246
<xs:attribute name="auto-config" type="xs:boolean">
12461247
<xs:annotation>
12471248
<xs:documentation>A legacy attribute which automatically registers a login form, BASIC authentication and a

config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -109,6 +109,7 @@
109109
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
110110
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
111111
import org.springframework.security.web.session.DisableEncodeUrlFilter;
112+
import org.springframework.security.web.transport.HttpsRedirectFilter;
112113
import org.springframework.test.web.servlet.MockMvc;
113114
import org.springframework.test.web.servlet.MvcResult;
114115
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
@@ -349,6 +350,21 @@ public void configureWhenInterceptUrlWithRequiresChannelThenAddedChannelFilterTo
349350
assertThat(getFilter(ChannelProcessingFilter.class)).isNotNull();
350351
}
351352

353+
@Test
354+
public void configureWhenRedirectToHttpsThenFilterAdded() {
355+
this.spring.configLocations(xml("RedirectToHttpsRequiresHttpsAny")).autowire();
356+
assertThat(getFilter(HttpsRedirectFilter.class)).isNotNull();
357+
}
358+
359+
@Test
360+
public void getWhenRedirectToHttpsAnyThenRedirects() throws Exception {
361+
this.spring.configLocations(xml("RedirectToHttpsRequiresHttpsAny")).autowire();
362+
// @formatter:off
363+
this.mvc.perform(get("http://localhost"))
364+
.andExpect(redirectedUrl("https://localhost"));
365+
// @formatter:on
366+
}
367+
352368
@Test
353369
public void getWhenPortsMappedThenRedirectedAccordingly() throws Exception {
354370
this.spring.configLocations(xml("PortsMappedInterceptUrlMethodRequiresAny")).autowire();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2002-2018 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
19+
xmlns:util="http://www.springframework.org/schema/util"
20+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
21+
xmlns="http://www.springframework.org/schema/security"
22+
xsi:schemaLocation="
23+
http://www.springframework.org/schema/security
24+
https://www.springframework.org/schema/security/spring-security.xsd
25+
http://www.springframework.org/schema/beans
26+
https://www.springframework.org/schema/beans/spring-beans.xsd
27+
http://www.springframework.org/schema/util
28+
https://www.springframework.org/schema/util/spring-util.xsd
29+
">
30+
31+
<http redirect-to-https-request-matcher-ref="any">
32+
<http-basic/>
33+
<intercept-url pattern="/**" method="GET" access="hasRole('ADMIN')" requires-channel="https"/>
34+
<intercept-url pattern="/**" access="permitAll"/>
35+
</http>
36+
<util:constant id="any" static-field="org.springframework.security.web.util.matcher.AnyRequestMatcher.INSTANCE" />
37+
38+
<b:import resource="MiscHttpConfigTests-controllers.xml"/>
39+
<b:import resource="userservice.xml"/>
40+
</b:beans>

docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ If no pattern is defined, all requests will be matched, so the most specific pat
118118
Sets the realm name used for basic authentication (if enabled).
119119
Corresponds to the `realmName` property on `BasicAuthenticationEntryPoint`.
120120

121+
[[nsa-redirect-to-https-request-matcher-ref]]
122+
* **redirect-to-https-request-matcher-ref**
123+
A reference to a bean that implements `RequestMatcher` that will determine which requests must redirect to HTTPS.
124+
This is helpful when, for example, wanting to run HTTP locally and HTTPS in production using a request header.
121125

122126
[[nsa-http-request-matcher]]
123127
* **request-matcher**

0 commit comments

Comments
 (0)