浏览代码

Add setFavorRelativeUris

This places the new functionality behind a setting so that
we can remain passive until we can change the setting in
the next major release.

Issue gh-7273
Josh Cummings 8 月之前
父节点
当前提交
3eeb4317f6
共有 25 个文件被更改,包括 288 次插入98 次删除
  1. 3 3
      config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java
  2. 2 2
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java
  3. 3 2
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java
  4. 4 4
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
  5. 4 4
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java
  6. 3 3
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java
  7. 2 2
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
  8. 10 10
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
  9. 7 7
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
  10. 2 2
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
  11. 3 4
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java
  12. 5 3
      config/src/test/java/org/springframework/security/config/http/CsrfConfigTests.java
  13. 3 3
      config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java
  14. 5 5
      config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java
  15. 3 3
      config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java
  16. 7 7
      config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java
  17. 3 3
      config/src/test/java/org/springframework/security/config/http/PlaceHolderAndELConfigTests.java
  18. 3 3
      config/src/test/java/org/springframework/security/config/http/Saml2LoginBeanDefinitionParserTests.java
  19. 8 8
      config/src/test/java/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests.java
  20. 4 4
      config/src/test/kotlin/org/springframework/security/config/annotation/web/ExceptionHandlingDslTests.kt
  21. 2 2
      config/src/test/kotlin/org/springframework/security/config/annotation/web/FormLoginDslTests.kt
  22. 3 3
      config/src/test/kotlin/org/springframework/security/config/annotation/web/RememberMeDslTests.kt
  23. 104 0
      docs/modules/ROOT/pages/migration-7/web.adoc
  24. 40 6
      web/src/main/java/org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.java
  25. 55 5
      web/src/test/java/org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPointTests.java

+ 3 - 3
config/src/test/java/org/springframework/security/config/annotation/web/builders/NamespaceHttpTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -77,7 +77,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 
 /**
 /**
@@ -167,7 +167,7 @@ public class NamespaceHttpTests {
 		// @formatter:off
 		// @formatter:off
 		this.mockMvc.perform(get("/"))
 		this.mockMvc.perform(get("/"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/entry-point"));
+				.andExpect(redirectedUrlPattern("**/entry-point"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 

+ 2 - 2
config/src/test/java/org/springframework/security/config/annotation/web/configurers/DefaultLoginPageConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2023 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -82,7 +82,7 @@ public class DefaultLoginPageConfigurerTests {
 	@Test
 	@Test
 	public void getWhenFormLoginEnabledThenRedirectsToLoginPage() throws Exception {
 	public void getWhenFormLoginEnabledThenRedirectsToLoginPage() throws Exception {
 		this.spring.register(DefaultLoginPageConfig.class).autowire();
 		this.spring.register(DefaultLoginPageConfig.class).autowire();
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("/login"));
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
 	}
 	}
 
 
 	@Test
 	@Test

+ 3 - 2
config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -213,7 +213,8 @@ public class ExceptionHandlingConfigurerTests {
 	@Test
 	@Test
 	public void getWhenUsingDefaultsAndUnauthenticatedThenRedirectsToLogin() throws Exception {
 	public void getWhenUsingDefaultsAndUnauthenticatedThenRedirectsToLogin() throws Exception {
 		this.spring.register(DefaultHttpConfig.class).autowire();
 		this.spring.register(DefaultHttpConfig.class).autowire();
-		this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type")).andExpect(redirectedUrl("/login"));
+		this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type"))
+			.andExpect(redirectedUrl("http://localhost/login"));
 	}
 	}
 
 
 	@Test
 	@Test

+ 4 - 4
config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -162,7 +162,7 @@ public class FormLoginConfigurerTests {
 		// @formatter:off
 		// @formatter:off
 		this.mockMvc.perform(get("/private"))
 		this.mockMvc.perform(get("/private"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -217,7 +217,7 @@ public class FormLoginConfigurerTests {
 		// @formatter:off
 		// @formatter:off
 		this.mockMvc.perform(get("/private"))
 		this.mockMvc.perform(get("/private"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -331,7 +331,7 @@ public class FormLoginConfigurerTests {
 		// @formatter:off
 		// @formatter:off
 		this.mockMvc.perform(get("/login?error"))
 		this.mockMvc.perform(get("/login?error"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 

+ 4 - 4
config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpFormLoginTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@ public class NamespaceHttpFormLoginTests {
 	@Test
 	@Test
 	public void formLoginWhenDefaultConfigurationThenMatchesNamespace() throws Exception {
 	public void formLoginWhenDefaultConfigurationThenMatchesNamespace() throws Exception {
 		this.spring.register(FormLoginConfig.class, UserDetailsServiceConfig.class).autowire();
 		this.spring.register(FormLoginConfig.class, UserDetailsServiceConfig.class).autowire();
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("/login"));
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
 		this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/login?error"));
 		this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/login?error"));
 		// @formatter:off
 		// @formatter:off
 		MockHttpServletRequestBuilder loginRequest = post("/login")
 		MockHttpServletRequestBuilder loginRequest = post("/login")
@@ -79,7 +79,7 @@ public class NamespaceHttpFormLoginTests {
 	@Test
 	@Test
 	public void formLoginWithCustomEndpointsThenBehaviorMatchesNamespace() throws Exception {
 	public void formLoginWithCustomEndpointsThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(FormLoginCustomConfig.class, UserDetailsServiceConfig.class).autowire();
 		this.spring.register(FormLoginCustomConfig.class, UserDetailsServiceConfig.class).autowire();
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("/authentication/login"));
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
 		this.mvc.perform(post("/authentication/login/process").with(csrf()))
 		this.mvc.perform(post("/authentication/login/process").with(csrf()))
 			.andExpect(redirectedUrl("/authentication/login?failed"));
 			.andExpect(redirectedUrl("/authentication/login?failed"));
 		// @formatter:off
 		// @formatter:off
@@ -94,7 +94,7 @@ public class NamespaceHttpFormLoginTests {
 	@Test
 	@Test
 	public void formLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
 	public void formLoginWithCustomHandlersThenBehaviorMatchesNamespace() throws Exception {
 		this.spring.register(FormLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
 		this.spring.register(FormLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
-		this.mvc.perform(get("/")).andExpect(redirectedUrl("/login"));
+		this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
 		this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/custom/failure"));
 		this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/custom/failure"));
 		verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class));
 		verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class));
 		// @formatter:off
 		// @formatter:off

+ 3 - 3
config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceRememberMeTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -104,7 +104,7 @@ public class NamespaceRememberMeTests {
 				.with(csrf())
 				.with(csrf())
 				.cookie(rememberMe);
 				.cookie(rememberMe);
 		this.mvc.perform(authenticationClassRequest)
 		this.mvc.perform(authenticationClassRequest)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn();
 				.andReturn();
 		// @formatter:on
 		// @formatter:on
 	}
 	}
@@ -150,7 +150,7 @@ public class NamespaceRememberMeTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(somewhereRequest)
 		this.mvc.perform(somewhereRequest)
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		MockHttpServletRequestBuilder loginWithRememberme = post("/login").with(rememberMeLogin());
 		MockHttpServletRequestBuilder loginWithRememberme = post("/login").with(rememberMeLogin());
 		Cookie withKey = this.mvc.perform(loginWithRememberme)
 		Cookie withKey = this.mvc.perform(loginWithRememberme)
 				.andReturn()
 				.andReturn()

+ 2 - 2
config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2023 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -240,7 +240,7 @@ public class RememberMeConfigurerTests {
 				.with(csrf())
 				.with(csrf())
 				.cookie(expiredRememberMeCookie);
 				.cookie(expiredRememberMeCookie);
 		// @formatter:on
 		// @formatter:on
-		this.mvc.perform(expiredRequest).andExpect(redirectedUrl("/login"));
+		this.mvc.perform(expiredRequest).andExpect(redirectedUrl("http://localhost/login"));
 	}
 	}
 
 
 	@Test
 	@Test

+ 10 - 10
config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -90,7 +90,7 @@ public class RequestCacheConfigurerTests {
 		this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
 		this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
 		// @formatter:off
 		// @formatter:off
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/favicon.ico"))
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/favicon.ico"))
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -104,7 +104,7 @@ public class RequestCacheConfigurerTests {
 		this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
 		this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
 		// @formatter:off
 		// @formatter:off
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/favicon.png"))
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/favicon.png"))
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -120,7 +120,7 @@ public class RequestCacheConfigurerTests {
 		MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
 		MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
 		// @formatter:off
 		// @formatter:off
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -140,7 +140,7 @@ public class RequestCacheConfigurerTests {
 				.header("X-Requested-With", "XMLHttpRequest");
 				.header("X-Requested-With", "XMLHttpRequest");
 		MockHttpSession session = (MockHttpSession) this.mvc
 		MockHttpSession session = (MockHttpSession) this.mvc
 				.perform(xRequestedWith)
 				.perform(xRequestedWith)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -157,7 +157,7 @@ public class RequestCacheConfigurerTests {
 				MediaType.TEXT_EVENT_STREAM);
 				MediaType.TEXT_EVENT_STREAM);
 		// @formatter:off
 		// @formatter:off
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -174,7 +174,7 @@ public class RequestCacheConfigurerTests {
 		MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.ALL);
 		MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.ALL);
 		// @formatter:off
 		// @formatter:off
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -188,7 +188,7 @@ public class RequestCacheConfigurerTests {
 		MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
 		MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
 		// @formatter:off
 		// @formatter:off
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -203,7 +203,7 @@ public class RequestCacheConfigurerTests {
 		MockHttpServletRequestBuilder request = get("/messages")
 		MockHttpServletRequestBuilder request = get("/messages")
 				.header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
 				.header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();
@@ -218,7 +218,7 @@ public class RequestCacheConfigurerTests {
 		MockHttpServletRequestBuilder request = get("/messages")
 		MockHttpServletRequestBuilder request = get("/messages")
 				.header("X-Requested-With", "com.android");
 				.header("X-Requested-With", "com.android");
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession();
 				.getSession();

+ 7 - 7
config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java

@@ -437,7 +437,7 @@ public class OAuth2LoginConfigurerTests {
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request.setServletPath(requestUri);
 		this.request.setServletPath(requestUri);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-		assertThat(this.response.getRedirectedUrl()).matches("/oauth2/authorization/google");
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/oauth2/authorization/google");
 	}
 	}
 
 
 	// gh-6802
 	// gh-6802
@@ -448,7 +448,7 @@ public class OAuth2LoginConfigurerTests {
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request.setServletPath(requestUri);
 		this.request.setServletPath(requestUri);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-		assertThat(this.response.getRedirectedUrl()).matches("/login");
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/login");
 	}
 	}
 
 
 	// gh-5347
 	// gh-5347
@@ -461,7 +461,7 @@ public class OAuth2LoginConfigurerTests {
 		this.request.setServletPath(requestUri);
 		this.request.setServletPath(requestUri);
 		this.request.addHeader(HttpHeaders.ACCEPT, new MediaType("image", "*").toString());
 		this.request.addHeader(HttpHeaders.ACCEPT, new MediaType("image", "*").toString());
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-		assertThat(this.response.getRedirectedUrl()).matches("/login");
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/login");
 	}
 	}
 
 
 	// gh-5347
 	// gh-5347
@@ -472,7 +472,7 @@ public class OAuth2LoginConfigurerTests {
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request.setServletPath(requestUri);
 		this.request.setServletPath(requestUri);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-		assertThat(this.response.getRedirectedUrl()).matches("/login");
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/login");
 	}
 	}
 
 
 	// gh-6812
 	// gh-6812
@@ -521,7 +521,7 @@ public class OAuth2LoginConfigurerTests {
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request.setServletPath(requestUri);
 		this.request.setServletPath(requestUri);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-		assertThat(this.response.getRedirectedUrl()).matches("/oauth2/authorization/google");
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/oauth2/authorization/google");
 	}
 	}
 
 
 	@Test
 	@Test
@@ -531,7 +531,7 @@ public class OAuth2LoginConfigurerTests {
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request.setServletPath(requestUri);
 		this.request.setServletPath(requestUri);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-		assertThat(this.response.getRedirectedUrl()).matches("/custom-login");
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/custom-login");
 	}
 	}
 
 
 	@Test
 	@Test
@@ -541,7 +541,7 @@ public class OAuth2LoginConfigurerTests {
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request = new MockHttpServletRequest("GET", requestUri);
 		this.request.setServletPath(requestUri);
 		this.request.setServletPath(requestUri);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
 		this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-		assertThat(this.response.getRedirectedUrl()).matches("/custom-login");
+		assertThat(this.response.getRedirectedUrl()).matches("http://localhost/custom-login");
 	}
 	}
 
 
 	@Test
 	@Test

+ 2 - 2
config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -1210,7 +1210,7 @@ public class OAuth2ResourceServerConfigurerTests {
 		MvcResult result = this.mvc.perform(get("/authenticated")
 		MvcResult result = this.mvc.perform(get("/authenticated")
 				.header("Accept", "text/html"))
 				.header("Accept", "text/html"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("http://localhost/login"))
 				.andReturn();
 				.andReturn();
 		// @formatter:on
 		// @formatter:on
 		assertThat(result.getRequest().getSession(false)).isNotNull();
 		assertThat(result.getRequest().getSession(false)).isNotNull();

+ 3 - 4
config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -412,11 +412,10 @@ public class Saml2LoginConfigurerTests {
 		this.spring.register(Saml2LoginConfig.class).autowire();
 		this.spring.register(Saml2LoginConfig.class).autowire();
 		this.mvc.perform(get("/favicon.ico").accept(MediaType.TEXT_HTML))
 		this.mvc.perform(get("/favicon.ico").accept(MediaType.TEXT_HTML))
 			.andExpect(status().isFound())
 			.andExpect(status().isFound())
-			.andExpect(redirectedUrl("/login"));
+			.andExpect(redirectedUrl("http://localhost/login"));
 		this.mvc.perform(get("/").accept(MediaType.TEXT_HTML))
 		this.mvc.perform(get("/").accept(MediaType.TEXT_HTML))
 			.andExpect(status().isFound())
 			.andExpect(status().isFound())
-			.andExpect(header().string("Location", startsWith("/saml2/authenticate")));
-
+			.andExpect(header().string("Location", startsWith("http://localhost/saml2/authenticate")));
 	}
 	}
 
 
 	@Test
 	@Test

+ 5 - 3
config/src/test/java/org/springframework/security/config/http/CsrfConfigTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -342,7 +342,7 @@ public class CsrfConfigTests {
 		this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
 		this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
 		// simulates a request that has no authentication (e.g. session time-out)
 		// simulates a request that has no authentication (e.g. session time-out)
 		MvcResult result = this.mvc.perform(post("/authenticated").with(csrf()))
 		MvcResult result = this.mvc.perform(post("/authenticated").with(csrf()))
-			.andExpect(redirectedUrl("/login"))
+			.andExpect(redirectedUrl("http://localhost/login"))
 			.andReturn();
 			.andReturn();
 		MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
 		MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
 		// if the request cache is consulted, then it will redirect back to /some-url,
 		// if the request cache is consulted, then it will redirect back to /some-url,
@@ -363,7 +363,9 @@ public class CsrfConfigTests {
 			throws Exception {
 			throws Exception {
 		this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
 		this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
 		// simulates a request that has no authentication (e.g. session time-out)
 		// simulates a request that has no authentication (e.g. session time-out)
-		MvcResult result = this.mvc.perform(get("/authenticated")).andExpect(redirectedUrl("/login")).andReturn();
+		MvcResult result = this.mvc.perform(get("/authenticated"))
+			.andExpect(redirectedUrl("http://localhost/login"))
+			.andReturn();
 		MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
 		MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
 		// if the request cache is consulted, then it will redirect back to /some-url,
 		// if the request cache is consulted, then it will redirect back to /some-url,
 		// which we do want
 		// which we do want

+ 3 - 3
config/src/test/java/org/springframework/security/config/http/FormLoginConfigTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -73,7 +73,7 @@ public class FormLoginConfigTests {
 		this.spring.configLocations(this.xml("WithAntRequestMatcher")).autowire();
 		this.spring.configLocations(this.xml("WithAntRequestMatcher")).autowire();
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -107,7 +107,7 @@ public class FormLoginConfigTests {
 		this.mvc.perform(invalidPassword)
 		this.mvc.perform(invalidPassword)
 				.andExpect(redirectedUrl(WebConfigUtilsTests.URL + "/failure"));
 				.andExpect(redirectedUrl(WebConfigUtilsTests.URL + "/failure"));
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
-				.andExpect(redirectedUrl(WebConfigUtilsTests.URL + "/login"));
+				.andExpect(redirectedUrl("http://localhost" + WebConfigUtilsTests.URL + "/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 

+ 5 - 5
config/src/test/java/org/springframework/security/config/http/HttpConfigTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@ public class HttpConfigTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -81,7 +81,7 @@ public class HttpConfigTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -95,7 +95,7 @@ public class HttpConfigTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 		verify(authorizationManager).check(any(), any());
 		verify(authorizationManager).check(any(), any());
 	}
 	}
@@ -109,7 +109,7 @@ public class HttpConfigTests {
 		proxy.doFilter(request, new EncodeUrlDenyingHttpServletResponseWrapper(response), (req, resp) -> {
 		proxy.doFilter(request, new EncodeUrlDenyingHttpServletResponseWrapper(response), (req, resp) -> {
 		});
 		});
 		assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
 		assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
-		assertThat(response.getRedirectedUrl()).isEqualTo("/login");
+		assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/login");
 	}
 	}
 
 
 	@Test
 	@Test

+ 3 - 3
config/src/test/java/org/springframework/security/config/http/MiscHttpConfigTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -573,7 +573,7 @@ public class MiscHttpConfigTests {
 		proxy.doFilter(request, new EncodeUrlDenyingHttpServletResponseWrapper(response), (req, resp) -> {
 		proxy.doFilter(request, new EncodeUrlDenyingHttpServletResponseWrapper(response), (req, resp) -> {
 		});
 		});
 		assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
 		assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
-		assertThat(response.getRedirectedUrl()).isEqualTo("/login");
+		assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/login");
 	}
 	}
 
 
 	@Test
 	@Test
@@ -802,7 +802,7 @@ public class MiscHttpConfigTests {
 		this.spring.configLocations(xml("PortsMappedRequiresHttps")).autowire();
 		this.spring.configLocations(xml("PortsMappedRequiresHttps")).autowire();
 		// @formatter:off
 		// @formatter:off
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("https://localhost:9080/protected"))
 		MockHttpSession session = (MockHttpSession) this.mvc.perform(get("https://localhost:9080/protected"))
-				.andExpect(redirectedUrl("/login"))
+				.andExpect(redirectedUrl("https://localhost:9443/login"))
 				.andReturn()
 				.andReturn()
 				.getRequest()
 				.getRequest()
 				.getSession(false);
 				.getSession(false);

+ 7 - 7
config/src/test/java/org/springframework/security/config/http/OAuth2LoginBeanDefinitionParserTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -174,7 +174,7 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/oauth2/authorization/google-login"));
+				.andExpect(redirectedUrl("http://localhost/oauth2/authorization/google-login"));
 		// @formatter:on
 		// @formatter:on
 		verify(this.requestCache).saveRequest(any(), any());
 		verify(this.requestCache).saveRequest(any(), any());
 	}
 	}
@@ -187,7 +187,7 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/favicon.ico").accept(new MediaType("image", "*")))
 		this.mvc.perform(get("/favicon.ico").accept(new MediaType("image", "*")))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -199,7 +199,7 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/").header("X-Requested-With", "XMLHttpRequest"))
 		this.mvc.perform(get("/").header("X-Requested-With", "XMLHttpRequest"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -411,7 +411,7 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -421,7 +421,7 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/custom-login"));
+				.andExpect(redirectedUrl("http://localhost/custom-login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -433,7 +433,7 @@ public class OAuth2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 

+ 3 - 3
config/src/test/java/org/springframework/security/config/http/PlaceHolderAndELConfigTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -73,7 +73,7 @@ public class PlaceHolderAndELConfigTests {
 		// login-page setting
 		// login-page setting
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/secured"))
 		this.mvc.perform(get("/secured"))
-				.andExpect(redirectedUrl("/loginPage"));
+				.andExpect(redirectedUrl("http://localhost/loginPage"));
 		// login-processing-url setting
 		// login-processing-url setting
 		// default-target-url setting
 		// default-target-url setting
 		this.mvc.perform(post("/loginPage").param("username", "user").param("password", "password"))
 		this.mvc.perform(post("/loginPage").param("username", "user").param("password", "password"))
@@ -98,7 +98,7 @@ public class PlaceHolderAndELConfigTests {
 		// login-page setting
 		// login-page setting
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/secured"))
 		this.mvc.perform(get("/secured"))
-				.andExpect(redirectedUrl("/loginPage"));
+				.andExpect(redirectedUrl("http://localhost/loginPage"));
 		// login-processing-url setting
 		// login-processing-url setting
 		// default-target-url setting
 		// default-target-url setting
 		this.mvc.perform(post("/loginPage").param("username", "user").param("password", "password"))
 		this.mvc.perform(post("/loginPage").param("username", "user").param("password", "password"))

+ 3 - 3
config/src/test/java/org/springframework/security/config/http/Saml2LoginBeanDefinitionParserTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -161,7 +161,7 @@ public class Saml2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/saml2/authenticate/one"));
+				.andExpect(redirectedUrl("http://localhost/saml2/authenticate/one"));
 		// @formatter:on
 		// @formatter:on
 		verify(this.requestCache).saveRequest(any(), any());
 		verify(this.requestCache).saveRequest(any(), any());
 	}
 	}
@@ -172,7 +172,7 @@ public class Saml2LoginBeanDefinitionParserTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/"))
 		this.mvc.perform(get("/"))
 				.andExpect(status().is3xxRedirection())
 				.andExpect(status().is3xxRedirection())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 

+ 8 - 8
config/src/test/java/org/springframework/security/config/http/SecurityContextHolderAwareRequestConfigTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2018 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ public class SecurityContextHolderAwareRequestConfigTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/authenticate"))
 		this.mvc.perform(get("/authenticate"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -114,7 +114,7 @@ public class SecurityContextHolderAwareRequestConfigTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/authenticate"))
 		this.mvc.perform(get("/authenticate"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -137,10 +137,10 @@ public class SecurityContextHolderAwareRequestConfigTests {
 		// @formatter:off
 		// @formatter:off
 		this.mvc.perform(get("/authenticate"))
 		this.mvc.perform(get("/authenticate"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login"));
+				.andExpect(redirectedUrl("http://localhost/login"));
 		this.mvc.perform(get("/v2/authenticate"))
 		this.mvc.perform(get("/v2/authenticate"))
 				.andExpect(status().isFound())
 				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/login2"));
+				.andExpect(redirectedUrl("http://localhost/login2"));
 		// @formatter:on
 		// @formatter:on
 	}
 	}
 
 
@@ -177,10 +177,10 @@ public class SecurityContextHolderAwareRequestConfigTests {
 	@Test
 	@Test
 	public void servletLogoutWhenUsingCustomLogoutThenUsesSpringSecurity() throws Exception {
 	public void servletLogoutWhenUsingCustomLogoutThenUsesSpringSecurity() throws Exception {
 		this.spring.configLocations(this.xml("Logout")).autowire();
 		this.spring.configLocations(this.xml("Logout")).autowire();
-		// @formatter:off
 		this.mvc.perform(get("/authenticate"))
 		this.mvc.perform(get("/authenticate"))
-				.andExpect(status().isFound())
-				.andExpect(redirectedUrl("/signin"));
+			.andExpect(status().isFound())
+			.andExpect(redirectedUrl("http://localhost/signin"));
+		// @formatter:off
 		MvcResult result = this.mvc.perform(get("/good-login"))
 		MvcResult result = this.mvc.perform(get("/good-login"))
 				.andReturn();
 				.andReturn();
 		// @formatter:on
 		// @formatter:on

+ 4 - 4
config/src/test/kotlin/org/springframework/security/config/annotation/web/ExceptionHandlingDslTests.kt

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -217,7 +217,7 @@ class ExceptionHandlingDslTests {
         this.mockMvc.get("/")
         this.mockMvc.get("/")
                 .andExpect {
                 .andExpect {
                     status { isFound() }
                     status { isFound() }
-                    redirectedUrl("/custom-login")
+                    redirectedUrl("http://localhost/custom-login")
                 }
                 }
     }
     }
 
 
@@ -246,13 +246,13 @@ class ExceptionHandlingDslTests {
         this.mockMvc.get("/secured1")
         this.mockMvc.get("/secured1")
                 .andExpect {
                 .andExpect {
                     status { isFound() }
                     status { isFound() }
-                    redirectedUrl("/custom-login1")
+                    redirectedUrl("http://localhost/custom-login1")
                 }
                 }
 
 
         this.mockMvc.get("/secured2")
         this.mockMvc.get("/secured2")
                 .andExpect {
                 .andExpect {
                     status { isFound() }
                     status { isFound() }
-                    redirectedUrl("/custom-login2")
+                    redirectedUrl("http://localhost/custom-login2")
                 }
                 }
     }
     }
 
 

+ 2 - 2
config/src/test/kotlin/org/springframework/security/config/annotation/web/FormLoginDslTests.kt

@@ -143,7 +143,7 @@ class FormLoginDslTests {
         this.mockMvc.get("/")
         this.mockMvc.get("/")
                 .andExpect {
                 .andExpect {
                     status { isFound() }
                     status { isFound() }
-                    redirectedUrl("/login")
+                    redirectedUrl("http://localhost/login")
                 }
                 }
     }
     }
 
 
@@ -169,7 +169,7 @@ class FormLoginDslTests {
         this.mockMvc.get("/")
         this.mockMvc.get("/")
                 .andExpect {
                 .andExpect {
                     status { isFound() }
                     status { isFound() }
-                    redirectedUrl("/log-in")
+                    redirectedUrl("http://localhost/log-in")
                 }
                 }
     }
     }
 
 

+ 3 - 3
config/src/test/kotlin/org/springframework/security/config/annotation/web/RememberMeDslTests.kt

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2024 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -153,7 +153,7 @@ internal class RememberMeDslTests {
             cookie(expiredRememberMeCookie)
             cookie(expiredRememberMeCookie)
         }.andExpect {
         }.andExpect {
             status { isFound() }
             status { isFound() }
-            redirectedUrl("/login")
+            redirectedUrl("http://localhost/login")
         }
         }
     }
     }
 
 
@@ -229,7 +229,7 @@ internal class RememberMeDslTests {
             cookie(withoutKeyRememberMeCookie)
             cookie(withoutKeyRememberMeCookie)
         }.andExpect {
         }.andExpect {
             status { isFound() }
             status { isFound() }
-            redirectedUrl("/login")
+            redirectedUrl("http://localhost/login")
         }
         }
         val keyMvcResult = mockMvc.post("/login") {
         val keyMvcResult = mockMvc.post("/login") {
             loginRememberMeRequest()
             loginRememberMeRequest()

+ 104 - 0
docs/modules/ROOT/pages/migration-7/web.adoc

@@ -0,0 +1,104 @@
+= Web Migrations
+
+== Favor Relative URIs
+
+When redirecting to a login endpoint, Spring Security has favored absolute URIs in the past.
+For example, if you set your login page like so:
+
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+http
+    // ...
+    .formLogin((form) -> form.loginPage("/my-login"))
+    // ...
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+http {
+    formLogin {
+        loginPage = "/my-login"
+    }
+}
+----
+
+Xml::
++
+[source,kotlin,role="secondary"]
+----
+<http ...>
+    <form-login login-page="/my-login"/>
+</http>
+----
+======
+
+then when redirecting to `/my-login` Spring Security would use a `Location:` like the following:
+
+[source]
+----
+302 Found
+// ...
+Location: https://myapp.example.org/my-login
+----
+
+However, this is no longer necessary given that the RFC is was based on is now obsolete.
+
+In Spring Security 7, this is changed to use a relative URI like so:
+
+[source]
+----
+302 Found
+// ...
+Location: /my-login
+----
+
+Most applications will not notice a difference.
+However, in the event that this change causes problems, you can switch back to the Spring Security 6 behavior by setting the `favorRelativeUrls` value:
+
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("/my-login");
+entryPoint.setFavorRelativeUris(false);
+http
+    // ...
+    .exceptionHandling((exceptions) -> exceptions.authenticaitonEntryPoint(entryPoint))
+    // ...
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+LoginUrlAuthenticationEntryPoint entryPoint = LoginUrlAuthenticationEntryPoint("/my-login")
+entryPoint.setFavorRelativeUris(false)
+
+http {
+    exceptionHandling {
+        authenticationEntryPoint = entryPoint
+    }
+}
+----
+
+Xml::
++
+[source,kotlin,role="secondary"]
+----
+<http entry-point-ref="myEntryPoint">
+    <!-- ... -->
+</http>
+
+<b:bean id="myEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
+    <b:property name="favorRelativeUris" value="true"/>
+</b:bean>
+----
+======

+ 40 - 6
web/src/main/java/org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.java

@@ -78,6 +78,8 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
 
 
 	private boolean useForward = false;
 	private boolean useForward = false;
 
 
+	private boolean favorRelativeUris = false;
+
 	private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
 	private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
 
 
 	/**
 	/**
@@ -144,23 +146,41 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
 	protected String buildRedirectUrlToLoginPage(HttpServletRequest request, HttpServletResponse response,
 	protected String buildRedirectUrlToLoginPage(HttpServletRequest request, HttpServletResponse response,
 			AuthenticationException authException) {
 			AuthenticationException authException) {
 		String loginForm = determineUrlToUseForThisRequest(request, response, authException);
 		String loginForm = determineUrlToUseForThisRequest(request, response, authException);
-		if (UrlUtils.isAbsoluteUrl(loginForm) || !this.forceHttps || "https".equals(request.getScheme())) {
+		if (UrlUtils.isAbsoluteUrl(loginForm)) {
 			return loginForm;
 			return loginForm;
 		}
 		}
+		if (requiresRewrite(request)) {
+			return httpsUri(request, loginForm);
+		}
+		return this.favorRelativeUris ? loginForm : absoluteUri(request, loginForm).getUrl();
+	}
+
+	private boolean requiresRewrite(HttpServletRequest request) {
+		return this.forceHttps && "http".equals(request.getScheme());
+	}
+
+	private String httpsUri(HttpServletRequest request, String path) {
 		int serverPort = this.portResolver.getServerPort(request);
 		int serverPort = this.portResolver.getServerPort(request);
 		Integer httpsPort = this.portMapper.lookupHttpsPort(serverPort);
 		Integer httpsPort = this.portMapper.lookupHttpsPort(serverPort);
 		if (httpsPort == null) {
 		if (httpsPort == null) {
 			logger.warn(LogMessage.format("Unable to redirect to HTTPS as no port mapping found for HTTP port %s",
 			logger.warn(LogMessage.format("Unable to redirect to HTTPS as no port mapping found for HTTP port %s",
 					serverPort));
 					serverPort));
-			return loginForm;
+			return this.favorRelativeUris ? path : absoluteUri(request, path).getUrl();
 		}
 		}
+		RedirectUrlBuilder builder = absoluteUri(request, path);
+		builder.setScheme("https");
+		builder.setPort(httpsPort);
+		return builder.getUrl();
+	}
+
+	private RedirectUrlBuilder absoluteUri(HttpServletRequest request, String path) {
 		RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
 		RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
-		urlBuilder.setScheme("https");
+		urlBuilder.setScheme(request.getScheme());
 		urlBuilder.setServerName(request.getServerName());
 		urlBuilder.setServerName(request.getServerName());
-		urlBuilder.setPort(httpsPort);
+		urlBuilder.setPort(this.portResolver.getServerPort(request));
 		urlBuilder.setContextPath(request.getContextPath());
 		urlBuilder.setContextPath(request.getContextPath());
-		urlBuilder.setPathInfo(loginForm);
-		return urlBuilder.getUrl();
+		urlBuilder.setPathInfo(path);
+		return urlBuilder;
 	}
 	}
 
 
 	/**
 	/**
@@ -238,4 +258,18 @@ public class LoginUrlAuthenticationEntryPoint implements AuthenticationEntryPoin
 		return this.useForward;
 		return this.useForward;
 	}
 	}
 
 
+	/**
+	 * Favor using relative URIs when formulating a redirect.
+	 *
+	 * <p>
+	 * Note that a relative redirect is not always possible. For example, when redirecting
+	 * from {@code http} to {@code https}, the URL needs to be absolute.
+	 * </p>
+	 * @param favorRelativeUris whether to favor relative URIs or not
+	 * @since 6.5
+	 */
+	public void setFavorRelativeUris(boolean favorRelativeUris) {
+		this.favorRelativeUris = favorRelativeUris;
+	}
+
 }
 }

+ 55 - 5
web/src/test/java/org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPointTests.java

@@ -129,18 +129,18 @@ public class LoginUrlAuthenticationEntryPointTests {
 		ep.setPortResolver(new MockPortResolver(80, 443));
 		ep.setPortResolver(new MockPortResolver(80, 443));
 		ep.afterPropertiesSet();
 		ep.afterPropertiesSet();
 		ep.commence(request, response, null);
 		ep.commence(request, response, null);
-		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+		assertThat(response.getRedirectedUrl()).isEqualTo("https://www.example.com/bigWebApp/hello");
 		request.setServerPort(8443);
 		request.setServerPort(8443);
 		response = new MockHttpServletResponse();
 		response = new MockHttpServletResponse();
 		ep.setPortResolver(new MockPortResolver(8080, 8443));
 		ep.setPortResolver(new MockPortResolver(8080, 8443));
 		ep.commence(request, response, null);
 		ep.commence(request, response, null);
-		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+		assertThat(response.getRedirectedUrl()).isEqualTo("https://www.example.com:8443/bigWebApp/hello");
 		// access to https via http port
 		// access to https via http port
 		request.setServerPort(8080);
 		request.setServerPort(8080);
 		response = new MockHttpServletResponse();
 		response = new MockHttpServletResponse();
 		ep.setPortResolver(new MockPortResolver(8080, 8443));
 		ep.setPortResolver(new MockPortResolver(8080, 8443));
 		ep.commence(request, response, null);
 		ep.commence(request, response, null);
-		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+		assertThat(response.getRedirectedUrl()).isEqualTo("https://www.example.com:8443/bigWebApp/hello");
 	}
 	}
 
 
 	@Test
 	@Test
@@ -158,7 +158,7 @@ public class LoginUrlAuthenticationEntryPointTests {
 		request.setServerPort(80);
 		request.setServerPort(80);
 		MockHttpServletResponse response = new MockHttpServletResponse();
 		MockHttpServletResponse response = new MockHttpServletResponse();
 		ep.commence(request, response, null);
 		ep.commence(request, response, null);
-		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+		assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/bigWebApp/hello");
 	}
 	}
 
 
 	@Test
 	@Test
@@ -178,7 +178,7 @@ public class LoginUrlAuthenticationEntryPointTests {
 		ep.commence(request, response, null);
 		ep.commence(request, response, null);
 		// Response doesn't switch to HTTPS, as we didn't know HTTP port 8888 to HTTP port
 		// Response doesn't switch to HTTPS, as we didn't know HTTP port 8888 to HTTP port
 		// mapping
 		// mapping
-		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+		assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost:8888/bigWebApp/hello");
 	}
 	}
 
 
 	@Test
 	@Test
@@ -237,4 +237,54 @@ public class LoginUrlAuthenticationEntryPointTests {
 		assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet);
 		assertThatIllegalArgumentException().isThrownBy(ep::afterPropertiesSet);
 	}
 	}
 
 
+	@Test
+	public void commenceWhenFavorRelativeUrisThenHttpsSchemeNotIncluded() throws Exception {
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.setRequestURI("/some_path");
+		request.setScheme("https");
+		request.setServerName("www.example.com");
+		request.setContextPath("/bigWebApp");
+		request.setServerPort(443);
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		LoginUrlAuthenticationEntryPoint ep = new LoginUrlAuthenticationEntryPoint("/hello");
+		ep.setFavorRelativeUris(true);
+		ep.setPortMapper(new PortMapperImpl());
+		ep.setForceHttps(true);
+		ep.setPortMapper(new PortMapperImpl());
+		ep.setPortResolver(new MockPortResolver(80, 443));
+		ep.afterPropertiesSet();
+		ep.commence(request, response, null);
+		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+		request.setServerPort(8443);
+		response = new MockHttpServletResponse();
+		ep.setPortResolver(new MockPortResolver(8080, 8443));
+		ep.commence(request, response, null);
+		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+		// access to https via http port
+		request.setServerPort(8080);
+		response = new MockHttpServletResponse();
+		ep.setPortResolver(new MockPortResolver(8080, 8443));
+		ep.commence(request, response, null);
+		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+	}
+
+	@Test
+	public void commenceWhenFavorRelativeUrisThenHttpSchemeNotIncluded() throws Exception {
+		LoginUrlAuthenticationEntryPoint ep = new LoginUrlAuthenticationEntryPoint("/hello");
+		ep.setFavorRelativeUris(true);
+		ep.setPortMapper(new PortMapperImpl());
+		ep.setPortResolver(new MockPortResolver(80, 443));
+		ep.afterPropertiesSet();
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.setRequestURI("/some_path");
+		request.setContextPath("/bigWebApp");
+		request.setScheme("http");
+		request.setServerName("localhost");
+		request.setContextPath("/bigWebApp");
+		request.setServerPort(80);
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		ep.commence(request, response, null);
+		assertThat(response.getRedirectedUrl()).isEqualTo("/bigWebApp/hello");
+	}
+
 }
 }