Merge pull request #664 from atlassian/WW-5288-exemption-strict

WW-5288 Make excluded package exemption logic more strict
This commit is contained in:
Lukasz Lenart
2023-03-21 19:29:45 +01:00
committed by GitHub
10 changed files with 231 additions and 774 deletions
@@ -18,12 +18,10 @@
*/
package com.opensymphony.xwork2.conversion.impl;
import com.opensymphony.xwork2.ActionContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.StrutsInternalTestCase;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -19,7 +19,8 @@
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.util.TextParseUtil;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
@@ -31,21 +32,29 @@ import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
public class SecurityMemberAccessTest extends TestCase {
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class SecurityMemberAccessTest {
private Map context;
private FooBar target;
protected SecurityMemberAccess sma;
@Override
@Before
public void setUp() throws Exception {
context = new HashMap();
context = new HashMap<>();
target = new FooBar();
assignNewSma(true);
}
protected void assignNewSma(boolean allowStaticFieldAccess) {
sma = new SecurityMemberAccess(allowStaticFieldAccess);
}
@Test
public void testWithoutClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getMethod(formGetterName(propertyName));
@@ -56,10 +65,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue(accessible);
}
@Test
public void testClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getDeclaredMethod(formGetterName(propertyName));
@@ -74,10 +82,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse(accessible);
}
@Test
public void testObjectClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "toString";
Member member = FooBar.class.getMethod(propertyName);
@@ -88,10 +95,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("toString() from Object is accessible!!!", accessible);
}
@Test
public void testObjectOverwrittenMethodsExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "hashCode";
Member member = FooBar.class.getMethod(propertyName);
@@ -102,10 +108,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("hashCode() from FooBar isn't accessible!!!", accessible);
}
@Test
public void testInterfaceInheritanceExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
@@ -120,10 +125,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
}
@Test
public void testMiddleOfInheritanceExclusion1() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "fooLogic";
Member member = FooBar.class.getMethod(propertyName);
@@ -138,10 +142,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("fooLogic() from FooInterface isn't accessible!!!", accessible);
}
@Test
public void testMiddleOfInheritanceExclusion2() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
@@ -156,10 +159,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
}
@Test
public void testMiddleOfInheritanceExclusion3() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
@@ -174,10 +176,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("barLogic() from BarInterface isn't accessible!!!", accessible);
}
@Test
public void testMiddleOfInheritanceExclusion4() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
@@ -192,10 +193,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
}
@Test
public void testPackageExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
@@ -210,10 +210,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("stringField is accessible!", actual);
}
@Test
public void testPackageExclusionExemption() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
@@ -232,10 +231,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("stringField isn't accessible!", actual);
}
@Test
public void testPackageNameExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<String> excluded = new HashSet<>();
excluded.add(FooBar.class.getPackage().getName());
sma.setExcludedPackageNames(excluded);
@@ -250,11 +248,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("stringField is accessible!", actual);
}
@Test
public void testPackageNameExclusionExemption() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false);
Set<String> excluded = new HashSet<>();
excluded.add(FooBar.class.getPackage().getName());
sma.setExcludedPackageNames(excluded);
@@ -273,14 +269,14 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("stringField isn't accessible!", actual);
}
public void testPackageNameExclusionExemptionInheritance() throws Exception {
@Test
public void testPackageNameExclusionExemption2() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false);
Set<String> excluded = new HashSet<>();
excluded.add(FooBar.class.getPackage().getName());
sma.setExcludedPackageNames(excluded);
// Exemption must exist for both classes (target and member) if they both match a banned package
Set<Class<?>> allowed = new HashSet<>();
allowed.add(BarInterface.class);
sma.setExcludedPackageExemptClasses(allowed);
@@ -291,44 +287,67 @@ public class SecurityMemberAccessTest extends TestCase {
// when
boolean actual = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("barLogic is accessible!", actual);
}
@Test
public void testPackageNameExclusionExemption3() throws Exception {
// given
Set<String> excluded = new HashSet<>();
excluded.add(FooBar.class.getPackage().getName());
sma.setExcludedPackageNames(excluded);
// Exemption must exist for both classes (target and member) if they both match a banned package
Set<Class<?>> allowed = new HashSet<>();
allowed.add(BarInterface.class);
allowed.add(FooBar.class);
sma.setExcludedPackageExemptClasses(allowed);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
// when
boolean actual = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue("barLogic isn't accessible!", actual);
}
public void testDefaultPackageExclusion() {
@Test
public void testDefaultPackageExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
Class<?> clazz = Class.forName("PackagelessAction");
// when
boolean actual = sma.isPackageExcluded(null, null);
boolean actual = sma.isPackageExcluded(clazz, clazz);
// then
assertFalse("default package is excluded!", actual);
}
public void testDefaultPackageExclusion2() {
@Test
public void testDefaultPackageExclusion2() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^$"));
sma.setExcludedPackageNamePatterns(excluded);
Class<?> clazz = Class.forName("PackagelessAction");
// when
boolean actual = sma.isPackageExcluded(null, null);
boolean actual = sma.isPackageExcluded(clazz, clazz);
// then
assertTrue("default package isn't excluded!", actual);
}
@Test
public void testAccessEnum() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
// when
Member values = MyValues.class.getMethod("values");
boolean actual = sma.isAccessible(context, MyValues.class, values, null);
@@ -337,9 +356,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("Access to enums is blocked!", actual);
}
@Test
public void testAccessStaticMethod() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -350,9 +369,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("Access to static method is not blocked!", actual);
}
@Test
public void testAccessStaticField() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -363,9 +382,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("Access to static field is blocked!", actual);
}
@Test
public void testBlockedStaticFieldWhenFlagIsFalse() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -377,7 +396,7 @@ public class SecurityMemberAccessTest extends TestCase {
// public static final test
// given
sma = new SecurityMemberAccess(true);
assignNewSma(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -389,7 +408,7 @@ public class SecurityMemberAccessTest extends TestCase {
// package static test
// given
sma = new SecurityMemberAccess(true);
assignNewSma(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -401,7 +420,7 @@ public class SecurityMemberAccessTest extends TestCase {
// package final static test
// given
sma = new SecurityMemberAccess(true);
assignNewSma(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -413,7 +432,7 @@ public class SecurityMemberAccessTest extends TestCase {
// protected static test
// given
sma = new SecurityMemberAccess(true);
assignNewSma(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -425,7 +444,7 @@ public class SecurityMemberAccessTest extends TestCase {
// protected final static test
// given
sma = new SecurityMemberAccess(true);
assignNewSma(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -437,7 +456,7 @@ public class SecurityMemberAccessTest extends TestCase {
// private static test
// given
sma = new SecurityMemberAccess(true);
assignNewSma(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -449,7 +468,7 @@ public class SecurityMemberAccessTest extends TestCase {
// private final static test
// given
sma = new SecurityMemberAccess(true);
assignNewSma(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -460,9 +479,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("Access to private final static field is allowed?", actual);
}
@Test
public void testBlockedStaticFieldWhenClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Arrays.asList(Class.class, StaticTester.class)));
// when
@@ -473,9 +492,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("Access to static field isn't blocked!", actual);
}
@Test
public void testBlockStaticMethodAccess() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -486,9 +505,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("Access to static isn't blocked!", actual);
}
@Test
public void testBlockStaticAccessIfClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
@@ -499,9 +518,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("Access to static method of excluded class isn't blocked!", actual);
}
@Test
public void testAllowStaticAccessIfClassIsNotExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(ClassLoader.class)));
// when
@@ -512,9 +531,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("Invalid test! Access to static method of excluded class is blocked!", actual);
}
@Test
public void testAccessPrimitiveInt() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang.,ognl,javax"));
String propertyName = "intField";
@@ -527,9 +546,9 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue(accessible);
}
@Test
public void testAccessPrimitiveDoubleWithNames() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("ognl.,javax."));
@@ -542,10 +561,11 @@ public class SecurityMemberAccessTest extends TestCase {
sma.setExcludedClasses(excluded);
String propertyName = "doubleValue";
double myDouble = 1;
Member member = Double.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
boolean accessible = sma.isAccessible(context, myDouble, member, propertyName);
// then
assertTrue(accessible);
@@ -579,26 +599,27 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue(accessible);
}
@Test
public void testAccessPrimitiveDoubleWithPackageRegExs() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> patterns = new HashSet<>();
patterns.add(Pattern.compile("^java\\.lang\\..*"));
sma.setExcludedPackageNamePatterns(patterns);
String propertyName = "doubleValue";
double myDouble = 1;
Member member = Double.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
boolean accessible = sma.isAccessible(context, myDouble, member, propertyName);
// then
assertTrue(accessible);
}
@Test
public void testAccessMemberAccessIsAccessible() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(ognl.MemberAccess.class);
sma.setExcludedClasses(excluded);
@@ -608,15 +629,15 @@ public class SecurityMemberAccessTest extends TestCase {
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
boolean accessible = sma.isAccessible(context, sma, member, propertyName);
// then
assertTrue(accessible);
}
@Test
public void testAccessMemberAccessIsBlocked() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(SecurityMemberAccess.class);
sma.setExcludedClasses(excluded);
@@ -626,21 +647,19 @@ public class SecurityMemberAccessTest extends TestCase {
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
boolean accessible = sma.isAccessible(context, sma, member, propertyName);
// then
assertFalse(accessible);
}
@Test
public void testPackageNameExclusionAsCommaDelimited() {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang."));
// when
boolean actual = sma.isPackageExcluded(String.class.getPackage(), null);
actual &= sma.isPackageExcluded(null, String.class.getPackage());
boolean actual = sma.isPackageExcluded(String.class, String.class);
// then
assertTrue("package java.lang. is accessible!", actual);
@@ -20,14 +20,14 @@ package com.test;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
class TestSecurityMemberAccess extends SecurityMemberAccess {
class ExternalSecurityMemberAccess extends SecurityMemberAccess {
TestSecurityMemberAccess(boolean allowStaticFieldAccess) {
ExternalSecurityMemberAccess(boolean allowStaticFieldAccess) {
super(allowStaticFieldAccess);
}
@Override
public boolean isPackageExcluded(Package targetPackage, Package memberPackage) {
return super.isPackageExcluded(targetPackage, memberPackage);
public boolean isPackageExcluded(Class<?> targetClass, Class<?> memberClass) {
return super.isPackageExcluded(targetClass, memberClass);
}
}
@@ -0,0 +1,33 @@
/*
* 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.test;
import com.opensymphony.xwork2.ognl.SecurityMemberAccessTest;
/**
* Runs the same test suite using a SecurityMemberAccess class that is outside the
* com.opensymphony.xwork2.ognl package.
*/
public class ExternalSecurityMemberAccessTest extends SecurityMemberAccessTest {
@Override
protected void assignNewSma(boolean allowStaticFieldAccess) {
sma = new ExternalSecurityMemberAccess(allowStaticFieldAccess);
}
}
@@ -1,651 +0,0 @@
/*
* 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.test;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
import com.opensymphony.xwork2.util.TextParseUtil;
import junit.framework.TestCase;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
public class SecurityMemberAccessTest extends TestCase {
private Map context;
private FooBar target;
@Override
public void setUp() throws Exception {
context = new HashMap();
target = new FooBar();
}
public void testWithoutClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getDeclaredMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
Set<Class<?>> excluded = new HashSet<>();
excluded.add(FooBar.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse(accessible);
}
public void testObjectClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "toString";
Member member = FooBar.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("toString() from Object is accessible!!!", accessible);
}
public void testObjectOverwrittenMethodsExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "hashCode";
Member member = FooBar.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue("hashCode() from FooBar isn't accessible!!!", accessible);
}
public void testInterfaceInheritanceExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(BarInterface.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
}
public void testMiddleOfInheritanceExclusion1() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "fooLogic";
Member member = FooBar.class.getMethod(propertyName);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(BarInterface.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue("fooLogic() from FooInterface isn't accessible!!!", accessible);
}
public void testMiddleOfInheritanceExclusion3() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue("barLogic() from BarInterface isn't accessible!!!", accessible);
}
public void testMiddleOfInheritanceExclusion4() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(FooBarInterface.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
}
public void testPackageExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
String propertyName = "stringField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean actual = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("stringField is accessible!", actual);
}
public void testPackageNameExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<String> excluded = new HashSet<>();
excluded.add(FooBar.class.getPackage().getName());
sma.setExcludedPackageNames(excluded);
String propertyName = "stringField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean actual = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("stringField is accessible!", actual);
}
public void testDefaultPackageExclusion() {
// given
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
// when
boolean actual = sma.isPackageExcluded(null, null);
// then
assertFalse("default package is excluded!", actual);
}
public void testDefaultPackageExclusion2() {
// given
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^$"));
sma.setExcludedPackageNamePatterns(excluded);
// when
boolean actual = sma.isPackageExcluded(null, null);
// then
assertTrue("default package isn't excluded!", actual);
}
public void testAccessEnum() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
// when
Member values = MyValues.class.getMethod("values");
boolean actual = sma.isAccessible(context, MyValues.class, values, null);
// then
assertTrue("Access to enums is blocked!", actual);
}
public void testAccessStaticMethod() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getMethod("sayHello");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertFalse("Access to static method is not blocked!", actual);
}
public void testAccessStaticField() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
boolean actual = sma.isAccessible(context, null, method, null);
// then
assertTrue("Access to static field is blocked!", actual);
}
public void testBlockedStaticFieldWhenFlagIsFalse() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
boolean actual = sma.isAccessible(context, null, method, null);
// then
assertTrue("Access to public static field is blocked?", actual);
// public static final test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.class.getField("MIN_VALUE");
actual = sma.isAccessible(context, null, method, null);
// then
assertTrue("Access to public final static field is blocked?", actual);
// package static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PACKAGE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to package static field is allowed?", actual);
// package final static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PACKAGE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to package final static field is allowed?", actual);
// protected static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PROTECTED_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to protected static field is allowed?", actual);
// protected final static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PROTECTED_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to protected final static field is allowed?", actual);
// private static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PRIVATE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to private static field is allowed?", actual);
// private final static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PRIVATE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to private final static field is allowed?", actual);
}
public void testBlockedStaticFieldWhenClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Arrays.asList(Class.class, StaticTester.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
boolean actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to static field isn't blocked!", actual);
}
public void testBlockStaticAccess() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getMethod("sayHello");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertFalse("Access to static isn't blocked!", actual);
}
public void testBlockStaticAccessIfClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = Class.class.getMethod("getClassLoader");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertFalse("Access to static method of excluded class isn't blocked!", actual);
}
public void testAllowStaticAccessIfClassIsNotExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(ClassLoader.class)));
// when
Member method = Class.class.getMethod("getClassLoader");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertTrue("Invalid test! Access to static method of excluded class is blocked!", actual);
}
public void testAccessPrimitiveInt() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang.,ognl,javax"));
String propertyName = "intField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessPrimitiveDoubleWithNames() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("ognl.,javax."));
Set<Class<?>> excluded = new HashSet<>();
excluded.add(Object.class);
excluded.add(Runtime.class);
excluded.add(System.class);
excluded.add(Class.class);
excluded.add(ClassLoader.class);
sma.setExcludedClasses(excluded);
String propertyName = "doubleValue";
Member member = Double.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
// given
propertyName = "exit";
member = System.class.getMethod(propertyName, int.class);
// when
accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse(accessible);
// given
propertyName = "intField";
member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
// given
propertyName = "doubleField";
member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessPrimitiveDoubleWithPackageRegExs() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> patterns = new HashSet<>();
patterns.add(Pattern.compile("^java\\.lang\\..*"));
sma.setExcludedPackageNamePatterns(patterns);
String propertyName = "doubleValue";
Member member = Double.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessMemberAccessIsAccessible() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(ognl.MemberAccess.class);
sma.setExcludedClasses(excluded);
String propertyName = "excludedClasses";
String setter = "setExcludedClasses";
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessMemberAccessIsBlocked() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(SecurityMemberAccess.class);
sma.setExcludedClasses(excluded);
String propertyName = "excludedClasses";
String setter = "setExcludedClasses";
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse(accessible);
}
public void testPackageNameExclusionAsCommaDelimited() {
// given
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang."));
// when
boolean actual = sma.isPackageExcluded(String.class.getPackage(), null);
actual &= sma.isPackageExcluded(null, String.class.getPackage());
// then
assertTrue("package java.lang. is accessible!", actual);
}
}
class FooBar implements FooBarInterface {
private String stringField;
private int intField;
private Double doubleField;
public String getStringField() {
return stringField;
}
public void setStringField(String stringField) {
this.stringField = stringField;
}
public String fooLogic() {
return "fooLogic";
}
public String barLogic() {
return "barLogic";
}
@Override
public int hashCode() {
return 1;
}
public int getIntField() {
return intField;
}
public void setIntField(int intField) {
this.intField = intField;
}
public Double getDoubleField() {
return doubleField;
}
public void setDoubleField(Double doubleField) {
this.doubleField = doubleField;
}
}
interface FooInterface {
String fooLogic();
}
interface BarInterface {
String barLogic();
}
interface FooBarInterface extends FooInterface, BarInterface {
}
enum MyValues {
ONE, TWO, THREE
}
class StaticTester {
public static int MAX_VALUE = 0;
public static final int MIN_VALUE = 0;
static String PACKAGE_STRING = "package_string";
static final String FINAL_PACKAGE_STRING = "final_package_string";
static String PROTECTED_STRING = "protected_string";
static final String FINAL_PROTECTED_STRING = "final_protected_string";
static String PRIVATE_STRING = "private_string";
static final String FINAL_PRIVATE_STRING = "final_private_string";
public static String sayHello() {
return "Hello";
}
protected static Field getFieldByName(String fieldName) throws NoSuchFieldException {
if (fieldName != null && fieldName.length() > 0) {
return StaticTester.class.getDeclaredField(fieldName);
} else {
throw new NoSuchFieldException("field: " + fieldName + " does not exist");
}
}
}
@@ -18,21 +18,14 @@
*/
package org.apache.struts2.config.entities;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.TestBean;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.components.TextField;
import org.apache.struts2.dispatcher.StaticContentLoader;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
@@ -83,9 +76,11 @@ public class ConstantConfigTest {
constantConfig.setExcludedClasses(null);
constantConfig.setExcludedPackageNamePatterns(null);
constantConfig.setExcludedPackageNames(null);
constantConfig.setExcludedPackageExemptClasses(null);
constantConfig.setDevModeExcludedClasses(null);
constantConfig.setDevModeExcludedPackageNamePatterns(null);
constantConfig.setDevModeExcludedPackageNames(null);
constantConfig.setDevModeExcludedPackageExemptClasses(null);
Map<String, String> map = constantConfig.getAllAsStringsMap();
Assert.assertNull(map.get(StrutsConstants.STRUTS_EXCLUDED_CLASSES));
@@ -115,6 +110,25 @@ public class ConstantConfigTest {
map.get(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES));
}
@Test
public void testExemptClassesToString() {
ConstantConfig constantConfig = new ConstantConfig();
Set<Class<?>> exemptClasses = new LinkedHashSet<>();
exemptClasses.add(Object.class);
exemptClasses.add(Runtime.class);
exemptClasses.add(System.class);
constantConfig.setExcludedPackageExemptClasses(exemptClasses);
constantConfig.setDevModeExcludedPackageExemptClasses(exemptClasses);
Map<String, String> map = constantConfig.getAllAsStringsMap();
Assert.assertEquals("java.lang.Object,java.lang.Runtime,java.lang.System",
map.get(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES));
Assert.assertEquals("java.lang.Object,java.lang.Runtime,java.lang.System",
map.get(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES));
}
@Test
public void testSettingStaticContentPath() {
// given
@@ -20,7 +20,7 @@ package org.apache.struts2.util;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.TestAction;
import org.apache.struts2.views.jsp.ActionTag;
import javax.servlet.jsp.tagext.TagSupport;
import java.lang.reflect.Member;
@@ -51,7 +51,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
Member member = TagSupport.class.getMethod("doStartTag");
// when
boolean actual = sma.isAccessible(context, new TestAction(), member, propertyName);
boolean actual = sma.isAccessible(context, new ActionTag(), member, propertyName);
// then
assertTrue("javax.servlet package isn't accessible!", actual);
@@ -61,7 +61,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<Pattern>();
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^javax\\..+"));
sma.setExcludedPackageNamePatterns(excluded);
@@ -69,7 +69,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
Member member = TagSupport.class.getMethod("doStartTag");
// when
boolean actual = sma.isAccessible(context, new TestAction(), member, propertyName);
boolean actual = sma.isAccessible(context, new ActionTag(), member, propertyName);
// then
assertFalse("javax.servlet package is accessible!", actual);