package com.brightgenerous.lang; import java.io.FileDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.InetAddress; import java.security.Permission; class SecurityManagerWrapper extends SecurityManager { private final SecurityManager deleg; private final Class<? extends SecurityManager> delegClazz; private final ISecurityManagerFilter filter; public SecurityManagerWrapper() { this((SecurityManager) null); } public SecurityManagerWrapper(SecurityManager deleg) { this(deleg, null); } public SecurityManagerWrapper(ISecurityManagerFilter filter) { this(null, filter); } public SecurityManagerWrapper(SecurityManager deleg, ISecurityManagerFilter filter) { this.deleg = deleg; if (deleg == null) { delegClazz = null; } else { delegClazz = deleg.getClass(); } this.filter = filter; } @Override public void checkAccept(String host, int port) { if (filter != null) { filter.checkAccept(host, port); } if (deleg == null) { return; } deleg.checkAccept(host, port); } @Override public void checkAccess(Thread t) { if (filter != null) { filter.checkAccess(t); } if (deleg == null) { return; } deleg.checkAccess(t); } @Override public void checkAccess(ThreadGroup t) { if (filter != null) { filter.checkAccess(t); } if (deleg == null) { return; } deleg.checkAccess(t); } @Override public void checkAwtEventQueueAccess() { if (filter != null) { filter.checkAwtEventQueueAccess(); } if (deleg == null) { return; } deleg.checkAwtEventQueueAccess(); } @Override public void checkConnect(String host, int port) { if (filter != null) { filter.checkConnect(host, port); } if (deleg == null) { return; } deleg.checkConnect(host, port); } @Override public void checkConnect(String host, int port, Object context) { if (filter != null) { filter.checkConnect(host, port, context); } if (deleg == null) { return; } deleg.checkConnect(host, port, context); } @Override public void checkCreateClassLoader() { if (filter != null) { filter.checkCreateClassLoader(); } if (deleg == null) { return; } deleg.checkCreateClassLoader(); } @Override public void checkDelete(String file) { if (filter != null) { filter.checkDelete(file); } if (deleg == null) { return; } deleg.checkDelete(file); } @Override public void checkExec(String cmd) { if (filter != null) { filter.checkExec(cmd); } if (deleg == null) { return; } deleg.checkExec(cmd); } @Override public void checkExit(int status) { if (filter != null) { filter.checkExit(status); } if (deleg == null) { return; } deleg.checkExit(status); } @Override public void checkLink(String lib) { if (filter != null) { filter.checkLink(lib); } if (deleg == null) { return; } deleg.checkLink(lib); } @Override public void checkListen(int port) { if (filter != null) { filter.checkListen(port); } if (deleg == null) { return; } deleg.checkListen(port); } @Override public void checkMemberAccess(Class<?> clazz, int which) { if (filter != null) { filter.checkMemberAccess(clazz, which); } if (deleg == null) { return; } deleg.checkMemberAccess(clazz, which); } @Override public void checkMulticast(InetAddress maddr) { if (filter != null) { filter.checkMulticast(maddr); } if (deleg == null) { return; } deleg.checkMulticast(maddr); } @SuppressWarnings("deprecation") @Override public void checkMulticast(InetAddress maddr, byte ttl) { if (filter != null) { filter.checkMulticast(maddr, ttl); } if (deleg == null) { return; } deleg.checkMulticast(maddr, ttl); } @Override public void checkPackageAccess(String pkg) { if (filter != null) { filter.checkPackageAccess(pkg); } if (deleg == null) { return; } deleg.checkPackageAccess(pkg); } @Override public void checkPackageDefinition(String pkg) { if (filter != null) { filter.checkPackageDefinition(pkg); } if (deleg == null) { return; } deleg.checkPackageDefinition(pkg); } @Override public void checkPermission(Permission perm) { if (filter != null) { filter.checkPermission(perm); } if (deleg == null) { return; } deleg.checkPermission(perm); } @Override public void checkPermission(Permission perm, Object context) { if (filter != null) { filter.checkPermission(perm, context); } if (deleg == null) { return; } deleg.checkPermission(perm, context); } @Override public void checkPrintJobAccess() { if (filter != null) { filter.checkPrintJobAccess(); } if (deleg == null) { return; } deleg.checkPrintJobAccess(); } @Override public void checkPropertiesAccess() { if (filter != null) { filter.checkPropertiesAccess(); } if (deleg == null) { return; } deleg.checkPropertiesAccess(); } @Override public void checkPropertyAccess(String key) { if (filter != null) { filter.checkPropertyAccess(key); } if (deleg == null) { return; } deleg.checkPropertyAccess(key); } @Override public void checkRead(FileDescriptor fd) { if (filter != null) { filter.checkRead(fd); } if (deleg == null) { return; } deleg.checkRead(fd); } @Override public void checkRead(String file) { if (filter != null) { filter.checkRead(file); } if (deleg == null) { return; } deleg.checkRead(file); } @Override public void checkRead(String file, Object context) { if (filter != null) { filter.checkRead(file, context); } if (deleg == null) { return; } deleg.checkRead(file, context); } @Override public void checkSecurityAccess(String target) { if (filter != null) { filter.checkSecurityAccess(target); } if (deleg == null) { return; } deleg.checkSecurityAccess(target); } @Override public void checkSetFactory() { if (filter != null) { filter.checkSetFactory(); } if (deleg == null) { return; } deleg.checkSetFactory(); } @Override public void checkSystemClipboardAccess() { if (filter != null) { filter.checkSystemClipboardAccess(); } if (deleg == null) { return; } deleg.checkSystemClipboardAccess(); } @Override public boolean checkTopLevelWindow(Object window) { if (filter != null) { if (!filter.checkTopLevelWindow(window)) { return false; } } if (deleg == null) { return false; } return deleg.checkTopLevelWindow(window); } @Override public void checkWrite(FileDescriptor fd) { if (filter != null) { filter.checkWrite(fd); } if (deleg == null) { return; } deleg.checkWrite(fd); } @Override public void checkWrite(String file) { if (filter != null) { filter.checkWrite(file); } if (deleg == null) { return; } deleg.checkWrite(file); } private transient volatile Method classDepth; @Override protected int classDepth(String name) { if (deleg == null) { return -1; } if (classDepth == null) { synchronized (this) { if (classDepth == null) { classDepth = getMethod(delegClazz, "classDepth", String.class); } } } return ((Integer) invoke(deleg, classDepth, name)).intValue(); } private transient volatile Method classLoaderDepth; @Override protected int classLoaderDepth() { if (deleg == null) { return -1; } if (classLoaderDepth == null) { synchronized (this) { if (classLoaderDepth == null) { classLoaderDepth = getMethod(delegClazz, "classLoaderDepth"); } } } return ((Integer) invoke(deleg, classLoaderDepth)).intValue(); } private transient volatile Method currentClassLoader; @Override protected ClassLoader currentClassLoader() { if (deleg == null) { return null; } if (currentClassLoader == null) { synchronized (this) { if (currentClassLoader == null) { currentClassLoader = getMethod(delegClazz, "currentClassLoader"); } } } return (ClassLoader) invoke(deleg, currentClassLoader); } private transient volatile Method currentLoadedClass; @Override protected Class<?> currentLoadedClass() { if (deleg == null) { return null; } if (currentLoadedClass == null) { synchronized (this) { if (currentLoadedClass == null) { currentLoadedClass = getMethod(delegClazz, "currentLoadedClass"); } } } return (Class<?>) invoke(deleg, currentLoadedClass); } private transient volatile Method getClassContext; @Override protected Class<?>[] getClassContext() { if (deleg == null) { return new Class<?>[0]; } if (getClassContext == null) { synchronized (this) { if (getClassContext == null) { getClassContext = getMethod(delegClazz, "getClassContext"); } } } return (Class<?>[]) invoke(deleg, getClassContext); } @SuppressWarnings("deprecation") @Override public boolean getInCheck() { if (deleg == null) { return false; } return deleg.getInCheck(); } @Override public Object getSecurityContext() { if (deleg == null) { return null; } return deleg.getSecurityContext(); } @Override public ThreadGroup getThreadGroup() { if (deleg == null) { return null; } return deleg.getThreadGroup(); } private transient volatile Method inClass; @Override protected boolean inClass(String name) { if (deleg == null) { return false; } if (inClass == null) { synchronized (this) { if (inClass == null) { inClass = getMethod(delegClazz, "inClass", String.class); } } } return ((Boolean) invoke(deleg, inClass, name)).booleanValue(); } private transient volatile Method inClassLoader; @Override protected boolean inClassLoader() { if (deleg == null) { return false; } if (inClassLoader == null) { synchronized (this) { if (inClassLoader == null) { inClassLoader = getMethod(delegClazz, "inClassLoader"); } } } return ((Boolean) invoke(deleg, inClassLoader)).booleanValue(); } private static Method getMethod(Class<? extends SecurityManager> clazz, String name, Class<?>... paramTypes) { try { Method method = clazz.getDeclaredMethod(name, paramTypes); if (!Modifier.isPublic(method.getModifiers()) && !method.isAccessible()) { method.setAccessible(true); } return method; } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException(e); } } private static <T> T invoke(SecurityManager deleg, Method method, Object... params) { try { return (T) method.invoke(deleg, params); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new RuntimeException(e); } } }