Uses OGNL 3.2.2 which always requires MemberAccess

This commit is contained in:
Lukasz Lenart
2017-05-22 08:30:46 +02:00
parent d63cc99f24
commit 5cd409d382
14 changed files with 118 additions and 59 deletions
@@ -18,8 +18,10 @@
*/
package com.opensymphony.xwork2;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.util.ValueStack;
import ognl.OgnlContext;
import org.apache.struts2.dispatcher.HttpParameters;
import java.io.Serializable;
@@ -184,6 +186,10 @@ public class ActionContext implements Serializable {
* @return the context map.
*/
public Map<String, Object> getContextMap() {
Map<String, Object> context = getContext().context;
if (context instanceof OgnlContext) {
((OgnlContext) context).put(TypeConverter.TYPE_CONVERTER_CONTEXT_KEY, ((OgnlContext) context).getTypeConverter());
}
return context;
}
@@ -677,7 +677,7 @@ public class OgnlUtil {
memberAccess.setExcludedPackageNames(excludedPackageNames);
memberAccess.setDisallowProxyMemberAccess(disallowProxyMemberAccess);
return Ognl.createDefaultContext(root, resolver, defaultConverter, memberAccess);
return Ognl.createDefaultContext(root, memberAccess, resolver, defaultConverter);
}
private interface OgnlTask<T> {
@@ -94,7 +94,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
boolean allowStaticMethodAccess) {
this.root = compoundRoot;
this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess);
this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess);
this.context = Ognl.createDefaultContext(this.root, securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter));
context.put(VALUE_STACK, this);
((OgnlContext) context).setTraceEvaluations(false);
((OgnlContext) context).setKeepLastEvaluation(false);
@@ -19,11 +19,13 @@
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.util.ProxyUtil;
import ognl.DefaultMemberAccess;
import ognl.MemberAccess;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.*;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -34,7 +36,7 @@ import java.util.regex.Pattern;
* Allows access decisions to be made on the basis of whether a member is static or not.
* Also blocks or allows access to properties.
*/
public class SecurityMemberAccess extends DefaultMemberAccess {
public class SecurityMemberAccess implements MemberAccess {
private static final Logger LOG = LogManager.getLogger(SecurityMemberAccess.class);
@@ -47,7 +49,6 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
private boolean disallowProxyMemberAccess;
public SecurityMemberAccess(boolean method) {
super(false);
allowStaticMethodAccess = method;
}
@@ -55,6 +56,28 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
return allowStaticMethodAccess;
}
@Override
public Object setup(Map context, Object target, Member member, String propertyName) {
Object result = null;
if (isAccessible(context, target, member, propertyName)) {
AccessibleObject accessible = (AccessibleObject) member;
if (!accessible.isAccessible()) {
result = Boolean.TRUE;
accessible.setAccessible(true);
}
}
return result;
}
@Override
public void restore(Map context, Object target, Member member, String propertyName, Object state) {
if (state != null) {
((AccessibleObject) member).setAccessible((Boolean) state);
}
}
@Override
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
LOG.debug("Checking access for [target: {}, member: {}, property: {}]", target, member, propertyName);
@@ -105,8 +128,7 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
return false;
}
// Now check for standard scope rules
return super.isAccessible(context, target, member, propertyName) && isAcceptableProperty(propertyName);
return Modifier.isPublic(member.getModifiers()) && isAcceptableProperty(propertyName);
}
protected boolean checkStaticMethodAccess(Member member) {
@@ -132,7 +154,7 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
if (targetPackage == null || memberPackage == null) {
LOG.warn("The use of the default (unnamed) package is discouraged!");
}
final String targetPackageName = targetPackage == null ? "" : targetPackage.getName();
final String memberPackageName = memberPackage == null ? "" : memberPackage.getName();
@@ -142,7 +164,7 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
}
}
for (String packageName: excludedPackageNames) {
for (String packageName : excludedPackageNames) {
if (targetPackageName.startsWith(packageName) || targetPackageName.equals(packageName)
|| memberPackageName.startsWith(packageName) || memberPackageName.equals(packageName)) {
return true;
@@ -18,7 +18,7 @@
*/
package org.apache.struts2.views.jsp.ui;
import ognl.Ognl;
import com.opensymphony.xwork2.ActionContext;
import ognl.OgnlException;
import com.opensymphony.xwork2.inject.Inject;
@@ -30,18 +30,18 @@ import com.opensymphony.xwork2.ognl.OgnlUtil;
public class OgnlTool {
private OgnlUtil ognlUtil;
public OgnlTool() {
}
@Inject
public void setOgnlUtil(OgnlUtil ognlUtil) {
this.ognlUtil = ognlUtil;
}
public Object findValue(String expr, Object context) {
try {
return Ognl.getValue(ognlUtil.compile(expr), context);
return ognlUtil.getValue(expr, ActionContext.getContext().getContextMap(), context);
} catch (OgnlException e) {
return null;
}
@@ -49,7 +49,6 @@
ognl.ClassResolver,
ognl.TypeConverter,
ognl.MemberAccess,
ognl.DefaultMemberAccess,
com.opensymphony.xwork2.ognl.SecurityMemberAccess,
com.opensymphony.xwork2.ActionContext" />
@@ -105,11 +105,8 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
public void testInvokingExistingExecuteMethod() throws Exception {
// given
DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
public ValueStack getStack() {
return new StubValueStack();
}
};
DefaultActionInvocation dai = new DefaultActionInvocation(ActionContext.getContext().getContextMap(), false);
container.inject(dai);
SimpleAction action = new SimpleAction() {
@Override
@@ -120,6 +117,7 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
MockActionProxy proxy = new MockActionProxy();
proxy.setMethod("execute");
dai.stack = container.getInstance(ValueStackFactory.class).createValueStack();
dai.proxy = proxy;
dai.ognlUtil = new OgnlUtil();
@@ -132,11 +130,8 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
public void testInvokingMissingMethod() throws Exception {
// given
DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
public ValueStack getStack() {
return new StubValueStack();
}
};
DefaultActionInvocation dai = new DefaultActionInvocation(ActionContext.getContext().getContextMap(), false);
container.inject(dai);
SimpleAction action = new SimpleAction() {
@Override
@@ -154,6 +149,7 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
}
};
dai.stack = container.getInstance(ValueStackFactory.class).createValueStack();
dai.proxy = proxy;
dai.ognlUtil = new OgnlUtil();
dai.unknownHandlerManager = uhm;
@@ -173,11 +169,8 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
public void testInvokingExistingMethodThatThrowsException() throws Exception {
// given
DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
public ValueStack getStack() {
return new StubValueStack();
}
};
DefaultActionInvocation dai = new DefaultActionInvocation(ActionContext.getContext().getContextMap(), false);
container.inject(dai);
SimpleAction action = new SimpleAction() {
@Override
@@ -188,6 +181,7 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
MockActionProxy proxy = new MockActionProxy();
proxy.setMethod("execute");
dai.stack = container.getInstance(ValueStackFactory.class).createValueStack();
dai.proxy = proxy;
dai.ognlUtil = new OgnlUtil();
@@ -206,11 +200,8 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
public void testUnknownHandlerManagerThatThrowsException() throws Exception {
// given
DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
public ValueStack getStack() {
return new StubValueStack();
}
};
DefaultActionInvocation dai = new DefaultActionInvocation(ActionContext.getContext().getContextMap(), false);
container.inject(dai);
UnknownHandlerManager uhm = new DefaultUnknownHandlerManager() {
@Override
@@ -227,6 +218,7 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
MockActionProxy proxy = new MockActionProxy();
proxy.setMethod("notExists");
dai.stack = container.getInstance(ValueStackFactory.class).createValueStack();
dai.proxy = proxy;
dai.ognlUtil = new OgnlUtil();
dai.unknownHandlerManager = uhm;
@@ -247,11 +239,8 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
public void testUnknownHandlerManagerThatReturnsNull() throws Exception {
// given
DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
public ValueStack getStack() {
return new StubValueStack();
}
};
DefaultActionInvocation dai = new DefaultActionInvocation(ActionContext.getContext().getContextMap(), false);
container.inject(dai);
UnknownHandlerManager uhm = new DefaultUnknownHandlerManager() {
@Override
@@ -268,6 +257,7 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
MockActionProxy proxy = new MockActionProxy();
proxy.setMethod("notExists");
dai.stack = container.getInstance(ValueStackFactory.class).createValueStack();
dai.proxy = proxy;
dai.ognlUtil = new OgnlUtil();
dai.unknownHandlerManager = uhm;
@@ -287,11 +277,8 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
public void testUnknownHandlerManagerThatReturnsSuccess() throws Exception {
// given
DefaultActionInvocation dai = new DefaultActionInvocation(new HashMap<String, Object>(), false) {
public ValueStack getStack() {
return new StubValueStack();
}
};
DefaultActionInvocation dai = new DefaultActionInvocation(ActionContext.getContext().getContextMap(), false);
container.inject(dai);
UnknownHandlerManager uhm = new DefaultUnknownHandlerManager() {
@Override
@@ -308,6 +295,7 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
MockActionProxy proxy = new MockActionProxy();
proxy.setMethod("notExists");
dai.stack = container.getInstance(ValueStackFactory.class).createValueStack();
dai.proxy = proxy;
dai.ognlUtil = new OgnlUtil();
dai.unknownHandlerManager = uhm;
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.test.ModelDrivenAnnotationAction2;
import com.opensymphony.xwork2.util.Bar;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import ognl.Ognl;
import ognl.OgnlException;
import ognl.OgnlRuntime;
@@ -57,7 +57,7 @@ public class SetPropertiesTest extends XWorkTestCase {
}
public void testOgnlUtilEmptyStringAsLong() {
Bar bar = new Bar();
Map context = Ognl.createDefaultContext(bar);
Map context = Ognl.createDefaultContext(bar, new SecurityMemberAccess(false));
context.put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
bar.setId(null);
@@ -18,6 +18,7 @@
*/
package org.apache.struts2.factory;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.config.entities.ResultConfig;
@@ -39,10 +40,9 @@ public class StrutsResultFactoryTest extends StrutsInternalTestCase {
params.put("accept", "ok");
params.put("reject", "bad");
ResultConfig config = new ResultConfig.Builder("struts", MyResult.class.getName()).addParams(params).build();
Map<String, Object> context = new HashMap<String, Object>();
// when
Result result = builder.buildResult(config, context);
Result result = builder.buildResult(config, ActionContext.getContext().getContextMap());
// then
assertEquals("ok", ((MyResult)result).getAccept());
@@ -179,7 +179,7 @@ public class ServletActionRedirectResultTest extends StrutsInternalTestCase {
.build();
ObjectFactory factory = container.getInstance(ObjectFactory.class);
ServletActionRedirectResult result = (ServletActionRedirectResult) factory.buildResult(resultConfig, new HashMap<String, Object>());
ServletActionRedirectResult result = (ServletActionRedirectResult) factory.buildResult(resultConfig, ActionContext.getContext().getContextMap());
assertNotNull(result);
}
@@ -57,8 +57,6 @@ public class ServletDispatcherResultTest extends StrutsInternalTestCase implemen
Mock responseMock = new Mock(HttpServletResponse.class);
responseMock.expectAndReturn("isCommitted", Boolean.TRUE);
ActionContext ac = new ActionContext(Ognl.createDefaultContext(null));
ActionContext.setContext(ac);
ServletActionContext.setRequest((HttpServletRequest) requestMock.proxy());
ServletActionContext.setResponse((HttpServletResponse) responseMock.proxy());
@@ -92,8 +90,6 @@ public class ServletDispatcherResultTest extends StrutsInternalTestCase implemen
Mock responseMock = new Mock(HttpServletResponse.class);
responseMock.expectAndReturn("isCommitted", Boolean.FALSE);
ActionContext ac = new ActionContext(Ognl.createDefaultContext(null));
ActionContext.setContext(ac);
ServletActionContext.setRequest((HttpServletRequest) requestMock.proxy());
ServletActionContext.setResponse((HttpServletResponse) responseMock.proxy());
@@ -127,14 +123,11 @@ public class ServletDispatcherResultTest extends StrutsInternalTestCase implemen
Mock responseMock = new Mock(HttpServletResponse.class);
responseMock.expectAndReturn("isCommitted", Boolean.FALSE);
ActionContext ac = new ActionContext(Ognl.createDefaultContext(null));
ac.setContainer(container);
ActionContext.setContext(ac);
ServletActionContext.setRequest((HttpServletRequest) requestMock.proxy());
ServletActionContext.setResponse((HttpServletResponse) responseMock.proxy());
MockActionInvocation mockActionInvocation = new MockActionInvocation();
mockActionInvocation.setInvocationContext(ac);
mockActionInvocation.setInvocationContext(ActionContext.getContext());
mockActionInvocation.setStack(container.getInstance(ValueStackFactory.class).createValueStack());
try {
@@ -34,6 +34,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
import ognl.Ognl;
import org.apache.struts2.ServletActionContext;
@@ -342,7 +343,7 @@ public class ServletRedirectResultTest extends StrutsInternalTestCase implements
ActionConfig actionConfig = new ActionConfig.Builder("", "", "")
.addResultConfigs(results).build();
ActionContext ac = new ActionContext(Ognl.createDefaultContext(null));
ActionContext ac = new ActionContext(Ognl.createDefaultContext(null, new SecurityMemberAccess(false)));
ac.put(ServletActionContext.HTTP_REQUEST, requestMock.proxy());
ac.put(ServletActionContext.HTTP_RESPONSE, responseMock.proxy());
MockActionInvocation ai = new MockActionInvocation();
@@ -26,7 +26,13 @@ import com.opensymphony.xwork2.Validateable;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil;
import com.opensymphony.xwork2.ognl.OgnlUtil;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
import com.opensymphony.xwork2.util.ValueStack;
import net.sf.oval.exception.ExpressionEvaluationException;
import net.sf.oval.expression.ExpressionLanguage;
import net.sf.oval.expression.ExpressionLanguageOGNLImpl;
import ognl.*;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import com.opensymphony.xwork2.validator.DelegatingValidatorContext;
@@ -43,6 +49,8 @@ import org.apache.struts2.oval.annotation.Profiles;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/*
This interceptor provides validation using the OVal validation framework
@@ -59,6 +67,8 @@ public class OValValidationInterceptor extends MethodFilterInterceptor {
protected boolean validateJPAAnnotations;
protected TextProviderFactory textProviderFactory;
private ExpressionLanguage ognlExpressionLanguage;
@Inject
public void setValidationManager(OValValidationManager validationManager) {
this.validationManager = validationManager;
@@ -77,6 +87,16 @@ public class OValValidationInterceptor extends MethodFilterInterceptor {
this.validateJPAAnnotations = Boolean.parseBoolean(validateJPAAnnotations);
}
@Inject
public void setOgnlUtil(OgnlUtil ognlUtil) {
SecurityMemberAccess securityMemberAccess = new SecurityMemberAccess(false);
securityMemberAccess.setExcludedClasses(ognlUtil.getExcludedClasses());
securityMemberAccess.setExcludedPackageNamePatterns(ognlUtil.getExcludedPackageNamePatterns());
securityMemberAccess.setExcludedPackageNames(ognlUtil.getExcludedPackageNames());
ognlExpressionLanguage = new ExpressionLanguageOGNL(securityMemberAccess);
}
/**
* Determines if {@link com.opensymphony.xwork2.Validateable}'s <code>validate()</code> should be called,
* as well as methods whose name that start with "validate". Defaults to "true".
@@ -153,6 +173,7 @@ public class OValValidationInterceptor extends MethodFilterInterceptor {
List<Configurer> configurers = validationManager.getConfigurers(clazz, context, validateJPAAnnotations);
Validator validator = configurers.isEmpty() ? new Validator() : new Validator(configurers);
validator.addExpressionLanguage("ognl", ognlExpressionLanguage);
//if the method is annotated with a @Profiles annotation, use those profiles
Method method = clazz.getMethod(methodName, new Class[0]);
if (method != null) {
@@ -284,4 +305,32 @@ public class OValValidationInterceptor extends MethodFilterInterceptor {
return message;
}
}
}
class ExpressionLanguageOGNL extends ExpressionLanguageOGNLImpl {
private static final Logger LOG = LogManager.getLogger(ExpressionLanguageOGNL.class);
private MemberAccess memberAccess;
public ExpressionLanguageOGNL(MemberAccess memberAccess) {
this.memberAccess = memberAccess;
}
public Object evaluate(final String expression, final Map<String, ? > values) throws ExpressionEvaluationException {
try {
final OgnlContext ctx = (OgnlContext) Ognl.createDefaultContext(null, memberAccess);
for (final Map.Entry<String, ?> entry : values.entrySet()) {
ctx.put(entry.getKey(), entry.getValue());
}
LOG.debug("Evaluating OGNL expression: {1}", expression);
return Ognl.getValue(expression, ctx, ctx);
} catch (final OgnlException ex) {
throw new ExpressionEvaluationException("Evaluating script with OGNL failed.", ex);
}
}
}