From 584634a9b5ed66eabc5655a49d704a7038bd1e27 Mon Sep 17 00:00:00 2001 From: Brian Andle Date: Tue, 7 Jun 2022 21:50:34 -0700 Subject: [PATCH] WW-5184 - Added ParameterValueAware interface and unit test --- .../interceptor/ParameterValueAware.java | 37 ++++++++++++++++ .../interceptor/ParametersInterceptor.java | 14 +++--- .../ParametersInterceptorTest.java | 44 +++++++++++++++++++ 3 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterValueAware.java diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterValueAware.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterValueAware.java new file mode 100644 index 000000000..7f077f7c9 --- /dev/null +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterValueAware.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package com.opensymphony.xwork2.interceptor; + +/** + * This interface is implemented by actions that want to declare acceptable parameter value. Works in conjunction with {@link + * ParametersInterceptor}. For example, actions may want to create a white list of parameter values they will accept or a + * blacklist of parameter values they will reject to prevent clients from setting other unexpected (and possibly dangerous) + * parameter values. + */ +public interface ParameterValueAware { + + /** + * Tests if the the action will accept the parameter with the given value. + * + * @param parameterValue the parameter value + * @return true if accepted, false otherwise + */ + boolean acceptableParameterValue(String parameterValue); + +} diff --git a/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java index b592cfb13..f81ba15fd 100644 --- a/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java +++ b/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java @@ -191,7 +191,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor { for (Map.Entry entry : params.entrySet()) { String parameterName = entry.getKey(); boolean isAcceptableParameter = isAcceptableParameter(parameterName, action); - isAcceptableParameter &= isAcceptableParameterValue(entry.getValue()); + isAcceptableParameter &= isAcceptableParameterValue(entry.getValue(), action); if (isAcceptableParameter) { acceptableParameters.put(parameterName, entry.getValue()); @@ -280,14 +280,14 @@ public class ParametersInterceptor extends MethodFilterInterceptor { * @param action current action * @return true if parameter is accepted */ - protected boolean isAcceptableParameterValue(Parameter param) { + protected boolean isAcceptableParameterValue(Parameter param, Object action) { + ParameterValueAware parameterValueAware = (action instanceof ParameterValueAware) ? (ParameterValueAware) action : null; + boolean acceptableParmValue = (parameterValueAware == null || parameterValueAware.acceptableParameterValue(param.getValue())); if(hasParamValuesToExclude() || hasParamValuesToAccept()) { - // We have something to check. - return acceptableValue(param.getName(), param.getValue()); - } else { - // No exclude/accept defined. Return true/allowed. - return true; + // Additional validations to process + acceptableParmValue &= acceptableValue(param.getName(), param.getValue()); } + return acceptableParmValue; } /** diff --git a/core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java b/core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java index d26ceef81..ce8fe8498 100644 --- a/core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/interceptor/ParametersInterceptorTest.java @@ -888,6 +888,50 @@ public class ParametersInterceptorTest extends XWorkTestCase { pi.setParameters(new NoParametersAction(), stack, HttpParameters.create(parameters).build()); assertEquals(expected, actual); } + + public void testExcludedParametersValuesAreIgnoredWithParameterValueAware() throws Exception { + ParametersInterceptor pi = createParametersInterceptor(); + // Contains (based on pattern) + pi.setExcludeValuePatterns(".*\\$\\{.*?\\}.*,.*%\\{.*?\\}.*"); + + assertTrue("${2*2} was excluded by isParamValueExcluded", pi.isParamValueExcluded("${2*2}")); + + final Map actual = injectValueStackFactory(pi); + ValueStack stack = injectValueStack(actual); + + final Map expected = new HashMap() { + { + // acceptableParameterValue only allows fooValue even though fooKey2 and fooKey3 pass the excludeValuePatterns check + put("fooKey", "fooValue"); + } + }; + + Object a = new ParameterValueAware() { + @Override + public boolean acceptableParameterValue(String parameterValue) { + // Only fooValue will be allowed because the excludeValuePatterns will block ${2+2} + return parameterValue.equals("fooValue") || parameterValue.equals("${2+2}"); + } + }; + + Map parameters = new HashMap() { + { + put("barKey$", "${2+2}"); + put("barKey2$", "foo${2+2}"); + put("barKey3$", "foo${2+2}foo"); + put("barKey%", "%{2+2}"); + put("barKey2%", "foo%{2+2}"); + put("barKey3%", "foo%{2+2}foo"); + put("allowedKey", "${foo}"); + put("allowedKey2", "%{bar}"); + put("fooKey", "fooValue"); + put("fooKey2", "fooValue2"); + put("fooKey3", ""); + } + }; + pi.setParameters(a, stack, HttpParameters.create(parameters).build()); + assertEquals(expected, actual); + } private ValueStack injectValueStack(Map actual) {