Skip to content

Commit e80c22c

Browse files
committed
Add RequestMatcher for H2 console
Fixes spring-projectsgh-11704
1 parent db2580f commit e80c22c

File tree

7 files changed

+234
-29
lines changed

7 files changed

+234
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.security.servlet;
18+
19+
import javax.servlet.http.HttpServletRequest;
20+
21+
import org.springframework.boot.autoconfigure.h2.H2ConsoleProperties;
22+
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
23+
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
24+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
25+
import org.springframework.security.web.util.matcher.RequestMatcher;
26+
27+
/**
28+
* Factory that can be used to create a {@link RequestMatcher} for commonly used paths.
29+
*
30+
* @author Madhura Bhave
31+
* @author Phillip Webb
32+
* @since 2.0.0
33+
*/
34+
public final class PathRequest {
35+
36+
private PathRequest() {
37+
}
38+
39+
/**
40+
* Returns a {@link StaticResourceRequest} that can be used to create a matcher for
41+
* {@link StaticResourceLocation Locations}.
42+
* @return a {@link StaticResourceRequest}
43+
*/
44+
public static StaticResourceRequest toStaticResources() {
45+
return StaticResourceRequest.get();
46+
}
47+
48+
/**
49+
* Returns a matcher that includes the H2 console location. For example: <pre class="code">
50+
* PathRequest.toH2Console()
51+
* </pre>
52+
* @return the configured {@link RequestMatcher}
53+
*/
54+
public static H2ConsoleRequestMatcher toH2Console() {
55+
return new H2ConsoleRequestMatcher();
56+
}
57+
58+
/**
59+
* The request matcher used to match against h2 console path.
60+
*/
61+
public static final class H2ConsoleRequestMatcher
62+
extends ApplicationContextRequestMatcher<H2ConsoleProperties> {
63+
64+
private RequestMatcher delegate;
65+
66+
private H2ConsoleRequestMatcher() {
67+
super(H2ConsoleProperties.class);
68+
}
69+
70+
@Override
71+
protected void initialized(H2ConsoleProperties h2ConsoleProperties) {
72+
this.delegate = new AntPathRequestMatcher(h2ConsoleProperties.getPath());
73+
}
74+
75+
@Override
76+
protected boolean matches(HttpServletRequest request, H2ConsoleProperties context) {
77+
return this.delegate.matches(request);
78+
}
79+
80+
}
81+
82+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequest.java

+21-10
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@
3434
import org.springframework.util.Assert;
3535

3636
/**
37-
* Factory that can be used to create a {@link RequestMatcher} for static resources in
38-
* commonly used locations.
37+
* Used to create a {@link RequestMatcher} for static resources in
38+
* commonly used locations. Returned by {@link PathRequest#toStaticResources()}.
3939
*
4040
* @author Madhura Bhave
4141
* @author Phillip Webb
4242
* @since 2.0.0
43+
* @see PathRequest
4344
*/
4445
public final class StaticResourceRequest {
4546

47+
private static final StaticResourceRequest INSTANCE = new StaticResourceRequest();
48+
4649
private StaticResourceRequest() {
4750
}
4851

@@ -52,41 +55,49 @@ private StaticResourceRequest() {
5255
* {@link StaticResourceRequestMatcher#excluding(StaticResourceLocation, StaticResourceLocation...)
5356
* excluding} method can be used to remove specific locations if required. For
5457
* example: <pre class="code">
55-
* StaticResourceRequest.toCommonLocations().excluding(StaticResourceLocation.CSS)
58+
* StaticResourceRequest.atCommonLocations().excluding(StaticResourceLocation.CSS)
5659
* </pre>
5760
* @return the configured {@link RequestMatcher}
5861
*/
59-
public static StaticResourceRequestMatcher toCommonLocations() {
60-
return to(EnumSet.allOf(StaticResourceLocation.class));
62+
public StaticResourceRequestMatcher atCommonLocations() {
63+
return at(EnumSet.allOf(StaticResourceLocation.class));
6164
}
6265

6366
/**
6467
* Returns a matcher that includes the specified {@link StaticResourceLocation
6568
* Locations}. For example: <pre class="code">
66-
* StaticResourceRequest.to(StaticResourceLocation.CSS, StaticResourceLocation.JAVA_SCRIPT)
69+
* StaticResourceRequest.at(StaticResourceLocation.CSS, StaticResourceLocation.JAVA_SCRIPT)
6770
* </pre>
6871
* @param first the first location to include
6972
* @param rest additional locations to include
7073
* @return the configured {@link RequestMatcher}
7174
*/
72-
public static StaticResourceRequestMatcher to(StaticResourceLocation first,
75+
public StaticResourceRequestMatcher at(StaticResourceLocation first,
7376
StaticResourceLocation... rest) {
74-
return to(EnumSet.of(first, rest));
77+
return at(EnumSet.of(first, rest));
7578
}
7679

7780
/**
7881
* Returns a matcher that includes the specified {@link StaticResourceLocation
7982
* Locations}. For example: <pre class="code">
80-
* StaticResourceRequest.to(locations)
83+
* StaticResourceRequest.at(locations)
8184
* </pre>
8285
* @param locations the locations to include
8386
* @return the configured {@link RequestMatcher}
8487
*/
85-
public static StaticResourceRequestMatcher to(Set<StaticResourceLocation> locations) {
88+
public StaticResourceRequestMatcher at(Set<StaticResourceLocation> locations) {
8689
Assert.notNull(locations, "Locations must not be null");
8790
return new StaticResourceRequestMatcher(new LinkedHashSet<>(locations));
8891
}
8992

93+
/**
94+
* Return the static resource request.
95+
* @return the static resource request
96+
*/
97+
static StaticResourceRequest get() {
98+
return INSTANCE;
99+
}
100+
90101
/**
91102
* The request matcher used to match against resource {@link StaticResourceLocation
92103
* Locations}.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.security.servlet;
18+
19+
import javax.servlet.http.HttpServletRequest;
20+
21+
import org.assertj.core.api.AssertDelegateTarget;
22+
import org.junit.Rule;
23+
import org.junit.Test;
24+
import org.junit.rules.ExpectedException;
25+
26+
import org.springframework.boot.autoconfigure.web.ServerProperties;
27+
import org.springframework.mock.web.MockHttpServletRequest;
28+
import org.springframework.mock.web.MockServletContext;
29+
import org.springframework.security.web.util.matcher.RequestMatcher;
30+
import org.springframework.web.context.WebApplicationContext;
31+
import org.springframework.web.context.support.StaticWebApplicationContext;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
/**
36+
* Tests for {@link PathRequest}.
37+
*
38+
* @author Madhura Bhave
39+
*/
40+
public class PathRequestTests {
41+
42+
@Rule
43+
public ExpectedException thrown = ExpectedException.none();
44+
45+
@Test
46+
public void toStaticResourcesShouldReturnStaticResourceRequest() {
47+
assertThat(PathRequest.toStaticResources()).isInstanceOf(StaticResourceRequest.class);
48+
}
49+
50+
@Test
51+
public void toH2ConsoleShouldMatchH2ConsolePath() {
52+
RequestMatcher matcher = PathRequest.toH2Console();
53+
assertMatcher(matcher).matches("/h2-console");
54+
assertMatcher(matcher).doesNotMatch("/js/file.js");
55+
}
56+
57+
private RequestMatcherAssert assertMatcher(RequestMatcher matcher) {
58+
StaticWebApplicationContext context = new StaticWebApplicationContext();
59+
context.registerBean(ServerProperties.class);
60+
return assertThat(new RequestMatcherAssert(context, matcher));
61+
}
62+
63+
private static class RequestMatcherAssert implements AssertDelegateTarget {
64+
65+
private final WebApplicationContext context;
66+
67+
private final RequestMatcher matcher;
68+
69+
RequestMatcherAssert(WebApplicationContext context, RequestMatcher matcher) {
70+
this.context = context;
71+
this.matcher = matcher;
72+
}
73+
74+
public void matches(String path) {
75+
matches(mockRequest(path));
76+
}
77+
78+
private void matches(HttpServletRequest request) {
79+
assertThat(this.matcher.matches(request))
80+
.as("Matches " + getRequestPath(request)).isTrue();
81+
}
82+
83+
public void doesNotMatch(String path) {
84+
doesNotMatch(mockRequest(path));
85+
}
86+
87+
private void doesNotMatch(HttpServletRequest request) {
88+
assertThat(this.matcher.matches(request))
89+
.as("Does not match " + getRequestPath(request)).isFalse();
90+
}
91+
92+
private MockHttpServletRequest mockRequest(String path) {
93+
MockServletContext servletContext = new MockServletContext();
94+
servletContext.setAttribute(
95+
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
96+
this.context);
97+
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
98+
request.setPathInfo(path);
99+
return request;
100+
}
101+
102+
private String getRequestPath(HttpServletRequest request) {
103+
String url = request.getServletPath();
104+
if (request.getPathInfo() != null) {
105+
url += request.getPathInfo();
106+
}
107+
return url;
108+
}
109+
110+
}
111+
112+
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/servlet/StaticResourceRequestTests.java

+14-14
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.boot.autoconfigure.security.servlet;
1818

19-
import java.util.Set;
20-
2119
import javax.servlet.http.HttpServletRequest;
2220

2321
import org.assertj.core.api.AssertDelegateTarget;
@@ -43,12 +41,14 @@
4341
*/
4442
public class StaticResourceRequestTests {
4543

44+
private StaticResourceRequest resourceRequest = StaticResourceRequest.get();
45+
4646
@Rule
4747
public ExpectedException thrown = ExpectedException.none();
4848

4949
@Test
50-
public void toCommonLocationsShouldMatchCommonLocations() {
51-
RequestMatcher matcher = StaticResourceRequest.toCommonLocations();
50+
public void atCommonLocationsShouldMatchCommonLocations() {
51+
RequestMatcher matcher = this.resourceRequest.atCommonLocations();
5252
assertMatcher(matcher).matches("/css/file.css");
5353
assertMatcher(matcher).matches("/js/file.js");
5454
assertMatcher(matcher).matches("/images/file.css");
@@ -58,42 +58,42 @@ public void toCommonLocationsShouldMatchCommonLocations() {
5858
}
5959

6060
@Test
61-
public void toCommonLocationsWithExcludeShouldNotMatchExcluded() {
62-
RequestMatcher matcher = StaticResourceRequest.toCommonLocations()
61+
public void atCommonLocationsWithExcludeShouldNotMatchExcluded() {
62+
RequestMatcher matcher = this.resourceRequest.atCommonLocations()
6363
.excluding(StaticResourceLocation.CSS);
6464
assertMatcher(matcher).doesNotMatch("/css/file.css");
6565
assertMatcher(matcher).matches("/js/file.js");
6666
}
6767

6868
@Test
69-
public void toLocationShouldMatchLocation() {
70-
RequestMatcher matcher = StaticResourceRequest.to(StaticResourceLocation.CSS);
69+
public void atLocationShouldMatchLocation() {
70+
RequestMatcher matcher = this.resourceRequest.at(StaticResourceLocation.CSS);
7171
assertMatcher(matcher).matches("/css/file.css");
7272
assertMatcher(matcher).doesNotMatch("/js/file.js");
7373
}
7474

7575
@Test
76-
public void toLocationWhenHasServletPathShouldMatchLocation() {
76+
public void atLocationWhenHasServletPathShouldMatchLocation() {
7777
ServerProperties serverProperties = new ServerProperties();
7878
serverProperties.getServlet().setPath("/foo");
79-
RequestMatcher matcher = StaticResourceRequest.to(StaticResourceLocation.CSS);
79+
RequestMatcher matcher = this.resourceRequest.at(StaticResourceLocation.CSS);
8080
assertMatcher(matcher, serverProperties).matches("/foo", "/css/file.css");
8181
assertMatcher(matcher, serverProperties).doesNotMatch("/foo", "/js/file.js");
8282
}
8383

8484
@Test
85-
public void toLocationsFromSetWhenSetIsNullShouldThrowException() {
85+
public void atLocationsFromSetWhenSetIsNullShouldThrowException() {
8686
this.thrown.expect(IllegalArgumentException.class);
8787
this.thrown.expectMessage("Locations must not be null");
88-
StaticResourceRequest.to((Set<StaticResourceLocation>) null);
88+
this.resourceRequest.at(null);
8989
}
9090

9191
@Test
9292
public void excludeFromSetWhenSetIsNullShouldThrowException() {
9393
this.thrown.expect(IllegalArgumentException.class);
9494
this.thrown.expectMessage("Locations must not be null");
95-
StaticResourceRequest.toCommonLocations()
96-
.excluding((Set<StaticResourceLocation>) null);
95+
this.resourceRequest.atCommonLocations()
96+
.excluding(null);
9797
}
9898

9999
private RequestMatcherAssert assertMatcher(RequestMatcher matcher) {

spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3013,7 +3013,7 @@ Access rules can be overridden by adding a custom `WebSecurityConfigurerAdapter`
30133013
Boot provides convenience methods that can be used to override access rules for actuator
30143014
endpoints and static resources. `EndpointRequest` can be used to create a `RequestMatcher`
30153015
that is based on the `management.endpoints.web.base-path` property.
3016-
`StaticResourceRequest` can be used to create a `RequestMatcher` for static resources in
3016+
`PathRequest` can be used to create a `RequestMatcher` for resources in
30173017
commonly used locations.
30183018

30193019

spring-boot-samples/spring-boot-sample-actuator-custom-security/src/main/java/sample/actuator/customsecurity/SecurityConfiguration.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package sample.actuator.customsecurity;
1818

1919
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
20-
import org.springframework.boot.autoconfigure.security.servlet.StaticResourceRequest;
20+
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
2121
import org.springframework.context.annotation.Bean;
2222
import org.springframework.context.annotation.Configuration;
2323
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -43,7 +43,7 @@ protected void configure(HttpSecurity http) throws Exception {
4343
http.authorizeRequests()
4444
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
4545
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR")
46-
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
46+
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
4747
.antMatchers("/foo").permitAll()
4848
.antMatchers("/**").hasRole("USER")
4949
.and()

spring-boot-samples/spring-boot-sample-web-secure/src/main/java/sample/web/secure/SampleWebSecureApplication.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import java.util.Map;
2121

2222
import org.springframework.boot.autoconfigure.SpringBootApplication;
23-
import org.springframework.boot.autoconfigure.security.servlet.StaticResourceRequest;
23+
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
2424
import org.springframework.boot.builder.SpringApplicationBuilder;
2525
import org.springframework.context.annotation.Configuration;
2626
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -64,7 +64,7 @@ protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter
6464
protected void configure(HttpSecurity http) throws Exception {
6565
// @formatter:off
6666
http.authorizeRequests()
67-
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
67+
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
6868
.anyRequest().fullyAuthenticated()
6969
.and()
7070
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll()

0 commit comments

Comments
 (0)