Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/security/BasicPermission.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.Map;29import java.util.HashMap;30import java.util.Hashtable;31import java.util.Collections;32import java.io.ObjectStreamField;33import java.io.ObjectOutputStream;34import java.io.ObjectInputStream;35import java.io.IOException;3637/**38* The BasicPermission class extends the Permission class, and39* can be used as the base class for permissions that want to40* follow the same naming convention as BasicPermission.41* <P>42* The name for a BasicPermission is the name of the given permission43* (for example, "exit",44* "setFactory", "print.queueJob", etc). The naming45* convention follows the hierarchical property naming convention.46* An asterisk may appear by itself, or if immediately preceded by a "."47* may appear at the end of the name, to signify a wildcard match.48* For example, "*" and "java.*" signify a wildcard match, while "*java", "a*b",49* and "java*" do not.50* <P>51* The action string (inherited from Permission) is unused.52* Thus, BasicPermission is commonly used as the base class for53* "named" permissions54* (ones that contain a name but no actions list; you either have the55* named permission or you don't.)56* Subclasses may implement actions on top of BasicPermission,57* if desired.58* <p>59* @see java.security.Permission60* @see java.security.Permissions61* @see java.security.PermissionCollection62* @see java.lang.SecurityManager63*64* @author Marianne Mueller65* @author Roland Schemers66*/6768public abstract class BasicPermission extends Permission69implements java.io.Serializable70{7172private static final long serialVersionUID = 6279438298436773498L;7374// does this permission have a wildcard at the end?75private transient boolean wildcard;7677// the name without the wildcard on the end78private transient String path;7980// is this permission the old-style exitVM permission (pre JDK 1.6)?81private transient boolean exitVM;8283/**84* initialize a BasicPermission object. Common to all constructors.85*/86private void init(String name) {87if (name == null)88throw new NullPointerException("name can't be null");8990int len = name.length();9192if (len == 0) {93throw new IllegalArgumentException("name can't be empty");94}9596char last = name.charAt(len - 1);9798// Is wildcard or ends with ".*"?99if (last == '*' && (len == 1 || name.charAt(len - 2) == '.')) {100wildcard = true;101if (len == 1) {102path = "";103} else {104path = name.substring(0, len - 1);105}106} else {107if (name.equals("exitVM")) {108wildcard = true;109path = "exitVM.";110exitVM = true;111} else {112path = name;113}114}115}116117/**118* Creates a new BasicPermission with the specified name.119* Name is the symbolic name of the permission, such as120* "setFactory",121* "print.queueJob", or "topLevelWindow", etc.122*123* @param name the name of the BasicPermission.124*125* @throws NullPointerException if {@code name} is {@code null}.126* @throws IllegalArgumentException if {@code name} is empty.127*/128public BasicPermission(String name) {129super(name);130init(name);131}132133134/**135* Creates a new BasicPermission object with the specified name.136* The name is the symbolic name of the BasicPermission, and the137* actions String is currently unused.138*139* @param name the name of the BasicPermission.140* @param actions ignored.141*142* @throws NullPointerException if {@code name} is {@code null}.143* @throws IllegalArgumentException if {@code name} is empty.144*/145public BasicPermission(String name, String actions) {146super(name);147init(name);148}149150/**151* Checks if the specified permission is "implied" by152* this object.153* <P>154* More specifically, this method returns true if:155* <ul>156* <li> <i>p</i>'s class is the same as this object's class, and157* <li> <i>p</i>'s name equals or (in the case of wildcards)158* is implied by this object's159* name. For example, "a.b.*" implies "a.b.c".160* </ul>161*162* @param p the permission to check against.163*164* @return true if the passed permission is equal to or165* implied by this permission, false otherwise.166*/167public boolean implies(Permission p) {168if ((p == null) || (p.getClass() != getClass()))169return false;170171BasicPermission that = (BasicPermission) p;172173if (this.wildcard) {174if (that.wildcard) {175// one wildcard can imply another176return that.path.startsWith(path);177} else {178// make sure ap.path is longer so a.b.* doesn't imply a.b179return (that.path.length() > this.path.length()) &&180that.path.startsWith(this.path);181}182} else {183if (that.wildcard) {184// a non-wildcard can't imply a wildcard185return false;186}187else {188return this.path.equals(that.path);189}190}191}192193/**194* Checks two BasicPermission objects for equality.195* Checks that <i>obj</i>'s class is the same as this object's class196* and has the same name as this object.197* <P>198* @param obj the object we are testing for equality with this object.199* @return true if <i>obj</i>'s class is the same as this object's class200* and has the same name as this BasicPermission object, false otherwise.201*/202public boolean equals(Object obj) {203if (obj == this)204return true;205206if ((obj == null) || (obj.getClass() != getClass()))207return false;208209BasicPermission bp = (BasicPermission) obj;210211return getName().equals(bp.getName());212}213214215/**216* Returns the hash code value for this object.217* The hash code used is the hash code of the name, that is,218* {@code getName().hashCode()}, where {@code getName} is219* from the Permission superclass.220*221* @return a hash code value for this object.222*/223public int hashCode() {224return this.getName().hashCode();225}226227/**228* Returns the canonical string representation of the actions,229* which currently is the empty string "", since there are no actions for230* a BasicPermission.231*232* @return the empty string "".233*/234public String getActions() {235return "";236}237238/**239* Returns a new PermissionCollection object for storing BasicPermission240* objects.241*242* <p>BasicPermission objects must be stored in a manner that allows them243* to be inserted in any order, but that also enables the244* PermissionCollection {@code implies} method245* to be implemented in an efficient (and consistent) manner.246*247* @return a new PermissionCollection object suitable for248* storing BasicPermissions.249*/250public PermissionCollection newPermissionCollection() {251return new BasicPermissionCollection(this.getClass());252}253254/**255* readObject is called to restore the state of the BasicPermission from256* a stream.257*/258private void readObject(ObjectInputStream s)259throws IOException, ClassNotFoundException260{261s.defaultReadObject();262// init is called to initialize the rest of the values.263init(getName());264}265266/**267* Returns the canonical name of this BasicPermission.268* All internal invocations of getName should invoke this method, so269* that the pre-JDK 1.6 "exitVM" and current "exitVM.*" permission are270* equivalent in equals/hashCode methods.271*272* @return the canonical name of this BasicPermission.273*/274final String getCanonicalName() {275return exitVM ? "exitVM.*" : getName();276}277}278279/**280* A BasicPermissionCollection stores a collection281* of BasicPermission permissions. BasicPermission objects282* must be stored in a manner that allows them to be inserted in any283* order, but enable the implies function to evaluate the implies284* method in an efficient (and consistent) manner.285*286* A BasicPermissionCollection handles comparing a permission like "a.b.c.d.e"287* with a Permission such as "a.b.*", or "*".288*289* @see java.security.Permission290* @see java.security.Permissions291*292*293* @author Roland Schemers294*295* @serial include296*/297298final class BasicPermissionCollection299extends PermissionCollection300implements java.io.Serializable301{302303private static final long serialVersionUID = 739301742472979399L;304305/**306* Key is name, value is permission. All permission objects in307* collection must be of the same type.308* Not serialized; see serialization section at end of class.309*/310private transient Map<String, Permission> perms;311312/**313* This is set to {@code true} if this BasicPermissionCollection314* contains a BasicPermission with '*' as its permission name.315*316* @see #serialPersistentFields317*/318private boolean all_allowed;319320/**321* The class to which all BasicPermissions in this322* BasicPermissionCollection belongs.323*324* @see #serialPersistentFields325*/326private Class<?> permClass;327328/**329* Create an empty BasicPermissionCollection object.330*331*/332333public BasicPermissionCollection(Class<?> clazz) {334perms = new HashMap<String, Permission>(11);335all_allowed = false;336permClass = clazz;337}338339/**340* Adds a permission to the BasicPermissions. The key for the hash is341* permission.path.342*343* @param permission the Permission object to add.344*345* @exception IllegalArgumentException - if the permission is not a346* BasicPermission, or if347* the permission is not of the348* same Class as the other349* permissions in this collection.350*351* @exception SecurityException - if this BasicPermissionCollection object352* has been marked readonly353*/354public void add(Permission permission) {355if (! (permission instanceof BasicPermission))356throw new IllegalArgumentException("invalid permission: "+357permission);358if (isReadOnly())359throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");360361BasicPermission bp = (BasicPermission) permission;362363// make sure we only add new BasicPermissions of the same class364// Also check null for compatibility with deserialized form from365// previous versions.366if (permClass == null) {367// adding first permission368permClass = bp.getClass();369} else {370if (bp.getClass() != permClass)371throw new IllegalArgumentException("invalid permission: " +372permission);373}374375synchronized (this) {376perms.put(bp.getCanonicalName(), permission);377}378379// No sync on all_allowed; staleness OK380if (!all_allowed) {381if (bp.getCanonicalName().equals("*"))382all_allowed = true;383}384}385386/**387* Check and see if this set of permissions implies the permissions388* expressed in "permission".389*390* @param permission the Permission object to compare391*392* @return true if "permission" is a proper subset of a permission in393* the set, false if not.394*/395public boolean implies(Permission permission) {396if (! (permission instanceof BasicPermission))397return false;398399BasicPermission bp = (BasicPermission) permission;400401// random subclasses of BasicPermission do not imply each other402if (bp.getClass() != permClass)403return false;404405// short circuit if the "*" Permission was added406if (all_allowed)407return true;408409// strategy:410// Check for full match first. Then work our way up the411// path looking for matches on a.b..*412413String path = bp.getCanonicalName();414//System.out.println("check "+path);415416Permission x;417418synchronized (this) {419x = perms.get(path);420}421422if (x != null) {423// we have a direct hit!424return x.implies(permission);425}426427// work our way up the tree...428int last, offset;429430offset = path.length()-1;431432while ((last = path.lastIndexOf(".", offset)) != -1) {433434path = path.substring(0, last+1) + "*";435//System.out.println("check "+path);436437synchronized (this) {438x = perms.get(path);439}440441if (x != null) {442return x.implies(permission);443}444offset = last -1;445}446447// we don't have to check for "*" as it was already checked448// at the top (all_allowed), so we just return false449return false;450}451452/**453* Returns an enumeration of all the BasicPermission objects in the454* container.455*456* @return an enumeration of all the BasicPermission objects.457*/458public Enumeration<Permission> elements() {459// Convert Iterator of Map values into an Enumeration460synchronized (this) {461return Collections.enumeration(perms.values());462}463}464465// Need to maintain serialization interoperability with earlier releases,466// which had the serializable field:467//468// @serial the Hashtable is indexed by the BasicPermission name469//470// private Hashtable permissions;471/**472* @serialField permissions java.util.Hashtable473* The BasicPermissions in this BasicPermissionCollection.474* All BasicPermissions in the collection must belong to the same class.475* The Hashtable is indexed by the BasicPermission name; the value476* of the Hashtable entry is the permission.477* @serialField all_allowed boolean478* This is set to {@code true} if this BasicPermissionCollection479* contains a BasicPermission with '*' as its permission name.480* @serialField permClass java.lang.Class481* The class to which all BasicPermissions in this482* BasicPermissionCollection belongs.483*/484private static final ObjectStreamField[] serialPersistentFields = {485new ObjectStreamField("permissions", Hashtable.class),486new ObjectStreamField("all_allowed", Boolean.TYPE),487new ObjectStreamField("permClass", Class.class),488};489490/**491* @serialData Default fields.492*/493/*494* Writes the contents of the perms field out as a Hashtable for495* serialization compatibility with earlier releases. all_allowed496* and permClass unchanged.497*/498private void writeObject(ObjectOutputStream out) throws IOException {499// Don't call out.defaultWriteObject()500501// Copy perms into a Hashtable502Hashtable<String, Permission> permissions =503new Hashtable<>(perms.size()*2);504505synchronized (this) {506permissions.putAll(perms);507}508509// Write out serializable fields510ObjectOutputStream.PutField pfields = out.putFields();511pfields.put("all_allowed", all_allowed);512pfields.put("permissions", permissions);513pfields.put("permClass", permClass);514out.writeFields();515}516517/**518* readObject is called to restore the state of the519* BasicPermissionCollection from a stream.520*/521private void readObject(java.io.ObjectInputStream in)522throws IOException, ClassNotFoundException523{524// Don't call defaultReadObject()525526// Read in serialized fields527ObjectInputStream.GetField gfields = in.readFields();528529// Get permissions530// writeObject writes a Hashtable<String, Permission> for the531// permissions key, so this cast is safe, unless the data is corrupt.532@SuppressWarnings("unchecked")533Hashtable<String, Permission> permissions =534(Hashtable<String, Permission>)gfields.get("permissions", null);535perms = new HashMap<String, Permission>(permissions.size()*2);536perms.putAll(permissions);537538// Get all_allowed539all_allowed = gfields.get("all_allowed", false);540541// Get permClass542permClass = (Class<?>) gfields.get("permClass", null);543544if (permClass == null) {545// set permClass546Enumeration<Permission> e = permissions.elements();547if (e.hasMoreElements()) {548Permission p = e.nextElement();549permClass = p.getClass();550}551}552}553}554555556