< prev index next >

test/java/lang/invoke/AccessControlTest.java

Print this page


   1 /*
   2  * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */


 101             return (that instanceof LookupCase && equals((LookupCase)that));
 102         }
 103         public boolean equals(LookupCase that) {
 104             return (this.lookupClass() == that.lookupClass() &&
 105                     this.lookupModes() == that.lookupModes());
 106         }
 107 
 108         @Override
 109         public int hashCode() {
 110             return lookupClass().hashCode() + (lookupModes() * 31);
 111         }
 112 
 113         /** Simulate all assertions in the spec. for Lookup.toString. */
 114         private String lookupString() {
 115             String name = lookupClass.getName();
 116             String suffix = "";
 117             if (lookupModes == 0)
 118                 suffix = "/noaccess";
 119             else if (lookupModes == PUBLIC)
 120                 suffix = "/public";


 121             else if (lookupModes == (PUBLIC|MODULE))
 122                 suffix = "/module";
 123             else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
 124                 suffix = "/package";
 125             else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
 126                 suffix = "/private";
 127             else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
 128                 suffix = "";
 129             else
 130                 suffix = "/#"+Integer.toHexString(lookupModes);
 131             return name+suffix;
 132         }
 133 
 134         /** Simulate all assertions from the spec. for Lookup.in:
 135          * <hr>
 136          * Creates a lookup on the specified new lookup class.
 137          * [A1] The resulting object will report the specified
 138          * class as its own {@link #lookupClass lookupClass}.
 139          * <p>
 140          * [A2] However, the resulting {@code Lookup} object is guaranteed
 141          * to have no more access capabilities than the original.
 142          * In particular, access capabilities can be lost as follows:<ul>
 143          * <li>[A3] If the new lookup class differs from the old one,
 144          * protected members will not be accessible by virtue of inheritance.








 145          * (Protected members may continue to be accessible because of package sharing.)
 146          * <li>[A4] If the new lookup class is in a different package
 147          * than the old one, protected and default (package) members will not be accessible.
 148          * <li>[A5] If the new lookup class is not within the same package member
 149          * as the old one, private members will not be accessible.
 150          * <li>[A6] If the new lookup class is not accessible to the old lookup class,
 151          * using the original access modes,
 152          * then no members, not even public members, will be accessible.
 153          * <li>[A7] If the new lookup class for this {@code Lookup} is in the unnamed module,
 154          * and the new lookup class is in a named module {@code M}, then no members in
 155          * {@code M}'s non-exported packages will be accessible.
 156          * <li>[A8] If the lookup for this {@code Lookup} is in a named module, and the
 157          * new lookup class is in a different module, then no members, not even
 158          * public members in {@code M}'s exported packages, will be accessible.
 159          * [A8] (In all other cases, public members will continue to be accessible.)
 160          * </ul>
 161          * Other than the above cases, the new lookup will have the same
 162          * access capabilities as the original. [A10]
 163          * <hr>
 164          */
 165         public LookupCase in(Class<?> c2) {
 166             Class<?> c1 = lookupClass();
 167             int m1 = lookupModes();
 168             int changed = 0;
 169             // for the purposes of access control then treat classes in different unnamed
 170             // modules as being in the same module.
 171             boolean sameModule = (c1.getModule() == c2.getModule()) ||
 172                                  (!c1.getModule().isNamed() && !c2.getModule().isNamed());
 173             boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
 174                                    packagePrefix(c1).equals(packagePrefix(c2)));
 175             boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
 176             boolean sameClass = (c1 == c2);
 177             assert(samePackage  || !sameTopLevel);
 178             assert(sameTopLevel || !sameClass);
 179             boolean accessible = sameClass;  // [A6]
 180             if ((m1 & PACKAGE) != 0)  accessible |= samePackage;
 181             if ((m1 & PUBLIC ) != 0)  accessible |= (c2.getModifiers() & PUBLIC) != 0;
 182             if (!sameModule) {
 183                 if (c1.getModule().isNamed()) {
 184                     accessible = false;  // [A8]
 185                 } else {
 186                     // Different module; loose MODULE and lower access.
 187                     changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A7]
 188                 }
 189             }
 190             if (!accessible) {
 191                 // Different package and no access to c2; lose all access.
 192                 changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A6]
 193             }
 194             if (!samePackage) {
 195                 // Different package; loose PACKAGE and lower access.
 196                 changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A4]
 197             }
 198             if (!sameTopLevel) {
 199                 // Different top-level class.  Lose PRIVATE and lower access.
 200                 changed |= (PRIVATE|PROTECTED);  // [A5]
 201             }
 202             if (!sameClass) {
 203                 changed |= (PROTECTED);     // [A3]
 204             } else {
 205                 assert(changed == 0);       // [A10] (no deprivation if same class)
 206             }
 207             if (accessible)  assert((changed & PUBLIC) == 0);  // [A9]
 208             int m2 = m1 & ~changed;
 209             LookupCase l2 = new LookupCase(c2, m2);
 210             assert(l2.lookupClass() == c2); // [A1]
 211             assert((m1 | m2) == m1);        // [A2] (no elevation of access)
 212             return l2;
 213         }
 214 
 215         @Override
 216         public String toString() {
 217             String s = lookupClass().getSimpleName();
 218             String lstr = lookupString();
 219             int sl = lstr.indexOf('/');
 220             if (sl >= 0)  s += lstr.substring(sl);
 221             ClassLoader cld = lookupClass().getClassLoader();
 222             if (cld != THIS_LOADER)  s += "/loader#"+numberOf(cld);
 223             return s;
 224         }
 225 
 226         /** Predict the success or failure of accessing this method. */
 227         public boolean willAccess(Method m) {
 228             Class<?> c1 = lookupClass();
 229             Class<?> c2 = m.getDeclaringClass();
 230 
 231             // if the lookup class is in a loose module with PUBLIC access then
 232             // public members of public types in all unnamed modules can be accessed
 233             if (isLooseModule(c1.getModule())
 234                 && (lookupModes & PUBLIC) != 0
 235                 && (!c2.getModule().isNamed())
 236                 && Modifier.isPublic(c2.getModifiers())
 237                 && Modifier.isPublic(m.getModifiers()))
 238                 return true;
 239 
 240             LookupCase lc = this.in(c2);
 241             int m1 = lc.lookupModes();
 242             int m2 = fixMods(m.getModifiers());
 243             // privacy is strictly enforced on lookups
 244             if (c1 != c2)  m1 &= ~PRIVATE;
 245             // protected access is sometimes allowed
 246             if ((m2 & PROTECTED) != 0) {
 247                 int prev = m2;
 248                 m2 |= PACKAGE;  // it acts like a package method also
 249                 if ((lookupModes() & PROTECTED) != 0 &&
 250                     c2.isAssignableFrom(c1))
 251                     m2 |= PUBLIC;  // from a subclass, it acts like a public method also
 252             }
 253             if (verbosity >= 2)
 254                 System.out.println(this+" willAccess "+lc+" m1="+m1+" m2="+m2+" => "+((m2 & m1) != 0));
 255             return (m2 & m1) != 0;
 256         }
 257 
 258         /** Predict the success or failure of accessing this class. */
 259         public boolean willAccessClass(Class<?> c2, boolean load) {
 260             Class<?> c1 = lookupClass();
 261             if (load && c2.getClassLoader() != null) {
 262                 if (c1.getClassLoader() == null) {
 263                     // not visible
 264                 return false;
 265             }
 266                 if (c1 == publicLookup().lookupClass()) {
 267                     // not visible as lookup class is defined by child of the boot loader
 268                     return false;
 269                 }
 270             }
 271 
 272             // if the lookup class is in a loose module with PUBLIC access then
 273             // public types in all unnamed modules can be accessed
 274             if (isLooseModule(c1.getModule())
 275                 && (lookupModes & PUBLIC) != 0
 276                 && (!c2.getModule().isNamed())
 277                 && Modifier.isPublic(c2.getModifiers()))
 278                 return true;
 279 
 280             LookupCase lc = this.in(c2);
 281             int m1 = lc.lookupModes();
 282             boolean r = false;
 283             if (m1 == 0) {
 284                 r = false;
 285             } else {
 286                 int m2 = fixMods(c2.getModifiers());
 287                 if ((m2 & PUBLIC) != 0) {
 288                     r = true;
 289                 } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
 290                     r = true;
 291                 }
 292             }
 293             if (verbosity >= 2) {
 294                 System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
 295             }
 296             return r;
 297         }
 298 
 299         private boolean isLooseModule(Module m) {
 300             ClassLoader cl = new ClassLoader() { };
 301             return m.canRead(cl.getUnnamedModule());
 302         }
 303     }
 304 
 305     private static Class<?> topLevelClass(Class<?> cls) {
 306         Class<?> c = cls;
 307         for (Class<?> ec; (ec = c.getEnclosingClass()) != null; )
 308             c = ec;
 309         assert(c.getEnclosingClass() == null);
 310         assert(c == cls || cls.getEnclosingClass() != null);
 311         return c;
 312     }
 313 
 314     private static String packagePrefix(Class<?> c) {
 315         while (c.isArray())  c = c.getComponentType();
 316         String s = c.getName();
 317         assert(s.indexOf('/') < 0);
 318         return s.substring(0, s.lastIndexOf('.')+1);
 319     }
 320 
 321 
 322     private final TreeSet<LookupCase> CASES = new TreeSet<>();
 323     private final TreeMap<LookupCase,TreeSet<LookupCase>> CASE_EDGES = new TreeMap<>();
 324     private final ArrayList<ClassLoader> LOADERS = new ArrayList<>();
 325     private final ClassLoader THIS_LOADER = this.getClass().getClassLoader();
 326     { if (THIS_LOADER != null)  LOADERS.add(THIS_LOADER); }  // #1
 327 
 328     private LookupCase lookupCase(String name) {
 329         for (LookupCase lc : CASES) {
 330             if (lc.toString().equals(name))
 331                 return lc;
 332         }
 333         throw new AssertionError(name);
 334     }
 335 
 336     private int numberOf(ClassLoader cl) {
 337         if (cl == null)  return 0;
 338         int i = LOADERS.indexOf(cl);
 339         if (i < 0) {
 340             i = LOADERS.size();
 341             LOADERS.add(cl);


   1 /*
   2  * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */


 101             return (that instanceof LookupCase && equals((LookupCase)that));
 102         }
 103         public boolean equals(LookupCase that) {
 104             return (this.lookupClass() == that.lookupClass() &&
 105                     this.lookupModes() == that.lookupModes());
 106         }
 107 
 108         @Override
 109         public int hashCode() {
 110             return lookupClass().hashCode() + (lookupModes() * 31);
 111         }
 112 
 113         /** Simulate all assertions in the spec. for Lookup.toString. */
 114         private String lookupString() {
 115             String name = lookupClass.getName();
 116             String suffix = "";
 117             if (lookupModes == 0)
 118                 suffix = "/noaccess";
 119             else if (lookupModes == PUBLIC)
 120                 suffix = "/public";
 121              else if (lookupModes == (PUBLIC|UNCONDITIONAL))
 122                 suffix = "/publicLookup";
 123             else if (lookupModes == (PUBLIC|MODULE))
 124                 suffix = "/module";
 125             else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
 126                 suffix = "/package";
 127             else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE))
 128                 suffix = "/private";
 129             else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED))
 130                 suffix = "";
 131             else
 132                 suffix = "/#"+Integer.toHexString(lookupModes);
 133             return name+suffix;
 134         }
 135 
 136         /** Simulate all assertions from the spec. for Lookup.in:
 137          * <hr>
 138          * Creates a lookup on the specified new lookup class.
 139          * [A1] The resulting object will report the specified
 140          * class as its own {@link #lookupClass lookupClass}.
 141          * <p>
 142          * [A2] However, the resulting {@code Lookup} object is guaranteed
 143          * to have no more access capabilities than the original.
 144          * In particular, access capabilities can be lost as follows:<ul>
 145          * <li> [A3] If the old lookup class is in a named module, and the new
 146          * lookup class is in a different module {@code M}, then no members, not
 147          * even public members in {@code M}'s exported packages, will be accessible.
 148          * The exception to this is when this lookup is publicLookup, in which case
 149          * public access is not lost.
 150          * <li> [A4] If the old lookup class is in an unnamed module, and the new
 151          * lookup class is a different module then module access is lost.
 152          * <li> [A5] If the new lookup class differs from the old one then UNCONDITIONAL
 153          * is lost. If the new lookup class is not within the same package member as the
 154          * old one, protected members will not be accessible by virtue of inheritance.
 155          * (Protected members may continue to be accessible because of package sharing.)
 156          * <li> [A6] If the new lookup class is in a different package than the old one,
 157          * protected and default (package) members will not be accessible.
 158          * <li> [A7] If the new lookup class is not within the same package member
 159          * as the old one, private members will not be accessible.
 160          * <li> [A8] If the new lookup class is not accessible to the old lookup class,

 161          * then no members, not even public members, will be accessible.
 162          * <li> [A9] (In all other cases, public members will continue to be accessible.)






 163          * </ul>
 164          * Other than the above cases, the new lookup will have the same
 165          * access capabilities as the original. [A10]
 166          * <hr>
 167          */
 168         public LookupCase in(Class<?> c2) {
 169             Class<?> c1 = lookupClass();
 170             int m1 = lookupModes();
 171             int changed = 0;
 172             // for the purposes of access control then treat classes in different unnamed
 173             // modules as being in the same module.
 174             boolean sameModule = (c1.getModule() == c2.getModule()) ||
 175                                  (!c1.getModule().isNamed() && !c2.getModule().isNamed());
 176             boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
 177                                    c1.getPackageName().equals(c2.getPackageName()));
 178             boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
 179             boolean sameClass = (c1 == c2);
 180             assert(samePackage  || !sameTopLevel);
 181             assert(sameTopLevel || !sameClass);
 182             boolean accessible = sameClass;
 183             if ((m1 & PACKAGE) != 0)  accessible |= samePackage;
 184             if ((m1 & PUBLIC ) != 0)  accessible |= (c2.getModifiers() & PUBLIC) != 0;
 185             if (!sameModule) {
 186                 if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) {
 187                     accessible = false;  // [A3]
 188                 } else {
 189                     changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED);    // [A3] [A4]

 190                 }
 191             }
 192             if (!accessible) {
 193                 // Different package and no access to c2; lose all access.
 194                 changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A8]
 195             }
 196             if (!samePackage) {
 197                 // Different package; loose PACKAGE and lower access.
 198                 changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A6]
 199             }
 200             if (!sameTopLevel) {
 201                 // Different top-level class.  Lose PRIVATE and PROTECTED access.
 202                 changed |= (PRIVATE|PROTECTED);  // [A5] [A7]
 203             }
 204             if (!sameClass) {
 205                 changed |= (UNCONDITIONAL);     // [A5]
 206             } else {
 207                 assert(changed == 0);       // [A10] (no deprivation if same class)
 208             }
 209             if (accessible)  assert((changed & PUBLIC) == 0);  // [A9]
 210             int m2 = m1 & ~changed;
 211             LookupCase l2 = new LookupCase(c2, m2);
 212             assert(l2.lookupClass() == c2); // [A1]
 213             assert((m1 | m2) == m1);        // [A2] (no elevation of access)
 214             return l2;
 215         }
 216 
 217         @Override
 218         public String toString() {
 219             String s = lookupClass().getSimpleName();
 220             String lstr = lookupString();
 221             int sl = lstr.indexOf('/');
 222             if (sl >= 0)  s += lstr.substring(sl);
 223             ClassLoader cld = lookupClass().getClassLoader();
 224             if (cld != THIS_LOADER)  s += "/loader#"+numberOf(cld);
 225             return s;
 226         }
 227 
 228         /** Predict the success or failure of accessing this method. */
 229         public boolean willAccess(Method m) {
 230             Class<?> c1 = lookupClass();
 231             Class<?> c2 = m.getDeclaringClass();
 232 
 233             // publicLookup has access to all public types/members of types in unnamed modules
 234             if ((lookupModes & UNCONDITIONAL) != 0

 235                 && (lookupModes & PUBLIC) != 0
 236                 && !c2.getModule().isNamed()
 237                 && Modifier.isPublic(c2.getModifiers())
 238                 && Modifier.isPublic(m.getModifiers()))
 239                 return true;
 240 
 241             LookupCase lc = this.in(c2);
 242             int m1 = lc.lookupModes();
 243             int m2 = fixMods(m.getModifiers());
 244             // privacy is strictly enforced on lookups
 245             if (c1 != c2)  m1 &= ~PRIVATE;
 246             // protected access is sometimes allowed
 247             if ((m2 & PROTECTED) != 0) {
 248                 int prev = m2;
 249                 m2 |= PACKAGE;  // it acts like a package method also
 250                 if ((lookupModes() & PROTECTED) != 0 &&
 251                     c2.isAssignableFrom(c1))
 252                     m2 |= PUBLIC;  // from a subclass, it acts like a public method also
 253             }
 254             if (verbosity >= 2)
 255                 System.out.println(this+" willAccess "+lc+" m1="+m1+" m2="+m2+" => "+((m2 & m1) != 0));
 256             return (m2 & m1) != 0;
 257         }
 258 
 259         /** Predict the success or failure of accessing this class. */
 260         public boolean willAccessClass(Class<?> c2, boolean load) {
 261             Class<?> c1 = lookupClass();
 262             if (load && c2.getClassLoader() != null) {
 263                 if (c1.getClassLoader() == null) {
 264                     // not visible
 265                     return false;
 266                 }




 267             }
 268 
 269             // publicLookup has access to all public types/members of types in unnamed modules
 270             if ((lookupModes & UNCONDITIONAL) != 0

 271                 && (lookupModes & PUBLIC) != 0
 272                 && (!c2.getModule().isNamed())
 273                 && Modifier.isPublic(c2.getModifiers()))
 274                 return true;
 275 
 276             LookupCase lc = this.in(c2);
 277             int m1 = lc.lookupModes();
 278             boolean r = false;
 279             if (m1 == 0) {
 280                 r = false;
 281             } else {
 282                 int m2 = fixMods(c2.getModifiers());
 283                 if ((m2 & PUBLIC) != 0) {
 284                     r = true;
 285                 } else if ((m1 & PACKAGE) != 0 && c1.getPackage() == c2.getPackage()) {
 286                     r = true;
 287                 }
 288             }
 289             if (verbosity >= 2) {
 290                 System.out.println(this+" willAccessClass "+lc+" c1="+c1+" c2="+c2+" => "+r);
 291             }
 292             return r;
 293         }





 294     }
 295 
 296     private static Class<?> topLevelClass(Class<?> cls) {
 297         Class<?> c = cls;
 298         for (Class<?> ec; (ec = c.getEnclosingClass()) != null; )
 299             c = ec;
 300         assert(c.getEnclosingClass() == null);
 301         assert(c == cls || cls.getEnclosingClass() != null);
 302         return c;
 303     }
 304 








 305     private final TreeSet<LookupCase> CASES = new TreeSet<>();
 306     private final TreeMap<LookupCase,TreeSet<LookupCase>> CASE_EDGES = new TreeMap<>();
 307     private final ArrayList<ClassLoader> LOADERS = new ArrayList<>();
 308     private final ClassLoader THIS_LOADER = this.getClass().getClassLoader();
 309     { if (THIS_LOADER != null)  LOADERS.add(THIS_LOADER); }  // #1
 310 
 311     private LookupCase lookupCase(String name) {
 312         for (LookupCase lc : CASES) {
 313             if (lc.toString().equals(name))
 314                 return lc;
 315         }
 316         throw new AssertionError(name);
 317     }
 318 
 319     private int numberOf(ClassLoader cl) {
 320         if (cl == null)  return 0;
 321         int i = LOADERS.indexOf(cl);
 322         if (i < 0) {
 323             i = LOADERS.size();
 324             LOADERS.add(cl);


< prev index next >