Skip to content

Commit

Permalink
Fixes #6184 - JEP-411 will deprecate/remove the SecurityManager from …
Browse files Browse the repository at this point in the history
…the JVM.

Removed usages of `SecurityManager` and `AccessControlller.doPrivileged()`.
In places where they are still necessary, now using reflection.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
  • Loading branch information
sbordet committed Apr 3, 2023
1 parent ee3ca3f commit 96ece88
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 162 deletions.
Expand Up @@ -60,9 +60,7 @@ public AuthConfigProvider getConfigProvider(String layer, String appContext, Reg
@Override
public String registerConfigProvider(String className, Map properties, String layer, String appContext, String description)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AuthPermission("registerAuthConfigProvider"));
checkPermission("registerAuthConfigProvider");

String key = getKey(layer, appContext);
AuthConfigProvider configProvider = createConfigProvider(className, properties);
Expand All @@ -76,9 +74,7 @@ public String registerConfigProvider(String className, Map properties, String la
@Override
public String registerConfigProvider(AuthConfigProvider provider, String layer, String appContext, String description)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AuthPermission("registerAuthConfigProvider"));
checkPermission("registerAuthConfigProvider");

String key = getKey(layer, appContext);
DefaultRegistrationContext context = new DefaultRegistrationContext(provider, layer, appContext, description, false);
Expand All @@ -91,9 +87,7 @@ public String registerConfigProvider(AuthConfigProvider provider, String layer,
@Override
public boolean removeRegistration(String registrationID)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AuthPermission("removeAuthRegistration"));
checkPermission("removeAuthRegistration");

DefaultRegistrationContext registrationContext = _registrations.remove(registrationID);
if (registrationContext == null)
Expand All @@ -106,9 +100,7 @@ public boolean removeRegistration(String registrationID)
@Override
public String[] detachListener(RegistrationListener listener, String layer, String appContext)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AuthPermission("detachAuthListener"));
checkPermission("detachAuthListener");

List<String> registrationIds = new ArrayList<>();
for (DefaultRegistrationContext registration : _registrations.values())
Expand Down Expand Up @@ -145,13 +137,43 @@ public RegistrationContext getRegistrationContext(String registrationID)
@Override
public void refresh()
{
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPermission(new AuthPermission("refreshAuth"));
checkPermission("refreshAuth");

// TODO: maybe we should re-construct providers created from classname.
}

private static void checkPermission(String permission)
{
try
{
Object securityManager = getSecurityManager();
if (securityManager == null)
return;
securityManager.getClass().getMethod("checkPermission")
.invoke(securityManager, new AuthPermission(permission));
}
catch (SecurityException x)
{
throw x;
}
catch (Throwable ignored)
{
}
}

private static Object getSecurityManager()
{
try
{
// Use reflection to work with Java versions that have and don't have SecurityManager.
return System.class.getMethod("getSecurityManager").invoke(null);
}
catch (Throwable ignored)
{
return null;
}
}

private static String getKey(String layer, String appContext)
{
return layer + "/" + appContext;
Expand Down
Expand Up @@ -20,8 +20,6 @@
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -219,7 +217,7 @@ private enum ProtectedTargetType
private int _maxFormKeys = Integer.getInteger(MAX_FORM_KEYS_KEY, DEFAULT_MAX_FORM_KEYS);
private int _maxFormContentSize = Integer.getInteger(MAX_FORM_CONTENT_SIZE_KEY, DEFAULT_MAX_FORM_CONTENT_SIZE);
private boolean _compactPath = false;
private boolean _usingSecurityManager = System.getSecurityManager() != null;
private boolean _usingSecurityManager = getSecurityManager() != null;

private final List<EventListener> _programmaticListeners = new CopyOnWriteArrayList<>();
private final List<ServletContextListener> _servletContextListeners = new CopyOnWriteArrayList<>();
Expand Down Expand Up @@ -326,7 +324,7 @@ public boolean isUsingSecurityManager()

public void setUsingSecurityManager(boolean usingSecurityManager)
{
if (usingSecurityManager && System.getSecurityManager() == null)
if (usingSecurityManager && getSecurityManager() == null)
throw new IllegalStateException("No security manager");
_usingSecurityManager = usingSecurityManager;
}
Expand Down Expand Up @@ -2114,6 +2112,19 @@ public void clearAliasChecks()
_aliasChecks.clear();
}

private static Object getSecurityManager()
{
try
{
// Use reflection to work with Java versions that have and don't have SecurityManager.
return System.class.getMethod("getSecurityManager").invoke(null);
}
catch (Throwable ignored)
{
return null;
}
}

/**
* Context.
* <p>
Expand Down Expand Up @@ -2561,23 +2572,41 @@ public ClassLoader getClassLoader()
{
// check to see if the classloader of the caller is the same as the context
// classloader, or a parent of it, as required by the javadoc specification.

// Wrap in a PrivilegedAction so that only Jetty code will require the
// "createSecurityManager" permission, not also application code that calls this method.
Caller caller = AccessController.doPrivileged((PrivilegedAction<Caller>)Caller::new);
ClassLoader callerLoader = caller.getCallerClassLoader(2);
ClassLoader callerLoader = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.getCallerClass()
.getClassLoader();
while (callerLoader != null)
{
if (callerLoader == _classLoader)
return _classLoader;
else
callerLoader = callerLoader.getParent();
}
System.getSecurityManager().checkPermission(new RuntimePermission("getClassLoader"));
checkPermission();
return _classLoader;
}
}

private void checkPermission()
{
try
{
// Use reflection to work with Java versions that still have the SecurityManager.
Object securityManager = getSecurityManager();
if (securityManager == null)
return;
securityManager.getClass().getMethod("checkPermission")
.invoke(securityManager, new RuntimePermission("getClassLoader"));
}
catch (SecurityException x)
{
throw x;
}
catch (Throwable ignored)
{
}
}

@Override
public JspConfigDescriptor getJspConfigDescriptor()
{
Expand Down Expand Up @@ -3103,17 +3132,4 @@ public static interface ContextScopeListener extends EventListener
*/
void exitScope(Context context, Request request);
}

private static class Caller extends SecurityManager
{
public ClassLoader getCallerClassLoader(int depth)
{
if (depth < 0)
return null;
Class<?>[] classContext = getClassContext();
if (classContext.length <= depth)
return null;
return classContext[depth].getClassLoader();
}
}
}
Expand Up @@ -16,8 +16,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Locale;
import java.util.Properties;
Expand Down Expand Up @@ -161,29 +159,26 @@ public TimeZone getTimeZone(String key)
*/
public JettyLoggerConfiguration load(ClassLoader loader)
{
return AccessController.doPrivileged((PrivilegedAction<JettyLoggerConfiguration>)() ->
// First see if the jetty-logging.properties object exists in the classpath.
// * This is an optional feature used by embedded mode use, and test cases to allow for early
// * configuration of the Log class in situations where access to the System.properties are
// * either too late or just impossible.
load(readProperties(loader, "jetty-logging.properties"));

// Next see if an OS specific jetty-logging.properties object exists in the classpath.
// This really for setting up test specific logging behavior based on OS.
String osName = System.getProperty("os.name");
if (osName != null && osName.length() > 0)
{
// First see if the jetty-logging.properties object exists in the classpath.
// * This is an optional feature used by embedded mode use, and test cases to allow for early
// * configuration of the Log class in situations where access to the System.properties are
// * either too late or just impossible.
load(readProperties(loader, "jetty-logging.properties"));

// Next see if an OS specific jetty-logging.properties object exists in the classpath.
// This really for setting up test specific logging behavior based on OS.
String osName = System.getProperty("os.name");
if (osName != null && osName.length() > 0)
{
// NOTE: cannot use jetty-util's StringUtil.replace() as it may initialize logging itself.
osName = osName.toLowerCase(Locale.ENGLISH).replace(' ', '-');
load(readProperties(loader, "jetty-logging-" + osName + ".properties"));
}
// NOTE: cannot use jetty-util's StringUtil.replace() as it may initialize logging itself.
osName = osName.toLowerCase(Locale.ENGLISH).replace(' ', '-');
load(readProperties(loader, "jetty-logging-" + osName + ".properties"));
}

// Now load the System.properties as-is into the properties,
// these values will override any key conflicts in properties.
load(System.getProperties());
return this;
});
// Now load the System.properties as-is into the properties,
// these values will override any key conflicts in properties.
load(System.getProperties());
return this;
}

public String getString(String key, String defValue)
Expand Down
14 changes: 2 additions & 12 deletions jetty-util/src/main/java/org/eclipse/jetty/util/MemoryUtils.java
Expand Up @@ -13,9 +13,6 @@

package org.eclipse.jetty.util;

import java.security.AccessController;
import java.security.PrivilegedAction;

/**
* MemoryUtils provides an abstraction over memory properties and operations.
*/
Expand All @@ -25,18 +22,11 @@ public class MemoryUtils

static
{
final int defaultValue = 64;
int defaultValue = 64;
int value = defaultValue;
try
{
value = Integer.parseInt(AccessController.doPrivileged(new PrivilegedAction<String>()
{
@Override
public String run()
{
return System.getProperty("org.eclipse.jetty.util.cacheLineBytes", String.valueOf(defaultValue));
}
}));
value = Integer.parseInt(System.getProperty("org.eclipse.jetty.util.cacheLineBytes", String.valueOf(defaultValue)));
}
catch (Exception ignored)
{
Expand Down
Expand Up @@ -26,9 +26,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -671,7 +669,7 @@ public static URI getCodeSourceLocation(Class<?> clazz)
{
try
{
ProtectionDomain domain = AccessController.doPrivileged((PrivilegedAction<ProtectionDomain>)() -> clazz.getProtectionDomain());
ProtectionDomain domain = clazz.getProtectionDomain();
if (domain != null)
{
CodeSource source = domain.getCodeSource();
Expand Down

0 comments on commit 96ece88

Please sign in to comment.