Skip to content

Commit

Permalink
Introduced SecurityUtils to gather in a central place the handling of…
Browse files Browse the repository at this point in the history
… JEP 411 changes.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
  • Loading branch information
sbordet committed Apr 5, 2023
1 parent 98fe896 commit 97fb457
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.security.auth.message.config.AuthConfigProvider;
import javax.security.auth.message.config.RegistrationListener;

import org.eclipse.jetty.util.security.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -144,34 +145,7 @@ public void refresh()

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;
}
SecurityUtils.checkPermission(new AuthPermission(permission));
}

private static String getKey(String layer, String appContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
import org.eclipse.jetty.util.component.Graceful;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.security.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -2114,15 +2115,7 @@ public void clearAliasChecks()

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;
}
return SecurityUtils.getSecurityManager();
}

/**
Expand Down Expand Up @@ -2582,31 +2575,11 @@ public ClassLoader getClassLoader()
else
callerLoader = callerLoader.getParent();
}
checkPermission();
SecurityUtils.checkPermission(new RuntimePermission("getClassLoader"));
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//
// ========================================================================
// Copyright (c) 2023 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.util.security;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.Permission;
import java.security.PrivilegedAction;

/**
* <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>
*/
public class SecurityUtils
{
private static final MethodHandle doPrivileged = lookup();

private static MethodHandle lookup()
{
try
{
// Use reflection to work with Java versions that have and don't have AccessController.
Class<?> klass = ClassLoader.getPlatformClassLoader().loadClass("java.security.AccessController");
MethodHandles.Lookup lookup = MethodHandles.lookup();
return lookup.findStatic(klass, "doPrivileged", MethodType.methodType(Object.class, PrivilegedAction.class));
}
catch (Throwable x)
{
return null;
}
}

/**
* @return the current security manager, if available
*/
public 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;
}
}

/**
* <p>Checks the given permission, if the {@link #getSecurityManager() security manager}
* is set.</p>
*
* @param permission the permission to check
* @throws SecurityException if the permission check fails
*/
public static void checkPermission(Permission permission) throws SecurityException
{
Object securityManager = SecurityUtils.getSecurityManager();
if (securityManager == null)
return;
try
{
securityManager.getClass().getMethod("checkPermission")
.invoke(securityManager, permission);
}
catch (SecurityException x)
{
throw x;
}
catch (Throwable ignored)
{
}
}

/**
* <p>Runs the given action with the calling context restricted
* to just the calling frame, not all the frames in the stack.</p>
*
* @param action the action to run
* @return the result of running the action
* @param <T> the type of the result
*/
public static <T> T doPrivileged(PrivilegedAction<T> action)
{
// Keep this method short and inlineable.
MethodHandle methodHandle = doPrivileged;
if (methodHandle == null)
return action.run();
return doPrivileged(methodHandle, action);
}

@SuppressWarnings("unchecked")
private static <T> T doPrivileged(MethodHandle doPrivileged, PrivilegedAction<T> action)
{
try
{
return (T)doPrivileged.invoke(action);
}
catch (RuntimeException | Error x)
{
throw x;
}
catch (Throwable x)
{
throw new RuntimeException(x);
}
}

private SecurityUtils()
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@

package org.eclipse.jetty.util.thread;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.function.Supplier;

import org.eclipse.jetty.util.security.SecurityUtils;

/**
* <p>Convenience {@link Thread} factory that ensure threads are
* created without referencing any web application {@link ClassLoader}.</p>
Expand All @@ -41,55 +40,16 @@
*/
class PrivilegedThreadFactory
{
private static final MethodHandle privileged = lookup();

private static MethodHandle lookup()
{
try
{
// Use reflection to work with Java versions that have and don't have AccessController.
Class<?> klass = ClassLoader.getPlatformClassLoader().loadClass("java.security.AccessController");
MethodHandles.Lookup lookup = MethodHandles.lookup();
return lookup.findStatic(klass, "doPrivileged", MethodType.methodType(Object.class, PrivilegedAction.class));
}
catch (Throwable x)
{
return null;
}
}

/**
* <p>Creates a new {@link Thread} from the given {@link Supplier},
* without retaining the calling context.</p>
*
* @param supplier the {@link Supplier} that creates the {@link Thread}
* @param creator the action that creates the {@link Thread}
* @return a new {@link Thread} without retaining the calling context
*/
static <T extends Thread> T newThread(Supplier<T> supplier)
{
// Keep this method short and inlineable.
MethodHandle methodHandle = privileged;
if (methodHandle == null)
return supplier.get();
return privilegedNewThread(methodHandle, supplier);
}

@SuppressWarnings("unchecked")
private static <T extends Thread> T privilegedNewThread(MethodHandle privileged, Supplier<T> supplier)
static <T extends Thread> T newThread(PrivilegedAction<T> creator)
{
try
{
PrivilegedAction<T> action = supplier::get;
return (T)privileged.invoke(action);
}
catch (RuntimeException | Error x)
{
throw x;
}
catch (Throwable x)
{
throw new RuntimeException(x);
}
return SecurityUtils.doPrivileged(creator);
}

private PrivilegedThreadFactory()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,11 @@
public class ShutdownThread extends Thread
{
private static final Logger LOG = LoggerFactory.getLogger(ShutdownThread.class);
private static final ShutdownThread _thread = PrivilegedThreadFactory.newThread(() ->
{
return new ShutdownThread();
});
private static final ShutdownThread _thread = PrivilegedThreadFactory.newThread(ShutdownThread::new);

private final AutoLock _lock = new AutoLock();
private boolean _hooked;
private final List<LifeCycle> _lifeCycles = new CopyOnWriteArrayList<LifeCycle>();
private final List<LifeCycle> _lifeCycles = new CopyOnWriteArrayList<>();

/**
* Default constructor for the singleton
Expand Down

0 comments on commit 97fb457

Please sign in to comment.