javassist.util.proxy.SecurityActions Maven / Gradle / Ivy
The newest version!
/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist.util.proxy;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javassist.bytecode.ClassFile;
class SecurityActions extends SecurityManager
{
public static final SecurityActions stack = new SecurityActions();
/**
* Since Java 9 abruptly removed Reflection.getCallerClass()
* in favour of StackWalker
we are left having to find a
* solution for the older versions without upsetting the new compiler.
*
* The member scoped function getClassContext()
* available as a SecurityManager
sibling remains
* functional across all versions, for now.
*
* @return represents the declaring class of the method that invoked
* the method that called this or index 2 on the stack trace.
* @since 3.23
*/
public Class> getCallerClass() {
return getClassContext()[2];
}
static Method[] getDeclaredMethods(final Class> clazz)
{
if (System.getSecurityManager() == null)
return clazz.getDeclaredMethods();
else {
return AccessController.doPrivileged(
new PrivilegedAction() {
public Method[] run() {
return clazz.getDeclaredMethods();
}
});
}
}
static Constructor>[] getDeclaredConstructors(final Class> clazz)
{
if (System.getSecurityManager() == null)
return clazz.getDeclaredConstructors();
else {
return AccessController.doPrivileged(
new PrivilegedAction[]>() {
public Constructor>[] run() {
return clazz.getDeclaredConstructors();
}
});
}
}
static MethodHandle getMethodHandle(final Class> clazz, final
String name, final Class>[] params) throws NoSuchMethodException
{
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public MethodHandle run() throws IllegalAccessException,
NoSuchMethodException, SecurityException {
Method rmet = clazz.getDeclaredMethod(name, params);
rmet.setAccessible(true);
MethodHandle meth = MethodHandles.lookup().unreflect(rmet);
rmet.setAccessible(false);
return meth;
}
});
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException)
throw (NoSuchMethodException) e.getCause();
throw new RuntimeException(e.getCause());
}
}
static Method getDeclaredMethod(final Class> clazz, final String name,
final Class>[] types) throws NoSuchMethodException
{
if (System.getSecurityManager() == null)
return clazz.getDeclaredMethod(name, types);
else {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Method run() throws Exception {
return clazz.getDeclaredMethod(name, types);
}
});
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException)
throw (NoSuchMethodException) e.getCause();
throw new RuntimeException(e.getCause());
}
}
}
static Constructor> getDeclaredConstructor(final Class> clazz,
final Class>[] types)
throws NoSuchMethodException
{
if (System.getSecurityManager() == null)
return clazz.getDeclaredConstructor(types);
else {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction>() {
public Constructor> run() throws Exception {
return clazz.getDeclaredConstructor(types);
}
});
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException)
throw (NoSuchMethodException) e.getCause();
throw new RuntimeException(e.getCause());
}
}
}
static void setAccessible(final AccessibleObject ao,
final boolean accessible)
{
if (System.getSecurityManager() == null)
ao.setAccessible(accessible);
else {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
ao.setAccessible(accessible);
return null;
}
});
}
}
static void set(final Field fld, final Object target, final Object value)
throws IllegalAccessException
{
if (System.getSecurityManager() == null)
fld.set(target, value);
else {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Void run() throws Exception {
fld.set(target, value);
return null;
}
});
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException)
throw (IllegalAccessException) e.getCause();
throw new RuntimeException(e.getCause());
}
}
}
static TheUnsafe getSunMiscUnsafeAnonymously() throws ClassNotFoundException
{
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction() { public TheUnsafe run() throws
ClassNotFoundException, NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Class> unsafe = Class.forName("sun.misc.Unsafe");
Field theUnsafe = unsafe.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
TheUnsafe usf = stack.new TheUnsafe(unsafe, theUnsafe.get(null));
theUnsafe.setAccessible(false);
disableWarning(usf);
return usf;
}
});
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof ClassNotFoundException)
throw (ClassNotFoundException) e.getCause();
if (e.getCause() instanceof NoSuchFieldException)
throw new ClassNotFoundException("No such instance.", e.getCause());
if (e.getCause() instanceof IllegalAccessException
|| e.getCause() instanceof IllegalAccessException
|| e.getCause() instanceof SecurityException)
throw new ClassNotFoundException("Security denied access.", e.getCause());
throw new RuntimeException(e.getCause());
}
}
/**
* _The_ Notorious sun.misc.Unsafe in all its glory, but anonymous
* so as not to attract unwanted attention. Kept in two separate
* parts it manages to avoid detection from linker/compiler/general
* complainers and those. This functionality will vanish from the
* JDK soon but in the meantime it shouldn't be an obstacle.
*
* All exposed methods are cached in a dictionary with overloaded
* methods collected under their corresponding keys. Currently the
* implementation assumes there is only one, if you need find a
* need there will have to be a compare.
* @since 3.23 */
class TheUnsafe
{
final Class> unsafe;
final Object theUnsafe;
final Map> methods =
new HashMap>();
TheUnsafe(Class> c, Object o)
{
this.unsafe = c;
this.theUnsafe = o;
for (Method m: unsafe.getDeclaredMethods()) {
if (!methods.containsKey(m.getName())) {
methods.put(m.getName(), Collections.singletonList(m));
continue;
}
if (methods.get(m.getName()).size() == 1)
methods.put(m.getName(),
new ArrayList(methods.get(m.getName())));
methods.get(m.getName()).add(m);
}
}
private Method getM(String name, Object[] o)
{
return methods.get(name).get(0);
}
public Object call(String name, Object... args)
{
try {
return getM(name, args).invoke(theUnsafe, args);
} catch (Throwable t) {t.printStackTrace();}
return null;
}
}
/**
* Java 9 now complains about every privileged action regardless.
* Displaying warnings of "illegal usage" and then instructing users
* to go hassle the maintainers in order to have it fixed.
* Making it hush for now, see all fixed.
* @param tu theUnsafe that'll fix it */
static void disableWarning(TheUnsafe tu) {
try {
if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9)
return;
Class> cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field logger = cls.getDeclaredField("logger");
tu.call("putObjectVolatile", cls, tu.call("staticFieldOffset", logger), null);
} catch (Exception e) { /*swallow*/ }
}
}