Return-Path: <JDCTechTips@sun.com>
Received: from MIT.EDU by po10.mit.edu (8.9.2/4.7) id TAA23199; Thu, 1 Feb 2001 19:19:55 -0500 (EST)
From: <JDCTechTips@sun.com>
Received: from hermes.java.sun.com by MIT.EDU with SMTP
	id AA05365; Thu, 1 Feb 01 19:18:39 EST
Date: Thu, 1 Feb 01 19:18:39 EST
Message-Id: <10102020018.AA05365@MIT.EDU>
To: alexp@MIT.EDU
Subject: JDC Tech Tips  January 30, 2001
Reply-To: JDCTechTips@sun.com
Errors-To: root@hermes.java.sun.com
Precedence: junk
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Mailer: Beyond Email 2.2


 J  D  C    T  E  C  H    T  I  P  S

                      TIPS, TECHNIQUES, AND SAMPLE CODE


WELCOME to the Java Developer Connection(sm) (JDC) Tech Tips, 
January 30, 2001. This issue of the JDC Tech Tips covers 
techniques for controlling access to Java(tm) packages. The 
topics covered are:
 
         * Controlling Package Access With Security Permissions
         * Controlling Package Access With Sealed JAR Files         

This tip was developed using Java(tm) 2 SDK, Standard Edition, 
v 1.3.

This issue of the JDC Tech Tips is written by Stuart Halloway,
a Java specialist at DevelopMentor (http://www.develop.com/java).

You can view this issue of the Tech Tips on the Web at
http://java.sun.com/jdc/TechTips/2001/tt0130.html

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
CONTROLLING PACKAGE ACCESS WITH SECURITY PERMISSIONS

In the Java(tm) programming language, a package is an important
abstraction that supports object-oriented design. A package is 
a group of classes that work together on some common task. For
example, the java.io package handles input/output, and the 
java.net package handles network communications. Classes within 
the same package have a special relationship that is enforced 
by the language and the Java virtual machine*. If you declare 
a class, method, or field without an explicit access modifier, 
then it has default access, and is accessible to any class in 
the same package:

package com.develop.widgets;
//Both Helper and widgetCount are visible only within the
//com.develop.widgets package.
class Helper {
  static int widgetCount;
}

This level of access is invaluable for implementation details 
that need to be shared across multiple classes, and because of
that, cannot be marked "private."  However, default access only 
provides encapsulation if you control all the code that is loaded 
into your package. Otherwise, developers can accidentally (or
maliciously) add their own classes to your package, and gain 
access to all the default-access classes, methods, and fields 
inside of the package.

The Java platform provides several mechanisms to control package 
access. Two of these are built-in permissions relating to package
access, and JAR sealing, which is supported by the 
java.net.URLClassLoader class.

The Java security architecture defines two permission prefixes 
that control the use of packages: the RuntimePermissions that 
begin with "accessClassInPackage" and "defineClassInPackage."  
The accessClassInPackage permissions control whether a class can 
be loaded by a class loader, possibly by delegation to some other 
loader. These permissions are checked in the loadClass method of 
participating class loaders. The defineClassInPackage permissions 
allow a class to be defined by a specific class loader, and would 
probably be checked in the findClass method of a class loader. 
Depending on the class loaders in use in your application, you 
might need to specify both permissions. For example, if you want 
to be able to access the classes in the java.net and 
java.io packages from your application, you might specify a policy 
file entry like this:

//correct, but unnecessary for reasons you will see momentarily
grant {
  permission java.lang.RuntimePermission "accessClassInPackage.java.io";
  permission java.lang.RuntimePermission "accessClassInPackage.java.net";
  permission java.lang.RuntimePermission "defineClassInPackage.java.io";
  permission java.lang.RuntimePermission "defineClassInPackage.java.net";
};  

In each case, the suffix of the permission name is the name of 
the package. However, something is obviously missing from this 
story. Most Java policy files do not have any entries like these, 
yet Java applications are able to access these and other packages.  
The reason for this is that packages are not secured by default.  
To secure them, you must edit the java.security file in your
${JAVA_HOME}/jre/lib/security folder:

  #excerpted from java.security. Each property takes a comma delimited
  #list of package prefixes. Security checks apply only to packages 
  #that begin with an exact string match of one of these prefixes.
  package.access=sun.
  #package.definition=

As you can see, the only packages that are access protected are 
those prefixed with "sun." To see the protection in action, use 
the following test class, which simply verifies that it can load 
a class from a URL:

//place in file TestAccess.java
import java.net.*;
import java.security.*;

public class TestAccess {
  public static void testCL(ClassLoader ldr, String name) {
    try {
      Class cl = ldr.loadClass(name);
      System.out.println(ldr + " loaded " + cl);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    try {
      if (args.length != 2) {
        System.out.println("usage TestAccess URL class");
        System.exit(-1);
      }
      URL[] urls = new URL[] {new URL(args[0])};
      URLClassLoader ucl = URLClassLoader.newInstance(urls);
      testCL(ucl, args[1]);
    }
    catch (Throwable t) {
      t.printStackTrace();
    }
  }
}

//place in file Test.policy
grant {
  permission java.io.FilePermission "<<ALL FILES>>", "read";
  permission java.lang.RuntimePermission "createClassLoader";
};

Try running this class with the following command line (that is, 
all on one line):

  java -Djava.security.manager -Djava.security.policy=Test.policy 
       TestAccess file:someRandomURL/ sun.secret.Class

The java.security.manager flag activates the default security 
manager. The java.security.policy property is set to Test.policy;
the permissions in Test.policy allow your code to create a class 
loader and read from the local file system. 

If you run the class, you should see the following exception:

  java.security.AccessControlException: access denied 
  (java.lang.RuntimePermission accessClassInPackage.sun.secret)

It does not matter what URL you use, because the security check
against the package name occurs before the class loader tries to
access the URL. To give your code permission to access the 
sun.secret package, add the following entry to your Test.policy 
file:
  
  permission java.lang.RuntimePermission "accessClassInPackage.sun.secret";

If you retry the class with the same command line as before, you 
should see the more mundane error:

  java.lang.ClassNotFoundException: sun.secret.Class

Of course, had there really been a sun.secret.Class, you would
now have permission to access it.

You can use the same mechanism to protect you own package names 
by adding the package prefixes to either the package.access or 
package.definition properties in the java.security file. You can 
then limit access to trusted code by adding entries to the policy 
file.

There are a few caveats to this technique. First, you must make 
sure to use class loaders that participate in this part of the 
security architecture. The common class loaders' implementations 
of package security are summarized below:

 ----------------------------------------------------------
| Class Loader   |   Access Checks   |   Definition Checks |
| ---------------------------------------------------------|
| bootstrap      |   No              |   No                |
| extensions     |   No              |   No                |
| system         |   Yes             |   No                |
| URLClassLoader |   Maybe*          |   No                |
 ----------------------------------------------------------

As you can see, none of the class loaders provided with the JDK 
check for permission to define a class. If you want to add this 
capability, you need to use a custom class loader that overrides 
findClass. Also, beware the "Maybe" entry in the table for 
URLClassLoader. If you construct a URLClassLoader directly, it 
does not check if the package access is legal. But, if you use 
the static method URLClassLoader.newInstance to create a 
URLClassLoader, you receive a subclass of URLClassLoader that 
does check package access.

The other caveat has to do with editing the java.security file.  
The package name passed to the security manager does not have 
a trailing "." and the string matching is completely literal.  
As a result, you must be careful in deciding whether to use 
a trailing period in the policy file. For example, the default 
entry:

  package.access=sun.

protects "sun.misc" and "sun.tools" but it would not protect the 
sun package because there is no trailing period to match. But
if the entry were edited to read:
  
  package.access=sun

it would protect the sun package, but also other packages with 
names such as "sundance", "sung", and "sundry".

You can read more about RuntimePermissions at
http://java.sun.com/products/jdk/1.2/docs/guide/security/permissions.html#RuntimePermission

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
CONTROLLING PACKAGE ACCESS WITH SEALED JAR FILES

The security mechanisms discussed in the tip "Controlling Package 
Access With Security Permissions" approach the problem at 
a fairly low level. Most developers do not need this level of
control, and simply want to guarantee that all classes in 
a package come from the same code source. This common case is 
supported by JAR "sealing." You can seal a JAR file by specifying
a true value for the sealed attribute, that is: 
  
  Sealed: true

Note that the default value of the sealed attribute is false. 

After a class loader loads a class from a sealed JAR file, 
classes in the same package can only be loaded from that JAR 
file. You can override sealing on a per-package basis with 
additional attributes listed after the package name. For 
example, you can have a main section as follows (terminated 
by blank line):

  Sealed: false
  
And follow the main section with sub-sections that have per-entry 
attributes:

  Name: com/develop/impl/
  Sealed: true

To see sealing in action, move the TestAccess class that was
introduced in the tip "Controlling Package Access With Security 
Permissions" to a package named sealme:

  //place in file sealme/TestAccess.java
  package sealme;
  //repeat TestAccess.java contents from above

Then, create a manifest that seals all packages. The file
should have the following lines and end with a blank line:

  Manifest-Version: 1.0
  Sealed: true

Create a sealed jar file with the jar tool:

  jar cvmf manifest sealme.jar sealed/TestAccess.class
  
Now, create another class in a separate location from TestAccess.
Place it, say, in dynclass/sealme:

  package sealme;
  public class LoadMe {
  }

Try running sealme.TestAccess from the jar file, using it to
dynamically load sealme.LoadMe:

  java -cp sealme.jar sealme.TestAccess file:dynclass/ sealme.LoadMe  

Because the jar file is sealed, you will not be able to load
sealMe.LoadMe from an alternate location. You should see an 
exception like this:

  java.lang.SecurityException: sealing violation
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:234)
        (etc.)

Notice that package sealing works regardless of whether you have
installed a security manager. This is in marked contrast to the
RuntimePermissions discussed in the tip "Controlling Package Access 
With Security Permissions." Where the permission-based solution is 
flexible but difficult to configure, the package sealing approach is 
simple, blunt, and easy to use. Unless you have a compelling reason 
to do otherwise, you should consider sealed JAR files to be the 
default mechanism for delivering JAVA code.

It is interesting to note that the "java.-" packages are not
protected by either of the schemes discussed above. The 
documentation is confusing on this point.  For example, the 
documentation for the defineClassInPackage permission states that 

  "[granting] this is dangerous because malicious code with this 
  permission may define rogue classes in trusted packages like 
  java.security or java.lang, for example."  
  
This is doubly wrong.  First, the defineClassInPackage permission 
is not checked by any class loader supplied with the JDK. Second, 
as of JDK 1.3, the "java" packages are protected by a line that is
hard coded into the ClassLoader class:

  //from java.lang.ClassLoader.defineClass
  if ((name != null) && name.startsWith("java.")) {
    throw new SecurityException("Prohibited package name: " + 
                     name.substring(0, name.lastIndexOf('.')));
  }

Obviously Sun takes the protection of the core API packages very
seriously! You should take similar care when deploying own Java
packages.

JAR sealing is part of the Java extensions mechanism. For more
information, see
http://java.sun.com/products/jdk/1.2/docs/guide/extensions/index.html
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

- NOTE

Sun respects your online time and privacy. The Java Developer 
Connection mailing lists are used for internal Sun Microsystems 
purposes only. You have received this email because you elected 
to subscribe. To unsubscribe, go to the Subscriptions page 
(http://developer.java.sun.com/subscription/), uncheck the 
appropriate checkbox, and click the Update button.


- SUBSCRIBE

To subscribe to a JDC newsletter mailing list, go to the 
Subscriptions page (http://developer.java.sun.com/subscription/), 
choose the newsletters you want to subscribe to, and click Update.


- FEEDBACK
Comments? Send your feedback on the JDC Tech Tips to:

jdc-webmaster@sun.com


- ARCHIVES
You'll find the JDC Tech Tips archives at:

http://java.sun.com/jdc/TechTips/index.html


- COPYRIGHT
Copyright 2001 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.

This document is protected by copyright. For more information, see:

http://java.sun.com/jdc/copyright.html


JDC Tech Tips 
January 30, 2001





