Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/security/Permissions.java
38829 views
/*1* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.security;2627import java.util.Enumeration;28import java.util.Hashtable;29import java.util.NoSuchElementException;30import java.util.Map;31import java.util.HashMap;32import java.util.List;33import java.util.Iterator;34import java.util.Collections;35import java.io.Serializable;36import java.io.ObjectStreamField;37import java.io.ObjectOutputStream;38import java.io.ObjectInputStream;39import java.io.IOException;404142/**43* This class represents a heterogeneous collection of Permissions. That is,44* it contains different types of Permission objects, organized into45* PermissionCollections. For example, if any46* {@code java.io.FilePermission} objects are added to an instance of47* this class, they are all stored in a single48* PermissionCollection. It is the PermissionCollection returned by a call to49* the {@code newPermissionCollection} method in the FilePermission class.50* Similarly, any {@code java.lang.RuntimePermission} objects are51* stored in the PermissionCollection returned by a call to the52* {@code newPermissionCollection} method in the53* RuntimePermission class. Thus, this class represents a collection of54* PermissionCollections.55*56* <p>When the {@code add} method is called to add a Permission, the57* Permission is stored in the appropriate PermissionCollection. If no such58* collection exists yet, the Permission object's class is determined and the59* {@code newPermissionCollection} method is called on that class to create60* the PermissionCollection and add it to the Permissions object. If61* {@code newPermissionCollection} returns null, then a default62* PermissionCollection that uses a hashtable will be created and used. Each63* hashtable entry stores a Permission object as both the key and the value.64*65* <p> Enumerations returned via the {@code elements} method are66* not <em>fail-fast</em>. Modifications to a collection should not be67* performed while enumerating over that collection.68*69* @see Permission70* @see PermissionCollection71* @see AllPermission72*73*74* @author Marianne Mueller75* @author Roland Schemers76*77* @serial exclude78*/7980public final class Permissions extends PermissionCollection81implements Serializable82{83/**84* Key is permissions Class, value is PermissionCollection for that class.85* Not serialized; see serialization section at end of class.86*/87private transient Map<Class<?>, PermissionCollection> permsMap;8889// optimization. keep track of whether unresolved permissions need to be90// checked91private transient boolean hasUnresolved = false;9293// optimization. keep track of the AllPermission collection94// - package private for ProtectionDomain optimization95PermissionCollection allPermission;9697/**98* Creates a new Permissions object containing no PermissionCollections.99*/100public Permissions() {101permsMap = new HashMap<Class<?>, PermissionCollection>(11);102allPermission = null;103}104105/**106* Adds a permission object to the PermissionCollection for the class the107* permission belongs to. For example, if <i>permission</i> is a108* FilePermission, it is added to the FilePermissionCollection stored109* in this Permissions object.110*111* This method creates112* a new PermissionCollection object (and adds the permission to it)113* if an appropriate collection does not yet exist. <p>114*115* @param permission the Permission object to add.116*117* @exception SecurityException if this Permissions object is118* marked as readonly.119*120* @see PermissionCollection#isReadOnly()121*/122123public void add(Permission permission) {124if (isReadOnly())125throw new SecurityException(126"attempt to add a Permission to a readonly Permissions object");127128PermissionCollection pc;129130synchronized (this) {131pc = getPermissionCollection(permission, true);132pc.add(permission);133}134135// No sync; staleness -> optimizations delayed, which is OK136if (permission instanceof AllPermission) {137allPermission = pc;138}139if (permission instanceof UnresolvedPermission) {140hasUnresolved = true;141}142}143144/**145* Checks to see if this object's PermissionCollection for permissions of146* the specified permission's class implies the permissions147* expressed in the <i>permission</i> object. Returns true if the148* combination of permissions in the appropriate PermissionCollection149* (e.g., a FilePermissionCollection for a FilePermission) together150* imply the specified permission.151*152* <p>For example, suppose there is a FilePermissionCollection in this153* Permissions object, and it contains one FilePermission that specifies154* "read" access for all files in all subdirectories of the "/tmp"155* directory, and another FilePermission that specifies "write" access156* for all files in the "/tmp/scratch/foo" directory.157* Then if the {@code implies} method158* is called with a permission specifying both "read" and "write" access159* to files in the "/tmp/scratch/foo" directory, {@code true} is160* returned.161*162* <p>Additionally, if this PermissionCollection contains the163* AllPermission, this method will always return true.164* <p>165* @param permission the Permission object to check.166*167* @return true if "permission" is implied by the permissions in the168* PermissionCollection it169* belongs to, false if not.170*/171172public boolean implies(Permission permission) {173// No sync; staleness -> skip optimization, which is OK174if (allPermission != null) {175return true; // AllPermission has already been added176} else {177synchronized (this) {178PermissionCollection pc = getPermissionCollection(permission,179false);180if (pc != null) {181return pc.implies(permission);182} else {183// none found184return false;185}186}187}188}189190/**191* Returns an enumeration of all the Permission objects in all the192* PermissionCollections in this Permissions object.193*194* @return an enumeration of all the Permissions.195*/196197public Enumeration<Permission> elements() {198// go through each Permissions in the hash table199// and call their elements() function.200201synchronized (this) {202return new PermissionsEnumerator(permsMap.values().iterator());203}204}205206/**207* Gets the PermissionCollection in this Permissions object for208* permissions whose type is the same as that of <i>p</i>.209* For example, if <i>p</i> is a FilePermission,210* the FilePermissionCollection211* stored in this Permissions object will be returned.212*213* If createEmpty is true,214* this method creates a new PermissionCollection object for the specified215* type of permission objects if one does not yet exist.216* To do so, it first calls the {@code newPermissionCollection} method217* on <i>p</i>. Subclasses of class Permission218* override that method if they need to store their permissions in a219* particular PermissionCollection object in order to provide the220* correct semantics when the {@code PermissionCollection.implies}221* method is called.222* If the call returns a PermissionCollection, that collection is stored223* in this Permissions object. If the call returns null and createEmpty224* is true, then225* this method instantiates and stores a default PermissionCollection226* that uses a hashtable to store its permission objects.227*228* createEmpty is ignored when creating empty PermissionCollection229* for unresolved permissions because of the overhead of determining the230* PermissionCollection to use.231*232* createEmpty should be set to false when this method is invoked from233* implies() because it incurs the additional overhead of creating and234* adding an empty PermissionCollection that will just return false.235* It should be set to true when invoked from add().236*/237private PermissionCollection getPermissionCollection(Permission p,238boolean createEmpty) {239Class<?> c = p.getClass();240241PermissionCollection pc = permsMap.get(c);242243if (!hasUnresolved && !createEmpty) {244return pc;245} else if (pc == null) {246247// Check for unresolved permissions248pc = (hasUnresolved ? getUnresolvedPermissions(p) : null);249250// if still null, create a new collection251if (pc == null && createEmpty) {252253pc = p.newPermissionCollection();254255// still no PermissionCollection?256// We'll give them a PermissionsHash.257if (pc == null)258pc = new PermissionsHash();259}260261if (pc != null) {262permsMap.put(c, pc);263}264}265return pc;266}267268/**269* Resolves any unresolved permissions of type p.270*271* @param p the type of unresolved permission to resolve272*273* @return PermissionCollection containing the unresolved permissions,274* or null if there were no unresolved permissions of type p.275*276*/277private PermissionCollection getUnresolvedPermissions(Permission p)278{279// Called from within synchronized method so permsMap doesn't need lock280281UnresolvedPermissionCollection uc =282(UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);283284// we have no unresolved permissions if uc is null285if (uc == null)286return null;287288List<UnresolvedPermission> unresolvedPerms =289uc.getUnresolvedPermissions(p);290291// we have no unresolved permissions of this type if unresolvedPerms is null292if (unresolvedPerms == null)293return null;294295java.security.cert.Certificate certs[] = null;296297Object signers[] = p.getClass().getSigners();298299int n = 0;300if (signers != null) {301for (int j=0; j < signers.length; j++) {302if (signers[j] instanceof java.security.cert.Certificate) {303n++;304}305}306certs = new java.security.cert.Certificate[n];307n = 0;308for (int j=0; j < signers.length; j++) {309if (signers[j] instanceof java.security.cert.Certificate) {310certs[n++] = (java.security.cert.Certificate)signers[j];311}312}313}314315PermissionCollection pc = null;316synchronized (unresolvedPerms) {317int len = unresolvedPerms.size();318for (int i = 0; i < len; i++) {319UnresolvedPermission up = unresolvedPerms.get(i);320Permission perm = up.resolve(p, certs);321if (perm != null) {322if (pc == null) {323pc = p.newPermissionCollection();324if (pc == null)325pc = new PermissionsHash();326}327pc.add(perm);328}329}330}331return pc;332}333334private static final long serialVersionUID = 4858622370623524688L;335336// Need to maintain serialization interoperability with earlier releases,337// which had the serializable field:338// private Hashtable perms;339340/**341* @serialField perms java.util.Hashtable342* A table of the Permission classes and PermissionCollections.343* @serialField allPermission java.security.PermissionCollection344*/345private static final ObjectStreamField[] serialPersistentFields = {346new ObjectStreamField("perms", Hashtable.class),347new ObjectStreamField("allPermission", PermissionCollection.class),348};349350/**351* @serialData Default fields.352*/353/*354* Writes the contents of the permsMap field out as a Hashtable for355* serialization compatibility with earlier releases. allPermission356* unchanged.357*/358private void writeObject(ObjectOutputStream out) throws IOException {359// Don't call out.defaultWriteObject()360361// Copy perms into a Hashtable362Hashtable<Class<?>, PermissionCollection> perms =363new Hashtable<>(permsMap.size()*2); // no sync; estimate364synchronized (this) {365perms.putAll(permsMap);366}367368// Write out serializable fields369ObjectOutputStream.PutField pfields = out.putFields();370371pfields.put("allPermission", allPermission); // no sync; staleness OK372pfields.put("perms", perms);373out.writeFields();374}375376/*377* Reads in a Hashtable of Class/PermissionCollections and saves them in the378* permsMap field. Reads in allPermission.379*/380private void readObject(ObjectInputStream in) throws IOException,381ClassNotFoundException {382// Don't call defaultReadObject()383384// Read in serialized fields385ObjectInputStream.GetField gfields = in.readFields();386387// Get allPermission388allPermission = (PermissionCollection) gfields.get("allPermission", null);389390// Get permissions391// writeObject writes a Hashtable<Class<?>, PermissionCollection> for392// the perms key, so this cast is safe, unless the data is corrupt.393@SuppressWarnings("unchecked")394Hashtable<Class<?>, PermissionCollection> perms =395(Hashtable<Class<?>, PermissionCollection>)gfields.get("perms", null);396permsMap = new HashMap<Class<?>, PermissionCollection>(perms.size()*2);397permsMap.putAll(perms);398399// Set hasUnresolved400UnresolvedPermissionCollection uc =401(UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class);402hasUnresolved = (uc != null && uc.elements().hasMoreElements());403}404}405406final class PermissionsEnumerator implements Enumeration<Permission> {407408// all the perms409private Iterator<PermissionCollection> perms;410// the current set411private Enumeration<Permission> permset;412413PermissionsEnumerator(Iterator<PermissionCollection> e) {414perms = e;415permset = getNextEnumWithMore();416}417418// No need to synchronize; caller should sync on object as required419public boolean hasMoreElements() {420// if we enter with permissionimpl null, we know421// there are no more left.422423if (permset == null)424return false;425426// try to see if there are any left in the current one427428if (permset.hasMoreElements())429return true;430431// get the next one that has something in it...432permset = getNextEnumWithMore();433434// if it is null, we are done!435return (permset != null);436}437438// No need to synchronize; caller should sync on object as required439public Permission nextElement() {440441// hasMoreElements will update permset to the next permset442// with something in it...443444if (hasMoreElements()) {445return permset.nextElement();446} else {447throw new NoSuchElementException("PermissionsEnumerator");448}449450}451452private Enumeration<Permission> getNextEnumWithMore() {453while (perms.hasNext()) {454PermissionCollection pc = perms.next();455Enumeration<Permission> next =pc.elements();456if (next.hasMoreElements())457return next;458}459return null;460461}462}463464/**465* A PermissionsHash stores a homogeneous set of permissions in a hashtable.466*467* @see Permission468* @see Permissions469*470*471* @author Roland Schemers472*473* @serial include474*/475476final class PermissionsHash extends PermissionCollection477implements Serializable478{479/**480* Key and value are (same) permissions objects.481* Not serialized; see serialization section at end of class.482*/483private transient Map<Permission, Permission> permsMap;484485/**486* Create an empty PermissionsHash object.487*/488489PermissionsHash() {490permsMap = new HashMap<Permission, Permission>(11);491}492493/**494* Adds a permission to the PermissionsHash.495*496* @param permission the Permission object to add.497*/498499public void add(Permission permission) {500synchronized (this) {501permsMap.put(permission, permission);502}503}504505/**506* Check and see if this set of permissions implies the permissions507* expressed in "permission".508*509* @param permission the Permission object to compare510*511* @return true if "permission" is a proper subset of a permission in512* the set, false if not.513*/514515public boolean implies(Permission permission) {516// attempt a fast lookup and implies. If that fails517// then enumerate through all the permissions.518synchronized (this) {519Permission p = permsMap.get(permission);520521// If permission is found, then p.equals(permission)522if (p == null) {523for (Permission p_ : permsMap.values()) {524if (p_.implies(permission))525return true;526}527return false;528} else {529return true;530}531}532}533534/**535* Returns an enumeration of all the Permission objects in the container.536*537* @return an enumeration of all the Permissions.538*/539540public Enumeration<Permission> elements() {541// Convert Iterator of Map values into an Enumeration542synchronized (this) {543return Collections.enumeration(permsMap.values());544}545}546547private static final long serialVersionUID = -8491988220802933440L;548// Need to maintain serialization interoperability with earlier releases,549// which had the serializable field:550// private Hashtable perms;551/**552* @serialField perms java.util.Hashtable553* A table of the Permissions (both key and value are same).554*/555private static final ObjectStreamField[] serialPersistentFields = {556new ObjectStreamField("perms", Hashtable.class),557};558559/**560* @serialData Default fields.561*/562/*563* Writes the contents of the permsMap field out as a Hashtable for564* serialization compatibility with earlier releases.565*/566private void writeObject(ObjectOutputStream out) throws IOException {567// Don't call out.defaultWriteObject()568569// Copy perms into a Hashtable570Hashtable<Permission, Permission> perms =571new Hashtable<>(permsMap.size()*2);572synchronized (this) {573perms.putAll(permsMap);574}575576// Write out serializable fields577ObjectOutputStream.PutField pfields = out.putFields();578pfields.put("perms", perms);579out.writeFields();580}581582/*583* Reads in a Hashtable of Permission/Permission and saves them in the584* permsMap field.585*/586private void readObject(ObjectInputStream in) throws IOException,587ClassNotFoundException {588// Don't call defaultReadObject()589590// Read in serialized fields591ObjectInputStream.GetField gfields = in.readFields();592593// Get permissions594// writeObject writes a Hashtable<Class<?>, PermissionCollection> for595// the perms key, so this cast is safe, unless the data is corrupt.596@SuppressWarnings("unchecked")597Hashtable<Permission, Permission> perms =598(Hashtable<Permission, Permission>)gfields.get("perms", null);599permsMap = new HashMap<Permission, Permission>(perms.size()*2);600permsMap.putAll(perms);601}602}603604605