Remove usage of a SecurityManager from EE11 (#12032)

Use callAs rather than doAs
Disable after java 21
This commit is contained in:
Greg Wilkins 2024-07-15 13:32:34 +10:00 committed by GitHub
parent b0b204cb35
commit 12db285f17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 49 additions and 46 deletions

View File

@ -214,7 +214,7 @@ public class SPNEGOAuthentication extends AbstractAuthentication
String b64Input = headerInfo.getBase64();
byte[] input = b64Input == null ? new byte[0] : Base64.getDecoder().decode(b64Input);
byte[] output = SecurityUtils.doAs(spnegoContext.subject, initGSSContext(spnegoContext, request.getHost(), input));
byte[] output = SecurityUtils.callAs(spnegoContext.subject, initGSSContext(spnegoContext, request.getHost(), input));
String b64Output = output == null ? null : new String(Base64.getEncoder().encode(output));
// The result cannot be used for subsequent requests,

View File

@ -143,7 +143,7 @@ public class SPNEGOLoginService extends ContainerLifeCycle implements LoginServi
LoginContext loginContext = new LoginContext("", null, null, new SPNEGOConfiguration());
loginContext.login();
Subject subject = loginContext.getSubject();
_context = SecurityUtils.doAs(subject, newSpnegoContext(subject));
_context = SecurityUtils.callAs(subject, newSpnegoContext(subject));
super.doStart();
}
@ -182,10 +182,11 @@ public class SPNEGOLoginService extends ContainerLifeCycle implements LoginServi
gssContext = holder == null ? null : holder.gssContext;
}
if (gssContext == null)
gssContext = SecurityUtils.doAs(subject, newGSSContext());
gssContext = SecurityUtils.callAs(subject, newGSSContext());
byte[] input = Base64.getDecoder().decode((String)credentials);
byte[] output = SecurityUtils.doAs(_context._subject, acceptGSSContext(gssContext, input));
byte[] output = SecurityUtils.callAs(_context._subject, acceptGSSContext(gssContext, input));
String token = Base64.getEncoder().encodeToString(output);
String userName = toUserName(gssContext);

View File

@ -22,16 +22,22 @@ import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
import javax.security.auth.Subject;
import org.eclipse.jetty.util.JavaVersion;
/**
* <p>Collections of utility methods to deal with the scheduled removal
* of the security classes defined by <a href="https://openjdk.org/jeps/411">JEP 411</a>.</p>
* <p>To enable usage of a {@link SecurityManager}, the system property {@link #USE_SECURITY_MANAGER} must be set to {@code true}
* for JVMs after version 21.</p>
*/
public class SecurityUtils
{
private static final MethodHandle doAs = lookupDoAs();
public static final boolean USE_SECURITY_MANAGER = Boolean.parseBoolean(
System.getProperty("org.eclipse.jetty.util.security.useSecurityManager", JavaVersion.VERSION.getMajor() <= 21 ? "true" : "false"));
private static final MethodHandle callAs = lookupCallAs();
private static final MethodHandle doPrivileged = lookupDoPrivileged();
private static MethodHandle lookupDoAs()
private static MethodHandle lookupCallAs()
{
MethodHandles.Lookup lookup = MethodHandles.lookup();
try
@ -39,14 +45,15 @@ public class SecurityUtils
// Subject.doAs() is deprecated for removal and replaced by Subject.callAs().
// Lookup first the new API, since for Java versions where both exists, the
// new API delegates to the old API (for example Java 18, 19 and 20).
// Otherwise (Java 17), lookup the old API.
return lookup.findStatic(Subject.class, "callAs", MethodType.methodType(Object.class, Subject.class, Callable.class));
}
catch (Throwable x)
{
try
{
// Lookup the old API.
if (!USE_SECURITY_MANAGER)
return null;
// Otherwise (Java 17), lookup the old API.
MethodType oldSignature = MethodType.methodType(Object.class, Subject.class, PrivilegedAction.class);
MethodHandle doAs = lookup.findStatic(Subject.class, "doAs", oldSignature);
// Convert the Callable used in the new API to the PrivilegedAction used in the old API.
@ -63,6 +70,8 @@ public class SecurityUtils
private static MethodHandle lookupDoPrivileged()
{
if (!USE_SECURITY_MANAGER)
return null;
try
{
// Use reflection to work with Java versions that have and don't have AccessController.
@ -84,6 +93,8 @@ public class SecurityUtils
{
try
{
if (!USE_SECURITY_MANAGER)
return null;
// Use reflection to work with Java versions that have and don't have SecurityManager.
return System.class.getMethod("getSecurityManager").invoke(null);
}
@ -102,6 +113,8 @@ public class SecurityUtils
*/
public static void checkPermission(Permission permission) throws SecurityException
{
if (!USE_SECURITY_MANAGER)
return;
Object securityManager = SecurityUtils.getSecurityManager();
if (securityManager == null)
return;
@ -129,11 +142,9 @@ public class SecurityUtils
*/
public static <T> T doPrivileged(PrivilegedAction<T> action)
{
// Keep this method short and inlineable.
MethodHandle methodHandle = doPrivileged;
if (methodHandle == null)
if (!USE_SECURITY_MANAGER || doPrivileged == null)
return action.run();
return doPrivileged(methodHandle, action);
return doPrivileged(doPrivileged, action);
}
@SuppressWarnings("unchecked")
@ -153,6 +164,21 @@ public class SecurityUtils
}
}
/**
* <p>Runs the given action as the given subject.</p>
*
* @param subject the subject this action runs as
* @param action the action to run
* @return the result of the action
* @param <T> the type of the result
* @deprecated use {@link #callAs(Subject, Callable)}
*/
@Deprecated(forRemoval = true, since = "12.1.0")
public static <T> T doAs(Subject subject, Callable<T> action)
{
return callAs(subject, action);
}
/**
* <p>Runs the given action as the given subject.</p>
*
@ -162,14 +188,14 @@ public class SecurityUtils
* @param <T> the type of the result
*/
@SuppressWarnings("unchecked")
public static <T> T doAs(Subject subject, Callable<T> action)
public static <T> T callAs(Subject subject, Callable<T> action)
{
try
{
MethodHandle methodHandle = doAs;
if (methodHandle == null)
if (callAs == null)
return action.call();
return (T)methodHandle.invoke(subject, action);
return (T)callAs.invoke(subject, action);
}
catch (RuntimeException | Error x)
{

View File

@ -108,7 +108,6 @@ import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.util.security.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -219,7 +218,6 @@ public class ServletContextHandler extends ContextHandler
private Logger _logger;
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 _usingSecurityManager = getSecurityManager() != null;
private final List<EventListener> _programmaticListeners = new CopyOnWriteArrayList<>();
private final List<ServletContextListener> _servletContextListeners = new CopyOnWriteArrayList<>();
@ -324,16 +322,17 @@ public class ServletContextHandler extends ContextHandler
new DumpableCollection("initparams " + this, getInitParams().entrySet()));
}
@Deprecated(forRemoval = true, since = "12.1.0")
public boolean isUsingSecurityManager()
{
return _usingSecurityManager;
return false;
}
@Deprecated(forRemoval = true, since = "12.1.0")
public void setUsingSecurityManager(boolean usingSecurityManager)
{
if (usingSecurityManager && getSecurityManager() == null)
throw new IllegalStateException("No security manager");
_usingSecurityManager = usingSecurityManager;
if (usingSecurityManager)
throw new UnsupportedOperationException("SecurityManager not supported");
}
/**
@ -1712,11 +1711,6 @@ public class ServletContextHandler extends ContextHandler
getContext().destroy(listener);
}
private static Object getSecurityManager()
{
return SecurityUtils.getSecurityManager();
}
public static class JspPropertyGroup implements JspPropertyGroupDescriptor
{
private final List<String> _urlPatterns = new ArrayList<>();
@ -2980,25 +2974,7 @@ public class ServletContextHandler extends ContextHandler
@Override
public ClassLoader getClassLoader()
{
// no security manager just return the classloader
ClassLoader classLoader = ServletContextHandler.this.getClassLoader();
if (isUsingSecurityManager())
{
// 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.
ClassLoader callerLoader = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
.getCallerClass()
.getClassLoader();
while (callerLoader != null)
{
if (callerLoader == classLoader)
return classLoader;
else
callerLoader = callerLoader.getParent();
}
SecurityUtils.checkPermission(new RuntimePermission("getClassLoader"));
}
return classLoader;
return ServletContextHandler.this.getClassLoader();
}
public void setEnabled(boolean enabled)