This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch WW-5675-share-parsed-ognl-security-config in repository https://gitbox.apache.org/repos/asf/struts.git
commit cb3dff2ff2df3e375dbb2832de88f0d5be0ded61 Author: Lukasz Lenart <[email protected]> AuthorDate: Fri Aug 14 14:40:01 2026 +0200 WW-5675 refactor(ognl): drop the lazy dev-mode flip from the access path Co-Authored-By: Claude Opus 5 <[email protected]> --- .../apache/struts2/ognl/SecurityMemberAccess.java | 45 ---------------------- .../SecurityMemberAccessConfigSharingTest.java | 25 ++++++++++++ 2 files changed, 25 insertions(+), 45 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java b/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java index 8ba19f540..b7ed69caa 100644 --- a/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java +++ b/core/src/main/java/org/apache/struts2/ognl/SecurityMemberAccess.java @@ -86,13 +86,6 @@ public class SecurityMemberAccess implements MemberAccess { private Set<String> excludedPackageNames = emptySet(); private Set<String> excludedPackageExemptClasses = emptySet(); - private volatile boolean isDevModeInit; - private boolean isDevMode; - private Set<String> devModeExcludedClasses = Set.of(Object.class.getName()); - private Set<Pattern> devModeExcludedPackageNamePatterns = emptySet(); - private Set<String> devModeExcludedPackageNames = emptySet(); - private Set<String> devModeExcludedPackageExemptClasses = emptySet(); - private boolean enforceAllowlistEnabled = false; private Set<Class<?>> allowlistClasses = emptySet(); private Set<String> allowlistPackageNames = emptySet(); @@ -283,7 +276,6 @@ public class SecurityMemberAccess implements MemberAccess { * @return {@code true} if member access is allowed */ protected boolean checkExclusionList(Object target, Member member) { - useDevModeConfiguration(); Class<?> memberClass = member.getDeclaringClass(); if (isClassExcluded(memberClass)) { LOG.warn("Declaring class of member type [{}] is excluded!", memberClass); @@ -612,41 +604,4 @@ public class SecurityMemberAccess implements MemberAccess { this.disallowDefaultPackageAccess = BooleanUtils.toBoolean(disallowDefaultPackageAccess); } - @Inject(StrutsConstants.STRUTS_DEVMODE) - protected void useDevMode(String devMode) { - this.isDevMode = BooleanUtils.toBoolean(devMode); - } - - @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, required = false) - public void useDevModeExcludedClasses(String commaDelimitedClasses) { - this.devModeExcludedClasses = toNewClassesSet(devModeExcludedClasses, commaDelimitedClasses); - } - - @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false) - public void useDevModeExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) { - this.devModeExcludedPackageNamePatterns = toNewPatternsSet(devModeExcludedPackageNamePatterns, commaDelimitedPackagePatterns); - } - - @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, required = false) - public void useDevModeExcludedPackageNames(String commaDelimitedPackageNames) { - this.devModeExcludedPackageNames = toNewPackageNamesSet(devModeExcludedPackageNames, commaDelimitedPackageNames); - } - - @Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false) - public void useDevModeExcludedPackageExemptClasses(String commaDelimitedClasses) { - this.devModeExcludedPackageExemptClasses = toClassesSet(commaDelimitedClasses); - } - - private void useDevModeConfiguration() { - if (!isDevMode || isDevModeInit) { - return; - } - logWarningForFirstOccurrence("devMode", LOG, - "DevMode enabled, using DevMode excluded classes and packages for OGNL security enforcement!"); - isDevModeInit = true; - excludedClasses = devModeExcludedClasses; - excludedPackageNamePatterns = devModeExcludedPackageNamePatterns; - excludedPackageNames = devModeExcludedPackageNames; - excludedPackageExemptClasses = devModeExcludedPackageExemptClasses; - } } diff --git a/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessConfigSharingTest.java b/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessConfigSharingTest.java index 5680e59fb..eb09c9fb4 100644 --- a/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessConfigSharingTest.java +++ b/core/src/test/java/org/apache/struts2/ognl/SecurityMemberAccessConfigSharingTest.java @@ -148,4 +148,29 @@ public class SecurityMemberAccessConfigSharingTest extends XWorkTestCase { super(providerAllowlist, threadAllowlist); } } + + /** + * Dev-mode exclusions must be in force from the first access, with no lazy flip. + */ + public void testDevModeExclusionsApplyWithoutAnAccess() throws Exception { + loadButSet(Map.of( + StrutsConstants.STRUTS_DEVMODE, "true", + StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, "java.lang.ProcessBuilder")); + + SecurityMemberAccess sma = container.getInstance(SecurityMemberAccess.class); + Set<String> excluded = SecurityMemberAccessTest.reflectField(sma, "excludedClasses"); + + assertTrue("dev-mode exclusions were not applied at startup", + excluded.contains("java.lang.ProcessBuilder")); + } + + public void testDevModeMethodsAreGone() throws Exception { + for (String name : new String[]{"useDevMode", "useDevModeExcludedClasses", + "useDevModeExcludedPackageNamePatterns", "useDevModeExcludedPackageNames", + "useDevModeExcludedPackageExemptClasses", "useDevModeConfiguration"}) { + for (java.lang.reflect.Method method : SecurityMemberAccess.class.getDeclaredMethods()) { + assertFalse("SecurityMemberAccess still declares " + name, method.getName().equals(name)); + } + } + } }
