From d8c255eddf4eb5f80ba027329227b0d9e2cd9698 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Tue, 8 Feb 2022 14:30:48 -0500 Subject: [PATCH] Updates ShortcutConfigurable to use custom EvaluationContext. It uses a SimpleEvaluationContext as a delegate that adds a BeanResolver for bean references in SpEL. --- .../gateway/support/ShortcutConfigurable.java | 85 ++++++++++++++++++- .../support/ShortcutConfigurableTests.java | 19 +++++ 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java index 43456533..22a2d1ea 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/support/ShortcutConfigurable.java @@ -25,10 +25,21 @@ import java.util.stream.Collectors; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.expression.BeanResolver; +import org.springframework.expression.ConstructorResolver; +import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; +import org.springframework.expression.MethodResolver; +import org.springframework.expression.OperatorOverloader; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.TypeLocator; +import org.springframework.expression.TypedValue; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.expression.spel.support.SimpleEvaluationContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -54,8 +65,7 @@ public interface ShortcutConfigurable { } if (rawValue != null && rawValue.startsWith("#{") && entryValue.endsWith("}")) { // assume it's spel - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setBeanResolver(new BeanFactoryResolver(beanFactory)); + GatewayEvaluationContext context = new GatewayEvaluationContext(new BeanFactoryResolver(beanFactory)); Expression expression = parser.parseExpression(entryValue, new TemplateParserContext()); value = expression.getValue(context); } @@ -148,4 +158,73 @@ public interface ShortcutConfigurable { } + class GatewayEvaluationContext implements EvaluationContext { + + private final BeanFactoryResolver beanFactoryResolver; + + private SimpleEvaluationContext delegate = SimpleEvaluationContext.forReadOnlyDataBinding().build(); + + public GatewayEvaluationContext(BeanFactoryResolver beanFactoryResolver) { + this.beanFactoryResolver = beanFactoryResolver; + } + + @Override + public TypedValue getRootObject() { + return delegate.getRootObject(); + } + + @Override + public List getPropertyAccessors() { + return delegate.getPropertyAccessors(); + } + + @Override + public List getConstructorResolvers() { + return delegate.getConstructorResolvers(); + } + + @Override + public List getMethodResolvers() { + return delegate.getMethodResolvers(); + } + + @Override + @Nullable + public BeanResolver getBeanResolver() { + return this.beanFactoryResolver; + } + + @Override + public TypeLocator getTypeLocator() { + return delegate.getTypeLocator(); + } + + @Override + public TypeConverter getTypeConverter() { + return delegate.getTypeConverter(); + } + + @Override + public TypeComparator getTypeComparator() { + return delegate.getTypeComparator(); + } + + @Override + public OperatorOverloader getOperatorOverloader() { + return delegate.getOperatorOverloader(); + } + + @Override + public void setVariable(String name, Object value) { + delegate.setVariable(name, value); + } + + @Override + @Nullable + public Object lookupVariable(String name) { + return delegate.lookupVariable(name); + } + + } + } diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableTests.java index 54ac5dbc..158959bc 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/support/ShortcutConfigurableTests.java @@ -30,10 +30,12 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType; import org.springframework.context.annotation.Bean; +import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; @RunWith(SpringRunner.class) @SpringBootTest @@ -44,6 +46,23 @@ public class ShortcutConfigurableTests { private SpelExpressionParser parser; + @Test + public void testNormalizeDefaultTypeWithSpelAndInvalidInputFails() { + parser = new SpelExpressionParser(); + ShortcutConfigurable shortcutConfigurable = new ShortcutConfigurable() { + @Override + public List shortcutFieldOrder() { + return Arrays.asList("bean", "arg1"); + } + }; + Map args = new HashMap<>(); + args.put("bean", "#{T(java.lang.Runtime).getRuntime().exec(\"touch /tmp/x\")}"); + args.put("arg1", "val1"); + assertThatThrownBy(() -> { + ShortcutType.DEFAULT.normalize(args, shortcutConfigurable, parser, this.beanFactory); + }).isInstanceOf(SpelEvaluationException.class); + } + @Test public void testNormalizeDefaultTypeWithSpel() { parser = new SpelExpressionParser();