5.2. Permissions
The basic entity
that the access controller operates on is a permission
object--an instance of the Permission class
(java.security.Permission). The
Permission class itself is an abstract class
that represents a particular operation. The nomenclature here is a
little misleading, because a permission object can reflect two
things. When it is associated with a class (through a code source and
a protection domain), a permission object represents an actual
permission that has been granted to that class. Otherwise, a
permission object allows us to ask if we have a specific permission.
For example, if we construct a permission object that represents
access to a file, possession of that object does not mean that we
have permission to access the file. Rather, possession of the object
allows us to ask if we have permission to access the file.
An instance of the Permission class represents
one specific permission. A set of permissions--e.g., all the
permissions that are given to classes signed by a particular
individual--is represented by an instance of the
Permissions class
(java.security.Permissions). As developers and
administrators, we'll make extensive use of these classes, so
we'll need to investigate them in depth.
5.2.1. The Permission Class
Permissions have three properties:
-
A type
-
All
permissions carry a basic type that identifies what the permission
pertains to. A permission object to access a file will have a type of
FilePermission; an object to create a window
will have a type of AWTPermission; permission to
use the XYZ company payroll application would have a type of
XYZPayrollPermission.
-
A name
-
All permissions have a name that
identifies the specific object that a permission relates to. A
FilePermission has a name that is the name of
the file to be accessed; an AWTPermission to
create a window has a name of
showWindowWithoutWarningBanner; permission to
access a particular employee's payroll record would have the
name of that employee. Names are often based on
wildcards, so that a single file permission object may represent
permission to access several files, and so on.
The name of a permission is fairly arbitrary. In the case of file
permissions, the name is obviously the file. But the name of the
showWindowWithoutWarningBanner permission (among
many others) is chosen by convention, and it is up to all Java
programs to adhere to that convention. This is only a concern to
programmers when dealing with your own permission classes; as a
developer you rarely need to create permission objects for the types
of permissions defined in the Java API.
On the other hand, this naming convention is of concern to end users
and administrators, who must know the name of the permission they
want to grant to the programs they are going to run. These names must
go into the policy file (which we'll discuss in just a bit).
-
Actions
-
Some
permissions carry with them one or more actions. The presence of
these actions is dependent upon the semantics of the specific type of
permission. A file permission object has a list of actions that could
include read, write, and delete; an XYZ payroll permission object
could have a list of actions that includes view and update. On the
other hand, a window permission does not have an action: you either
have permission to create the window, or you don't. Actions can
also be specified by wildcards.The terms used to specify a list of
actions are also arbitrary and handled by convention.
Permissions can serve two roles. They allow the Java API to negotiate
access to several resources (files, sockets, and so on). Those
permissions are defined by convention within the Java API, and their
naming conventions are wholly within the domain of the Java API
itself. Hence, you can create an object that represents permission to
read a particular file, but you cannot create an object that
represents permission to copy a particular file, since the copy
action is not known within the file permission class.
On the other hand, you can create arbitrary permissions for use
within your own programs and completely define both the names of
those permissions as well as the actions (if any) that should apply.
If you are writing a payroll program, for example, you could create
your own permission class that uses the convention that the name of
the permission is the employee upon whose payroll information you
want to act; you could use the convention that the permissible
actions on the payroll permission are view and update. Then you can
use that permission in conjunction with the access controller to
allow employees to view their own payroll data and to allow managers
to change the payroll data for their employees.
We'll look at both of these cases, starting with the classes
that are provided within the Java API itself. These classes are used
by the Java API (and in particular, by the security manager) to
protect access to certain resources in ways that are fairly
intuitive, given our knowledge of the security manager (but
we'll examine that interaction in detail later).
5.2.2. Permissions of the Java API
There are 11 standard permissions in the
Java API, each of which is implemented as a class:
-
The FilePermission class
(java.io.FilePermission)
This class represents permissions for files. This class implements
two wildcard patterns for filenames: an asterisk matches all files in
a given directory, and a hyphen matches all files that reside in an
entire directory hierarchy. Valid actions for file permissions are
read, write, delete, and execute.
File permissions must be constructed with their platform-specific
name. Hence, /myclasses/xyz is a valid name for
a file permission on a Unix system, but not on a Macintosh (where an
equivalent name might be System
Disk:myclasses:xyz). When these strings are specified
programmatically, they are not too difficult to construct (using the
file separator property); when these strings need to be specified in
an external file, an appropriate syntax must be used.
Keep in mind the difference between an asterisk and a hyphen: an
asterisk only traverses a single directory, while a hyphen traverses
an entire filesystem. Hence /myclasses/* will
not include /myclasses/xyz/HRApplet.class,
but /my-classes/- will. A single asterisk will
access all files in the current directory, and a single hyphen will
access all files in the current directory and its subdirectories.
If you want to access all files on a particular machine, you specify
the special token <<ALL FILES>>.
A FilePermission object is constructed by
providing the name of the file and a list of actions on that file:
Class Definition
FilePermission p1 = new FilePermission("-", "execute");
FilePermission p2 = new FilePermission("/myclasses/*", "read, write");
FilePermission p3 = new FilePermission("<<ALL FILES>>", "read");
Here, p1 represents permission to execute all
files that are in the filesystem hierarchy under the current
directory, p2 represents permission to read and
write all files that exist in the directory
/myclasses, and p3
represents permission to read all the files on the
machine.
-
The SocketPermission class
(java.net.SocketPermission)
This class represents permissions to interact with network sockets.
The name of a socket permission is hostname:port, where each
component of the name may be specified by a wildcard. In particular,
the hostname may be given as a hostname (possibly DNS qualified) or
an IP address. The leftmost position of the hostname may be specified
as an asterisk, such that the host
piccolo.East.Sun.COM would be matched by each of
these strings:
Class Definition
piccolo
piccolo.East.Sun.COM
*.Sun.COM
*
129.151.119.8
The port component of the name can be
specified as a single port number or as a range of port numbers
(e.g., 1-1024). When a range is specified, either side of the range
may be excluded:
Class Definition
1024 (port 1024)
1024- (all ports greater than or equal to 1024)
-1024 (all ports less than or equal to 1024)
1-1024 (all ports between 1 and 1024, inclusive)
Valid actions for a socket permission are accept, connect, listen,
and resolve. These map into the socket API: accept is used by the
ServerSocket class to see if it can accept an
incoming connection from a particular host; connect is used by the
Socket class to see if it can make a connection
to a particular host, listen is used by the
ServerSocket class to see if a server socket can
be created at all, and resolve is used by the
Socket class to see if the IP address for a
particular host can be obtained.
Constructing a socket permission, then, is simply a matter of putting
together the desired strings in the correct format:
Class Definition
SocketPermission s1 = new SocketPermission("piccolo:6000", "connect");
SocketPermission s2 = new SocketPermission("piccolo:1024-",
"accept, listen");
Here s1 represents permission to connect to the
X server (port 6000) on machine piccolo, and
s2 represents permission for
piccolo to start a server on any nonprivileged
port.
-
The
PropertyPermission class
(java.util.PropertyPermission)
This class represents permissions for Java properties. Property
permission names are specified as dot-separated names (just as they
are in a Java property file); in addition, the last element can be a
wildcard asterisk: *, a.*, a.b.*, and so on.
The valid actions for this class are read and write. Hence, to
construct a property permission, you would do something like:
Class Definition
PropertyPermission p1 = new PropertyPermission("java.version", "read");
PropertyPermission p2 = new PropertyPermission("xyz.*", "read,write");
Here, p1 represents permission to read the
version of the virtual machine that's in use, and
p2 represents permission to read or write all
properties that begin with the token xyz.
-
The
RuntimePermission class
(java.lang.RuntimePermission)
This class represents permissions for the Java
runtime--essentially, permissions to perform any of the
operations encapsulated by the Runtime class,
including most thread operations. The names recognized by this class
are dot-separated names and are subject to the same wildcard asterisk
matching as the property permission class.
Runtime permissions have no associated actions--you either have
permission to perform those operations, or you don't. Hence, a
runtime permission is constructed as:
Class Definition
RuntimePermission r1 = new RuntimePermission("exitVM");
RuntimePermission r2 = new
RuntimePermission("accessClassInPackage.java");
Here, r1 represents permission to exit the
virtual machine, and r2 represents permission to
access classes in the java package.
-
The
AWTPermission
class (java.awt.AWTPermission)
This class represents permissions to access certain windowing
resources. In particular, as we might assume from the corresponding
methods in the security manager, there are three conventional names
in this class: showWindowWithoutWarningBanner,
accessClipboard, and
accessEventQueue.
There are no actions associated with this class. In addition, this
class technically supports wildcard matching, but since none of the
conventional names are in dot-separated format, that facility is
unused. Hence, an AWT permission is constructed like this:
Class Definition
AWTPermission a = new AWTPermission("showWindowWithoutWarningBanner");
-
The NetPermission class
(java.net.NetPermission)
-
The
NetPermission
class (java.net.NetPermission)
This class represents permissions to interact with two different
classes. The first is the
Authenticator class: there are no
concrete implementations of the Authenticator
class within the JDK, but implementations of that class provide HTTP
authentication for password-protected web pages. The valid names
associated with this class are setDefaultAuthenticator
and requestPasswordAuthentication.
Wildcard asterisk matching applies to these names.
In addition, this class encapsulates various URL-related permissions.
Permission to specify a stream handler in the URL class is named
specifyStreamHandler.
There are no associated actions with a net permission, so they are
constructed as follows:
Class Definition
NetPermission n1 = new NetPermission("requestPasswordAuthentication");
-
The
SecurityPermission class
(java.security.SecurityPermission)
This class represents permission to use the security package. Names
passed to this class are subject to wildcard asterisk matching, and
there are no actions associated with this class. The valid names to
this class include all the valid strings that can be passed to the
checkSecurityAccess() method of the security
manager; as we discuss the security API in the last half of this
book, we'll list these names for each class.
-
TheSerializablePermission class
(java.io.SerializablePermission)
This class represents various permissions relating to the
serialization and deserialization of an object. No wildcards or
actions are accepted by this class. This permission has two valid
names: enableSubstitution and
enableSubclassImplementation. The first of these
permissions allows the enableResolveObject()
method of the ObjectInputStream and the
enableReplaceObject() method of the
ObjectOutputStream classes to function. The
latter permission allows the ObjectInputStream
and ObjectOutputStream classes to be subclassed,
which would potentially override the
readObject() and
writeObject() methods.
-
The
ReflectPermission class
(java.lang.reflect.ReflectPermission)
This permission represents the ability to set the
accessible flag on objects that are to be used
with the reflection API. This class has a single name
(suppressAccessChecks) and no actions.
-
The
UnresolvedPermission class
(java.security.UnresolvedPermission)
This class is used internally in the Java API to represent external
permissions (i.e., permissions that are implemented by third-party
APIs) before the class that defines that permission is found. This
permission is only needed if you are writing an implementation of the
Policy class.
-
The
AllPermission class
(java.security.AllPermission)
This class represents permission to perform any
operation--including file, socket, and other operations that
have their own permission classes. Granting this type of permission
is obviously somewhat dangerous; this permission is usually given
only to classes within the Java API and to classes in Java
extensions. This class has no name or actions; it is constructed as
follows:
Class Definition
AllPermission ap = new AllPermission();
5.2.3. Using the Permission Class
We'll now look into the classes
upon which all these permissions are based: the
Permission class. This class abstracts the
notion of a permission and a name. From a programmatic standpoint,
the Permission class is really used only to
create your own types of permissions. It has some interesting
methods, but the operations that are implemented on a permission
object are not generally used in code that we write--they are
used instead by the access controller. Hence, we'll examine
this class primarily with an eye towards understanding how it can be
used to implement our own permissions.
Permission is an abstract class that contains
these public methods:
-
public
Permission(String name)
-
Construct a permission object that represents the desired permission.
-
public abstract boolean equals(Object o)
-
Subclasses of the Permission class are required
to implement their own test for equality. Often this is simply done
by comparing the name (and actions, if applicable) of the permission.
-
public abstract int hashCode()
-
Subclasses of the Permission class are required
to implement their own hash code. In order for the access controller
to function correctly, the hash code for a given permission object
must never change during execution of the virtual machine. In
addition, permissions that compare as equal must return the same hash
code from this method.
-
public final String getName()
-
Return the name that was used to construct this permission.
-
public abstract String
getActions()
-
Return the canonical form of the actions (if any) that were used to
construct this permission.
-
public String
toString()
-
The convention for
printing a permission is to print in parentheses the class name, the
name of the permission, and the actions. For example, a file
permission might return:
Class Definition
("java.io.FilePermission","/myclasses/xyz/HRApplet.class","read")
-
public abstract boolean
implies(Permission p)
-
This method is one of the keys of the Permission
class: it is responsible for determining whether or not a class that
is granted one permission is granted another. This method is normally
responsible for performing wildcard matching, so that, for example,
the file permission /myclasses/- implies the
file permission /myclasses/xyz/HRApplet.class.
But this method need not rely on wildcards; permission to write a
particular object in a database would probably imply permission to
read that object as well.
-
public PermissionCollection
newPermissionCollection()
-
Return a permission collection suitable for holding instances of this
type of permission. We'll discuss the topic of permission
collections in the next section. This method returns
null by default.
-
public void
checkGuard(Object o)
-
Call the security manager to see if the permission (i.e., the
this variable) has been granted, generating a
SecurityException if the permission has not been
granted. The object parameter of this method is unused. We'll
give more details about this method later in this chapter.
Implementing your own permission means providing a class with
concrete implementations of these abstract methods. Note that the
notions of wildcard matching and actions are not generally present in
this class--if you want your class to support either of these
features, you're responsible for implementing all of the
necessary logic to do so (although the
BasicPermission class that we'll look at
next can help us with that).
Say that you are implementing a program to administer payroll
information. You'll want to create permissions to allow users
to view their payment history. You'll also want to allow the HR
department to update the pay rate for employees. So we'll need
to implement a permission class to encapsulate all of that:
Class Definition
public class XYZPayrollPermission extends Permission {
protected int mask;
static private int VIEW = 0x01;
static private int UPDATE = 0x02;
public XYZPayrollPermission(String name) {
this(name, "view");
}
public XYZPayrollPermission(String name, String action) {
super(name);
parse(action);
}
private void parse(String action) {
StringTokenizer st = new StringTokenizer(action, ",\t ");
mask = 0;
while (st.hasMoreTokens()) {
String tok = st.nextToken();
if (tok.equals("view"))
mask |= VIEW;
else if (tok.equals("update"))
mask |= UPDATE;
else throw new IllegalArgumentException(
"Unknown action " + tok);
}
}
public boolean implies(Permission permission) {
if (!(permission instanceof XYZPayrollPermission))
return false;
XYZPayrollPermission p = (XYZPayrollPermission) permission;
String name = getName();
if (!name.equals("*") && !name.equals(p.getName()))
return false;
if ((mask & p.mask) != p.mask)
return false;
return true;
}
public boolean equals(Object o) {
if (!(o instanceof XYZPayrollPermission))
return false;
XYZPayrollPermission p = (XYZPayrollPermission) o;
return ((p.getName().equals(getName())) && (p.mask == mask));
}
public int hashCode() {
return getName().hashCode() ^ mask;
}
public String getActions() {
if (mask == 0)
return "";
else if (mask == VIEW)
return "view";
else if (mask == UPDATE)
return "update";
else if (mask == (VIEW | UPDATE))
return "view, update";
else throw new IllegalArgumentException("Unknown mask");
}
public PermissionCollection newPermissionsCollection() {
return new XYZPayrollPermissionCollection();
}
}
The instance variables in this class are required to hold the
information about the actions--even though our superclass makes
references to actions, it doesn't provide a manner in which to
store them or process them, so we have to provide that logic. That
logic is provided in the parse() method;
we've chosen the common convention of having the action string
treated as a list of actions that are separated by commas and
whitespace. Note also that we've stored the actual actions as
bits in a single integer--this simplifies some of the later
logic.
As required, we've implemented the
equals() and hashCode()
methods--and we've done so rather simply. We consider
objects equal if their names are equal and their masks (that is,
their actions) are equal, and construct a hash code accordingly.
Our implementation of the
getActions() method is typical: we're
required to return the same action string for a permission object
that was constructed with an action list of "view,
update" as for one that was constructed with an
action list of "update,view". This requirement is one of the
prime reasons why the actions are stored as a mask--because it
allows us to construct this action string in the proper format.
Finally, the
implies() method is responsible for determining
how wildcard and other implied permissions are handled. If the name
passed to construct our object is an asterisk, then we match any
other name; hence, an object to represent the permissions of the HR
department might be constructed as:
Class Definition
new XYZPayrollPermission("*", "view, update")
When the implies() method is called on this
wildcard object, the name will always match, and because the action
mask has the complete list of actions, the mask comparison will
always yield the mask that we're testing against. If the
implies() method is called with a different
object, however, it will only return true if the
names are equal and the object's mask is a subset of the target
mask.
Note that we also might have implemented the logic in such a way that
permission to perform an update implies permission to perform a view
simply by changing the logic of testing the mask--you're
not limited only to wildcard matching in the
implies() method.
5.2.4. The BasicPermission Class
If you need to implement your own permission class, the
BasicPermission class
(java.security.BasicPermission) provides some
useful semantics. This class implements a basic permission--that is, a
permission that doesn't have actions. Basic permissions can be
thought of as binary permission--you either have them, or you
don't. However, this restriction does not prevent you from
implementing actions in your subclasses of the
BasicPermission class (as the
PropertyPermission class does).
The prime benefit of this class is the manner in which it implements
wildcards. Names in basic permissions are considered to be
hierarchical, following a dot-separated convention. For example, if
the XYZ corporation wanted to create a set of basic permissions, they
might use the convention that the first word of the permission always
be xyz: xyz.readDatabase,
xyz.writeDatabase,
xyz.runPayrollProgram,
xyz.HRDepartment.accessCheck, and so on. These
permissions can then be specified by their full name, or they can be
specified with an asterisk wildcard:
xyz.* would match each of
these (no matter what depth), and * would match
every possible basic permission.
The wildcard matching of this class does not match partial names:
xyz.read* would not match any of the permissions
we just listed. Further, the wildcard must be in the rightmost
position: *.readDatabase would not match any
basic permission.
The BasicPermission class is abstract, although
it does not contain any abstract methods, and it completely
implements all the abstract methods of the
Permission class. Hence, a concrete
implementation of the BasicPermission need only
contain a constructor to call the correct constructor of the
superclass (since there is no default constructor in the
BasicPermission class). Subclasses must call one
of these constructors:
-
public BasicPermission(String name)
-
Construct a permission with the given name. This is the usual
constructor for this class, as basic permissions do not normally have
actions.
-
public BasicPermission(String name, String action)
-
Construct a permission with the given name and action. Even though
basic permissions do not usually have actions associated with them,
you must provide a constructor with this signature in all
implementations of the BasicPermission class due
to the mechanism that is used to construct permission objects from
the policy file (which we will see later in this
chapter).
5.2.5. Permission Collections
The access controller depends upon
the ability to aggregate permissions so that it can easily call the
implies() method on all of them. For example, a
particular user might be given permission to read several
directories: perhaps the user's home directory
(/home/sdo/-) and the system's temporary
directory (/tmp/-). When the access controller
needs to see if the user can access a particular file, it must test
both of these permissions to see if either one matches. This can be
done easily by aggregating all the file permissions into a single
permission collection.
Every permission class is required to implement a permission
collection, then, which is a mechanism where objects of the same
permission class may be grouped together and operated upon as a
single unit. This requirement is enforced by the
newPermissionCollection()
method of the Permission class.
The PermissionCollection class
(java.security.PermissionCollection) is defined
as follows:
-
public abstract class PermissionCollection
-
Implement an aggregate set of permissions. While permission
collections can handle heterogeneous sets of permissions, a
permission collection typically should be used to group together a
homogeneous group of permissions (e.g., all file permissions or all
socket permissions, etc.).
There are three basic operations that you can perform on a permission
collection:
-
public abstract void
add(Permission p)
-
Add the given permission to the permission collection.
-
public abstract boolean
implies(Permission p)
-
Check to see if any permission in the collection implies the given
permission. This can be done by enumerating all the permission
objects that have been added to the collection and calling the
implies() method on each of those objects in
turn, but it is typically implemented in a more efficient manner.
-
public abstract Enumeration
elements()
-
Return an enumeration of all the permissions in the collection.
The javadoc documentation of this class claims that a permission
collection is a collection of heterogeneous permission objects.
Forget that idea; introducing that notion into permission collections
vastly complicates matters, and the issue of a heterogeneous
collection of permission objects is better handled elsewhere
(we'll see how a little bit later). As far as we're
concerned, the purpose of a permission collection is to aggregate
only permission objects of a particular type.
Permission collections are typically implemented as inner classes, or
at least as classes that are private to the package in which they are
defined. There is, for example, a corresponding permission collection
class for the FilePermission class, one for the
SocketPermission class, and so on.
None of these collections is available as a public class that we can
use in our own program. Hence, in order to support the
newPermissionCollection() method in our
XYZPayrollPermission class, we'd need to
do something like this:
Class Definition
public class XYZPayrollPermissionCollection extends
PermissionCollection {
private Hashtable permissions;
private boolean addedAdmin;
private int adminMask;
XYZPayrollPermissionCollection() {
permissions = new Hashtable();
addedAdmin = false;
}
public void add(Permission p) {
if (!(p instanceof XYZPayrollPermission))
throw new IllegalArgumentException(
"Wrong permission type");
XYZPayrollPermission xyz = (XYZPayrollPermission) p;
String name = xyz.getName();
XYZPayrollPermission other =
(XYZPayrollPermission) permissions.get(name);
if (other != null)
xyz = merge(xyz, other);
if (name.equals("*")) {
addedAdmin = true;
adminMask = xyz.mask;
}
permissions.put(name, xyz);
}
public Enumeration elements() {
return permissions.elements();
}
public boolean implies(Permission p) {
if (!(p instanceof XYZPayrollPermission))
return false;
XYZPayrollPermission xyz = (XYZPayrollPermission) p;
if (addedAdmin && (adminMask & xyz.mask) == xyz.mask)
return true;
Permission inTable = (Permission)
permissions.get(xyz.getName());
if (inTable == null)
return false;
return inTable.implies(xyz);
}
private XYZPayrollPermission
merge(XYZPayrollPermission a, XYZPayrollPermission b) {
String aAction = a.getActions();
if (aAction.equals(""))
return b;
String bAction = b.getActions();
if (bAction.equals(""))
return a;
return new XYZPayrollPermission(a.getName(),
aAction + "," + bAction);
}
}
Note the logic within the implies()
method--it's the important part of this example. The
implies() method must test each permission in
the hashtable (or whatever other container you've used to store
the added permissions), but it should do so efficiently. We could
always call the implies() method of each entry
in the hashtable, but that would clearly not be
efficient--it's better to call only the
implies() method on a permission in the table
that has a matching name.
The only trick is that we won't find a matching name if
we're doing wildcard pattern matching--if we've
added the name "*" to the table, we'll always want
to return true, even though looking up the name
"John Smith" in the table will not return the
administrative entry. Implementing this wildcard pattern matching
efficiently is the key to writing a good permission collection.
When you use (or subclass) one of the concrete permission classes
that we listed earlier, there is no need to provide a permission
collection class--all concrete implementations provide their own
collection. In addition, there are two other cases when you do not
need to implement a permission collection:
-
When you extend the Permission class, but do not
do wildcard pattern matching.
Hidden internally within the Java API is a
PermissionsHash class, which is the default
permission collection class for permission objects. The
Permissions-Hash class stores the aggregated
permissions in a hashtable, so the implementations of its
add() and elements()
methods are straightforward. The implementation of its
implies() method is based on looking up the name
of the permission parameter in the hashtable collection: if an entry
is found, then the implies() method is called on
that entry.
-
When you extend the BasicPermission class and do
not provide support for actions.
The newPermissionClass() method of the
BasicPermission class will provide a permission
collection that handles wildcard pattern matching correctly (and
efficiently).
If you implement your own PermissionCollection
class, you must keep track of whether it has been marked as
read-only. There are two methods invlolved in this:
-
public boolean isReadOnly()
-
Return an indication of whether the collection has been marked as
read-only.
-
public void setReadOnly()
-
Set the collection to be read-only. Once the read-only flag has been
set, it cannot be unset: the collection will remain read-only
forever.
A permission collection is expected to throw a security exception
from its add() method if it has been marked as
read-only. Note that the read-only instance variable is private to
the PermissionCollection class, so subclasses
will have to rely on the isReadOnly() method to
test its value.
5.2.6. The Permissions Class
So far,
we've spoken about permission collections as homogeneous
collections: all permissions in the
XYZPayrollPermissionCollection class are
instances of the XYZPayrollPermission class; a
similar property holds for other permission collections. This idea
simplifies the implies() method that we showed
above. But to be truly useful, a permission collection needs to be
heterogeneous, so it can represent all the permissions a program
should have. A permission collection really needs to be able to
contain file permissions, socket permissions, and other types of
permissions.
This idea is present within the
PermissionCollection class; conceptually,
however, it is best to think of heterogeneous collections of
permissions as encapsulated by the Permissions
class (java.security.Permissions):
-
public final class Permissions extends PermissionCollection
-
Implement the PermissionCollection class. This
class allows you to create a heterogeneous collection of permissions:
the permission objects that are added to this collection need not
have the same type.
This class contains a concrete implementation of a permission
collection that organizes the aggregated permissions in terms of
their individual, homogenous permission collections. You can think of
a permissions object as containing an aggregation of permission
collections, each of which contains an aggregation of individual
permissions.
For example, let's consider an empty permissions object. When a
file permission is added to this object, the permissions object will
call the newPermissionCollection() method on the
file permission to get a homogeneous file permission collection
object. The file permission is then stored within this file
permission collection. When another file permission is added to the
permissions object, the permissions object will place that file
permission into the already existing file permission collection
object. When a payroll permission object is added to the permissions
object, a new payroll permission collection will be obtained, the
payroll permission added to it, and the collection added to the
permissions object. This process will continue, and the permissions
object will build up a set of permission collections.
When the implies() method of the permissions
object is called, it will search its set of permission collections
for a collection that can hold the given permission. It can then call
the implies() method on that (homogenous)
collection to obtain the correct answer.
The Permissions class thus supports any
arbitrary grouping of permissions. There is no need to develop your
own permission collection to handle heterogeneous groups.
 |  |  |
| 5.1. The CodeSource Class |  | 5.3. The Policy Class |

Copyright © 2001 O'Reilly & Associates. All rights reserved.
|