mirror of
https://github.com/apache/struts.git
synced 2026-08-06 23:27:07 +00:00
Merge pull request #800 from apache/WW-5364-populate-allowlist
WW-5364 Automatically populate OGNL allowlist
This commit is contained in:
@@ -34,6 +34,19 @@
|
||||
<constant name="struts.custom.i18n.resources" value="globalMessages" />
|
||||
<constant name="struts.action.extension" value="action,," />
|
||||
|
||||
<constant name="struts.allowlist.enable" value="true" />
|
||||
<constant name="struts.allowlist.packageNames"
|
||||
value="
|
||||
org.apache.struts2.showcase.model,
|
||||
org.apache.struts2.showcase.conversion
|
||||
"/>
|
||||
<constant name="struts.allowlist.classes"
|
||||
value="
|
||||
org.apache.struts2.showcase.UITagExample$Language,
|
||||
org.apache.struts2.showcase.UITagExample$VehicalType,
|
||||
org.apache.struts2.showcase.UITagExample$VehicalSpecific
|
||||
"/>
|
||||
|
||||
<constant name="struts.convention.package.locators.basePackage" value="org.apache.struts2.showcase" />
|
||||
<constant name="struts.convention.result.path" value="/WEB-INF" />
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Context;
|
||||
import com.opensymphony.xwork2.inject.Factory;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.test.StubConfigurationProvider;
|
||||
import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
public abstract class XWorkJUnit4TestCase {
|
||||
|
||||
protected ConfigurationManager configurationManager;
|
||||
protected Configuration configuration;
|
||||
protected Container container;
|
||||
protected ActionProxyFactory actionProxyFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
configurationManager = XWorkTestCaseHelper.setUp();
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
XWorkTestCaseHelper.tearDown(configurationManager);
|
||||
configurationManager = null;
|
||||
configuration = null;
|
||||
container = null;
|
||||
actionProxyFactory = null;
|
||||
}
|
||||
|
||||
protected void loadConfigurationProviders(ConfigurationProvider... providers) {
|
||||
configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final Object impl) {
|
||||
loadButAdd(type, Container.DEFAULT_NAME, impl);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final String name, final Object impl) {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
builder.factory(type, name, new Factory() {
|
||||
public Object create(Context context) throws Exception {
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class type() {
|
||||
return impl.getClass();
|
||||
}
|
||||
}, Scope.SINGLETON);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -68,10 +68,12 @@ import com.opensymphony.xwork2.factory.DefaultActionFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultResultFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultValidatorFactory;
|
||||
import com.opensymphony.xwork2.factory.InterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.ResultFactory;
|
||||
import com.opensymphony.xwork2.factory.StrutsConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.ValidatorFactory;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Context;
|
||||
@@ -107,6 +109,7 @@ import org.apache.struts2.conversion.StrutsConversionPropertiesProcessor;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterCreator;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterHolder;
|
||||
import org.apache.struts2.ognl.OgnlGuard;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.apache.struts2.ognl.StrutsOgnlGuard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -341,52 +344,13 @@ public class DefaultConfiguration implements Configuration {
|
||||
fmFactoryRegistered = true;
|
||||
}
|
||||
}
|
||||
builder.factory(ObjectFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ActionFactory.class, DefaultActionFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ResultFactory.class, DefaultResultFactory.class, Scope.SINGLETON);
|
||||
builder.factory(InterceptorFactory.class, DefaultInterceptorFactory.class, Scope.SINGLETON);
|
||||
builder.factory(com.opensymphony.xwork2.factory.ValidatorFactory.class, com.opensymphony.xwork2.factory.DefaultValidatorFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ConverterFactory.class, StrutsConverterFactory.class, Scope.SINGLETON);
|
||||
builder.factory(UnknownHandlerFactory.class, DefaultUnknownHandlerFactory.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON);
|
||||
bootstrapFactories(builder);
|
||||
bootstrapTypeConverters(builder);
|
||||
|
||||
if (!fmFactoryRegistered) {
|
||||
builder.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON);
|
||||
}
|
||||
builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
|
||||
builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(XWorkConverter.class, Scope.SINGLETON);
|
||||
builder.factory(ConversionPropertiesProcessor.class, StrutsConversionPropertiesProcessor.class, Scope.SINGLETON);
|
||||
builder.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON);
|
||||
builder.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverterCreator.class, StrutsTypeConverterCreator.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverterHolder.class, StrutsTypeConverterHolder.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_COLLECTION, CollectionConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_ARRAY, ArrayConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_DATE, DateConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_NUMBER, NumberConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_STRING, StringConverter.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(LocalizedTextProvider.class, StrutsLocalizedTextProvider.class, Scope.SINGLETON);
|
||||
builder.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON);
|
||||
builder.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
|
||||
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
|
||||
builder.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(OgnlUtil.class, Scope.SINGLETON);
|
||||
builder.factory(SecurityMemberAccess.class, Scope.PROTOTYPE);
|
||||
builder.factory(OgnlGuard.class, StrutsOgnlGuard.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
|
||||
for (Map.Entry<String, Object> entry : BOOTSTRAP_CONSTANTS.entrySet()) {
|
||||
builder.constant(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
@@ -395,6 +359,57 @@ public class DefaultConfiguration implements Configuration {
|
||||
return builder.create(true);
|
||||
}
|
||||
|
||||
public static ContainerBuilder bootstrapFactories(ContainerBuilder builder) {
|
||||
return builder
|
||||
// TODO: SpringObjectFactoryTest fails when these are SINGLETON
|
||||
.factory(ObjectFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ActionFactory.class, DefaultActionFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ResultFactory.class, DefaultResultFactory.class, Scope.PROTOTYPE)
|
||||
.factory(InterceptorFactory.class, DefaultInterceptorFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ConverterFactory.class, StrutsConverterFactory.class, Scope.PROTOTYPE)
|
||||
.factory(UnknownHandlerFactory.class, DefaultUnknownHandlerFactory.class, Scope.PROTOTYPE)
|
||||
|
||||
.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON)
|
||||
.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON)
|
||||
.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(XWorkConverter.class, Scope.SINGLETON)
|
||||
.factory(XWorkBasicConverter.class, Scope.SINGLETON)
|
||||
.factory(ConversionPropertiesProcessor.class, StrutsConversionPropertiesProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterCreator.class, StrutsTypeConverterCreator.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterHolder.class, StrutsTypeConverterHolder.class, Scope.SINGLETON)
|
||||
|
||||
.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON)
|
||||
.factory(LocalizedTextProvider.class, StrutsLocalizedTextProvider.class, Scope.SINGLETON)
|
||||
.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(OgnlUtil.class, Scope.SINGLETON)
|
||||
.factory(SecurityMemberAccess.class, Scope.PROTOTYPE)
|
||||
.factory(OgnlGuard.class, StrutsOgnlGuard.class, Scope.SINGLETON)
|
||||
.factory(ProviderAllowlist.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
}
|
||||
|
||||
public static ContainerBuilder bootstrapTypeConverters(ContainerBuilder builder) {
|
||||
return builder
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_COLLECTION, CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_ARRAY, ArrayConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_DATE, DateConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_NUMBER, NumberConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_STRING, StringConverter.class, Scope.SINGLETON);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This builds the internal runtime configuration used by Xwork for finding and configuring Actions from the
|
||||
|
||||
+41
-126
@@ -20,62 +20,24 @@ package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.DefaultActionProxyFactory;
|
||||
import com.opensymphony.xwork2.DefaultLocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.DefaultTextProvider;
|
||||
import com.opensymphony.xwork2.DefaultUnknownHandlerManager;
|
||||
import com.opensymphony.xwork2.FileManager;
|
||||
import com.opensymphony.xwork2.FileManagerFactory;
|
||||
import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.StrutsTextProviderFactory;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.UnknownHandlerManager;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
|
||||
import com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor;
|
||||
import com.opensymphony.xwork2.conversion.ConversionFileProcessor;
|
||||
import com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor;
|
||||
import com.opensymphony.xwork2.conversion.NullHandler;
|
||||
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
|
||||
import com.opensymphony.xwork2.conversion.TypeConverterCreator;
|
||||
import com.opensymphony.xwork2.conversion.TypeConverterHolder;
|
||||
import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.DateConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
|
||||
import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
|
||||
import com.opensymphony.xwork2.conversion.impl.NumberConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.StringConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.factory.ActionFactory;
|
||||
import com.opensymphony.xwork2.factory.ConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultActionFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultResultFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.InterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.ResultFactory;
|
||||
import com.opensymphony.xwork2.factory.StrutsConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.ObjectProxy;
|
||||
import com.opensymphony.xwork2.ognl.OgnlReflectionContextFactory;
|
||||
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
|
||||
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
|
||||
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.ObjectAccessor;
|
||||
@@ -94,17 +56,11 @@ import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecke
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.OgnlTextParser;
|
||||
import com.opensymphony.xwork2.util.PatternMatcher;
|
||||
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.TextParser;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.WildcardHelper;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManager;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import com.opensymphony.xwork2.validator.ActionValidatorManager;
|
||||
import com.opensymphony.xwork2.validator.AnnotationActionValidatorManager;
|
||||
import com.opensymphony.xwork2.validator.DefaultActionValidatorManager;
|
||||
@@ -114,15 +70,10 @@ import com.opensymphony.xwork2.validator.ValidatorFactory;
|
||||
import com.opensymphony.xwork2.validator.ValidatorFileParser;
|
||||
import ognl.MethodAccessor;
|
||||
import ognl.PropertyAccessor;
|
||||
import org.apache.struts2.conversion.StrutsConversionPropertiesProcessor;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterCreator;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterHolder;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.interceptor.exec.ExecutorProvider;
|
||||
import org.apache.struts2.interceptor.exec.StrutsExecutorProvider;
|
||||
import org.apache.struts2.ognl.OgnlGuard;
|
||||
import org.apache.struts2.ognl.StrutsOgnlGuard;
|
||||
import org.apache.struts2.url.QueryStringBuilder;
|
||||
import org.apache.struts2.url.QueryStringParser;
|
||||
import org.apache.struts2.url.StrutsQueryStringBuilder;
|
||||
@@ -162,96 +113,60 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(ContainerBuilder builder, LocatableProperties props)
|
||||
throws ConfigurationException {
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
|
||||
|
||||
builder
|
||||
.factory(ObjectFactory.class)
|
||||
.factory(ActionFactory.class, DefaultActionFactory.class)
|
||||
.factory(ResultFactory.class, DefaultResultFactory.class)
|
||||
.factory(InterceptorFactory.class, DefaultInterceptorFactory.class)
|
||||
.factory(com.opensymphony.xwork2.factory.ValidatorFactory.class, com.opensymphony.xwork2.factory.DefaultValidatorFactory.class)
|
||||
.factory(ConverterFactory.class, StrutsConverterFactory.class)
|
||||
.factory(UnknownHandlerFactory.class, DefaultUnknownHandlerFactory.class)
|
||||
DefaultConfiguration.bootstrapFactories(builder)
|
||||
.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class, Scope.SINGLETON)
|
||||
.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
|
||||
.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(XWorkConverter.class, Scope.SINGLETON)
|
||||
.factory(XWorkBasicConverter.class, Scope.SINGLETON)
|
||||
.factory(ConversionPropertiesProcessor.class, StrutsConversionPropertiesProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterCreator.class, StrutsTypeConverterCreator.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterHolder.class, StrutsTypeConverterHolder.class, Scope.SINGLETON)
|
||||
.factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.SINGLETON)
|
||||
.factory(ValidatorFileParser.class, DefaultValidatorFileParser.class, Scope.SINGLETON)
|
||||
.factory(PatternMatcher.class, WildcardHelper.class, Scope.SINGLETON)
|
||||
|
||||
.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON)
|
||||
.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON)
|
||||
.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON)
|
||||
.factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.SINGLETON)
|
||||
.factory(ValidatorFileParser.class, DefaultValidatorFileParser.class, Scope.SINGLETON)
|
||||
.factory(PatternMatcher.class, WildcardHelper.class, Scope.SINGLETON)
|
||||
.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON)
|
||||
.factory(ReflectionContextFactory.class, OgnlReflectionContextFactory.class, Scope.SINGLETON)
|
||||
.factory(ReflectionContextFactory.class, OgnlReflectionContextFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Object.class.getName(), ObjectAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Iterator.class.getName(), XWorkIteratorPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Enumeration.class.getName(), XWorkEnumerationAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Object.class.getName(), ObjectAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Iterator.class.getName(), XWorkIteratorPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Enumeration.class.getName(), XWorkEnumerationAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(UnknownHandlerManager.class, DefaultUnknownHandlerManager.class, Scope.SINGLETON)
|
||||
.factory(UnknownHandlerManager.class, DefaultUnknownHandlerManager.class, Scope.SINGLETON)
|
||||
|
||||
// silly workarounds for ognl since there is no way to flush its caches
|
||||
.factory(PropertyAccessor.class, List.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ArrayList.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashSet.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Set.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashMap.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Map.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Collection.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ObjectProxy.class.getName(), ObjectProxyPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HttpParameters.class.getName(), HttpParametersPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Parameter.class.getName(), ParameterPropertyAccessor.class, Scope.SINGLETON)
|
||||
// silly workarounds for ognl since there is no way to flush its caches
|
||||
.factory(PropertyAccessor.class, List.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ArrayList.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashSet.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Set.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashMap.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Map.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Collection.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ObjectProxy.class.getName(), ObjectProxyPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HttpParameters.class.getName(), HttpParametersPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Parameter.class.getName(), ParameterPropertyAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON)
|
||||
.factory(NullHandler.class, Object.class.getName(), InstantiatingNullHandler.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, AnnotationActionValidatorManager.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, "no-annotations", DefaultActionValidatorManager.class, Scope.SINGLETON)
|
||||
|
||||
.factory(NullHandler.class, Object.class.getName(), InstantiatingNullHandler.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, AnnotationActionValidatorManager.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, "no-annotations", DefaultActionValidatorManager.class, Scope.SINGLETON)
|
||||
.factory(CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(ArrayConverter.class, Scope.SINGLETON)
|
||||
.factory(DateConverter.class, Scope.SINGLETON)
|
||||
.factory(NumberConverter.class, Scope.SINGLETON)
|
||||
.factory(StringConverter.class, Scope.SINGLETON)
|
||||
|
||||
.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON)
|
||||
.factory(LocalizedTextProvider.class, StrutsLocalizedTextProvider.class, Scope.SINGLETON)
|
||||
.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(AcceptedPatternsChecker.class, DefaultAcceptedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(NotExcludedAcceptedPatternsChecker.class, DefaultNotExcludedAcceptedPatternsChecker.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(OgnlUtil.class, Scope.SINGLETON)
|
||||
.factory(SecurityMemberAccess.class, Scope.PROTOTYPE)
|
||||
.factory(OgnlGuard.class, StrutsOgnlGuard.class, Scope.SINGLETON)
|
||||
.factory(CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(ArrayConverter.class, Scope.SINGLETON)
|
||||
.factory(DateConverter.class, Scope.SINGLETON)
|
||||
.factory(NumberConverter.class, Scope.SINGLETON)
|
||||
.factory(StringConverter.class, Scope.SINGLETON)
|
||||
.factory(QueryStringBuilder.class, StrutsQueryStringBuilder.class, Scope.SINGLETON)
|
||||
.factory(QueryStringParser.class, StrutsQueryStringParser.class, Scope.SINGLETON)
|
||||
.factory(UrlEncoder.class, StrutsUrlEncoder.class, Scope.SINGLETON)
|
||||
.factory(UrlDecoder.class, StrutsUrlDecoder.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(AcceptedPatternsChecker.class, DefaultAcceptedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(NotExcludedAcceptedPatternsChecker.class, DefaultNotExcludedAcceptedPatternsChecker.class
|
||||
, Scope.SINGLETON)
|
||||
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(QueryStringBuilder.class, StrutsQueryStringBuilder.class, Scope.SINGLETON)
|
||||
.factory(QueryStringParser.class, StrutsQueryStringParser.class, Scope.SINGLETON)
|
||||
.factory(UrlEncoder.class, StrutsUrlEncoder.class, Scope.SINGLETON)
|
||||
.factory(UrlDecoder.class, StrutsUrlDecoder.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExecutorProvider.class, StrutsExecutorProvider.class, Scope.SINGLETON)
|
||||
;
|
||||
.factory(ExecutorProvider.class, StrutsExecutorProvider.class, Scope.SINGLETON);
|
||||
|
||||
for (Map.Entry<String, Object> entry : DefaultConfiguration.BOOTSTRAP_CONSTANTS.entrySet()) {
|
||||
props.setProperty(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
|
||||
+61
-27
@@ -45,9 +45,11 @@ import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.util.location.Location;
|
||||
import com.opensymphony.xwork2.util.location.LocationUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
@@ -92,8 +94,10 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
protected ObjectFactory objectFactory;
|
||||
protected Map<String, String> dtdMappings = new HashMap<>();
|
||||
protected Configuration configuration;
|
||||
protected ProviderAllowlist providerAllowlist;
|
||||
protected boolean throwExceptionOnDuplicateBeans = true;
|
||||
protected ValueSubstitutor valueSubstitutor;
|
||||
protected Set<Class<?>> allowlistClasses = new HashSet<>();
|
||||
|
||||
@Inject
|
||||
public void setObjectFactory(ObjectFactory objectFactory) {
|
||||
@@ -131,8 +135,22 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
private void registerAllowlist() {
|
||||
providerAllowlist = configuration.getContainer().getInstance(ProviderAllowlist.class);
|
||||
providerAllowlist.registerAllowlist(this, allowlistClasses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
providerAllowlist.clearAllowlist(this);
|
||||
}
|
||||
|
||||
protected Class<?> allowAndLoadClass(String className) throws ClassNotFoundException {
|
||||
Class<?> clazz = loadClass(className);
|
||||
allowlistClasses.add(clazz);
|
||||
allowlistClasses.addAll(ClassUtils.getAllSuperclasses(clazz));
|
||||
allowlistClasses.addAll(ClassUtils.getAllInterfaces(clazz));
|
||||
return clazz;
|
||||
}
|
||||
|
||||
protected Class<?> loadClass(String className) throws ClassNotFoundException {
|
||||
@@ -169,6 +187,7 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
|
||||
@Override
|
||||
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
|
||||
allowlistClasses.clear();
|
||||
Map<String, Node> loadedBeans = new HashMap<>();
|
||||
for (Document doc : documents) {
|
||||
iterateElementChildren(doc, child -> {
|
||||
@@ -197,7 +216,7 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
String name = child.getAttribute("name");
|
||||
String impl = child.getAttribute("class");
|
||||
try {
|
||||
Class<?> classImpl = loadClass(impl);
|
||||
Class<?> classImpl = ClassLoaderUtil.loadClass(impl, getClass());
|
||||
if (BeanSelectionProvider.class.isAssignableFrom(classImpl)) {
|
||||
BeanSelectionProvider provider = (BeanSelectionProvider) classImpl.newInstance();
|
||||
provider.register(containerBuilder, props);
|
||||
@@ -303,7 +322,7 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
loadExtraConfiguration(doc);
|
||||
}
|
||||
|
||||
if (reloads.size() > 0) {
|
||||
if (!reloads.isEmpty()) {
|
||||
reloadRequiredPackages(reloads);
|
||||
}
|
||||
|
||||
@@ -312,6 +331,7 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
}
|
||||
|
||||
declaredPackages.clear();
|
||||
registerAllowlist();
|
||||
configuration = null;
|
||||
}
|
||||
|
||||
@@ -442,13 +462,8 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
|
||||
Location location = DomHelper.getLocationObject(actionElement);
|
||||
|
||||
if (location == null) {
|
||||
LOG.warn("Location null for {}", className);
|
||||
}
|
||||
|
||||
if (!className.isEmpty() && !verifyAction(className, name, location)) {
|
||||
LOG.error("Unable to verify action [{}] with class [{}], from [{}]", name, className, location);
|
||||
return;
|
||||
if (!className.isEmpty()) {
|
||||
verifyAction(className, name, location);
|
||||
}
|
||||
|
||||
Map<String, ResultConfig> results;
|
||||
@@ -499,27 +514,30 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
*/
|
||||
@Deprecated
|
||||
protected boolean verifyAction(String className, String name, Location loc) {
|
||||
return verifyAction(className, loc);
|
||||
verifyAction(className, loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean verifyAction(String className, Location loc) {
|
||||
protected void verifyAction(String className, Location loc) {
|
||||
if (className.contains("{")) {
|
||||
LOG.debug("Action class [{}] contains a wildcard replacement value, so it can't be verified", className);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = allowAndLoadClass(className);
|
||||
if (objectFactory.isNoArgConstructorRequired()) {
|
||||
Class<?> clazz = loadClass(className);
|
||||
if (!Modifier.isPublic(clazz.getModifiers())) {
|
||||
throw new ConfigurationException("Action class [" + className + "] is not public", loc);
|
||||
}
|
||||
clazz.getConstructor();
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.debug("Class not found for action [{}]", className, e);
|
||||
throw new ConfigurationException("Action class [" + className + "] not found", loc);
|
||||
if (objectFactory.isNoArgConstructorRequired()) {
|
||||
throw new ConfigurationException("Action class [" + className + "] not found", e, loc);
|
||||
}
|
||||
LOG.warn("Action class [" + className + "] not found");
|
||||
LOG.debug("Action class [" + className + "] not found", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
LOG.debug("No constructor found for action [{}]", className, e);
|
||||
throw new ConfigurationException("Action class [" + className + "] does not have a public no-arg constructor", e, loc);
|
||||
} catch (RuntimeException ex) {
|
||||
// Probably not a big deal, like request or session-scoped Spring beans that need a real request
|
||||
@@ -527,10 +545,8 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
LOG.debug("Action verification cause", ex);
|
||||
} catch (Exception ex) {
|
||||
// Default to failing fast
|
||||
LOG.debug("Unable to verify action class [{}]", className, ex);
|
||||
throw new ConfigurationException(ex, loc);
|
||||
throw new ConfigurationException("Unable to verify action class [" + className + "]", ex, loc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void addResultTypes(PackageConfig.Builder packageContext, Element element) {
|
||||
@@ -541,9 +557,7 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
|
||||
Location loc = DomHelper.getLocationObject(resultTypeElement);
|
||||
Class<?> clazz = verifyResultType(className, loc);
|
||||
if (clazz == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String paramName = null;
|
||||
try {
|
||||
paramName = (String) clazz.getField("DEFAULT_PARAM").get(null);
|
||||
@@ -572,11 +586,10 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
|
||||
protected Class<?> verifyResultType(String className, Location loc) {
|
||||
try {
|
||||
return loadClass(className);
|
||||
return allowAndLoadClass(className);
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||
LOG.warn("Result class [{}] doesn't exist ({}) at {}, ignoring", className, e.getClass().getSimpleName(), loc, e);
|
||||
throw new ConfigurationException("Result class [" + className + "] not found", e, loc);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -888,7 +901,12 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
NodeList defaultClassRefList = element.getElementsByTagName("default-class-ref");
|
||||
if (defaultClassRefList.getLength() > 0) {
|
||||
Element defaultClassRefElement = (Element) defaultClassRefList.item(0);
|
||||
packageContext.defaultClassRef(defaultClassRefElement.getAttribute("class"));
|
||||
|
||||
String className = defaultClassRefElement.getAttribute("class");
|
||||
Location location = DomHelper.getLocationObject(defaultClassRefElement);
|
||||
verifyAction(className, location);
|
||||
|
||||
packageContext.defaultClassRef(className);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -927,10 +945,26 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
iterateChildrenByTagName(
|
||||
element,
|
||||
"interceptor",
|
||||
interceptorElement -> context.addInterceptorConfig(buildInterceptorConfig(interceptorElement)));
|
||||
interceptorElement -> {
|
||||
String className = interceptorElement.getAttribute("class");
|
||||
Location location = DomHelper.getLocationObject(interceptorElement);
|
||||
|
||||
verifyInterceptor(className, location);
|
||||
|
||||
context.addInterceptorConfig(buildInterceptorConfig(interceptorElement));
|
||||
});
|
||||
loadInterceptorStacks(element, context);
|
||||
}
|
||||
|
||||
protected void verifyInterceptor(String className, Location loc) {
|
||||
try {
|
||||
allowAndLoadClass(className);
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||
LOG.warn("Interceptor class [" + className + "] at location " + loc + " not found");
|
||||
LOG.debug("Interceptor class [" + className + "] not found", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected InterceptorConfig buildInterceptorConfig(Element interceptorElement) {
|
||||
String interceptorName = interceptorElement.getAttribute("name");
|
||||
String className = interceptorElement.getAttribute("class");
|
||||
|
||||
@@ -863,6 +863,7 @@ public class OgnlUtil {
|
||||
}
|
||||
|
||||
SecurityMemberAccess memberAccess = container.getInstance(SecurityMemberAccess.class);
|
||||
memberAccess.useEnforceAllowlistEnabled(Boolean.FALSE.toString());
|
||||
|
||||
if (devMode) {
|
||||
if (!warnReported.get()) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -39,6 +40,7 @@ import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toClassObjectsSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toClassesSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toNewClassesSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toNewPackageNamesSet;
|
||||
@@ -57,6 +59,19 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(SecurityMemberAccess.class);
|
||||
|
||||
private static final Set<String> ALLOWLIST_REQUIRED_PACKAGES = unmodifiableSet(new HashSet<>(Arrays.asList(
|
||||
"org.apache.struts2.components",
|
||||
"org.apache.struts2.views.jsp",
|
||||
"com.opensymphony.xwork2.validator.validators"
|
||||
)));
|
||||
|
||||
private static final Set<Class<?>> ALLOWLIST_REQUIRED_CLASSES = unmodifiableSet(new HashSet<>(Arrays.asList(
|
||||
java.lang.Enum.class,
|
||||
java.util.Date.class,
|
||||
java.util.HashMap.class
|
||||
)));
|
||||
|
||||
private final ProviderAllowlist providerAllowlist;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
private Set<Pattern> excludeProperties = emptySet();
|
||||
private Set<Pattern> acceptProperties = emptySet();
|
||||
@@ -65,12 +80,14 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
private Set<String> excludedPackageNames = emptySet();
|
||||
private Set<String> excludedPackageExemptClasses = emptySet();
|
||||
private boolean enforceAllowlistEnabled = false;
|
||||
private Set<String> allowlistClasses = emptySet();
|
||||
private Set<Class<?>> allowlistClasses = emptySet();
|
||||
private Set<String> allowlistPackageNames = emptySet();
|
||||
private boolean disallowProxyMemberAccess = false;
|
||||
private boolean disallowDefaultPackageAccess = false;
|
||||
|
||||
public SecurityMemberAccess() {
|
||||
@Inject
|
||||
public SecurityMemberAccess(@Inject ProviderAllowlist providerAllowlist) {
|
||||
this.providerAllowlist = providerAllowlist;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,10 +96,11 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
* - block or allow access to properties (configurable-after-construction)
|
||||
*
|
||||
* @param allowStaticFieldAccess if set to true static fields (constants) will be accessible
|
||||
* @deprecated since 6.4.0, use {@link #SecurityMemberAccess()} instead.
|
||||
* @deprecated since 6.4.0, use {@link #SecurityMemberAccess(ProviderAllowlist)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public SecurityMemberAccess(boolean allowStaticFieldAccess) {
|
||||
this(null);
|
||||
useAllowStaticFieldAccess(String.valueOf(allowStaticFieldAccess));
|
||||
}
|
||||
|
||||
@@ -199,7 +217,11 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
}
|
||||
|
||||
protected boolean isClassAllowlisted(Class<?> clazz) {
|
||||
return allowlistClasses.contains(clazz.getName()) || isClassBelongsToPackages(clazz, allowlistPackageNames);
|
||||
return allowlistClasses.contains(clazz)
|
||||
|| ALLOWLIST_REQUIRED_CLASSES.contains(clazz)
|
||||
|| (providerAllowlist != null && providerAllowlist.getProviderAllowlist().contains(clazz))
|
||||
|| isClassBelongsToPackages(clazz, ALLOWLIST_REQUIRED_PACKAGES)
|
||||
|| isClassBelongsToPackages(clazz, allowlistPackageNames);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -411,7 +433,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOWLIST_CLASSES, required = false)
|
||||
public void useAllowlistClasses(String commaDelimitedClasses) {
|
||||
this.allowlistClasses = toClassesSet(commaDelimitedClasses);
|
||||
this.allowlistClasses = toClassObjectsSet(commaDelimitedClasses);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOWLIST_PACKAGE_NAMES, required = false)
|
||||
|
||||
@@ -43,6 +43,11 @@ public class ConfigParseUtil {
|
||||
return unmodifiableSet(classNames);
|
||||
}
|
||||
|
||||
public static Set<Class<?>> toClassObjectsSet(String newDelimitedClasses) throws ConfigurationException {
|
||||
Set<String> classNames = commaDelimitedStringToSet(newDelimitedClasses);
|
||||
return unmodifiableSet(validateClasses(classNames, OgnlUtil.class.getClassLoader()));
|
||||
}
|
||||
|
||||
public static Set<String> toNewClassesSet(Set<String> oldClasses, String newDelimitedClasses) throws ConfigurationException {
|
||||
Set<String> classNames = commaDelimitedStringToSet(newDelimitedClasses);
|
||||
validateClasses(classNames, OgnlUtil.class.getClassLoader());
|
||||
@@ -64,14 +69,16 @@ public class ConfigParseUtil {
|
||||
return unmodifiableSet(newPatterns);
|
||||
}
|
||||
|
||||
public static void validateClasses(Set<String> classNames, ClassLoader validatingClassLoader) throws ConfigurationException {
|
||||
public static Set<Class<?>> validateClasses(Set<String> classNames, ClassLoader validatingClassLoader) throws ConfigurationException {
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
validatingClassLoader.loadClass(className);
|
||||
classes.add(validatingClassLoader.loadClass(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ConfigurationException("Cannot load class for exclusion/exemption configuration: " + className, e);
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
public static Set<String> toPackageNamesSet(String newDelimitedPackageNames) throws ConfigurationException {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 org.apache.struts2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
/**
|
||||
* Allows {@link ConfigurationProvider}s to register classes that should be allowed to be used in OGNL expressions.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*/
|
||||
public class ProviderAllowlist {
|
||||
|
||||
private final Map<ConfigurationProvider, Set<Class<?>>> allowlistMap;
|
||||
private Set<Class<?>> allowlistClasses;
|
||||
|
||||
public ProviderAllowlist() {
|
||||
allowlistMap = new HashMap<>();
|
||||
reconstructAllowlist();
|
||||
}
|
||||
|
||||
public synchronized void registerAllowlist(ConfigurationProvider configurationProvider, Set<Class<?>> allowlist) {
|
||||
Set<Class<?>> existingAllowlist = allowlistMap.get(configurationProvider);
|
||||
if (existingAllowlist != null) {
|
||||
clearAllowlist(configurationProvider);
|
||||
}
|
||||
this.allowlistMap.put(configurationProvider, new HashSet<>(allowlist));
|
||||
this.allowlistClasses.addAll(allowlist);
|
||||
}
|
||||
|
||||
public synchronized void clearAllowlist(ConfigurationProvider configurationProvider) {
|
||||
Set<Class<?>> allowlist = allowlistMap.get(configurationProvider);
|
||||
if (allowlist == null) {
|
||||
return;
|
||||
}
|
||||
this.allowlistMap.remove(configurationProvider);
|
||||
reconstructAllowlist();
|
||||
}
|
||||
|
||||
public Set<Class<?>> getProviderAllowlist() {
|
||||
return unmodifiableSet(allowlistClasses);
|
||||
}
|
||||
|
||||
private void reconstructAllowlist() {
|
||||
this.allowlistClasses = allowlistMap.values().stream().reduce(new HashSet<>(), (a, b) -> {
|
||||
a.addAll(b);
|
||||
return a;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -169,6 +169,7 @@
|
||||
<bean name="struts" class="com.opensymphony.xwork2.ognl.SecurityMemberAccess" scope="prototype"/>
|
||||
<bean type="org.apache.struts2.ognl.OgnlGuard" name="struts"
|
||||
class="org.apache.struts2.ognl.StrutsOgnlGuard"/>
|
||||
<bean class="org.apache.struts2.ognl.ProviderAllowlist"/>
|
||||
|
||||
<bean type="com.opensymphony.xwork2.util.TextParser" name="struts"
|
||||
class="com.opensymphony.xwork2.util.OgnlTextParser" scope="singleton"/>
|
||||
|
||||
@@ -44,8 +44,6 @@
|
||||
|
||||
<interceptors>
|
||||
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
|
||||
<interceptor name="autowiring"
|
||||
class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
|
||||
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
|
||||
<interceptor name="coep" class="org.apache.struts2.interceptor.CoepInterceptor"/>
|
||||
<interceptor name="conversionError"
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
java.lang.System,
|
||||
java.lang.Thread,
|
||||
java.lang.ThreadGroup,
|
||||
java.lang.ThreadLocal"/>
|
||||
java.lang.ThreadLocal
|
||||
"/>
|
||||
|
||||
<constant name="struts.devMode.excludedClasses"
|
||||
value="
|
||||
@@ -61,7 +62,8 @@
|
||||
java.lang.System,
|
||||
java.lang.Thread,
|
||||
java.lang.ThreadGroup,
|
||||
java.lang.ThreadLocal"/>
|
||||
java.lang.ThreadLocal
|
||||
"/>
|
||||
|
||||
<!-- this must be valid regex, each '.' in package name must be escaped! -->
|
||||
<!-- it's more flexible but slower than simple string comparison -->
|
||||
@@ -98,7 +100,8 @@
|
||||
org.wildfly.extension.undertow.deployment,
|
||||
org.yaml.snakeyaml,
|
||||
sun.misc,
|
||||
sun.reflect"/>
|
||||
sun.reflect
|
||||
"/>
|
||||
|
||||
<constant name="struts.devMode.excludedPackageNames"
|
||||
value="
|
||||
@@ -129,6 +132,7 @@
|
||||
org.wildfly.extension.undertow.deployment,
|
||||
org.yaml.snakeyaml,
|
||||
sun.misc,
|
||||
sun.reflect"/>
|
||||
sun.reflect
|
||||
"/>
|
||||
|
||||
</struts>
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.config.providers;
|
||||
|
||||
import com.opensymphony.xwork2.XWorkJUnit4TestCase;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase {
|
||||
|
||||
private final ConfigurationProvider testXml1 = new StrutsXmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowlist.xml");
|
||||
private final ConfigurationProvider testXml2 = new StrutsXmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowlist-2.xml");
|
||||
private ProviderAllowlist providerAllowlist;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
loadConfigurationProviders(testXml1, testXml2);
|
||||
providerAllowlist = container.getInstance(ProviderAllowlist.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowlist() throws Exception {
|
||||
loadConfigurationProviders(testXml1, testXml2);
|
||||
providerAllowlist = container.getInstance(ProviderAllowlist.class);
|
||||
|
||||
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ValidationAware"),
|
||||
Class.forName("com.opensymphony.xwork2.LocaleProvider"),
|
||||
Class.forName("java.io.Serializable"),
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockResult"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionChainResult"),
|
||||
Class.forName("com.opensymphony.xwork2.TextProvider"),
|
||||
Class.forName("org.apache.struts2.interceptor.NoOpInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.Interceptor"),
|
||||
Class.forName("java.lang.Object"),
|
||||
Class.forName("com.opensymphony.xwork2.Validateable"),
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Action"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Result"),
|
||||
Class.forName("com.opensymphony.xwork2.SimpleAction")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowlist_1only() throws Exception {
|
||||
loadConfigurationProviders(testXml1);
|
||||
providerAllowlist = container.getInstance(ProviderAllowlist.class);
|
||||
|
||||
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ValidationAware"),
|
||||
Class.forName("com.opensymphony.xwork2.LocaleProvider"),
|
||||
Class.forName("java.io.Serializable"),
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockResult"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.TextProvider"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.Interceptor"),
|
||||
Class.forName("java.lang.Object"),
|
||||
Class.forName("com.opensymphony.xwork2.Validateable"),
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Action"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Result"),
|
||||
Class.forName("com.opensymphony.xwork2.SimpleAction")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowlist_2only() throws Exception {
|
||||
loadConfigurationProviders(testXml2);
|
||||
providerAllowlist = container.getInstance(ProviderAllowlist.class);
|
||||
|
||||
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ValidationAware"),
|
||||
Class.forName("com.opensymphony.xwork2.LocaleProvider"),
|
||||
Class.forName("java.io.Serializable"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionChainResult"),
|
||||
Class.forName("com.opensymphony.xwork2.TextProvider"),
|
||||
Class.forName("org.apache.struts2.interceptor.NoOpInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.Interceptor"),
|
||||
Class.forName("java.lang.Object"),
|
||||
Class.forName("com.opensymphony.xwork2.Validateable"),
|
||||
Class.forName("com.opensymphony.xwork2.Action"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Result")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.test.TestBean2;
|
||||
import com.opensymphony.xwork2.util.Foo;
|
||||
import ognl.MemberAccess;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -44,22 +45,28 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SecurityMemberAccessTest {
|
||||
|
||||
private Map context;
|
||||
private FooBar target;
|
||||
protected SecurityMemberAccess sma;
|
||||
private ProviderAllowlist mockedProviderAllowlist;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
context = new HashMap<>();
|
||||
target = new FooBar();
|
||||
mockedProviderAllowlist = mock(ProviderAllowlist.class);
|
||||
assignNewSma(true);
|
||||
}
|
||||
|
||||
protected void assignNewSma(boolean allowStaticFieldAccess) {
|
||||
sma = new SecurityMemberAccess(allowStaticFieldAccess);
|
||||
when(mockedProviderAllowlist.getProviderAllowlist()).thenReturn(new HashSet<>());
|
||||
sma = new SecurityMemberAccess(mockedProviderAllowlist);
|
||||
sma.useAllowStaticFieldAccess(String.valueOf(allowStaticFieldAccess));
|
||||
}
|
||||
|
||||
private <T> T reflectField(String fieldName) throws IllegalAccessException {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 org.apache.struts2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ProviderAllowlistTest {
|
||||
|
||||
@Rule
|
||||
public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
private ProviderAllowlist providerAllowlist;
|
||||
|
||||
@Mock
|
||||
private ConfigurationProvider provider1;
|
||||
|
||||
@Mock
|
||||
private ConfigurationProvider provider2;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
providerAllowlist = new ProviderAllowlist();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerAllowlist() {
|
||||
providerAllowlist.registerAllowlist(provider1, new HashSet<>(asList(String.class, Integer.class)));
|
||||
providerAllowlist.registerAllowlist(provider2, new HashSet<>(asList(Double.class, Integer.class)));
|
||||
|
||||
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(String.class, Integer.class, Double.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerAllowlist_twice() {
|
||||
providerAllowlist.registerAllowlist(provider1, new HashSet<>(asList(String.class, Integer.class)));
|
||||
providerAllowlist.registerAllowlist(provider1, new HashSet<>(asList(Double.class, Integer.class)));
|
||||
|
||||
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(Integer.class, Double.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearAllowlist() {
|
||||
providerAllowlist.registerAllowlist(provider1, new HashSet<>(asList(String.class, Integer.class)));
|
||||
providerAllowlist.registerAllowlist(provider2, new HashSet<>(asList(Double.class, Integer.class)));
|
||||
|
||||
providerAllowlist.clearAllowlist(provider1);
|
||||
|
||||
assertThat(providerAllowlist.getProviderAllowlist()).containsExactlyInAnyOrder(Integer.class, Double.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearAllowlist_both() {
|
||||
providerAllowlist.registerAllowlist(provider1, new HashSet<>(asList(String.class, Integer.class)));
|
||||
providerAllowlist.registerAllowlist(provider2, new HashSet<>(asList(Double.class, Integer.class)));
|
||||
|
||||
providerAllowlist.clearAllowlist(provider1);
|
||||
providerAllowlist.clearAllowlist(provider2);
|
||||
|
||||
assertThat(providerAllowlist.getProviderAllowlist()).isEmpty();
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
<struts>
|
||||
<package name="allow2">
|
||||
<result-types>
|
||||
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult" default="true"/>
|
||||
</result-types>
|
||||
|
||||
<interceptors>
|
||||
<interceptor name="noop" class="org.apache.struts2.interceptor.NoOpInterceptor"/>
|
||||
</interceptors>
|
||||
|
||||
<action name="WildCard" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<result name="*" type="chain"/>
|
||||
<interceptor-ref name="noop"/>
|
||||
</action>
|
||||
|
||||
</package>
|
||||
</struts>
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
<struts>
|
||||
<package name="allow">
|
||||
<result-types>
|
||||
<result-type name="mock" class="com.opensymphony.xwork2.mock.MockResult"/>
|
||||
</result-types>
|
||||
|
||||
<interceptors>
|
||||
<interceptor name="test" class="com.opensymphony.xwork2.mock.MockInterceptor">
|
||||
<param name="foo">fooDefault</param>
|
||||
</interceptor>
|
||||
|
||||
<interceptor-stack name="defaultStack">
|
||||
<interceptor-ref name="test"/>
|
||||
</interceptor-stack>
|
||||
</interceptors>
|
||||
|
||||
<action name="Foo" class="com.opensymphony.xwork2.SimpleAction">
|
||||
<param name="foo">18</param>
|
||||
<param name="bar">24</param>
|
||||
<result name="success" type="mock"/>
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
</action>
|
||||
</package>
|
||||
</struts>
|
||||
@@ -21,7 +21,6 @@ package org.apache.struts2.junit;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
|
||||
@@ -18,74 +18,5 @@
|
||||
*/
|
||||
package org.apache.struts2.junit;
|
||||
|
||||
import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Context;
|
||||
import com.opensymphony.xwork2.inject.Factory;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.test.StubConfigurationProvider;
|
||||
import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
public abstract class XWorkJUnit4TestCase {
|
||||
|
||||
protected ConfigurationManager configurationManager;
|
||||
protected Configuration configuration;
|
||||
protected Container container;
|
||||
protected ActionProxyFactory actionProxyFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
configurationManager = XWorkTestCaseHelper.setUp();
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
XWorkTestCaseHelper.tearDown(configurationManager);
|
||||
configurationManager = null;
|
||||
configuration = null;
|
||||
container = null;
|
||||
actionProxyFactory = null;
|
||||
}
|
||||
|
||||
protected void loadConfigurationProviders(ConfigurationProvider... providers) {
|
||||
configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final Object impl) {
|
||||
loadButAdd(type, Container.DEFAULT_NAME, impl);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final String name, final Object impl) {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
builder.factory(type, name, new Factory() {
|
||||
public Object create(Context context) throws Exception {
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class type() {
|
||||
return impl.getClass();
|
||||
}
|
||||
}, Scope.SINGLETON);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public abstract class XWorkJUnit4TestCase extends com.opensymphony.xwork2.XWorkJUnit4TestCase {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 org.apache.struts2.junit;
|
||||
|
||||
public abstract class XWorkTestCase extends com.opensymphony.xwork2.XWorkTestCase {
|
||||
}
|
||||
Reference in New Issue
Block a user