Use PortResolver Beans by Default
Closes gh-16664
This commit is contained in:
+14
@@ -21,6 +21,7 @@ import java.util.Collections;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.PortResolver;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
@@ -272,6 +274,10 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
if (portMapper != null) {
|
||||
this.authenticationEntryPoint.setPortMapper(portMapper);
|
||||
}
|
||||
PortResolver portResolver = getBeanOrNull(http, PortResolver.class);
|
||||
if (portResolver != null) {
|
||||
this.authenticationEntryPoint.setPortResolver(portResolver);
|
||||
}
|
||||
RequestCache requestCache = http.getSharedObject(RequestCache.class);
|
||||
if (requestCache != null) {
|
||||
this.defaultSuccessHandler.setRequestCache(requestCache);
|
||||
@@ -412,6 +418,14 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
this.authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(loginPage);
|
||||
}
|
||||
|
||||
private <C> C getBeanOrNull(B http, Class<C> clazz) {
|
||||
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
return context.getBeanProvider(clazz).getIfUnique();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T getSelf() {
|
||||
return (T) this;
|
||||
|
||||
+7
-1
@@ -83,6 +83,7 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.PortResolver;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
@@ -578,8 +579,13 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
|
||||
RequestMatcher formLoginNotEnabled = getFormLoginNotEnabledRequestMatcher(http);
|
||||
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<>();
|
||||
LoginUrlAuthenticationEntryPoint loginUrlEntryPoint = new LoginUrlAuthenticationEntryPoint(providerLoginPage);
|
||||
PortResolver portResolver = getBeanOrNull(ResolvableType.forClass(PortResolver.class));
|
||||
if (portResolver != null) {
|
||||
loginUrlEntryPoint.setPortResolver(portResolver);
|
||||
}
|
||||
entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher),
|
||||
formLoginNotEnabled), new LoginUrlAuthenticationEntryPoint(providerLoginPage));
|
||||
formLoginNotEnabled), loginUrlEntryPoint);
|
||||
DelegatingAuthenticationEntryPoint loginEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
|
||||
loginEntryPoint.setDefaultEntryPoint(this.getAuthenticationEntryPoint());
|
||||
return loginEntryPoint;
|
||||
|
||||
+7
-1
@@ -52,6 +52,7 @@ import org.springframework.security.saml2.provider.service.web.authentication.Op
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
|
||||
import org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.PortResolver;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
@@ -344,8 +345,13 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
|
||||
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
|
||||
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<>();
|
||||
LoginUrlAuthenticationEntryPoint loginUrlEntryPoint = new LoginUrlAuthenticationEntryPoint(providerLoginPage);
|
||||
PortResolver portResolver = getBeanOrNull(http, PortResolver.class);
|
||||
if (portResolver != null) {
|
||||
loginUrlEntryPoint.setPortResolver(portResolver);
|
||||
}
|
||||
entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher)),
|
||||
new LoginUrlAuthenticationEntryPoint(providerLoginPage));
|
||||
loginUrlEntryPoint);
|
||||
DelegatingAuthenticationEntryPoint loginEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
|
||||
loginEntryPoint.setDefaultEntryPoint(this.getAuthenticationEntryPoint());
|
||||
return loginEntryPoint;
|
||||
|
||||
+4
@@ -240,6 +240,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private RuntimeBeanReference createPortResolver(BeanReference portMapper, ParserContext pc) {
|
||||
String beanName = "portResolver";
|
||||
if (pc.getRegistry().containsBeanDefinition(beanName)) {
|
||||
return new RuntimeBeanReference(beanName);
|
||||
}
|
||||
RootBeanDefinition portResolver = new RootBeanDefinition(PortResolverImpl.class);
|
||||
portResolver.getPropertyValues().addPropertyValue("portMapper", portMapper);
|
||||
String portResolverName = pc.getReaderContext().generateBeanName(portResolver);
|
||||
|
||||
+37
@@ -38,6 +38,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.PortResolver;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
@@ -378,6 +379,13 @@ public class FormLoginConfigurerTests {
|
||||
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenPortResolverBeanThenPortResolverUsed() throws Exception {
|
||||
this.spring.register(CustomPortResolverConfig.class).autowire();
|
||||
this.mockMvc.perform(get("/requires-authentication")).andExpect(status().is3xxRedirection());
|
||||
verify(this.spring.getContext().getBean(PortResolver.class)).getServerPort(any());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class RequestCacheConfig {
|
||||
@@ -723,6 +731,35 @@ public class FormLoginConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class CustomPortResolverConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((requests) -> requests
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.formLogin(withDefaults())
|
||||
.requestCache(withDefaults());
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
PortResolver portResolver() {
|
||||
return mock(PortResolver.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
UserDetailsService userDetailsService() {
|
||||
return new InMemoryUserDetailsManager(PasswordEncodedUser.user());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
|
||||
|
||||
@Override
|
||||
|
||||
+13
@@ -35,6 +35,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.PortResolver;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
@@ -210,6 +212,17 @@ public class FormLoginConfigTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void portResolver() throws Exception {
|
||||
this.spring.configLocations(this.xml("PortResolverBean")).autowire();
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/requires-authentication"))
|
||||
.andExpect(status().is3xxRedirection());
|
||||
// @formatter:on
|
||||
PortResolver portResolver = this.spring.getContext().getBean(PortResolver.class);
|
||||
verify(portResolver, atLeastOnce()).getServerPort(any());
|
||||
}
|
||||
|
||||
private Filter getFilter(ApplicationContext context, Class<? extends Filter> filterClass) {
|
||||
FilterChainProxy filterChain = context.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class);
|
||||
List<Filter> filters = filterChain.getFilters("/any");
|
||||
|
||||
+24
@@ -34,6 +34,7 @@ import org.springframework.security.core.userdetails.User
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
||||
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
|
||||
import org.springframework.security.web.PortResolver
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
|
||||
@@ -240,6 +241,29 @@ class FormLoginDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `portResolerBean is used`() {
|
||||
this.spring.register(PortResolverBeanConfig::class.java, AllSecuredConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
val portResolver = this.spring.context.getBean(PortResolver::class.java)
|
||||
every { portResolver.getServerPort(any()) }.returns(1234)
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
status().isFound
|
||||
redirectedUrl("http://localhost:1234/login")
|
||||
}
|
||||
|
||||
verify { portResolver.getServerPort(any()) }
|
||||
}
|
||||
|
||||
@Configuration
|
||||
open class PortResolverBeanConfig {
|
||||
@Bean
|
||||
open fun portResolverBean(): PortResolver {
|
||||
return mockk()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when custom failure url then used`() {
|
||||
this.spring.register(FailureHandlerConfig::class.java, UserConfig::class.java).autowire()
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2002-2022 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.
|
||||
-->
|
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<b:bean id="portResolver" class="org.mockito.Mockito" factory-method="mock" scope="singleton">
|
||||
<b:constructor-arg value="org.springframework.security.web.PortResolver" type="java.lang.Class"/>
|
||||
</b:bean>
|
||||
|
||||
<http auto-config="true">
|
||||
<csrf disabled="true"/>
|
||||
<intercept-url pattern="/**" access="authenticated"/>
|
||||
</http>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
||||
Reference in New Issue
Block a user