diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java index 10a4a15293..89fdda5267 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java @@ -23,6 +23,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -132,10 +133,10 @@ public final class EndpointRequest { } @Override - protected void initialized(PathMappedEndpoints pathMappedEndpoints) { + protected void initialized(Supplier pathMappedEndpoints) { Set paths = new LinkedHashSet<>(); if (this.includes.isEmpty()) { - paths.addAll(pathMappedEndpoints.getAllPaths()); + paths.addAll(pathMappedEndpoints.get().getAllPaths()); } streamPaths(this.includes, pathMappedEndpoints).forEach(paths::add); streamPaths(this.excludes, pathMappedEndpoints).forEach(paths::remove); @@ -143,9 +144,9 @@ public final class EndpointRequest { } private Stream streamPaths(List source, - PathMappedEndpoints pathMappedEndpoints) { + Supplier pathMappedEndpoints) { return source.stream().filter(Objects::nonNull).map(this::getEndpointId) - .map(pathMappedEndpoints::getPath); + .map(pathMappedEndpoints.get()::getPath); } private String getEndpointId(Object source) { @@ -173,7 +174,7 @@ public final class EndpointRequest { @Override protected Mono matches(ServerWebExchange exchange, - PathMappedEndpoints context) { + Supplier context) { return this.delegate.matches(exchange); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index aa14db5b67..dcab2acf71 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -23,6 +23,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -129,13 +130,13 @@ public final class EndpointRequest { } @Override - protected void initialized(PathMappedEndpoints pathMappedEndpoints) { + protected void initialized(Supplier pathMappedEndpoints) { Set paths = new LinkedHashSet<>(); if (this.includes.isEmpty()) { - paths.addAll(pathMappedEndpoints.getAllPaths()); + paths.addAll(pathMappedEndpoints.get().getAllPaths()); } - streamPaths(this.includes, pathMappedEndpoints).forEach(paths::add); - streamPaths(this.excludes, pathMappedEndpoints).forEach(paths::remove); + streamPaths(this.includes, pathMappedEndpoints.get()).forEach(paths::add); + streamPaths(this.excludes, pathMappedEndpoints.get()).forEach(paths::remove); this.delegate = new OrRequestMatcher(getDelegateMatchers(paths)); } @@ -169,7 +170,7 @@ public final class EndpointRequest { @Override protected boolean matches(HttpServletRequest request, - PathMappedEndpoints context) { + Supplier context) { return this.delegate.matches(request); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java index a12ed21603..023c9f8421 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/PathRequest.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.security.servlet; +import java.util.function.Supplier; + import javax.servlet.http.HttpServletRequest; import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties; @@ -69,14 +71,14 @@ public final class PathRequest { } @Override - protected void initialized(H2ConsoleProperties h2ConsoleProperties) { + protected void initialized(Supplier h2ConsoleProperties) { this.delegate = new AntPathRequestMatcher( - h2ConsoleProperties.getPath() + "/**"); + h2ConsoleProperties.get().getPath() + "/**"); } @Override protected boolean matches(HttpServletRequest request, - H2ConsoleProperties context) { + Supplier context) { return this.delegate.matches(request); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java index b037ec82a5..eafc839db6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java @@ -20,6 +20,7 @@ import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -133,8 +134,9 @@ public final class StaticResourceRequest { } @Override - protected void initialized(ServerProperties serverProperties) { - this.delegate = new OrRequestMatcher(getDelegateMatchers(serverProperties)); + protected void initialized(Supplier serverProperties) { + this.delegate = new OrRequestMatcher( + getDelegateMatchers(serverProperties.get())); } private List getDelegateMatchers( @@ -149,7 +151,8 @@ public final class StaticResourceRequest { } @Override - protected boolean matches(HttpServletRequest request, ServerProperties context) { + protected boolean matches(HttpServletRequest request, + Supplier context) { return this.delegate.matches(request); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcher.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcher.java index 2a951d693a..f809689fab 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcher.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcher.java @@ -16,9 +16,10 @@ package org.springframework.boot.security.reactive; +import java.util.function.Supplier; + import reactor.core.publisher.Mono; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; @@ -32,9 +33,8 @@ import org.springframework.web.server.ServerWebExchange; * that is autowired in the usual way. * * @param The type of the context that the match method actually needs to use. Can be - * an {@link ApplicationContext}, a class of an {@link ApplicationContext#getBean(Class) - * existing bean} or a custom type that will be - * {@link AutowireCapableBeanFactory#createBean(Class, int, boolean) created} on demand. + * an {@link ApplicationContext} or a class of an {@link ApplicationContext#getBean(Class) + * existing bean}. * @author Madhura Bhave * @since 2.0.0 */ @@ -43,7 +43,7 @@ public abstract class ApplicationContextServerWebExchangeMatcher private final Class contextClass; - private volatile C context; + private volatile Supplier context; private final Object contextLock = new Object(); @@ -60,12 +60,13 @@ public abstract class ApplicationContextServerWebExchangeMatcher /** * Decides whether the rule implemented by the strategy matches the supplied exchange. * @param exchange the source exchange - * @param context the context instance + * @param context a supplier for the initialized context (may throw an exception) * @return if the exchange matches */ - protected abstract Mono matches(ServerWebExchange exchange, C context); + protected abstract Mono matches(ServerWebExchange exchange, + Supplier context); - protected C getContext(ServerWebExchange exchange) { + protected Supplier getContext(ServerWebExchange exchange) { if (this.context == null) { synchronized (this.contextLock) { if (this.context == null) { @@ -79,26 +80,19 @@ public abstract class ApplicationContextServerWebExchangeMatcher /** * Called once the context has been initialized. - * @param context the initialized context + * @param context a supplier for the initialized context (may throw an exception) */ - protected void initialized(C context) { + protected void initialized(Supplier context) { } @SuppressWarnings("unchecked") - private C createContext(ServerWebExchange exchange) { + private Supplier createContext(ServerWebExchange exchange) { ApplicationContext context = exchange.getApplicationContext(); Assert.state(context != null, "No WebApplicationContext found."); if (this.contextClass.isInstance(context)) { - return (C) context; - } - try { - return context.getBean(this.contextClass); - } - catch (NoSuchBeanDefinitionException ex) { - return (C) context.getAutowireCapableBeanFactory().createBean( - this.contextClass, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, - false); + return () -> (C) context; } + return () -> context.getBean(this.contextClass); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java index 6bb4e85f39..84441b3eb4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcher.java @@ -16,9 +16,10 @@ package org.springframework.boot.security.servlet; +import java.util.function.Supplier; + import javax.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -33,9 +34,8 @@ import org.springframework.web.context.support.WebApplicationContextUtils; * that is autowired in the usual way. * * @param The type of the context that the match method actually needs to use. Can be - * an {@link ApplicationContext}, a class of an {@link ApplicationContext#getBean(Class) - * existing bean} or a custom type that will be - * {@link AutowireCapableBeanFactory#createBean(Class, int, boolean) created} on demand. + * an {@link ApplicationContext} or a class of an {@link ApplicationContext#getBean(Class) + * existing bean}. * @author Phillip Webb * @since 2.0.0 */ @@ -43,7 +43,7 @@ public abstract class ApplicationContextRequestMatcher implements RequestMatc private final Class contextClass; - private volatile C context; + private volatile Supplier context; private final Object contextLock = new Object(); @@ -60,12 +60,12 @@ public abstract class ApplicationContextRequestMatcher implements RequestMatc /** * Decides whether the rule implemented by the strategy matches the supplied request. * @param request the source request - * @param context the context instance + * @param context a supplier for the initialized context (may throw an exception) * @return if the request matches */ - protected abstract boolean matches(HttpServletRequest request, C context); + protected abstract boolean matches(HttpServletRequest request, Supplier context); - private C getContext(HttpServletRequest request) { + private Supplier getContext(HttpServletRequest request) { if (this.context == null) { synchronized (this.contextLock) { if (this.context == null) { @@ -79,26 +79,19 @@ public abstract class ApplicationContextRequestMatcher implements RequestMatc /** * Called once the context has been initialized. - * @param context the initialized context + * @param context a supplier for the initialized context (may throw an exception) */ - protected void initialized(C context) { + protected void initialized(Supplier context) { } @SuppressWarnings("unchecked") - private C createContext(HttpServletRequest request) { + private Supplier createContext(HttpServletRequest request) { WebApplicationContext context = WebApplicationContextUtils .getRequiredWebApplicationContext(request.getServletContext()); if (this.contextClass.isInstance(context)) { - return (C) context; - } - try { - return context.getBean(this.contextClass); - } - catch (NoSuchBeanDefinitionException ex) { - return (C) context.getAutowireCapableBeanFactory().createBean( - this.contextClass, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, - false); + return () -> (C) context; } + return () -> context.getBean(this.contextClass); } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcherTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcherTests.java index 4c20c26bf9..0d1bd17dcd 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcherTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcherTests.java @@ -16,11 +16,14 @@ package org.springframework.boot.security.reactive; +import java.util.function.Supplier; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import reactor.core.publisher.Mono; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.StaticApplicationContext; import org.springframework.http.server.reactive.ServerHttpRequest; @@ -58,8 +61,8 @@ public class ApplicationContextServerWebExchangeMatcherTests { StaticApplicationContext context = (StaticApplicationContext) exchange .getApplicationContext(); assertThat(new TestApplicationContextServerWebExchangeMatcher<>( - ApplicationContext.class).callMatchesAndReturnProvidedContext(exchange)) - .isEqualTo(context); + ApplicationContext.class).callMatchesAndReturnProvidedContext(exchange) + .get()).isEqualTo(context); } @Test @@ -70,19 +73,17 @@ public class ApplicationContextServerWebExchangeMatcherTests { context.registerSingleton("existingBean", ExistingBean.class); assertThat( new TestApplicationContextServerWebExchangeMatcher<>(ExistingBean.class) - .callMatchesAndReturnProvidedContext(exchange)) + .callMatchesAndReturnProvidedContext(exchange).get()) .isEqualTo(context.getBean(ExistingBean.class)); } @Test - public void matchesWhenContextClassIsNewBeanShouldProvideBean() { + public void matchesWhenContextClassIsMissingBeanShouldProvideException() { ServerWebExchange exchange = createHttpWebHandlerAdapter(); - StaticApplicationContext context = (StaticApplicationContext) exchange - .getApplicationContext(); - context.registerSingleton("existingBean", ExistingBean.class); - assertThat(new TestApplicationContextServerWebExchangeMatcher<>(NewBean.class) - .callMatchesAndReturnProvidedContext(exchange).getBean()) - .isEqualTo(context.getBean(ExistingBean.class)); + Supplier supplier = new TestApplicationContextServerWebExchangeMatcher<>( + ExistingBean.class).callMatchesAndReturnProvidedContext(exchange); + this.thrown.expect(NoSuchBeanDefinitionException.class); + supplier.get(); } @Test @@ -139,24 +140,25 @@ public class ApplicationContextServerWebExchangeMatcherTests { static class TestApplicationContextServerWebExchangeMatcher extends ApplicationContextServerWebExchangeMatcher { - private C providedContext; + private Supplier providedContext; TestApplicationContextServerWebExchangeMatcher(Class context) { super(context); } - C callMatchesAndReturnProvidedContext(ServerWebExchange exchange) { + Supplier callMatchesAndReturnProvidedContext(ServerWebExchange exchange) { matches(exchange); return getProvidedContext(); } @Override - protected Mono matches(ServerWebExchange exchange, C context) { + protected Mono matches(ServerWebExchange exchange, + Supplier context) { this.providedContext = context; return MatchResult.match(); } - C getProvidedContext() { + Supplier getProvidedContext() { return this.providedContext; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcherTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcherTests.java index e1101c6ad4..58e6b9a1ba 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcherTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/servlet/ApplicationContextRequestMatcherTests.java @@ -16,12 +16,15 @@ package org.springframework.boot.security.servlet; +import java.util.function.Supplier; + import javax.servlet.http.HttpServletRequest; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockServletContext; @@ -51,7 +54,7 @@ public class ApplicationContextRequestMatcherTests { public void matchesWhenContextClassIsApplicationContextShouldProvideContext() { StaticWebApplicationContext context = createWebApplicationContext(); assertThat(new TestApplicationContextRequestMatcher<>(ApplicationContext.class) - .callMatchesAndReturnProvidedContext(context)).isEqualTo(context); + .callMatchesAndReturnProvidedContext(context).get()).isEqualTo(context); } @Test @@ -59,17 +62,17 @@ public class ApplicationContextRequestMatcherTests { StaticWebApplicationContext context = createWebApplicationContext(); context.registerSingleton("existingBean", ExistingBean.class); assertThat(new TestApplicationContextRequestMatcher<>(ExistingBean.class) - .callMatchesAndReturnProvidedContext(context)) + .callMatchesAndReturnProvidedContext(context).get()) .isEqualTo(context.getBean(ExistingBean.class)); } @Test - public void matchesWhenContextClassIsNewBeanShouldProvideBean() { + public void matchesWhenContextClassIsBeanThatDoesntExistShouldSupplyException() { StaticWebApplicationContext context = createWebApplicationContext(); - context.registerSingleton("existingBean", ExistingBean.class); - assertThat(new TestApplicationContextRequestMatcher<>(NewBean.class) - .callMatchesAndReturnProvidedContext(context).getBean()) - .isEqualTo(context.getBean(ExistingBean.class)); + Supplier supplier = new TestApplicationContextRequestMatcher<>( + ExistingBean.class).callMatchesAndReturnProvidedContext(context); + this.thrown.expect(NoSuchBeanDefinitionException.class); + supplier.get(); } private StaticWebApplicationContext createWebApplicationContext() { @@ -102,29 +105,31 @@ public class ApplicationContextRequestMatcherTests { static class TestApplicationContextRequestMatcher extends ApplicationContextRequestMatcher { - private C providedContext; + private Supplier providedContext; TestApplicationContextRequestMatcher(Class context) { super(context); } - public C callMatchesAndReturnProvidedContext(WebApplicationContext context) { + public Supplier callMatchesAndReturnProvidedContext( + WebApplicationContext context) { return callMatchesAndReturnProvidedContext( new MockHttpServletRequest(context.getServletContext())); } - public C callMatchesAndReturnProvidedContext(HttpServletRequest request) { + public Supplier callMatchesAndReturnProvidedContext( + HttpServletRequest request) { matches(request); return getProvidedContext(); } @Override - protected boolean matches(HttpServletRequest request, C context) { + protected boolean matches(HttpServletRequest request, Supplier context) { this.providedContext = context; return false; } - public C getProvidedContext() { + public Supplier getProvidedContext() { return this.providedContext; }