This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 7.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit c4b1559d6e7f131be804373719fe41c26969df54
Author: Kyle Stiemann <kyle.stiem...@contrastsecurity.com>
AuthorDate: Thu Sep 10 16:47:21 2020 -0400

    Fix 64735 ServletContext.addJspFile() always fails with SecurityManager
---
 build.properties.default                           |  24 ++--
 build.xml                                          |  13 ++
 .../catalina/core/ApplicationContextFacade.java    |   1 +
 ...estApplicationContextFacadeSecurityManager.java | 153 +++++++++++++++++++++
 .../util/security/SecurityManagerBaseTest.java     |  50 +++++++
 webapps/docs/changelog.xml                         |   5 +
 6 files changed, 234 insertions(+), 12 deletions(-)

diff --git a/build.properties.default b/build.properties.default
index 96637e5..c4ab2ba 100644
--- a/build.properties.default
+++ b/build.properties.default
@@ -257,29 +257,29 @@ hamcrest.home=${base.path}/hamcrest-${hamcrest.version}
 hamcrest.jar=${hamcrest.home}/hamcrest-core-${hamcrest.version}.jar
 
hamcrest.loc=${base-maven.loc}/org/hamcrest/hamcrest-core/${hamcrest.version}/hamcrest-core-${hamcrest.version}.jar
 
-# ----- EasyMock, version 3.2 or later -----
-easymock.version=3.2
+# ----- EasyMock, version 3.6 or later -----
+easymock.version=3.6
 easymock.checksum.enabled=true
-easymock.checksum.algorithm=MD5|SHA-1
-easymock.checksum.value=0da4291328e18798621c36fdf8bc4c3a|00c82f7fa3ef377d8954b1db25123944b5af2ba4
+easymock.checksum.algorithm=SHA-512
+easymock.checksum.value=b49673e7872aa8b006d377a4ca56eed8f6e98e45ea4efe26d24cafe81ea569b557f5a326edcd387288267db8c4b59f2c3c61010f3ad01c4d1067a35430533794
 easymock.home=${base.path}/easymock-${easymock.version}
 easymock.jar=${easymock.home}/easymock-${easymock.version}.jar
 
easymock.loc=${base-maven.loc}/org/easymock/easymock/${easymock.version}/easymock-${easymock.version}.jar
 
-# ----- cglib, used by EasyMock, version 2.2 or later -----
-cglib.version=2.2.3
+# ----- cglib, used by EasyMock, version 3.3 or later -----
+cglib.version=3.3.0
 cglib.checksum.enabled=true
-cglib.checksum.algorithm=MD5|SHA-1
-cglib.checksum.value=694815351007f966c14ea093ec838323|6a4af5d9112066a5baf235fd55d5876969bc813c
+cglib.checksum.algorithm=SHA-512
+cglib.checksum.value=faa1d2121e87ae69e179e3aae217accd0834e0da716b91a029fd526e192612e71675f2740bedf48e23ef1edc45f672a2be1b3e78bbfb1ad59c96dd3d2feeedba
 cglib.home=${base.path}/cglib-${cglib.version}
 cglib.jar=${cglib.home}/cglib-nodep-${cglib.version}.jar
 cglib.loc=${base-sf.loc}/cglib/cglib-nodep-${cglib.version}.jar
 
-# ----- objenesis, used by EasyMock, version 1.2 or later -----
-objenesis.version=1.2
+# ----- objenesis, used by EasyMock, version 2.6 or later -----
+objenesis.version=2.6
 objenesis.checksum.enabled=true
-objenesis.checksum.algorithm=MD5|SHA-1
-objenesis.checksum.value=bee117291d50b41b8e8cf0ac5435df1d|bfcb0539a071a4c5a30690388903ac48c0667f2a
+objenesis.checksum.algorithm=SHA-512
+objenesis.checksum.value=23a593bded8cb43236faad2018b008da47bf4e29cc60c2e98fd4f2ed578fe2baddd3a98547dc14273017c82cb19ce8eaaab71d49273411856a2ba1a5d51015fc
 objenesis.home=${base.path}/objenesis-${objenesis.version}
 objenesis.jar=${objenesis.home}/objenesis-${objenesis.version}.jar
 
objenesis.loc=${base-maven.loc}/org/objenesis/objenesis/${objenesis.version}/objenesis-${objenesis.version}.jar
diff --git a/build.xml b/build.xml
index 707e630..5bd5a7c 100644
--- a/build.xml
+++ b/build.xml
@@ -1569,8 +1569,21 @@
             <exclude unless="java.7.home" 
name="org/apache/tomcat/websocket/**" />
             <!-- Exclude performance tests. E.g. on systems with 
slow/inconsistent timing -->
             <exclude name="**/*Performance.java" 
if="${test.excludePerformance}" />
+            <!--
+              Avoid running tests which require the SecurityManager with other
+              tests. See below for more details.
+            -->
+            <exclude name="**/*SecurityManager.java" />
           </fileset>
         </batchtest>
+        <!--
+           Run tests which require the SecurityManager in their own forked
+           batch to ensure that global/system security settings don't pollute
+           other tests. See SecurityManagerBaseTest.java for more details.
+        -->
+        <batchtest todir="${test.reports}" unless="test.entry" fork="true">
+          <fileset dir="test" includes="**/SecurityManager.java" 
excludes="${test.exclude}" />
+        </batchtest>
       </junit>
     </sequential>
   </macrodef>
diff --git a/java/org/apache/catalina/core/ApplicationContextFacade.java 
b/java/org/apache/catalina/core/ApplicationContextFacade.java
index 2c39404..544b219 100644
--- a/java/org/apache/catalina/core/ApplicationContextFacade.java
+++ b/java/org/apache/catalina/core/ApplicationContextFacade.java
@@ -117,6 +117,7 @@ public class ApplicationContextFacade implements 
ServletContext {
         classCache.put("getAttribute", clazz);
         classCache.put("log", clazz);
         classCache.put("setSessionTrackingModes", new Class[]{Set.class} );
+        classCache.put("declareRoles", new Class[]{String[].class});
     }
 
 
diff --git 
a/test/org/apache/catalina/core/TestApplicationContextFacadeSecurityManager.java
 
b/test/org/apache/catalina/core/TestApplicationContextFacadeSecurityManager.java
new file mode 100644
index 0000000..442e1e7
--- /dev/null
+++ 
b/test/org/apache/catalina/core/TestApplicationContextFacadeSecurityManager.java
@@ -0,0 +1,153 @@
+/*
+ * 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.catalina.core;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import org.apache.catalina.security.SecurityUtil;
+import org.apache.tomcat.util.security.SecurityManagerBaseTest;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.easymock.IExpectationSetters;
+import org.easymock.internal.LastControl;
+
+@RunWith(Parameterized.class)
+public final class TestApplicationContextFacadeSecurityManager extends 
SecurityManagerBaseTest {
+
+    /**
+     * @return {@link Collection} of non-static, non-object, public {@link
+     * Method}s in {@link ApplicationContextFacade} to be run with the the Java
+     * 2 {@link SecurityManager} been enabled.
+     */
+    @Parameterized.Parameters(name = "{index}: method={0}")
+    public static Collection<Method> publicApplicationContextFacadeMethods() {
+        List<Method> result = new ArrayList<Method>();
+        for (Method m : ApplicationContextFacade.class.getMethods()) {
+            if (!Modifier.isStatic(m.getModifiers())) {
+                try {
+                    Object.class.getMethod(m.getName(), m.getParameterTypes());
+                    // Skip;
+                } catch (final NoSuchMethodException e) {
+                    result.add(m);
+                }
+            }
+        }
+        return result;
+    }
+
+
+    private static Object[] getDefaultParams(final Method method) {
+        final Class<?>[] paramTypes = method.getParameterTypes();
+        final Object[] params = new Object[paramTypes.length];
+        for (int i = 0; i < params.length; i++) {
+            params[i] = getDefaultValue(paramTypes[i]);
+        }
+        return params;
+    }
+
+
+    @SuppressWarnings("unchecked")
+    private static <T> T getDefaultValue(final Class<T> clazz) {
+        return !isVoid(clazz) ? (T) Array.get(Array.newInstance(clazz, 1), 0) 
: null;
+    }
+
+
+    private static <T> boolean isVoid(Class<T> clazz) {
+        return void.class.equals(clazz) || Void.class.equals(clazz);
+    }
+
+
+    @Parameter(0)
+    public Method methodToTest;
+
+
+    /**
+     * Test for
+     * <a href="https://bz.apache.org/bugzilla/show_bug.cgi?id=64735";>Bug
+     * 64735</a> which confirms that {@link ApplicationContextFacade} behaves
+     * correctly when the Java 2 {@link SecurityManager} has been enabled.
+     *
+     * @throws NoSuchMethodException     Should never happen
+     * @throws IllegalAccessException    Should never happen
+     * @throws InvocationTargetException Should never happen
+     */
+    @Test
+    public void testBug64735()
+            throws NoSuchMethodException, IllegalAccessException, 
InvocationTargetException {
+        Assert.assertTrue(SecurityUtil.isPackageProtectionEnabled());
+
+        // Mock the ApplicationContext that we provide to the 
ApplicationContextFacade.
+        final ApplicationContext mockAppContext = 
EasyMock.createMock(ApplicationContext.class);
+        final Method expectedAppContextMethod =
+                ApplicationContext.class.getMethod(
+                        methodToTest.getName(),
+                        methodToTest.getParameterTypes());
+
+        // Expect that only the provided method which is being tested will be 
called exactly once.
+        final IExpectationSetters<Object> expectationSetters;
+        if (isVoid(expectedAppContextMethod.getReturnType())) {
+            expectedAppContextMethod.invoke(mockAppContext, 
getDefaultParams(methodToTest));
+            expectationSetters = EasyMock.expectLastCall();
+        } else {
+            expectationSetters =
+                    EasyMock.expect(expectedAppContextMethod.invoke(
+                            mockAppContext, getDefaultParams(methodToTest)));
+        }
+        expectationSetters.andAnswer(new IAnswer<Object>() {
+            @Override
+            public Object answer() throws Throwable {
+                Assert.assertEquals(
+                        expectedAppContextMethod,
+                        LastControl.getCurrentInvocation().getMethod());
+                return 
getDefaultValue(expectedAppContextMethod.getReturnType());
+            }
+
+        }).once();
+
+        EasyMock.replay(mockAppContext);
+        EasyMock.verifyUnexpectedCalls(mockAppContext);
+
+        // Invoke the method on ApplicationContextFacade. Fail if any 
unexpected exceptions are
+        // thrown.
+        try {
+            methodToTest.invoke(
+                    new ApplicationContextFacade(mockAppContext),
+                    getDefaultParams(methodToTest));
+        } catch (final IllegalAccessException e) {
+            throw new RuntimeException(
+                    "Failed to call " + methodToTest + " with SecurityManager 
enabled.", e);
+        } catch (final InvocationTargetException e) {
+            throw new RuntimeException(
+                    "Failed to call " + methodToTest + " with SecurityManager 
enabled.", e);
+        }
+
+        // Verify that the method called through to the wrapped 
ApplicationContext correctly.
+        EasyMock.verifyRecording();
+    }
+}
diff --git a/test/org/apache/tomcat/util/security/SecurityManagerBaseTest.java 
b/test/org/apache/tomcat/util/security/SecurityManagerBaseTest.java
new file mode 100644
index 0000000..af7ff8f
--- /dev/null
+++ b/test/org/apache/tomcat/util/security/SecurityManagerBaseTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.tomcat.util.security;
+
+import java.security.Permission;
+
+import org.apache.catalina.security.SecurityUtil;
+
+/**
+ * Base test class for unit tests which require the Java 2 {@link
+ * SecurityManager} to be enabled. Tests that extend this class must be run in 
a
+ * forked SecurityManager test batch since this class modifies global {@link
+ * System} settings which may interfere with other tests. On static class
+ * initialization, this class sets up the {@code "package.definition"} and
+ * {@code "package.access"} system properties and adds a no-op SecurityManager
+ * which does not check permissions. These settings are required in order to
+ * make {@link org.apache.catalina.Globals#IS_SECURITY_ENABLED} and {@link
+ * SecurityUtil#isPackageProtectionEnabled()} return true.
+ */
+public abstract class SecurityManagerBaseTest {
+    static {
+        System.setProperty("package.definition", "test");
+        System.setProperty("package.access", "test");
+        System.setSecurityManager(new SecurityManager() {
+            @Override
+            public void checkPermission(final Permission permission) {
+                // no-op
+            }
+
+            @Override
+            public void checkPermission(final Permission permission, Object 
context) {
+                // no-op
+            }
+        });
+    }
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 4471506..df99d4d 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -67,6 +67,11 @@
         request from John Bampton. (markt)
       </fix>
       <fix>
+        <bug>64735</bug>: Ensure that none of the methods on a
+        <code>ServletContext</code> instance always fail when running under a
+        SecurityManager. Pull request provided by Kyle Stiemann. (markt)
+      </fix>
+      <fix>
         <bug>64765</bug>: Ensure that the number of currently processing 
threads
         is tracked correctly when a web application is undeployed, long running
         requests are being processed and


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to