/*
 * Copyright (c) 1997, 2013, 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.util.Enumeration;
import java.util.Map;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Collections;
import java.io.ObjectStreamField;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;

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.

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.

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.

Author:Marianne Mueller, Roland Schemers
See Also:
/** * 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. * <p> * @see java.security.Permission * @see java.security.Permissions * @see java.security.PermissionCollection * @see java.lang.SecurityManager * * @author Marianne Mueller * @author Roland Schemers */
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.
/** * 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.
Params:
  • name – the name of the BasicPermission.
Throws:
/** * 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.
Params:
  • name – the name of the BasicPermission.
  • actions – ignored.
Throws:
/** * 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.

More specifically, this method returns true if:

  • p's class is the same as this object's class, and
  • 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".
Params:
  • p – the permission to check against.
Returns:true if the passed permission is equal to or implied by this permission, false otherwise.
/** * Checks if the specified permission is "implied" by * this object. * <P> * More specifically, this method returns true if: * <ul> * <li> <i>p</i>'s class is the same as this object's class, and * <li> <i>p</i>'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. */
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 obj's class is the same as this object's class and has the same name as this object.

Params:
  • obj – the object we are testing for equality with this object.
Returns:true if obj's class is the same as this object's class and has the same name as this BasicPermission object, false otherwise.
/** * Checks two BasicPermission objects for equality. * Checks that <i>obj</i>'s class is the same as this object's class * and has the same name as this object. * <P> * @param obj the object we are testing for equality with this object. * @return true if <i>obj</i>'s class is the same as this object's class * and has the same name as this BasicPermission object, false otherwise. */
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, getName().hashCode(), where getName is from the Permission superclass.
Returns:a hash code value for this object.
/** * 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. */
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.
Returns:the empty string "".
/** * 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 "". */
public String getActions() { return ""; }
Returns a new PermissionCollection object for storing BasicPermission objects.

BasicPermission objects must be stored in a manner that allows them to be inserted in any order, but that also enables the PermissionCollection implies method to be implemented in an efficient (and consistent) manner.

Returns:a new PermissionCollection object suitable for storing BasicPermissions.
/** * 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. */
public PermissionCollection newPermissionCollection() { return new BasicPermissionCollection(this.getClass()); }
readObject is called to restore the state of the BasicPermission from a stream.
/** * 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.
Returns:the canonical name of this BasicPermission.
/** * 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 "*".
Author:Roland Schemers
See Also:
@serialinclude
/** * 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.
/** * 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 Map<String, Permission> perms;
This is set to true if this BasicPermissionCollection contains a BasicPermission with '*' as its permission name.
See Also:
/** * 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 belongs.
See Also:
  • serialPersistentFields
/** * The class to which all BasicPermissions in this * BasicPermissionCollection belongs. * * @see #serialPersistentFields */
private Class<?> permClass;
Create an empty BasicPermissionCollection object.
/** * Create an empty BasicPermissionCollection object. * */
public BasicPermissionCollection(Class<?> clazz) { perms = new HashMap<String, Permission>(11); all_allowed = false; permClass = clazz; }
Adds a permission to the BasicPermissions. The key for the hash is permission.path.
Params:
  • permission – the Permission object to add.
Throws:
  • 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.
  • SecurityException – - if this BasicPermissionCollection object has been marked readonly
/** * 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 */
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); } synchronized (this) { perms.put(bp.getCanonicalName(), permission); } // No sync on all_allowed; staleness OK if (!all_allowed) { if (bp.getCanonicalName().equals("*")) all_allowed = true; } }
Check and see if this set of permissions implies the permissions expressed in "permission".
Params:
  • permission – the Permission object to compare
Returns:true if "permission" is a proper subset of a permission in the set, false if not.
/** * 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. */
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; synchronized (this) { 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); synchronized (this) { 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.
Returns:an enumeration of all the BasicPermission objects.
/** * Returns an enumeration of all the BasicPermission objects in the * container. * * @return an enumeration of all the BasicPermission objects. */
public Enumeration<Permission> elements() { // Convert Iterator of Map values into an Enumeration synchronized (this) { return Collections.enumeration(perms.values()); } } // 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;
@serialFieldpermissions 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.
@serialFieldall_allowed boolean This is set to true if this BasicPermissionCollection contains a BasicPermission with '*' as its permission name.
@serialFieldpermClass java.lang.Class The class to which all BasicPermissions in this BasicPermissionCollection belongs.
/** * @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), };
@serialDataDefault fields.
/** * @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); synchronized (this) { 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.
/** * 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 HashMap<String, Permission>(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(); } } } }