Fix request matcher management context support
Fix caching issues in `ApplicationContextRequestMatcher` and allow subclasses to ignore an application context entirely. Update existing matcher implementations so that they deal with the management context correctly. Prior to this commit, the `ApplicationContextRequestMatcher` would return a context cached from the first request. It also didn't provide any way to ignore a context. This meant that if the user was running the management server on a different port the matching results could be inconsistent depending on if the first request arrived on the regular context or the management context. It also meant that we could not distinguish between the regular context and the management context when matching. Closes gh-18012
This commit is contained in:
@@ -23,8 +23,10 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties;
|
||||
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
|
||||
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
|
||||
import org.springframework.boot.web.context.WebServerApplicationContext;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Factory that can be used to create a {@link RequestMatcher} for commonly used paths.
|
||||
@@ -69,6 +71,11 @@ public final class PathRequest {
|
||||
super(H2ConsoleProperties.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean ignoreApplicationContext(WebApplicationContext applicationContext) {
|
||||
return WebServerApplicationContext.hasServerNamespace(applicationContext, "management");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialized(Supplier<H2ConsoleProperties> h2ConsoleProperties) {
|
||||
this.delegate = new AntPathRequestMatcher(h2ConsoleProperties.get().getPath() + "/**");
|
||||
|
||||
@@ -29,10 +29,12 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
|
||||
import org.springframework.boot.web.context.WebServerApplicationContext;
|
||||
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.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Used to create a {@link RequestMatcher} for static resources in commonly used
|
||||
@@ -144,6 +146,11 @@ public final class StaticResourceRequest {
|
||||
.map(dispatcherServletPath::getRelativePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean ignoreApplicationContext(WebApplicationContext applicationContext) {
|
||||
return WebServerApplicationContext.hasServerNamespace(applicationContext, "management");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matches(HttpServletRequest request, Supplier<DispatcherServletPath> context) {
|
||||
return this.delegate.matches(request);
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -51,8 +50,20 @@ public class PathRequestTests {
|
||||
assertMatcher(matcher).doesNotMatch("/js/file.js");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toH2ConsoleWhenManagementContextShouldNeverMatch() {
|
||||
RequestMatcher matcher = PathRequest.toH2Console();
|
||||
assertMatcher(matcher, "management").doesNotMatch("/h2-console");
|
||||
assertMatcher(matcher, "management").doesNotMatch("/h2-console/subpath");
|
||||
assertMatcher(matcher, "management").doesNotMatch("/js/file.js");
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher) {
|
||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||
return assertMatcher(matcher, null);
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String serverNamespace) {
|
||||
TestWebApplicationContext context = new TestWebApplicationContext(serverNamespace);
|
||||
context.registerBean(ServerProperties.class);
|
||||
context.registerBean(H2ConsoleProperties.class);
|
||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
@@ -53,6 +52,16 @@ public class StaticResourceRequestTests {
|
||||
assertMatcher(matcher).doesNotMatch("/bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void atCommonLocationsWhenManagementContextShouldNeverMatch() {
|
||||
RequestMatcher matcher = this.resourceRequest.atCommonLocations();
|
||||
assertMatcher(matcher, "management").doesNotMatch("/css/file.css");
|
||||
assertMatcher(matcher, "management").doesNotMatch("/js/file.js");
|
||||
assertMatcher(matcher, "management").doesNotMatch("/images/file.css");
|
||||
assertMatcher(matcher, "management").doesNotMatch("/webjars/file.css");
|
||||
assertMatcher(matcher, "management").doesNotMatch("/foo/favicon.ico");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void atCommonLocationsWithExcludeShouldNotMatchExcluded() {
|
||||
RequestMatcher matcher = this.resourceRequest.atCommonLocations().excluding(StaticResourceLocation.CSS);
|
||||
@@ -70,8 +79,8 @@ public class StaticResourceRequestTests {
|
||||
@Test
|
||||
public void atLocationWhenHasServletPathShouldMatchLocation() {
|
||||
RequestMatcher matcher = this.resourceRequest.at(StaticResourceLocation.CSS);
|
||||
assertMatcher(matcher, "/foo").matches("/foo", "/css/file.css");
|
||||
assertMatcher(matcher, "/foo").doesNotMatch("/foo", "/js/file.js");
|
||||
assertMatcher(matcher, null, "/foo").matches("/foo", "/css/file.css");
|
||||
assertMatcher(matcher, null, "/foo").doesNotMatch("/foo", "/js/file.js");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -87,15 +96,16 @@ public class StaticResourceRequestTests {
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher) {
|
||||
DispatcherServletPath dispatcherServletPath = () -> "";
|
||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||
context.registerBean(DispatcherServletPath.class, () -> dispatcherServletPath);
|
||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||
return assertMatcher(matcher, null, "");
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String path) {
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String serverNamespace) {
|
||||
return assertMatcher(matcher, serverNamespace, "");
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String serverNamespace, String path) {
|
||||
DispatcherServletPath dispatcherServletPath = () -> path;
|
||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||
TestWebApplicationContext context = new TestWebApplicationContext(serverNamespace);
|
||||
context.registerBean(DispatcherServletPath.class, () -> dispatcherServletPath);
|
||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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 org.springframework.boot.web.context.WebServerApplicationContext;
|
||||
import org.springframework.boot.web.server.WebServer;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
|
||||
/**
|
||||
* Test {@link StaticWebApplicationContext} that also implements
|
||||
* {@link WebServerApplicationContext}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class TestWebApplicationContext extends StaticWebApplicationContext implements WebServerApplicationContext {
|
||||
|
||||
private final String serverNamespace;
|
||||
|
||||
TestWebApplicationContext(String serverNamespace) {
|
||||
this.serverNamespace = serverNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebServer getWebServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerNamespace() {
|
||||
return this.serverNamespace;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user