[ https://issues.apache.org/jira/browse/WW-5343?focusedWorklogId=891833&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-891833 ]
ASF GitHub Bot logged work on WW-5343: -------------------------------------- Author: ASF GitHub Bot Created on: 22/Nov/23 14:20 Start Date: 22/Nov/23 14:20 Worklog Time Spent: 10m Work Description: kusalk commented on code in PR #791: URL: https://github.com/apache/struts/pull/791#discussion_r1402127733 ########## core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java: ########## @@ -133,7 +134,6 @@ public class DefaultConfiguration implements Configuration { Map<String, Object> constants = new HashMap<>(); constants.put(StrutsConstants.STRUTS_DEVMODE, Boolean.FALSE); constants.put(StrutsConstants.STRUTS_OGNL_LOG_MISSING_PROPERTIES, Boolean.FALSE); - constants.put(StrutsConstants.STRUTS_OGNL_ENABLE_EVAL_EXPRESSION, Boolean.FALSE); Review Comment: This constant is not required for bootstrapping ########## core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java: ########## @@ -84,27 +77,15 @@ public class OgnlUtil { private final OgnlGuard ognlGuard; private boolean devMode; - private boolean enableExpressionCache = true; + private boolean enableExpressionCache; private boolean enableEvalExpression; - private Set<String> excludedClasses = emptySet(); Review Comment: All the configuration is now injected directly into `SecurityMemberAccess` except for devMode configuration ########## core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java: ########## @@ -175,166 +156,110 @@ protected void setEnableEvalExpression(String evalExpression) { } } - @Inject(value = StrutsConstants.STRUTS_EXCLUDED_CLASSES, required = false) + /** + * @deprecated since 6.4.0, no replacement. + */ + @Deprecated protected void setExcludedClasses(String commaDelimitedClasses) { - excludedClasses = toNewClassesSet(excludedClasses, commaDelimitedClasses); } @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, required = false) protected void setDevModeExcludedClasses(String commaDelimitedClasses) { - devModeExcludedClasses = toNewClassesSet(devModeExcludedClasses, commaDelimitedClasses); + this.devModeExcludedClasses = commaDelimitedClasses; } - private static Set<String> toClassesSet(String newDelimitedClasses) throws ConfigurationException { Review Comment: Moved these utility methods into their own class ########## core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java: ########## @@ -175,166 +156,110 @@ protected void setEnableEvalExpression(String evalExpression) { } } - @Inject(value = StrutsConstants.STRUTS_EXCLUDED_CLASSES, required = false) + /** + * @deprecated since 6.4.0, no replacement. + */ + @Deprecated protected void setExcludedClasses(String commaDelimitedClasses) { - excludedClasses = toNewClassesSet(excludedClasses, commaDelimitedClasses); } @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, required = false) protected void setDevModeExcludedClasses(String commaDelimitedClasses) { - devModeExcludedClasses = toNewClassesSet(devModeExcludedClasses, commaDelimitedClasses); + this.devModeExcludedClasses = commaDelimitedClasses; } - private static Set<String> toClassesSet(String newDelimitedClasses) throws ConfigurationException { - Set<String> classNames = commaDelimitedStringToSet(newDelimitedClasses); - validateClasses(classNames, OgnlUtil.class.getClassLoader()); - return unmodifiableSet(classNames); - } - - private static Set<String> toNewClassesSet(Set<String> oldClasses, String newDelimitedClasses) throws ConfigurationException { - Set<String> classNames = commaDelimitedStringToSet(newDelimitedClasses); - validateClasses(classNames, OgnlUtil.class.getClassLoader()); - Set<String> excludedClasses = new HashSet<>(oldClasses); - excludedClasses.addAll(classNames); - return unmodifiableSet(excludedClasses); - } - - private static void validateClasses(Set<String> classNames, ClassLoader validatingClassLoader) throws ConfigurationException { - for (String className : classNames) { - try { - validatingClassLoader.loadClass(className); - } catch (ClassNotFoundException e) { - throw new ConfigurationException("Cannot load class for exclusion/exemption configuration: " + className, e); - } - } - } - - @Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false) + /** + * @deprecated since 6.4.0, no replacement. + */ + @Deprecated protected void setExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) { - excludedPackageNamePatterns = toNewPatternsSet(excludedPackageNamePatterns, commaDelimitedPackagePatterns); } @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false) protected void setDevModeExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) { - devModeExcludedPackageNamePatterns = toNewPatternsSet(devModeExcludedPackageNamePatterns, commaDelimitedPackagePatterns); + this.devModeExcludedPackageNamePatterns = commaDelimitedPackagePatterns; } - private static Set<Pattern> toNewPatternsSet(Set<Pattern> oldPatterns, String newDelimitedPatterns) throws ConfigurationException { - Set<String> patterns = commaDelimitedStringToSet(newDelimitedPatterns); - Set<Pattern> newPatterns = new HashSet<>(oldPatterns); - for (String pattern: patterns) { - try { - newPatterns.add(Pattern.compile(pattern)); - } catch (PatternSyntaxException e) { - throw new ConfigurationException("Excluded package name patterns could not be parsed due to invalid regex: " + pattern, e); - } - } - return unmodifiableSet(newPatterns); - } - - @Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES, required = false) + /** + * @deprecated since 6.4.0, no replacement. + */ + @Deprecated protected void setExcludedPackageNames(String commaDelimitedPackageNames) { - excludedPackageNames = toNewPackageNamesSet(excludedPackageNames, commaDelimitedPackageNames); } @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, required = false) protected void setDevModeExcludedPackageNames(String commaDelimitedPackageNames) { - devModeExcludedPackageNames = toNewPackageNamesSet(devModeExcludedPackageNames, commaDelimitedPackageNames); - } - - private static Set<String> toPackageNamesSet(String newDelimitedPackageNames) throws ConfigurationException { - Set<String> packageNames = commaDelimitedStringToSet(newDelimitedPackageNames) - .stream().map(s -> strip(s, ".")).collect(toSet()); - validatePackageNames(packageNames); - return unmodifiableSet(packageNames); - } - - private static Set<String> toNewPackageNamesSet(Collection<String> oldPackageNames, String newDelimitedPackageNames) throws ConfigurationException { - Set<String> packageNames = commaDelimitedStringToSet(newDelimitedPackageNames) - .stream().map(s -> strip(s, ".")).collect(toSet()); - validatePackageNames(packageNames); - Set<String> newPackageNames = new HashSet<>(oldPackageNames); - newPackageNames.addAll(packageNames); - return unmodifiableSet(newPackageNames); + this.devModeExcludedPackageNames = commaDelimitedPackageNames; } - private static void validatePackageNames(Collection<String> packageNames) { - if (packageNames.stream().anyMatch(s -> Pattern.compile("\\s").matcher(s).find())) { - throw new ConfigurationException("Excluded package names could not be parsed due to erroneous whitespace characters: " + packageNames); - } - } - - @Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false) + /** + * @deprecated since 6.4.0, no replacement. + */ + @Deprecated public void setExcludedPackageExemptClasses(String commaDelimitedClasses) { - excludedPackageExemptClasses = toClassesSet(commaDelimitedClasses); } @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false) public void setDevModeExcludedPackageExemptClasses(String commaDelimitedClasses) { - devModeExcludedPackageExemptClasses = toClassesSet(commaDelimitedClasses); + this.devModeExcludedPackageExemptClasses = commaDelimitedClasses; } + /** + * @deprecated since 6.4.0, no replacement. + */ + @Deprecated public Set<String> getExcludedClasses() { - return excludedClasses; + return toClassesSet(container.getInstance(String.class, StrutsConstants.STRUTS_EXCLUDED_CLASSES)); Review Comment: Deprecated getters are still functional for API compatibility ########## core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStack.java: ########## @@ -77,38 +77,91 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS private boolean devMode; private boolean logMissingProperties; + /** + * @since 6.4.0 + */ + protected OgnlValueStack(ValueStack vs, + XWorkConverter xworkConverter, + CompoundRootAccessor accessor, + TextProvider prov, + SecurityMemberAccess securityMemberAccess) { + setRoot(xworkConverter, + accessor, + vs != null ? new CompoundRoot(vs.getRoot()) : new CompoundRoot(), + securityMemberAccess); + if (prov != null) { + push(prov); + } + } + + /** + * @since 6.4.0 + */ + protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, SecurityMemberAccess securityMemberAccess) { + this(null, xworkConverter, accessor, prov, securityMemberAccess); + } + + /** + * @since 6.4.0 + */ + protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, SecurityMemberAccess securityMemberAccess) { + this(vs, xworkConverter, accessor, null, securityMemberAccess); + } + + /** + * @deprecated since 6.4.0, use {@link #OgnlValueStack(ValueStack, XWorkConverter, CompoundRootAccessor, TextProvider, SecurityMemberAccess)} instead. + */ + @Deprecated + protected OgnlValueStack(ValueStack vs, + XWorkConverter xworkConverter, + CompoundRootAccessor accessor, + TextProvider prov, + boolean allowStaticFieldAccess) { + this(vs, xworkConverter, accessor, prov, new SecurityMemberAccess(allowStaticFieldAccess)); + } + + /** + * @deprecated since 6.4.0, use {@link #OgnlValueStack(XWorkConverter, CompoundRootAccessor, TextProvider, SecurityMemberAccess)} instead. + */ + @Deprecated protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticFieldAccess) { - setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticFieldAccess); - push(prov); + this(xworkConverter, accessor, prov, new SecurityMemberAccess(allowStaticFieldAccess)); } + /** + * @deprecated since 6.4.0, use {@link #OgnlValueStack(ValueStack, XWorkConverter, CompoundRootAccessor, SecurityMemberAccess)} instead. + */ + @Deprecated protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticFieldAccess) { - setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticFieldAccess); + this(vs, xworkConverter, accessor, new SecurityMemberAccess(allowStaticFieldAccess)); } @Inject protected void setOgnlUtil(OgnlUtil ognlUtil) { this.ognlUtil = ognlUtil; - securityMemberAccess.useExcludedClasses(ognlUtil.getExcludedClasses()); Review Comment: No more fragile configuration setting duplicated in multiple places ########## core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStack.java: ########## @@ -464,48 +517,42 @@ public int size() { return root.size(); } + /** + * Retained for serializability - see {@link com.opensymphony.xwork2.ognl.OgnlValueStackTest#testSerializable} + */ private Object readResolve() { // TODO: this should be done better ActionContext ac = ActionContext.getContext(); Container cont = ac.getContainer(); XWorkConverter xworkConverter = cont.getInstance(XWorkConverter.class); CompoundRootAccessor accessor = (CompoundRootAccessor) cont.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()); TextProvider prov = cont.getInstance(TextProvider.class, "system"); - final boolean allowStaticField = BooleanUtils.toBoolean(cont.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS)); - OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, allowStaticField); + SecurityMemberAccess sma = cont.getInstance(SecurityMemberAccess.class); + OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, sma); aStack.setOgnlUtil(cont.getInstance(OgnlUtil.class)); - aStack.setRoot(xworkConverter, accessor, this.root, allowStaticField); - + aStack.setRoot(xworkConverter, accessor, this.root, sma); return aStack; } - public void clearContextValues() { //this is an OGNL ValueStack so the context will be an OgnlContext //it would be better to make context of type OgnlContext ((OgnlContext) context).getValues().clear(); } - @Deprecated - public void setAcceptProperties(Set<Pattern> acceptedProperties) { - securityMemberAccess.useAcceptProperties(acceptedProperties); - } - public void useAcceptProperties(Set<Pattern> acceptedProperties) { securityMemberAccess.useAcceptProperties(acceptedProperties); } - @Deprecated - public void setExcludeProperties(Set<Pattern> excludeProperties) { - securityMemberAccess.useExcludeProperties(excludeProperties); - } - public void useExcludeProperties(Set<Pattern> excludeProperties) { securityMemberAccess.useExcludeProperties(excludeProperties); } - @Inject Review Comment: Not sure why this was injected again given it's already passed into the constructor ########## core/src/main/java/com/opensymphony/xwork2/util/MemberAccessValueStack.java: ########## @@ -31,15 +31,19 @@ public interface MemberAccessValueStack { * @deprecated please use {@link #useExcludeProperties(Set)} */ @Deprecated - void setExcludeProperties(Set<Pattern> excludeProperties); + default void setExcludeProperties(Set<Pattern> excludeProperties) { + useExcludeProperties(excludeProperties); Review Comment: Lifted the deprecated implementations into the interface for cleanliness ########## core/src/main/java/com/opensymphony/xwork2/ognl/OgnlUtil.java: ########## @@ -922,8 +855,7 @@ protected Map<String, Object> createDefaultContext(Object root, ClassResolver cl resolver = container.getInstance(CompoundRootAccessor.class); } - SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticFieldAccess); - memberAccess.disallowProxyMemberAccess(disallowProxyMemberAccess); + SecurityMemberAccess memberAccess = container.getInstance(SecurityMemberAccess.class); Review Comment: This is a prototype bean so will be a new instance per context ########## core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStackFactory.java: ########## @@ -105,10 +98,10 @@ protected void setContainer(Container container) throws ClassNotFoundException { } /** - * Retrieve allowStaticFieldAccess state from the container (allows for lazy fetching) + * @deprecated since 6.4.0, no replacement. */ + @Deprecated Review Comment: Couldn't see any use for this method ########## core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilStrutsTest.java: ########## @@ -31,33 +31,6 @@ public void setUp() throws Exception { ognlUtil = container.getInstance(OgnlUtil.class); } - public void testDefaultExcludes() { Review Comment: Deleted tests whose functionality is covered elsewhere ########## core/src/test/java/com/opensymphony/xwork2/ognl/OgnlValueStackTest.java: ########## @@ -1180,43 +1178,6 @@ public void testOgnlValueStackFromOgnlValueStackFactoryDefaultConfig() { assertNull("accessed private field (result not null) ?", accessedValue); } - /** - * Test a raw OgnlValueStackFactory and OgnlValueStack generated by it - * when no static access flags are set (not present in configuration). - */ - public void testOgnlValueStackFromOgnlValueStackFactoryNoFlagsSet() { Review Comment: This flag is now a required constant so this test is no longer applicable ########## core/src/test/java/com/opensymphony/xwork2/ognl/SecurityMemberAccessTest.java: ########## @@ -58,6 +62,82 @@ protected void assignNewSma(boolean allowStaticFieldAccess) { sma = new SecurityMemberAccess(allowStaticFieldAccess); } + private <T> T reflectField(String fieldName) throws IllegalAccessException { + return (T) FieldUtils.readField(sma, fieldName, true); + } + + @Test + public void defaultExclusionList() throws Exception { Review Comment: Moved/rewrote some tests here from `OgnlUtilTest` ########## core/src/main/java/org/apache/struts2/StrutsConstants.java: ########## @@ -234,6 +234,8 @@ public final class StrutsConstants { /** The name of the parameter to determine whether static field access will be allowed in OGNL expressions or not */ public static final String STRUTS_ALLOW_STATIC_FIELD_ACCESS = "struts.ognl.allowStaticFieldAccess"; + public static final String STRUTS_MEMBER_ACCESS = "struts.securityMemberAccess"; Review Comment: Extension point! Issue Time Tracking ------------------- Worklog Id: (was: 891833) Time Spent: 0.5h (was: 20m) > Make SecurityMemberAccess extensible and a prototype bean > --------------------------------------------------------- > > Key: WW-5343 > URL: https://issues.apache.org/jira/browse/WW-5343 > Project: Struts 2 > Issue Type: Improvement > Components: Core > Reporter: Kusal Kithul-Godage > Priority: Minor > Fix For: 6.4.0 > > Time Spent: 0.5h > Remaining Estimate: 0h > -- This message was sent by Atlassian Jira (v8.20.10#820010)