• No results found

All Permissions

5.3 The Policy Class

The third building block for the access controller is the facility to specify which permissions should apply to which code sources. We call this global set of permissions the security policy; it is encapsulated by the Policy class (java.security.Policy).

public abstract class Policy

Establish the security policy for a Java program. The policy encapsulates a mapping between code sources and permission objects in such a way that classes loaded from particular locations or signed

by specific individuals have the set of specified permissions.

A policy class is constructed as follows:

public Policy( )

Create a policy class. The constructor should initialize the policy object according to its internal rules (e.g., by reading the java.policy file).

There are two other methods in the Policy class:

public abstract Permissions getPermissions(CodeSource cs)

Create a permissions object that contains the set of permissions that should be granted to classes that came from the given code source (i.e., loaded from the code source's URL and signed by the keys in the code source).

public abstract void refresh( )

Refresh the policy object. For example, if the initial policy came from a file, re−read the file and install a new policy object based on the (presumably changed) information from the file.

In programmatic terms, writing a policy class involves implementing these methods. The default policy class is provided by the PolicyFile class (sun.security.provider.PolicyFile), which constructs permissions based on information found in the appropriate policy files.

Unfortunately, the PolicyFile class is in the sun package; it is not accessible to us as programmers.

Hence, while it's possible to write your own Policy class, it is a fairly involved process. You might want to write your own Policy class if you want to define a set of permissions through some other mechanism than a URL (e.g., loading the permissions via a policy server database). That implementation is fairly

straightforward: you need only provide a mechanism to map code sources to a set of permissions. Then, for each code source, construct each of the individual permission objects and aggregate them into a permissions object to be returned by the getPermissions( ) method.

Hence, a simple implementation of a policy class might looks like this:

package javasec.samples.ch05;

import java.security.*;

import java.util.*;

public class MyPolicy extends Policy {

// This inner class defines a simple set of permissions:

// either everything is allowed (the implies( ) method always // returns true, and the collection contains an AllPermission // object) or everything is prohibited (the implies( ) // method always returns false and the collection is empty).

static class SimplePermissions extends PermissionCollection { boolean allow;

Permissions perms;

SimplePermissions(boolean b) { allow = b;

perms = new Permissions( );

if (allow)

perms.add(new AllPermission( ));

}

public void add(Permission p) { if (isReadOnly( ))

throw new SecurityException(

"Can't add to this collection");

perms.add(p);

}

public Enumeration elements( ) { return perms.elements( );

}

public boolean implies(Permission p) { return allow;

} }

// We never change the policy public void refresh( ) {}

// If the code was loaded from a file, return a collection // that implies all permissions. Otherwise, return an // empty collection (one that implies no permissions).

public PermissionCollection getPermissions(CodeSource cs) { if (cs.getLocation().getProtocol( ).equals("file")) return new SimplePermissions(true);

return new SimplePermissions(false);

} }

This class implements a simple policy: if the class in question was loaded from the filesystem, then all operations are allowed. Otherwise, all operations are denied. Note that this implementation requires us to define a permission collection to return from the getPermissions( ) method. That's typically where all the work goes; in our case, we have either a simple collection with an all permission element or one with no elements. The implies( ) method in this case doesn't rely upon those elements, though it typically would.

5.3.1 Installing a Policy Class

Only a single instance of the policy class can be installed in the virtual machine at any time. However, the actual instance of the policy class can be replaced. There is a programmatic and an administrative way to install a policy class. As it turns out, both ways have their problems, though the administrative way is preferable.

These two methods install and retrieve the policy programatically:

public static Policy getPolicy( )

Return the currently installed policy object.

public static void setPolicy(Policy p)

Install the given policy object, replacing whatever policy object was previously installed.

Getting and setting the policy object requires going through the checkProperty( ) method of the security manager. By default, this succeeds only if you already have been granted a security permission with the name of getPolicy or setPolicy (as appropriate).

When the new policy is installed, it will only affect code sources that have not yet been established. To use this technique, you must install a policy file and then load classes through a new class loader; only those classes will be subject to the policy file that you've just installed.

You may also specify administratively which policy class to use by changing the policy.provider entry in the java.security file. By default, that entry is:

policy.provider=sun.security.provider.PolicyFile

So you can change sun.security.provider.PolicyFile to

javasec.samples.ch05.MyPolicy, and that will be the default policy. But the MyPolicy class must reside in the boot classpath of the virtual machine. That means that in order to use this technique, you must either add MyPolicy.class to the rt.jar file, or you must run the virtual machine with the appropriate argument to specify the boot classpath. This argument is nonstandard and is subject to change, but in 1.3 to load the MyPolicy class from /files/policy you'd use this command fragment:

piccolo% java −Xbootclasspath:/files/policy ...other args...

Nonetheless, installing the policy file through the java.security file is far easier on developers since it will apply to all classes, regardless of their class loader.