diff --git a/java/org/apache/catalina/loader/WebappClassLoaderBase.java b/java/org/apache/catalina/loader/WebappClassLoaderBase.java
index 0028264724e9..eddc1b8e758c 100644
--- a/java/org/apache/catalina/loader/WebappClassLoaderBase.java
+++ b/java/org/apache/catalina/loader/WebappClassLoaderBase.java
@@ -87,6 +87,7 @@
import org.apache.tomcat.util.compat.JreCompat;
import org.apache.tomcat.util.compat.JreVendor;
import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.security.PermissionCheck;
/**
* Specialized web application class loader.
@@ -135,7 +136,7 @@
* @author Craig R. McClanahan
*/
public abstract class WebappClassLoaderBase extends URLClassLoader
- implements Lifecycle, InstrumentableClassLoader {
+ implements Lifecycle, InstrumentableClassLoader, PermissionCheck {
private static final org.apache.juli.logging.Log log =
org.apache.juli.logging.LogFactory.getLog(WebappClassLoaderBase.class);
@@ -1935,6 +1936,27 @@ protected PermissionCollection getPermissions(CodeSource codeSource) {
}
+ @Override
+ public boolean check(Permission permission) {
+ if (!Globals.IS_SECURITY_ENABLED) {
+ return true;
+ }
+ Policy currentPolicy = Policy.getPolicy();
+ if (currentPolicy != null) {
+ ResourceEntry entry = findResourceInternal("/", "/", false);
+ if (entry != null) {
+ CodeSource cs = new CodeSource(
+ entry.codeBase, (java.security.cert.Certificate[]) null);
+ PermissionCollection pc = currentPolicy.getPermissions(cs);
+ if (pc.implies(permission)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
/**
* Returns the search path of URLs for loading classes and resources.
* This includes the original list of URLs specified to the constructor,
diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java
index dca07b5d3e31..087227f8e3f6 100644
--- a/java/org/apache/tomcat/util/digester/Digester.java
+++ b/java/org/apache/tomcat/util/digester/Digester.java
@@ -26,11 +26,13 @@
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.security.Permission;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.PropertyPermission;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
@@ -40,6 +42,7 @@
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.security.PermissionCheck;
import org.xml.sax.Attributes;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
@@ -81,6 +84,13 @@ private static class SystemPropertySource
implements IntrospectionUtils.PropertySource {
@Override
public String getProperty( String key ) {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ if (cl instanceof PermissionCheck) {
+ Permission p = new PropertyPermission(key, "read");
+ if (!((PermissionCheck) cl).check(p)) {
+ return null;
+ }
+ }
return System.getProperty(key);
}
}
diff --git a/java/org/apache/tomcat/util/security/PermissionCheck.java b/java/org/apache/tomcat/util/security/PermissionCheck.java
new file mode 100644
index 000000000000..ba2bdd3c7083
--- /dev/null
+++ b/java/org/apache/tomcat/util/security/PermissionCheck.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * This interface is implemented by components to enable privileged code to
+ * check whether the component has a given permission.
+ * This is typically used when a privileged component (e.g. the container) is
+ * performing an action on behalf of an untrusted component (e.g. a web
+ * application) without the current thread having passed through a code source
+ * provided by the untrusted component. Because the current thread has not
+ * passed through a code source provided by the untrusted component the
+ * SecurityManager assumes the code is trusted so the standard checking
+ * mechanisms can't be used.
+ */
+public interface PermissionCheck {
+
+ /**
+ * Does this component have the given permission?
+ *
+ * @param permission The permission to test
+ *
+ * @return {@code false} if a SecurityManager is enabled and the component
+ * does not have the given permission, otherwise {@code false}
+ */
+ boolean check(Permission permission);
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 6d0129229561..7d472762d72c 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -99,6 +99,14 @@
59839: Apply roleSearchAsUser
to all nested searches
in JNDIRealm. (fschumacher)
+
+ Provide a mechanism that enables the container to check if a component
+ (typically a web application) has been granted a given permission when
+ running under a SecurityManager without the current execution stack
+ having to have passed through the component. Use this new mechanism to
+ extend SecurityManager protection to the system property replacement
+ feature of the digester. (markt)
+