Java Programming, Lecture Notes # 715, Revised 5/16/99.
Students in Prof. Baldwin's Advanced Java Programming classes at ACC will be responsible for knowing and understanding all of the material in this lesson beginning with the spring semester of 1999.
This lesson was originally written on April 10, 1999 and has been updated several times since.
The purpose of this lesson is to provide an introduction to the use of security policy files under JDK 1.2.
I claim absolutely no expertise in the area of security. I am simply a college professor attempting to gather information about Java on one hand and present it to my students on the other. I disclaim any responsibility for any security problems that may occur as a result of anyone using any of the material in any of my tutorial lessons.
You are responsible for your own actions. With regard to security, you should study not only the material that I will present, but also material provided by others who possess expertise in the security area. Hopefully my material will be useful in getting you started in that direction.
Two good books on security published by O'Reilly & Associates are:
I highly recommend both of these books.
The pain of progress
When migrating from JDK 1.1 to JDK 1.2, you must contend with the fact that JDK 1.2 incorporates significant changes in the overall security model. Some programs that run fine under JDK 1.1 throw security exceptions and won't run under JDK 1.2.
This lesson provides a brief introduction to the use of security policy files. You are referred to the documentation available for JDK 1.2 for a more complete discussion.
This lesson is also designed to get you over the initial hump and show you how to create security policy files to get your JDK 1.1 programs back up and running under JDK 1.2.
Policy-based, easily-configurable, fine-grained access control
Sun refers to the new security capability introduced in JDK 1.2 as "Policy-based, easily-configurable, fine-grained access control." When code is loaded, it is assigned "permissions" based on the security policy currently in effect.
Each individual permission specifies a permitted access to a particular resource. Typical permissions are:
Basis for permissions
Permissions can be based on the source of the code, the signer of the code, or both. The policy that specifies which permissions are available for code from various signers/locations can be initialized from an external configurable policy file. This enables the JVM to offer fine-grain, configurable, flexible, and extensible access control. Such control can be specified for all Java code, including applets, applications, beans, and servlets.
What is a permission?
A permission represents access to a system resource. In order for access to a resource to be allowed for an applet (or for an application running with a security manager), the corresponding permission must be explicitly granted to the code attempting the access.
When are permissions required?
If the application is running without a security manager, there is no requirement to establish permissions for that application. By default, the application has full access to all resources. Therefore, when migrating from JDK 1.1 to JDK 1.2, you are most likely to encounter security problems when running JDK 1.1 applications that use a security manager. This includes all RMI applications.
How are permissions granted?
Permissions are granted by creating (and invoking) policy configuration files. Policy configuration files are text files that can be created using a text editor, or by using the graphical policytool program that is part of the JDK download. By using policytool, you can avoid the requirement to know the syntax of the policy configuration files or the class names of the permission classes. (See the JDK 1.2 documentation for instructions on how to use policytool.) However, policytool provides no help in knowing which permissions to grant for a particular situation, and how to grant them. You must get that information from the JDK 1.2 documentation.
How can you invoke a policy file?
Certain default policy files are invoked automatically. Additional policy files can be invoked at runtime by starting the JVM using a statement such as the following:
java -Djava.security.policy=Rmi02Client.policy Rmi02Client |
This statement causes the Rmi02Client application to be executed after setting a system property causing the file named Rmi02Client.policy to establish the security policy.
What is a Policy object?
A Policy object represents the policy for a Java application environment. The policy can be specified within one or more policy configuration files in the default Policy implementation. The policy file(s) specify the permissions that are granted to code from specified sources.
What are target names and actions?
A permission typically has a "target name" and, in some cases, a comma-separated list of one or more actions. For example, when included in a policy file, the following text grants permission for code that originates in the directory specified by the URL following the word codeBase to write a file named junk.txt. The target is junk.txt and the action is write.
grant codeBase "file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/"{ permission java.io.FilePermission "junk.txt", "write"; }; |
Where can I learn more about permission types and associated risks?
The JDK 1.2 documentation contains tables that describe the built-in JDK 1.2 permission types and discuss the risks of granting each of the available permissions. It also contains tables showing the methods that require permissions to be in effect for successful execution of the method. The required permissions are shown for each such method.
The policy for a Java application environment (specifying which permissions are available for code from various sources) is represented by a Policy subclass providing an implementation of the abstract methods in the Policy class (which is in the java.security package).
Where are the policy configuration files?
The source location for the policy information depends on the Policy implementation. The default Policy implementation obtains its information from static policy configuration files.
The policy can be specified within one or more policy configuration files in the default Policy implementation. The configuration file(s) specify what permissions are allowed for code from specified code sources.
By default, there is a single system-wide policy file, and a single (optional) user policy file. You can create additional policy configuration files and invoke them when you start the JVM.
Where is the system-wide policy configuration file located?
By default, the system-wide policy configuration file is located at:
In this representation, java.home refers to the value of the system property named "java.home", which specifies the directory into which the JDK was installed.
What is the purpose of the system-wide policy configuration file?
The system-wide policy file is intended to grant system-wide code permissions. The default java.policy file that is installed when you install the JDK
Where is the user policy configuration file located?
By default, the user policy file is located at
Note: user.home refers to the value of the system property named "user.home", which specifies the user's home directory.
On Windows systems the "user.home" property value defaults to
Loading Policy Files
The system policy is loaded first at initialization. Then the user policy is added to it. If neither policy is present, a built-in policy is used. According to the documentation, this built-in policy is the same as the original sandbox policy.
What and where is the security properties file?
The locations of the policy configuration files are also configurable. Policy file locations are specified in the security properties file, which is located at
If you need to modify the locations of the policy configuration files, see the JDK 1.2 documentation for more information on how to modify the security properties file.
Using Alternative Policy Files
As mentioned earlier, it is also possible to specify an additional or a different policy file when starting the JVM to execute an application. This is illustrated in the sample program presented later in this lesson.
To specify an alternative policy file when you start the JVM, use the following command line argument, which sets the value of the java.security.policy property.
"-Djava.security.policy"
For example, if myURL is a URL specifying the location of a policy file, and myApp is the name of an application, then
java -Djava.security.manager -Djava.security.policy=myURL myApp
will cause the specified policy file to be loaded in addition to all the policy files that are specified in the security properties file.
Note that "-Djava.security.manager" was specified in addition to the file containing the new security policy.
Why include -Djava.security.manager?
Inclusion of the "-Djava.security.manager" argument ensures that the default security manager is installed. This causes the application to be subject to policy checks. This argument is not required if the application installs a security manager.
Any limitations on the URL?
The URL can be any regular URL or simply the name of a policy file in the current directory, as shown below:
java -Djava.security.policy=Security03.policy Security03
This particular application installs its own security manager. Thus, there was no requirement to include the "-Djava.security.manager" argument
Using only one specific policy configuration file
The following format, which uses a double equal
java -Djava.security.manager -Djava.security.policy==myURL myApp
instructs that just the specified policy file will be used. All of the policy files specified in the security properties file will be ignored.
Using Alternative Policy Files with appletviewer
It is also possible to pass policy files to appletviewer using syntax such as the following. See the JDK 1.2 documentation for more information.
appletviewer -J-Djava.security.policy=myURL myApplet
Disabling Alternative Policy Files
It is also possible to disable the ability to specify an alternate security policy by setting the policy.allowSystemProperty property to false in the security properties file. The default is true.
Other aspects of security are configurable as well.
Once again, what are the policy configuration files used for?
The policy configuration file(s) for a JDK installation specify what permissions are allowed by code from specified code sources.
An applet, or an application running under a security manager, must be granted permission to perform secured actions (such as reading or writing a file) under JDK 1.2.
Exceptions to the rule
One exception is that code always automatically has permission to read files from its same (URL) location, and subdirectories of that location. It does not need explicit permission to do so.
What is a grant entry?
Other than this exception, by default, a permission must be granted by a grant entry in a policy configuration file. The overall format of a policy configuration file is a list of entries.
What is a keystore entry?
There may be zero or one keystore entry and zero or more grant entries. (The concept of a keystore will be addressed in a separate lesson and won't be discussed further here.)
Code being executed is considered to come from a particular "code source." An object of type CodeSource represents the code-source).
What is the source of the code?
The code source includes
(Certificates, public keys, and private keys will be discussed in a separate lesson.)
Format of grant Entries
Each grant entry includes one or more "permission entries".
The permission entries are preceded by optional codeBase and signedBy name/value pairs. These name/value pairs specify the code to which you want to grant the permissions.
In case you need to know it, the basic format of a grant entry is as follows. (The use of the policytool program eliminates the requirement for you to be concerned about such formats.)
grant signedBy "signer_names", codeBase "URL" { permission permission_class_name "target_name", "action", signedBy "signer_names"; permission permission_class_name "target_name", "action", signedBy "signer_names"; };
The signedBy value
A signedBy value indicates the alias for a certificate stored in the keystore. As mentioned earlier, I will have more to say about certificates and keystore in a separate lesson. The signedBy value can be a comma-separated list of multiple aliases where the comma indicates an AND relationship.
To use the exact wording from the Sun documentation, a statement like "Code signed by Adam" means
"Code in a class file contained in a JAR file, where the JAR file was signed using the private key corresponding to the public key that appears in a keystore certificate in an entry aliased by Adam." |
The signedBy field is optional. If it is omitted, it doesn't matter whether the code is signed or not or by whom.
The codeBase value
A codeBase value indicates the code source location. This field is also optional. By specifying a codeBase, you grant the specified permission(s) to code from that location. An empty codeBase entry signifies "any code." It doesn't matter where the code originates.
A codeBase value is a URL and must always use forward slashes (never backslashes) as the directory separator, even when the code source is actually on a Windows system. This is a requirement for you to know about even when using the policytool program to create your policy configuration files.
See the sample program later in this lesson for a URL representing a directory on the file system for a Windows 95 system.
The codeBase options
There are several optional formulations of codeBase. The exact meaning of a codeBase value depends on the characters at the end.
Permission Entries
A permission entry must begin with the word permission. A portion of the template presented above is repeated here for convenience.
permission permission_class_name "target_name", "action", signedBy "signer_names";
The permission_class_name is a specific permission type, such as java.io.FilePermission or java.lang.RuntimePermission. (Use of the policytool program eliminates the need for you to know the names of the permission classes.)
A permission type can require a target. For example, the "target_name" for java.io.FilePermission is the path/file name that specifies a particular directory or file.
Many, but not all, permission types require an "action" parameter. For example, java.io.FilePermission requires an action parameter to specify read, write, etc. (Use of the policytool program eliminates the need for you to know which permission types need action types. When it is not needed, the action field is "grayed out" in the dialog.)
The signedBy name/value pair for a permission entry is optional. It indicates that the permission class itself must be signed by the given alias(es) in order for the permission to be granted. For more details on this, see the Sun documentation.
Items in a Permission Entry
The order of the items in a permission entry must be as follows:
Tidbits
An entry is terminated with a semicolon.
Case is not important for the identifiers (permission, signedBy, codeBase, etc.) but is significant for the permission_class_name or for any string that is passed in as a value.
When you specify a java.io.FilePermission, the "target_name" is a file path. On Windows systems, whenever you directly specify a file path in a string (but not in a codeBase URL), you must include two backslashes for each actual single backslash in the path,
Name: Security03.java
This application and the two related files listed below are designed to illustrate the use of policy configuration files in JDK 1.2.
What does the program do?
This application illustrates writing and then reading a file where the application creates a security manager that doesn't allow writing and reading files.
Because the security manager doesn't allow writing and reading files, the application cannot be executed under JDK 1.1. It also cannot be executed under JDK 1.2 without invoking a policy configuration file that overrides the security manager set by the application.
Granting file write/read permission
Under JDK 1.2, a policy configuration file is created to grant the application permission to write and then read the file. In order to use the policy file to grant the permissions, it must be invoked when the application is started.
To make things simple and avoid typing errors, the following statement is encapsulated in a batch file to start the application and invoke the policy file named Security03.policy:
java -Djava.security.policy=Security03.policy Security03
The output from the program is:
Start the program and write a file Read, and print the file Dick End of program |
The following sections contain interesting code fragments from the three files. Complete listings of all three files are provided near the end of the lesson.
Defining a security manager class
The first fragment defines a security manager class for the application. Note that this class definition is completely empty.
Since this class doesn't override any of the methods of the SecurityManager class, an application that uses an object of this class as a security manger has almost no permission to access system resources.
class DummySecurityManager extends SecurityManager { } |
Setting the security manager for the application
The next fragment shows
Setting the security manager in this fashion effectively eliminates most permissions for access of resources by the application including permission to write and read files. However, the invocation of the policy configuration file shown later overrides the security manager set by the application and gives the application permission to write and then read a specific file on the local file system.
class Security03{ public static void main(String[] args){ System.setSecurityManager(new DummySecurityManager()); |
Writing and reading the file
The next fragment writes and then reads a file named junk.txt. By now you should have no difficulty understanding this code. I have included it here simply for completeness, but won't discuss it further.
System.out.println( "Start the program and write a file"); try{ FileOutputStream outFile = new FileOutputStream("junk.txt"); //Write four bytes to the file and close it outFile.write('D'); outFile.write('i'); outFile.write('c'); outFile.write('k'); outFile.close(); }catch(IOException e){System.out.println(e);} System.out.println("Read, and print the file"); try{ FileInputStream inFile = new FileInputStream("junk.txt"); int data; //Read and print until eof indicated by -1. while( (data = inFile.read()) != -1) System.out.print((char)data); inFile.close(); }catch(IOException e){System.out.println(e);} System.out.println("\nEnd of program"); }// end main }//end class Security03 |
The key to this lesson, and the key to making it possible for the above application to write and then read a file named junk.txt is the policy configuration file shown below.
/* File Security03.policy, rev 4/10/99, R.G.Baldwin*/ grant codeBase "file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/" { permission java.io.FilePermission "junk.txt", "write"; }; grant codeBase "file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/" { permission java.io.FilePermission "junk.txt", "read"; }; |
Granting very specific permission
When invoked to set security policy, the first entry in this file grants code originating at the URL permission to write a file named junk.txt on the local file system. This is true even though the security manager implemented by the application does not grant that privilege.
"file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/"
The second entry grants code originating at the same URL permission to read the same file.
The batch file that I used to start the program causes the policy configuration file named Security03.policy to be used to set security policy for the execution of the application. This, in turn, grants the write and read privileges discussed above.
java -Djava.security.policy=Security03.policy Security03 |
This section contains listing of all three files.
/* File Security03.java Copyright 1999, R.G.Baldwin This application and two related files named Security03.bat Security03.policy are designed to illustrate the use of security policy files in JDK 1.2. This application illustrates writing and then reading a file one byte at a time where the application creates a security manager to control itself. The security manager does not allow the writing and subsequent reading of disk files. Therefore, the application cannot be executed under JDK 1.1. Under JDK 1.2, a security policy file can be created locally to grant the application permission to write and then read the file. In order to use the policy file to grant the permissions, it must be invoked when the application is started. The following statement is encapsulated in a batch file to start the application and invoke the policy file named Security03.policy: java -Djava.security.policy=Security03.policy Security03 The contents of the policy file are shown below: grant codeBase "file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/" { permission java.io.FilePermission "junk.txt", "write"; }; grant codeBase "file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/" { permission java.io.FilePermission "junk.txt", "read"; }; These two segments of text in the policy file make it possible for class files loaded from the following URL file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/ to write and read a file named junk.txt on the local file system. The output from the program is: Start the program and write a file Read, and print the file Dick End of program **********************************************************/ import java.io.*; //Define a dummy security manager class. class DummySecurityManager extends SecurityManager{} //=======================================================// class Security03{ public static void main(String[] args){ //Create a dummy security manager. System.setSecurityManager(new DummySecurityManager()); System.out.println( "Start the program and write a file"); try{ FileOutputStream outFile = new FileOutputStream("junk.txt"); //Write four bytes to the file and close it outFile.write('D'); outFile.write('i'); outFile.write('c'); outFile.write('k'); outFile.close(); }catch(IOException e){System.out.println(e);} System.out.println("Read, and print the file"); try{ FileInputStream inFile = new FileInputStream("junk.txt"); int data; //Read and print until eof indicated by -1. while( (data = inFile.read()) != -1) System.out.print((char)data); inFile.close(); }catch(IOException e){System.out.println(e);} System.out.println("\nEnd of program"); }// end main }//end class Security03 |
/* File Rmi02Server.policy, rev 4/10/99, R.G.Baldwin*/ grant codeBase "file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/" { permission java.io.FilePermission "junk.txt", "write"; }; grant codeBase "file:/G:/Baldwin/AA-School/JavaProg/Combined/Java/" { permission java.io.FilePermission "junk.txt", "read"; }; |
rem File Secuity03.bat Rev 4/10/99 RGB java -Djava.security.policy=Security03.policy Security03 |
-end-