Skip to content

Commit b2b75c6

Browse files
committed
Add customer BeanFactoryResolver
1 parent dc4c469 commit b2b75c6

File tree

4 files changed

+110
-4
lines changed

4 files changed

+110
-4
lines changed

spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.beans.factory.BeanFactory;
2828
import org.springframework.context.expression.BeanFactoryResolver;
2929
import org.springframework.core.env.Environment;
30+
import org.springframework.expression.AccessException;
3031
import org.springframework.expression.BeanResolver;
3132
import org.springframework.expression.ConstructorResolver;
3233
import org.springframework.expression.EvaluationContext;
@@ -46,6 +47,9 @@
4647
import org.springframework.lang.Nullable;
4748
import org.springframework.util.Assert;
4849

50+
import static org.springframework.context.ConfigurableApplicationContext.SYSTEM_ENVIRONMENT_BEAN_NAME;
51+
import static org.springframework.context.ConfigurableApplicationContext.SYSTEM_PROPERTIES_BEAN_NAME;
52+
4953
/**
5054
* @author Spencer Gibb
5155
*/
@@ -176,14 +180,31 @@ public abstract Map<String, Object> normalize(Map<String, String> args, Shortcut
176180

177181
}
178182

183+
class GatewayBeanFactoryResolver extends BeanFactoryResolver {
184+
185+
public GatewayBeanFactoryResolver(BeanFactory beanFactory) {
186+
super(beanFactory);
187+
}
188+
189+
@Override
190+
public Object resolve(EvaluationContext context, String beanName) throws AccessException {
191+
if (SYSTEM_ENVIRONMENT_BEAN_NAME.equals(beanName) || SYSTEM_PROPERTIES_BEAN_NAME.equals(beanName)) {
192+
throw new AccessException(beanName
193+
+ " is not accessible when spring.cloud.gateway.restrictive-property-accessor.enabled=true");
194+
}
195+
return super.resolve(context, beanName);
196+
}
197+
198+
}
199+
179200
class GatewayEvaluationContext implements EvaluationContext {
180201

181202
private final BeanFactoryResolver beanFactoryResolver;
182203

183204
private final SimpleEvaluationContext delegate;
184205

185206
public GatewayEvaluationContext(BeanFactory beanFactory) {
186-
this.beanFactoryResolver = new BeanFactoryResolver(beanFactory);
207+
this.beanFactoryResolver = new ShortcutConfigurable.GatewayBeanFactoryResolver(beanFactory);
187208
Environment env = beanFactory.getBean(Environment.class);
188209
boolean restrictive = env.getProperty("spring.cloud.gateway.restrictive-property-accessor.enabled",
189210
Boolean.class, true);

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/actuate/GatewayControllerEndpointTests.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,52 @@ public void testPostValidRouteDefinition() {
229229
.isCreated();
230230
}
231231

232+
@Test
233+
public void testPostInvalidSpelRouteDefinition() {
234+
RouteDefinition testRouteDefinition = new RouteDefinition();
235+
testRouteDefinition.setUri(URI.create("http://example.org"));
236+
237+
FilterDefinition prefixPathFilterDefinition = new FilterDefinition("PrefixPath=/test-path");
238+
FilterDefinition redirectToFilterDefinition = new FilterDefinition(
239+
"AddResponseHeader=#{ @systemProperties['user.home'] ?: 'n.a' }");
240+
testRouteDefinition.setFilters(Arrays.asList(prefixPathFilterDefinition, redirectToFilterDefinition));
241+
242+
PredicateDefinition hostRoutePredicateDefinition = new PredicateDefinition("Host=myhost.org");
243+
PredicateDefinition methodRoutePredicateDefinition = new PredicateDefinition("Method=GET");
244+
testRouteDefinition.setPredicates(Arrays.asList(hostRoutePredicateDefinition, methodRoutePredicateDefinition));
245+
246+
testClient.post()
247+
.uri("http://localhost:" + port + "/actuator/gateway/routes/test-route")
248+
.accept(MediaType.APPLICATION_JSON)
249+
.body(BodyInserters.fromValue(testRouteDefinition))
250+
.exchange()
251+
.expectStatus()
252+
.isCreated();
253+
// The refresh will try and create the new route but this should fail with an
254+
// exception due to
255+
// the invalid SpEL expression
256+
// The HTTP request still returns a 200 because all this is doing is firing an
257+
// event and it
258+
// is a "fire and forget" operation
259+
testClient.post()
260+
.uri("http://localhost:" + port + "/actuator/gateway/refresh")
261+
.exchange()
262+
.expectStatus()
263+
.isOk();
264+
265+
// Check to make sure the route was not actually created
266+
testClient.get()
267+
.uri("http://localhost:" + port + "/actuator/gateway/routes")
268+
.exchange()
269+
.expectStatus()
270+
.isOk()
271+
.expectBodyList(Map.class)
272+
.consumeWith(result -> {
273+
List<Map> responseBody = result.getResponseBody();
274+
assertThat(responseBody).extracting("route_id").doesNotContain("test-route");
275+
});
276+
}
277+
232278
@Test
233279
public void testRefreshByGroup() {
234280
RouteDefinition testRouteDefinition = new RouteDefinition();

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableNonRestrictiveTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public List<String> shortcutFieldOrder() {
5555
}
5656
};
5757
Map<String, String> args = new HashMap<>();
58-
args.put("barproperty", "#{@bar.getInt}");
58+
args.put("barproperty", "#{@bar.property}");
5959
args.put("arg1", "val1");
6060
Map<String, Object> map = ShortcutType.DEFAULT.normalize(args, shortcutConfigurable, parser, this.beanFactory);
6161
assertThat(map).isNotNull().containsEntry("barproperty", 42).containsEntry("arg1", "val1");
@@ -94,6 +94,8 @@ public Bar bar() {
9494

9595
protected static class Bar {
9696

97+
public int property = 42;
98+
9799
public int getInt() {
98100
return 42;
99101
}

spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableTests.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,24 @@ public List<String> shortcutFieldOrder() {
8282
}
8383

8484
@Test
85-
public void testNormalizeDefaultTypeWithSpelAndInvalidPropertyReferenceFails() {
85+
public void testNormalizeDefaultTypeWithSpelSystemPropertiesFails() {
86+
parser = new SpelExpressionParser();
87+
ShortcutConfigurable shortcutConfigurable = new ShortcutConfigurable() {
88+
@Override
89+
public List<String> shortcutFieldOrder() {
90+
return Arrays.asList("bean", "arg1");
91+
}
92+
};
93+
Map<String, String> args = new HashMap<>();
94+
args.put("bean", "#{ @systemProperties['user.home'] ?: 'n.a' }");
95+
args.put("arg1", "val1");
96+
assertThatThrownBy(() -> {
97+
ShortcutType.DEFAULT.normalize(args, shortcutConfigurable, parser, this.beanFactory);
98+
}).isInstanceOf(SpelEvaluationException.class);
99+
}
100+
101+
@Test
102+
public void testNormalizeDefaultTypeWithSpelEnvironmentVariablesFails() {
86103
parser = new SpelExpressionParser();
87104
ShortcutConfigurable shortcutConfigurable = new ShortcutConfigurable() {
88105
@Override
@@ -91,13 +108,31 @@ public List<String> shortcutFieldOrder() {
91108
}
92109
};
93110
Map<String, String> args = new HashMap<>();
94-
args.put("barproperty", "#{@bar.getInt}");
111+
args.put("bean", "#{ @systemEnvironment['user.home'] ?: 'n.a' }");
95112
args.put("arg1", "val1");
96113
assertThatThrownBy(() -> {
97114
ShortcutType.DEFAULT.normalize(args, shortcutConfigurable, parser, this.beanFactory);
98115
}).isInstanceOf(SpelEvaluationException.class);
99116
}
100117

118+
@Test
119+
public void testNormalizeDefaultTypeWithSpelAndInvalidPropertyReferenceFails() {
120+
parser = new SpelExpressionParser();
121+
ShortcutConfigurable shortcutConfigurable = new ShortcutConfigurable() {
122+
@Override
123+
public List<String> shortcutFieldOrder() {
124+
return Arrays.asList("bean", "arg1");
125+
}
126+
};
127+
Map<String, String> args = new HashMap<>();
128+
args.put("barproperty", "#{@bar.property}");
129+
args.put("arg1", "val1");
130+
assertThatThrownBy(() -> {
131+
ShortcutType.DEFAULT.normalize(args, shortcutConfigurable, parser, this.beanFactory);
132+
}).isInstanceOf(SpelEvaluationException.class)
133+
.hasMessageContaining("Property or field 'property' cannot be found");
134+
}
135+
101136
@Test
102137
public void testNormalizeDefaultTypeWithSpelAndInvalidMethodReferenceFails() {
103138
parser = new SpelExpressionParser();
@@ -247,6 +282,8 @@ public Map<String, Object> myMap() {
247282

248283
protected static class Bar {
249284

285+
public int property = 42;
286+
250287
public int getInt() {
251288
return 42;
252289
}

0 commit comments

Comments
 (0)