Skip to content

Commit bd0a41d

Browse files
committed
Merge branch '2.0.x'
2 parents 620d88e + 1150f46 commit bd0a41d

File tree

6 files changed

+477
-82
lines changed

6 files changed

+477
-82
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/web/servlet/EndpointRequest.java

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
3636
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
3737
import org.springframework.boot.autoconfigure.security.web.servlet.RequestMatcherProvider;
38-
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
3938
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
4039
import org.springframework.core.annotation.AnnotatedElementUtils;
4140
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -139,23 +138,13 @@ protected final boolean matches(HttpServletRequest request,
139138

140139
private RequestMatcher createDelegate(WebApplicationContext context) {
141140
try {
142-
String pathPrefix = getPathPrefix(context);
143-
return createDelegate(context, new RequestMatcherFactory(pathPrefix));
141+
return createDelegate(context, new RequestMatcherFactory());
144142
}
145143
catch (NoSuchBeanDefinitionException ex) {
146144
return EMPTY_MATCHER;
147145
}
148146
}
149147

150-
private String getPathPrefix(WebApplicationContext context) {
151-
try {
152-
return context.getBean(DispatcherServletPath.class).getPrefix();
153-
}
154-
catch (NoSuchBeanDefinitionException ex) {
155-
return "";
156-
}
157-
}
158-
159148
protected abstract RequestMatcher createDelegate(WebApplicationContext context,
160149
RequestMatcherFactory requestMatcherFactory);
161150

@@ -313,15 +302,9 @@ protected RequestMatcher createDelegate(WebApplicationContext context,
313302
*/
314303
private static class RequestMatcherFactory {
315304

316-
private final String prefix;
317-
318-
RequestMatcherFactory(String prefix) {
319-
this.prefix = prefix;
320-
}
321-
322305
public RequestMatcher antPath(RequestMatcherProvider matcherProvider,
323306
String... parts) {
324-
StringBuilder pattern = new StringBuilder(this.prefix);
307+
StringBuilder pattern = new StringBuilder();
325308
for (String part : parts) {
326309
pattern.append(part);
327310
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
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+
package org.springframework.boot.actuate.autoconfigure.security.servlet;
17+
18+
import java.util.ArrayList;
19+
import java.util.Base64;
20+
import java.util.List;
21+
22+
import org.junit.Test;
23+
24+
import org.springframework.boot.actuate.autoconfigure.security.web.servlet.EndpointRequest;
25+
import org.springframework.boot.actuate.endpoint.EndpointId;
26+
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
27+
import org.springframework.boot.actuate.endpoint.Operation;
28+
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
29+
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
30+
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
31+
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
32+
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
33+
import org.springframework.boot.logging.LogLevel;
34+
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
35+
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
36+
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
37+
import org.springframework.context.annotation.Bean;
38+
import org.springframework.context.annotation.Configuration;
39+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
40+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
41+
import org.springframework.test.web.reactive.server.WebTestClient;
42+
43+
import static org.mockito.BDDMockito.given;
44+
import static org.mockito.Mockito.mock;
45+
46+
/**
47+
* Abstract base class for {@link EndpointRequest} tests.
48+
*
49+
* @author Madhura Bhave
50+
*/
51+
public abstract class AbstractEndpointRequestIntegrationTests {
52+
53+
protected abstract WebApplicationContextRunner getContextRunner();
54+
55+
@Test
56+
public void toEndpointShouldMatch() {
57+
getContextRunner().run((context) -> {
58+
WebTestClient webTestClient = getWebTestClient(context);
59+
webTestClient.get().uri("/actuator/e1").exchange().expectStatus().isOk();
60+
});
61+
}
62+
63+
@Test
64+
public void toAllEndpointsShouldMatch() {
65+
getContextRunner()
66+
.withInitializer(
67+
new ConditionEvaluationReportLoggingListener(LogLevel.INFO))
68+
.withPropertyValues("spring.security.user.password=password")
69+
.run((context) -> {
70+
WebTestClient webTestClient = getWebTestClient(context);
71+
webTestClient.get().uri("/actuator/e2").exchange().expectStatus()
72+
.isUnauthorized();
73+
webTestClient.get().uri("/actuator/e2")
74+
.header("Authorization", getBasicAuth()).exchange()
75+
.expectStatus().isOk();
76+
});
77+
}
78+
79+
@Test
80+
public void toLinksShouldMatch() {
81+
getContextRunner().run((context) -> {
82+
WebTestClient webTestClient = getWebTestClient(context);
83+
webTestClient.get().uri("/actuator").exchange().expectStatus().isOk();
84+
webTestClient.get().uri("/actuator/").exchange().expectStatus().isOk();
85+
});
86+
}
87+
88+
protected WebTestClient getWebTestClient(AssertableWebApplicationContext context) {
89+
int port = context
90+
.getSourceApplicationContext(
91+
AnnotationConfigServletWebServerApplicationContext.class)
92+
.getWebServer().getPort();
93+
return WebTestClient.bindToServer().baseUrl("http://localhost:" + port).build();
94+
}
95+
96+
String getBasicAuth() {
97+
return "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes());
98+
}
99+
100+
static class BaseConfiguration {
101+
102+
@Bean
103+
public TestEndpoint1 endpoint1() {
104+
return new TestEndpoint1();
105+
}
106+
107+
@Bean
108+
public TestEndpoint2 endpoint2() {
109+
return new TestEndpoint2();
110+
}
111+
112+
@Bean
113+
public TestEndpoint3 endpoint3() {
114+
return new TestEndpoint3();
115+
}
116+
117+
@Bean
118+
public PathMappedEndpoints pathMappedEndpoints() {
119+
List<ExposableEndpoint<?>> endpoints = new ArrayList<>();
120+
endpoints.add(mockEndpoint("e1"));
121+
endpoints.add(mockEndpoint("e2"));
122+
endpoints.add(mockEndpoint("e3"));
123+
return new PathMappedEndpoints("/actuator", () -> endpoints);
124+
}
125+
126+
private TestPathMappedEndpoint mockEndpoint(String id) {
127+
TestPathMappedEndpoint endpoint = mock(TestPathMappedEndpoint.class);
128+
given(endpoint.getEndpointId()).willReturn(EndpointId.of(id));
129+
given(endpoint.getRootPath()).willReturn(id);
130+
return endpoint;
131+
}
132+
133+
}
134+
135+
@Endpoint(id = "e1")
136+
static class TestEndpoint1 {
137+
138+
@ReadOperation
139+
public Object getAll() {
140+
return "endpoint 1";
141+
}
142+
143+
}
144+
145+
@Endpoint(id = "e2")
146+
static class TestEndpoint2 {
147+
148+
@ReadOperation
149+
public Object getAll() {
150+
return "endpoint 2";
151+
}
152+
153+
}
154+
155+
@Endpoint(id = "e3")
156+
static class TestEndpoint3 {
157+
158+
@ReadOperation
159+
public Object getAll() {
160+
return null;
161+
}
162+
163+
}
164+
165+
interface TestPathMappedEndpoint
166+
extends ExposableEndpoint<Operation>, PathMappedEndpoint {
167+
168+
}
169+
170+
@Configuration
171+
static class SecurityConfiguration {
172+
173+
@Bean
174+
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
175+
return new WebSecurityConfigurerAdapter() {
176+
@Override
177+
protected void configure(HttpSecurity http) throws Exception {
178+
http.authorizeRequests().requestMatchers(EndpointRequest.toLinks())
179+
.permitAll()
180+
.requestMatchers(EndpointRequest.to(TestEndpoint1.class))
181+
.permitAll().requestMatchers(EndpointRequest.toAnyEndpoint())
182+
.authenticated().anyRequest().hasRole("ADMIN").and()
183+
.httpBasic();
184+
}
185+
};
186+
}
187+
188+
}
189+
190+
}

0 commit comments

Comments
 (0)