--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/security/BasicPermission.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The BasicPermission class extends the Permission class, and
+ * can be used as the base class for permissions that want to
+ * follow the same naming convention as BasicPermission.
+ * <P>
+ * The name for a BasicPermission is the name of the given permission
+ * (for example, "exit",
+ * "setFactory", "print.queueJob", etc). The naming
+ * convention follows the hierarchical property naming convention.
+ * An asterisk may appear by itself, or if immediately preceded by a "."
+ * may appear at the end of the name, to signify a wildcard match.
+ * For example, "*" and "java.*" signify a wildcard match, while "*java", "a*b",
+ * and "java*" do not.
+ * <P>
+ * The action string (inherited from Permission) is unused.
+ * Thus, BasicPermission is commonly used as the base class for
+ * "named" permissions
+ * (ones that contain a name but no actions list; you either have the
+ * named permission or you don't.)
+ * Subclasses may implement actions on top of BasicPermission,
+ * if desired.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.PermissionCollection
+ * @see java.lang.SecurityManager
+ *
+ * @author Marianne Mueller
+ * @author Roland Schemers
+ * @since 1.2
+ */
+
+public abstract class BasicPermission extends Permission
+ implements java.io.Serializable
+{
+
+ private static final long serialVersionUID = 6279438298436773498L;
+
+ // does this permission have a wildcard at the end?
+ private transient boolean wildcard;
+
+ // the name without the wildcard on the end
+ private transient String path;
+
+ // is this permission the old-style exitVM permission (pre JDK 1.6)?
+ private transient boolean exitVM;
+
+ /**
+ * initialize a BasicPermission object. Common to all constructors.
+ */
+ private void init(String name) {
+ if (name == null)
+ throw new NullPointerException("name can't be null");
+
+ int len = name.length();
+
+ if (len == 0) {
+ throw new IllegalArgumentException("name can't be empty");
+ }
+
+ char last = name.charAt(len - 1);
+
+ // Is wildcard or ends with ".*"?
+ if (last == '*' && (len == 1 || name.charAt(len - 2) == '.')) {
+ wildcard = true;
+ if (len == 1) {
+ path = "";
+ } else {
+ path = name.substring(0, len - 1);
+ }
+ } else {
+ if (name.equals("exitVM")) {
+ wildcard = true;
+ path = "exitVM.";
+ exitVM = true;
+ } else {
+ path = name;
+ }
+ }
+ }
+
+ /**
+ * Creates a new BasicPermission with the specified name.
+ * Name is the symbolic name of the permission, such as
+ * "setFactory",
+ * "print.queueJob", or "topLevelWindow", etc.
+ *
+ * @param name the name of the BasicPermission.
+ *
+ * @throws NullPointerException if {@code name} is {@code null}.
+ * @throws IllegalArgumentException if {@code name} is empty.
+ */
+ public BasicPermission(String name) {
+ super(name);
+ init(name);
+ }
+
+
+ /**
+ * Creates a new BasicPermission object with the specified name.
+ * The name is the symbolic name of the BasicPermission, and the
+ * actions String is currently unused.
+ *
+ * @param name the name of the BasicPermission.
+ * @param actions ignored.
+ *
+ * @throws NullPointerException if {@code name} is {@code null}.
+ * @throws IllegalArgumentException if {@code name} is empty.
+ */
+ public BasicPermission(String name, String actions) {
+ super(name);
+ init(name);
+ }
+
+ /**
+ * Checks if the specified permission is "implied" by
+ * this object.
+ * <P>
+ * More specifically, this method returns true if:
+ * <ul>
+ * <li> {@code p}'s class is the same as this object's class, and
+ * <li> {@code p}'s name equals or (in the case of wildcards)
+ * is implied by this object's
+ * name. For example, "a.b.*" implies "a.b.c".
+ * </ul>
+ *
+ * @param p the permission to check against.
+ *
+ * @return true if the passed permission is equal to or
+ * implied by this permission, false otherwise.
+ */
+ @Override
+ public boolean implies(Permission p) {
+ if ((p == null) || (p.getClass() != getClass()))
+ return false;
+
+ BasicPermission that = (BasicPermission) p;
+
+ if (this.wildcard) {
+ if (that.wildcard) {
+ // one wildcard can imply another
+ return that.path.startsWith(path);
+ } else {
+ // make sure ap.path is longer so a.b.* doesn't imply a.b
+ return (that.path.length() > this.path.length()) &&
+ that.path.startsWith(this.path);
+ }
+ } else {
+ if (that.wildcard) {
+ // a non-wildcard can't imply a wildcard
+ return false;
+ }
+ else {
+ return this.path.equals(that.path);
+ }
+ }
+ }
+
+ /**
+ * Checks two BasicPermission objects for equality.
+ * Checks that {@code obj}'s class is the same as this object's class
+ * and has the same name as this object.
+ *
+ * @param obj the object we are testing for equality with this object.
+ * @return true if {@code obj}'s class is the same as this object's class
+ * and has the same name as this BasicPermission object, false otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+
+ if ((obj == null) || (obj.getClass() != getClass()))
+ return false;
+
+ BasicPermission bp = (BasicPermission) obj;
+
+ return getName().equals(bp.getName());
+ }
+
+
+ /**
+ * Returns the hash code value for this object.
+ * The hash code used is the hash code of the name, that is,
+ * {@code getName().hashCode()}, where {@code getName} is
+ * from the Permission superclass.
+ *
+ * @return a hash code value for this object.
+ */
+ @Override
+ public int hashCode() {
+ return this.getName().hashCode();
+ }
+
+ /**
+ * Returns the canonical string representation of the actions,
+ * which currently is the empty string "", since there are no actions for
+ * a BasicPermission.
+ *
+ * @return the empty string "".
+ */
+ @Override
+ public String getActions() {
+ return "";
+ }
+
+ /**
+ * Returns a new PermissionCollection object for storing BasicPermission
+ * objects.
+ *
+ * <p>BasicPermission objects must be stored in a manner that allows them
+ * to be inserted in any order, but that also enables the
+ * PermissionCollection {@code implies} method
+ * to be implemented in an efficient (and consistent) manner.
+ *
+ * @return a new PermissionCollection object suitable for
+ * storing BasicPermissions.
+ */
+ @Override
+ public PermissionCollection newPermissionCollection() {
+ return new BasicPermissionCollection(this.getClass());
+ }
+
+ /**
+ * readObject is called to restore the state of the BasicPermission from
+ * a stream.
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ // init is called to initialize the rest of the values.
+ init(getName());
+ }
+
+ /**
+ * Returns the canonical name of this BasicPermission.
+ * All internal invocations of getName should invoke this method, so
+ * that the pre-JDK 1.6 "exitVM" and current "exitVM.*" permission are
+ * equivalent in equals/hashCode methods.
+ *
+ * @return the canonical name of this BasicPermission.
+ */
+ final String getCanonicalName() {
+ return exitVM ? "exitVM.*" : getName();
+ }
+}
+
+/**
+ * A BasicPermissionCollection stores a collection
+ * of BasicPermission permissions. BasicPermission objects
+ * must be stored in a manner that allows them to be inserted in any
+ * order, but enable the implies function to evaluate the implies
+ * method in an efficient (and consistent) manner.
+ *
+ * A BasicPermissionCollection handles comparing a permission like "a.b.c.d.e"
+ * with a Permission such as "a.b.*", or "*".
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ *
+ *
+ * @author Roland Schemers
+ *
+ * @serial include
+ */
+
+final class BasicPermissionCollection
+ extends PermissionCollection
+ implements java.io.Serializable
+{
+
+ private static final long serialVersionUID = 739301742472979399L;
+
+ /**
+ * Key is name, value is permission. All permission objects in
+ * collection must be of the same type.
+ * Not serialized; see serialization section at end of class.
+ */
+ private transient ConcurrentHashMap<String, Permission> perms;
+
+ /**
+ * This is set to {@code true} if this BasicPermissionCollection
+ * contains a BasicPermission with '*' as its permission name.
+ *
+ * @see #serialPersistentFields
+ */
+ private boolean all_allowed;
+
+ /**
+ * The class to which all BasicPermissions in this
+ * BasicPermissionCollection belong.
+ *
+ * @see #serialPersistentFields
+ */
+ private Class<?> permClass;
+
+ /**
+ * Create an empty BasicPermissionCollection object.
+ *
+ */
+ public BasicPermissionCollection(Class<?> clazz) {
+ perms = new ConcurrentHashMap<>(11);
+ all_allowed = false;
+ permClass = clazz;
+ }
+
+ /**
+ * Adds a permission to the BasicPermissions. The key for the hash is
+ * permission.path.
+ *
+ * @param permission the Permission object to add.
+ *
+ * @exception IllegalArgumentException - if the permission is not a
+ * BasicPermission, or if
+ * the permission is not of the
+ * same Class as the other
+ * permissions in this collection.
+ *
+ * @exception SecurityException - if this BasicPermissionCollection object
+ * has been marked readonly
+ */
+ @Override
+ public void add(Permission permission) {
+ if (! (permission instanceof BasicPermission))
+ throw new IllegalArgumentException("invalid permission: "+
+ permission);
+ if (isReadOnly())
+ throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");
+
+ BasicPermission bp = (BasicPermission) permission;
+
+ // make sure we only add new BasicPermissions of the same class
+ // Also check null for compatibility with deserialized form from
+ // previous versions.
+ if (permClass == null) {
+ // adding first permission
+ permClass = bp.getClass();
+ } else {
+ if (bp.getClass() != permClass)
+ throw new IllegalArgumentException("invalid permission: " +
+ permission);
+ }
+
+ String canonName = bp.getCanonicalName();
+ perms.put(canonName, permission);
+
+ // No sync on all_allowed; staleness OK
+ if (!all_allowed) {
+ if (canonName.equals("*"))
+ all_allowed = true;
+ }
+ }
+
+ /**
+ * Check and see if this set of permissions implies the permissions
+ * expressed in "permission".
+ *
+ * @param permission the Permission object to compare
+ *
+ * @return true if "permission" is a proper subset of a permission in
+ * the set, false if not.
+ */
+ @Override
+ public boolean implies(Permission permission) {
+ if (! (permission instanceof BasicPermission))
+ return false;
+
+ BasicPermission bp = (BasicPermission) permission;
+
+ // random subclasses of BasicPermission do not imply each other
+ if (bp.getClass() != permClass)
+ return false;
+
+ // short circuit if the "*" Permission was added
+ if (all_allowed)
+ return true;
+
+ // strategy:
+ // Check for full match first. Then work our way up the
+ // path looking for matches on a.b..*
+
+ String path = bp.getCanonicalName();
+ //System.out.println("check "+path);
+
+ Permission x = perms.get(path);
+
+ if (x != null) {
+ // we have a direct hit!
+ return x.implies(permission);
+ }
+
+ // work our way up the tree...
+ int last, offset;
+
+ offset = path.length()-1;
+
+ while ((last = path.lastIndexOf('.', offset)) != -1) {
+
+ path = path.substring(0, last+1) + "*";
+ //System.out.println("check "+path);
+
+ x = perms.get(path);
+
+ if (x != null) {
+ return x.implies(permission);
+ }
+ offset = last -1;
+ }
+
+ // we don't have to check for "*" as it was already checked
+ // at the top (all_allowed), so we just return false
+ return false;
+ }
+
+ /**
+ * Returns an enumeration of all the BasicPermission objects in the
+ * container.
+ *
+ * @return an enumeration of all the BasicPermission objects.
+ */
+ @Override
+ public Enumeration<Permission> elements() {
+ return perms.elements();
+ }
+
+ // Need to maintain serialization interoperability with earlier releases,
+ // which had the serializable field:
+ //
+ // @serial the Hashtable is indexed by the BasicPermission name
+ //
+ // private Hashtable permissions;
+ /**
+ * @serialField permissions java.util.Hashtable
+ * The BasicPermissions in this BasicPermissionCollection.
+ * All BasicPermissions in the collection must belong to the same class.
+ * The Hashtable is indexed by the BasicPermission name; the value
+ * of the Hashtable entry is the permission.
+ * @serialField all_allowed boolean
+ * This is set to {@code true} if this BasicPermissionCollection
+ * contains a BasicPermission with '*' as its permission name.
+ * @serialField permClass java.lang.Class
+ * The class to which all BasicPermissions in this
+ * BasicPermissionCollection belongs.
+ */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("permissions", Hashtable.class),
+ new ObjectStreamField("all_allowed", Boolean.TYPE),
+ new ObjectStreamField("permClass", Class.class),
+ };
+
+ /**
+ * @serialData Default fields.
+ */
+ /*
+ * Writes the contents of the perms field out as a Hashtable for
+ * serialization compatibility with earlier releases. all_allowed
+ * and permClass unchanged.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ // Don't call out.defaultWriteObject()
+
+ // Copy perms into a Hashtable
+ Hashtable<String, Permission> permissions =
+ new Hashtable<>(perms.size()*2);
+
+ permissions.putAll(perms);
+
+ // Write out serializable fields
+ ObjectOutputStream.PutField pfields = out.putFields();
+ pfields.put("all_allowed", all_allowed);
+ pfields.put("permissions", permissions);
+ pfields.put("permClass", permClass);
+ out.writeFields();
+ }
+
+ /**
+ * readObject is called to restore the state of the
+ * BasicPermissionCollection from a stream.
+ */
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ // Don't call defaultReadObject()
+
+ // Read in serialized fields
+ ObjectInputStream.GetField gfields = in.readFields();
+
+ // Get permissions
+ // writeObject writes a Hashtable<String, Permission> for the
+ // permissions key, so this cast is safe, unless the data is corrupt.
+ @SuppressWarnings("unchecked")
+ Hashtable<String, Permission> permissions =
+ (Hashtable<String, Permission>)gfields.get("permissions", null);
+ perms = new ConcurrentHashMap<>(permissions.size()*2);
+ perms.putAll(permissions);
+
+ // Get all_allowed
+ all_allowed = gfields.get("all_allowed", false);
+
+ // Get permClass
+ permClass = (Class<?>) gfields.get("permClass", null);
+
+ if (permClass == null) {
+ // set permClass
+ Enumeration<Permission> e = permissions.elements();
+ if (e.hasMoreElements()) {
+ Permission p = e.nextElement();
+ permClass = p.getClass();
+ }
+ }
+ }
+}