Deny unauthorized access to the error page

Fixes gh-26356

Co-authored-by Andy Wilkinson <wilkinsona@vmware.com>
This commit is contained in:
Madhura Bhave
2021-05-17 16:50:20 -07:00
parent 8bd3d53085
commit dd1d1482dc
13 changed files with 377 additions and 11 deletions

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2012-2021 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.boot.autoconfigure.security.servlet;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
/**
* Configures the {@link ErrorPageSecurityFilter}.
*
* @author Madhura Bhave
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
class ErrorPageSecurityFilterConfiguration {
@Bean
@ConditionalOnBean(WebInvocationPrivilegeEvaluator.class)
FilterRegistrationBean<ErrorPageSecurityFilter> errorPageSecurityInterceptor(ApplicationContext context) {
FilterRegistrationBean<ErrorPageSecurityFilter> registration = new FilterRegistrationBean<>(
new ErrorPageSecurityFilter(context));
registration.setDispatcherTypes(EnumSet.of(DispatcherType.ERROR));
return registration;
}
}

View File

@@ -41,7 +41,7 @@ import org.springframework.security.authentication.DefaultAuthenticationEventPub
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class,
SecurityDataConfiguration.class })
SecurityDataConfiguration.class, ErrorPageSecurityFilterConfiguration.class })
public class SecurityAutoConfiguration {
@Bean

View File

@@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.security.servlet;
import java.security.interfaces.RSAPublicKey;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
@@ -36,11 +37,14 @@ import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter;
import org.springframework.boot.web.servlet.filter.OrderedFilter;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.mock.web.MockServletContext;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
@@ -53,6 +57,7 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -224,6 +229,19 @@ class SecurityAutoConfigurationTests {
.run((context) -> assertThat(context.getBean(JwtProperties.class).getPublicKey()).isNotNull());
}
@Test
@SuppressWarnings("unchecked")
void filterRegistrationBeanForErrorPageSecurityInterceptor() {
this.contextRunner.withInitializer((context) -> context.setServletContext(new MockServletContext()))
.run(((context) -> {
FilterRegistrationBean<?> bean = context.getBean(FilterRegistrationBean.class);
assertThat(bean.getFilter()).isInstanceOf(ErrorPageSecurityFilter.class);
EnumSet<DispatcherType> dispatcherTypes = (EnumSet<DispatcherType>) ReflectionTestUtils
.getField(bean, "dispatcherTypes");
assertThat(dispatcherTypes).containsExactly(DispatcherType.ERROR);
}));
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
static class EntityConfiguration {

View File

@@ -34,6 +34,7 @@ import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredFilter;
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
import org.springframework.context.annotation.Bean;
@@ -81,6 +82,7 @@ class FilterOrderingIntegrationTests {
assertThat(iterator.next()).isInstanceOf(Filter.class);
assertThat(iterator.next()).isInstanceOf(Filter.class);
assertThat(iterator.next()).isInstanceOf(OrderedRequestContextFilter.class);
assertThat(iterator.next()).isInstanceOf(ErrorPageSecurityFilter.class);
assertThat(iterator.next()).isInstanceOf(FilterChainProxy.class);
}