src/share/classes/java/lang/reflect/Proxy.java

Print this page

        

*** 26,36 **** package java.lang.reflect; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.security.AccessController; - import java.security.Permission; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; --- 26,35 ----
*** 51,70 **** * dynamic proxy classes created by those methods. * * <p>To create a proxy for some interface {@code Foo}: * <pre> * InvocationHandler handler = new MyInvocationHandler(...); ! * Class proxyClass = Proxy.getProxyClass( ! * Foo.class.getClassLoader(), new Class[] { Foo.class }); ! * Foo f = (Foo) proxyClass. ! * getConstructor(new Class[] { InvocationHandler.class }). ! * newInstance(new Object[] { handler }); * </pre> * or more simply: * <pre> * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), ! * new Class[] { Foo.class }, * handler); * </pre> * * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy * class</i> below) is a class that implements a list of interfaces --- 50,67 ---- * dynamic proxy classes created by those methods. * * <p>To create a proxy for some interface {@code Foo}: * <pre> * InvocationHandler handler = new MyInvocationHandler(...); ! * Class&lt;?&gt; proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class); ! * Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class). ! * newInstance(handler); * </pre> * or more simply: * <pre> * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), ! * new Class&lt;?&gt;[] { Foo.class }, * handler); * </pre> * * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy * class</i> below) is a class that implements a list of interfaces
*** 89,99 **** * the proxy instance. * * <p>A proxy class has the following properties: * * <ul> ! * <li>Proxy classes are public, final, and not abstract. * * <li>The unqualified name of a proxy class is unspecified. The space * of class names that begin with the string {@code "$Proxy"} * should be, however, reserved for proxy classes. * --- 86,100 ---- * the proxy instance. * * <p>A proxy class has the following properties: * * <ul> ! * <li>Proxy classes are <em>public, final, and not abstract</em> if ! * all proxy interfaces are public.</li> ! * ! * <li>Proxy classes are <em>non-public, final, and not abstract</em> if ! * any of the proxy interfaces is non-public.</li> * * <li>The unqualified name of a proxy class is unspecified. The space * of class names that begin with the string {@code "$Proxy"} * should be, however, reserved for proxy classes. *
*** 271,350 **** * for its invocation handler. * * @param h the invocation handler for this proxy instance */ protected Proxy(InvocationHandler h) { - doNewInstanceCheck(); this.h = h; } - private static class ProxyAccessHelper { - // The permission is implementation specific. - static final Permission PROXY_PERMISSION = - new ReflectPermission("proxyConstructorNewInstance"); - // These system properties are defined to provide a short-term - // workaround if customers need to disable the new security checks. - static final boolean allowNewInstance; - static final boolean allowNullLoader; - static { - allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance"); - allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader"); - } - - private static boolean getBooleanProperty(final String key) { - String s = AccessController.doPrivileged(new PrivilegedAction<String>() { - public String run() { - return System.getProperty(key); - } - }); - return Boolean.valueOf(s); - } - - static boolean needsNewInstanceCheck(Class<?> proxyClass) { - if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) { - return false; - } - - if (proxyClass.getName().startsWith(ReflectUtil.PROXY_PACKAGE + ".")) { - // all proxy interfaces are public - return false; - } - for (Class<?> intf : proxyClass.getInterfaces()) { - if (!Modifier.isPublic(intf.getModifiers())) { - return true; - } - } - return false; - } - } - - /* - * Access check on a proxy class that implements any non-public interface. - * - * @throws SecurityException if a security manager exists, and - * the caller does not have the permission. - */ - private void doNewInstanceCheck() { - SecurityManager sm = System.getSecurityManager(); - Class<?> proxyClass = this.getClass(); - if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) { - try { - sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION); - } catch (SecurityException e) { - throw new SecurityException("Not allowed to construct a Proxy " - + "instance that implements a non-public interface", e); - } - } - } - /** * Returns the {@code java.lang.Class} object for a proxy class * given a class loader and an array of interfaces. The proxy class * will be defined by the specified class loader and will implement ! * all of the supplied interfaces. If a proxy class for the same ! * permutation of interfaces has already been defined by the class ! * loader, then the existing proxy class will be returned; otherwise, * a proxy class for those interfaces will be generated dynamically * and defined by the class loader. * * <p>There are several restrictions on the parameters that may be * passed to {@code Proxy.getProxyClass}: --- 272,292 ---- * for its invocation handler. * * @param h the invocation handler for this proxy instance */ protected Proxy(InvocationHandler h) { this.h = h; } /** * Returns the {@code java.lang.Class} object for a proxy class * given a class loader and an array of interfaces. The proxy class * will be defined by the specified class loader and will implement ! * all of the supplied interfaces. If any of the given interfaces ! * is non-public, the proxy class will be non-public. If a proxy class ! * for the same permutation of interfaces has already been defined by the ! * class loader, then the existing proxy class will be returned; otherwise, * a proxy class for those interfaces will be generated dynamically * and defined by the class loader. * * <p>There are several restrictions on the parameters that may be * passed to {@code Proxy.getProxyClass}:
*** 405,414 **** --- 347,372 ---- * @return a proxy class that is defined in the specified class loader * and that implements the specified interfaces * @throws IllegalArgumentException if any of the restrictions on the * parameters that may be passed to {@code getProxyClass} * are violated + * @throws SecurityException if a security manager, <em>s</em>, is present + * and any of the following conditions is met: + * <ul> + * <li> the given {@code loader} is {@code null} and + * the caller's class loader is not {@code null} and the + * invocation of {@link SecurityManager#checkPermission + * s.checkPermission} with + * {@code RuntimePermission("getClassLoader")} permission + * denies access.</li> + * <li> the caller's class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to any one of the + * given proxy interfaces.</li> + * </ul> + * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null} */ @CallerSensitive public static Class<?> getProxyClass(ClassLoader loader,
*** 447,460 **** { SecurityManager sm = System.getSecurityManager(); if (sm != null) { ClassLoader ccl = caller.getClassLoader(); if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) { - if (!ProxyAccessHelper.allowNullLoader) { sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); } - } ReflectUtil.checkProxyPackageAccess(ccl, interfaces); } } /** --- 405,416 ----
*** 591,609 **** --- 547,567 ---- } while (true); } try { String proxyPkg = null; // package to define proxy class in + int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (int i = 0; i < interfaces.length; i++) { int flags = interfaces[i].getModifiers(); if (!Modifier.isPublic(flags)) { + accessFlags = Modifier.FINAL; String name = interfaces[i].getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg;
*** 635,645 **** /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( ! proxyName, interfaces); try { proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* --- 593,603 ---- /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( ! proxyName, interfaces, accessFlags); try { proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /*
*** 676,691 **** } /** * Returns an instance of a proxy class for the specified interfaces * that dispatches method invocations to the specified invocation ! * handler. This method is equivalent to: ! * <pre> ! * Proxy.getProxyClass(loader, interfaces). ! * getConstructor(new Class[] { InvocationHandler.class }). ! * newInstance(new Object[] { handler }); ! * </pre> * * <p>{@code Proxy.newProxyInstance} throws * {@code IllegalArgumentException} for the same reasons that * {@code Proxy.getProxyClass} does. * --- 634,644 ---- } /** * Returns an instance of a proxy class for the specified interfaces * that dispatches method invocations to the specified invocation ! * handler. * * <p>{@code Proxy.newProxyInstance} throws * {@code IllegalArgumentException} for the same reasons that * {@code Proxy.getProxyClass} does. *
*** 697,706 **** --- 650,680 ---- * proxy class that is defined by the specified class loader * and that implements the specified interfaces * @throws IllegalArgumentException if any of the restrictions on the * parameters that may be passed to {@code getProxyClass} * are violated + * @throws SecurityException if a security manager, <em>s</em>, is present + * and any of the following conditions is met: + * <ul> + * <li> the given {@code loader} is {@code null} and + * the caller's class loader is not {@code null} and the + * invocation of {@link SecurityManager#checkPermission + * s.checkPermission} with + * {@code RuntimePermission("getClassLoader")} permission + * denies access;</li> + * <li> the caller's class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to any one of the + * given proxy interfaces.</li> + * <li> any of the given proxy interfaces is non-public and the + * caller class is not in the same {@linkplain Package runtime package} + * as the non-public interface and the invocation of + * {@link SecurityManager#checkPermission s.checkPermission} with + * {@code ReflectPermission("newProxyInPackage.{package name}")} + * permission denies access.</li> + * </ul> * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null}, or * if the invocation handler, {@code h}, is * {@code null} */
*** 726,753 **** /* * Invoke its constructor with the designated invocation handler. */ try { final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; ! if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { ! // create proxy instance with doPrivilege as the proxy class may ! // implement non-public interfaces that requires a special permission ! return AccessController.doPrivileged(new PrivilegedAction<Object>() { ! public Object run() { ! return newInstance(cons, ih); } }); } else { ! return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } } private static Object newInstance(Constructor<?> cons, InvocationHandler h) { try { return cons.newInstance(new Object[] {h} ); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString(), e); --- 700,764 ---- /* * Invoke its constructor with the designated invocation handler. */ try { + if (sm != null) { + checkNewProxyPermission(Reflection.getCallerClass(), cl); + } + final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; ! if (!Modifier.isPublic(cl.getModifiers())) { ! AccessController.doPrivileged(new PrivilegedAction<Void>() { ! public Void run() { ! cons.setAccessible(true); ! return null; } }); + } + return cons.newInstance(new Object[]{h}); + } catch (IllegalAccessException|InstantiationException e) { + throw new InternalError(e.toString(), e); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof RuntimeException) { + throw (RuntimeException) t; } else { ! throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } } + private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + String pcn = proxyClass.getName(); + if (pcn.startsWith(ReflectUtil.PROXY_PACKAGE + ".")) { + // all proxy interfaces are public + return; + } + + ClassLoader ccl = caller.getClassLoader(); + ClassLoader pcl = proxyClass.getClassLoader(); + + // do permission check if the caller is in a different runtime package + // of the proxy class + int n = pcn.lastIndexOf('.'); + String pkg = (n == -1) ? "" : pcn.substring(0, n); + + n = caller.getName().lastIndexOf('.'); + String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n); + + if (pcl != ccl || !pkg.equals(callerPkg)) { + sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg)); + } + } + } + private static Object newInstance(Constructor<?> cons, InvocationHandler h) { try { return cons.newInstance(new Object[] {h} ); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString(), e);