Temporarily remove security matchers

Temporarily back out `SpringBootSecurity` to enable easier
package refactoring.

See gh-10261
This commit is contained in:
Phillip Webb 2017-09-04 23:52:03 -07:00
parent ecb8461e8c
commit 0f99b29b1a
7 changed files with 27 additions and 390 deletions

View File

@ -16,14 +16,10 @@
package org.springframework.boot.autoconfigure.security;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorController;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.endpoint.DefaultEndpointPathResolver;
import org.springframework.boot.endpoint.EndpointPathResolver;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -56,20 +52,6 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
AuthenticationManagerConfiguration.class, SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public EndpointPathResolver endpointPathResolver() {
return new DefaultEndpointPathResolver();
}
@Bean
public SpringBootSecurity springBootSecurity(
EndpointPathResolver endpointPathResolver,
ObjectProvider<ErrorController> errorController) {
return new SpringBootSecurity(endpointPathResolver,
errorController.getIfAvailable());
}
@Bean
@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
public DefaultAuthenticationEventPublisher authenticationEventPublisher(

View File

@ -1,141 +0,0 @@
/*
* Copyright 2012-2017 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
*
* http://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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorController;
import org.springframework.boot.endpoint.Endpoint;
import org.springframework.boot.endpoint.EndpointPathResolver;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Provides request matchers that can be used to configure security for static resources
* and the error controller path in a custom {@link WebSecurityConfigurerAdapter}.
*
* @author Madhura Bhave
* @since 2.0.0
*/
public final class SpringBootSecurity {
/**
* Used as a wildcard matcher for all endpoints.
*/
public final static String ALL_ENDPOINTS = "**";
private static String[] STATIC_RESOURCES = new String[] { "/css/**", "/js/**",
"/images/**", "/webjars/**", "/**/favicon.ico" };
private final EndpointPathResolver endpointPathResolver;
private final ErrorController errorController;
SpringBootSecurity(EndpointPathResolver endpointPathResolver,
ErrorController errorController) {
this.endpointPathResolver = endpointPathResolver;
this.errorController = errorController;
}
/**
* Returns a {@link RequestMatcher} that matches on all endpoint paths with given ids.
* @param ids the endpoint ids
* @return the request matcher
*/
public RequestMatcher endpointIds(String... ids) {
Assert.notEmpty(ids, "At least one endpoint id must be specified.");
List<String> pathList = Arrays.asList(ids);
if (pathList.contains(ALL_ENDPOINTS)) {
return new AntPathRequestMatcher(
this.endpointPathResolver.resolvePath(ALL_ENDPOINTS), null);
}
return getEndpointsRequestMatcher(pathList);
}
/**
* Returns a {@link RequestMatcher} that matches on all endpoint paths for the given
* classes with the {@link Endpoint} annotation.
* @param endpoints the endpoint classes
* @return the request matcher
*/
public RequestMatcher endpoints(Class<?>... endpoints) {
Assert.notEmpty(endpoints, "At least one endpoint must be specified.");
List<String> paths = Arrays.stream(endpoints).map((e) -> {
if (e.isAnnotationPresent(Endpoint.class)) {
return e.getAnnotation(Endpoint.class).id();
}
throw new IllegalArgumentException(
"Only classes annotated with @Endpoint are supported.");
}).collect(Collectors.toList());
return getEndpointsRequestMatcher(paths);
}
/**
* Returns a {@link RequestMatcher} that matches on all static resources.
* @return the request matcher
*/
public RequestMatcher staticResources() {
return getRequestMatcher(STATIC_RESOURCES);
}
/**
* Returns a {@link RequestMatcher} that matches on the {@link ErrorController} path,
* if present.
* @return the request matcher
*/
public RequestMatcher error() {
if (this.errorController == null) {
throw new IllegalStateException(
"Path for error controller could not be determined.");
}
String path = normalizePath(this.errorController.getErrorPath());
return new AntPathRequestMatcher(path + "/**", null);
}
private RequestMatcher getEndpointsRequestMatcher(List<String> ids) {
List<RequestMatcher> matchers = new ArrayList<>();
for (String id : ids) {
String path = this.endpointPathResolver.resolvePath(id);
matchers.add(new AntPathRequestMatcher(path + "/**", null));
}
return new OrRequestMatcher(matchers);
}
private static RequestMatcher getRequestMatcher(String... paths) {
List<RequestMatcher> matchers = new ArrayList<>();
for (String path : paths) {
matchers.add(new AntPathRequestMatcher(path, null));
}
return new OrRequestMatcher(matchers);
}
private String normalizePath(String errorPath) {
String result = StringUtils.cleanPath(errorPath);
if (!result.startsWith("/")) {
result = "/" + result;
}
return result;
}
}

View File

@ -1,178 +0,0 @@
/*
* Copyright 2012-2017 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
*
* http://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;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorController;
import org.springframework.boot.endpoint.Endpoint;
import org.springframework.boot.endpoint.EndpointPathResolver;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SpringBootSecurity}.
*
* @author Madhura Bhave
*/
public class SpringBootSecurityTests {
private SpringBootSecurity bootSecurity;
private EndpointPathResolver endpointPathResolver = new TestEndpointPathResolver();
private ErrorController errorController = new TestErrorController();
private MockHttpServletRequest request = new MockHttpServletRequest();
private static String[] STATIC_RESOURCES = new String[] { "/css/**", "/js/**",
"/images/**", "/webjars/**", "/**/favicon.ico" };
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setUp() throws Exception {
this.bootSecurity = new SpringBootSecurity(this.endpointPathResolver,
this.errorController);
}
@Test
public void endpointIdsShouldThrowIfNoEndpointPaths() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("At least one endpoint id must be specified.");
this.bootSecurity.endpointIds();
}
@Test
public void endpointIdsShouldReturnRequestMatcherWithEndpointPaths()
throws Exception {
RequestMatcher requestMatcher = this.bootSecurity.endpointIds("id-1", "id-2");
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
this.request.setServletPath("/test/id-1");
assertThat(requestMatcher.matches(this.request)).isTrue();
this.request.setServletPath("/test/id-2");
assertThat(requestMatcher.matches(this.request)).isTrue();
this.request.setServletPath("/test/other-id");
assertThat(requestMatcher.matches(this.request)).isFalse();
}
@Test
public void endpointIdsShouldReturnRequestMatcherWithAllEndpointPaths()
throws Exception {
RequestMatcher requestMatcher = this.bootSecurity
.endpointIds(SpringBootSecurity.ALL_ENDPOINTS);
this.request.setServletPath("/test/id-1");
assertThat(requestMatcher.matches(this.request)).isTrue();
this.request.setServletPath("/test/id-2");
assertThat(requestMatcher.matches(this.request)).isTrue();
this.request.setServletPath("/test/other-id");
assertThat(requestMatcher.matches(this.request)).isTrue();
}
@Test
public void endpointsShouldReturnRequestMatcherWithEndpointPaths() throws Exception {
RequestMatcher requestMatcher = this.bootSecurity.endpoints(TestEndpoint1.class);
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
this.request.setServletPath("/test/id-1");
assertThat(requestMatcher.matches(this.request)).isTrue();
this.request.setServletPath("/test/id-2");
assertThat(requestMatcher.matches(this.request)).isFalse();
}
@Test
public void endpointsShouldThrowIfNoEndpointPaths() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("At least one endpoint must be specified.");
this.bootSecurity.endpoints();
}
@Test
public void endpointsShouldThrowExceptionWhenClassNotEndpoint() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Only classes annotated with @Endpoint are supported.");
this.bootSecurity.endpoints(FakeEndpoint.class);
}
@Test
public void staticResourcesShouldReturnRequestMatcherWithStaticResources()
throws Exception {
RequestMatcher requestMatcher = this.bootSecurity.staticResources();
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
for (String resource : STATIC_RESOURCES) {
this.request.setServletPath(resource);
assertThat(requestMatcher.matches(this.request)).isTrue();
}
}
@Test
public void errorShouldReturnRequestMatcherWithErrorControllerPath()
throws Exception {
RequestMatcher requestMatcher = this.bootSecurity.error();
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
this.request.setServletPath("/test/error");
assertThat(requestMatcher.matches(this.request)).isTrue();
}
@Test
public void errorShouldThrowExceptionWhenNoErrorController() throws Exception {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("Path for error controller could not be determined.");
this.bootSecurity = new SpringBootSecurity(this.endpointPathResolver, null);
this.bootSecurity.error();
}
static class TestEndpointPathResolver implements EndpointPathResolver {
@Override
public String resolvePath(String endpointId) {
return "/test/" + endpointId;
}
}
static class TestErrorController implements ErrorController {
@Override
public String getErrorPath() {
return "/test/error";
}
}
@Endpoint(id = "id-1")
static class TestEndpoint1 {
}
@Endpoint(id = "id-2")
static class TestEndpoint2 {
}
static class FakeEndpoint {
}
}

View File

@ -1,6 +1,5 @@
package sample.actuator.customsecurity;
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@ -9,12 +8,6 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private SpringBootSecurity bootSecurity;
public SecurityConfiguration(SpringBootSecurity bootSecurity) {
this.bootSecurity = bootSecurity;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password")
@ -24,18 +17,18 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// FIXME
// @formatter:off
http.authorizeRequests()
.requestMatchers(this.bootSecurity.endpointIds("status", "info")).permitAll()
.requestMatchers(this.bootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS)).hasRole("ACTUATOR")
.requestMatchers(this.bootSecurity.staticResources()).permitAll()
.antMatchers("/foo").permitAll()
.antMatchers("/**").hasRole("USER")
.and()
.cors()
.and()
.httpBasic();
// http.authorizeRequests()
// .requestMatchers(endpointIds("status", "info")).permitAll()
// .requestMatchers(endpointIds(SpringBootSecurity.ALL_ENDPOINTS)).hasRole("ACTUATOR")
// .requestMatchers(staticResources()).permitAll()
// .antMatchers("/foo").permitAll()
// .antMatchers("/**").hasRole("USER")
// .and()
// .cors()
// .and()
// .httpBasic();
// @formatter:on
}

View File

@ -1,6 +1,5 @@
package sample.secure.oauth2.actuator;
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@ -15,19 +14,14 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
@Order(2) // before the resource server configuration
public class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final SpringBootSecurity springBootSecurity;
public ActuatorSecurityConfiguration(SpringBootSecurity springBootSecurity) {
this.springBootSecurity = springBootSecurity;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// FIXME
// @formatter:off
http.requestMatcher(this.springBootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS)).authorizeRequests()
.antMatchers("/**").authenticated()
.and()
.httpBasic();
// http.requestMatcher(ALL_ENDPOINTS).authorizeRequests()
// .antMatchers("/**").authenticated()
// .and()
// .httpBasic();
// @formatter:on
}

View File

@ -20,7 +20,6 @@ import java.util.Date;
import java.util.Map;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@ -103,17 +102,11 @@ public class SampleMethodSecurityApplication implements WebMvcConfigurer {
@Order(1)
protected static class ActuatorSecurity extends WebSecurityConfigurerAdapter {
private final SpringBootSecurity springBootSecurity;
public ActuatorSecurity(SpringBootSecurity springBootSecurity) {
this.springBootSecurity = springBootSecurity;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(
this.springBootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS))
.authorizeRequests().anyRequest().authenticated().and().httpBasic();
// FIXME
// http.requestMatcher(ALL_ENDPOINTS)
// .authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}

View File

@ -20,7 +20,6 @@ import java.util.Date;
import java.util.Map;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@ -61,22 +60,17 @@ public class SampleWebSecureApplication implements WebMvcConfigurer {
@Configuration
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
private final SpringBootSecurity springBootSecurity;
public ApplicationSecurity(SpringBootSecurity springBootSecurity) {
this.springBootSecurity = springBootSecurity;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// FIXME
// @formatter:off
http.authorizeRequests()
.requestMatchers(this.springBootSecurity.staticResources()).permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
.and()
.logout().permitAll();
// http.authorizeRequests()
// .requestMatchers(staticResources()).permitAll()
// .anyRequest().fullyAuthenticated()
// .and()
// .formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
// .and()
// .logout().permitAll();
// @formatter:on
}