Sun Java System Access Manager 7.1 Developer's Guide

Overview of JAAS Authorization

JAAS is a set of APIs that enable services to authenticate and enforce access controls upon users. It implements a Java technology version of the standard Pluggable Authentication Module (PAM) framework, and supports user-based authorization. JAAS authorization extends the Java security architecture which uses a security policy to specify what access rights are granted to executing code. That architecture, introduced in the Java 2 platform, is code-based. The permissions are granted based on code characteristics such as where the code is coming from, whether it is digitally signed, and if so, the identity of the signer.

Overview of JAAS Authorization illustrates a Java security policy. This grants the code in the am_services.jar file, located in the current directory, the specified permission. No signer is specified, so it doesn’t matter whether the code is signed or not.


Example 4–1 Example of a Java Security Policy


grant codebase Cfile:./am_services.jar" {
            permission javax.security.auth.AuthPermission
                             "createLoginContext.AMLoginContext";
         };


         

JAAS authorization adds user centric access control that applies control based on what code is running as well as on who is running it.

By default, JAAS comes with a reference implementation of Policy (com.sun.security.auth.PolicyFile) which is file-based. This implementation parses the Java.policy file ${java.home}/lib/security directory and uses that to direct the associations of permissions to code. You can change the pointer to some other PolicyFile implementation or use a combination of files. By default, two files are consulted to evaluate policy. One is com.sun.security.auth.PolicyFile, mentioned above, and the other is .java.policy as defined in user’s home directory.

To make JAAS authorization take place, include a Principal field in the grant statement or statements in your policy file. A Principal field indicates which user executing the code is allowed the designated permissions. The Policy file grant statements can now optionally include one or more Principal fields. Including Principal field in the grant statement indicates that the user represented by the specified Principal, who is executing the specified code, has the designated permissions. See the Principal field example in Overview of JAAS Authorization.


Example 4–2 A Policy File Grant Statement


              grant   codebase "file:./am_services.jar",

                      Principal javax.security.auth.XXXprincipal


                      "your_user_name@your_domain"  {


                 permission java.util.PropertyPermission "java.home", "read";
                 permission java.util.PropertyPermission "user.home", "read";
                 permission java.io.FilePermission "foo.txt", "read";
              };


         

How Policy Enforcement Works

The Java 2 runtime enforces access controls via the java.lang.SecurityManager , which is consulted any time untrusted code attempts to perform a sensitive operation (accesses to the local file system, for example). To determine whether the code has sufficient permissions, the SecurityManager implementation delegates responsibility to the java.security.AccessController, which first obtains an image of the current AccessControlContext, and then ensures that the retrieved AccessControlContext contains sufficient permissions for the operation to be permitted.

JAAS supplements this architecture by providing the method Subject.doAs to dynamically associate an authenticated subject with the current AccessControlContext. As subsequent access control checks are made, the AccessController can base its decisions upon both the executing code itself, and upon the principals associated with the subject. Access Manager provides support for JAAS authentication, which results in the population of the subject with Principals that represents the user.


Example 4–3 The Subject.doAs Method


public final class Subject {
                ...
                // associate the subject with the current
                // AccessControlContext and execute the action
                public static Object doAs(Subject s,
                                java.security.PrivilegedAction action) { }
            }

            

To illustrate a usage scenario for the doAs method, consider a service that authenticates a remote subject, and then performs some work on behalf of that subject. For security reasons, the server should run in an AccessControlContext bound by the subject’s permissions. Using JAAS, the server can ensure this by preparing the work to be performed as a java.security.PrivilegedAction . Then, by invoking the doAs method, the server provides both the authenticated subject and the prepared PrivilegedAction. The doAs implementation associates the subject with the current AccessControlContext and then executes the action. When security checks occur during execution, the Java 2 SecurityManager queries the JAAS policy, updates the current AccessControlContext with the permissions granted to the subject and the executing codesource, and then performs its regular permission checks. When the action is completed, the doAs method removes the subject from the current AccessControlContext, and returns the result back to the caller. How Policy Enforcement Works illustrates this flow.


Example 4–4 Sample Code for Subject.doAS


public static void main(String[] args) {
        try {
            // Create an SSOToken
            AuthContext ac = new AuthContext("dc=iplanet,dc=com");
            ac.login();
            Callback[] callbacks = null;
            if (ac.hasMoreRequirements()) {
                callbacks = ac.getRequirements();

                if (callbacks != null) {
                    try {
                        addLoginCallbackMessage(callbacks); 
						// this method sets appropriate responses in the callbacks.
                        ac.submitRequirements(callbacks);
                    } catch (Exception e) { }
                }
            }
            if (ac.getStatus() == AuthContext.Status.SUCCESS) {
                  Subject subject = ac.getSubject(); 
						// get the authenticated subject
                  FilePermission perm = new FilePermission("/tmp/test","read");

                      Subject.doAs(subject, new PrivilegedExceptionAction() {
                      /* above statement means execute  run() method of the
								 /* Class PrivilegedExceptionAction()
                          as the specified subject */
                      public Object run() throws IOException  {
                          // if the above run()  was not throwing Exception 
									/* could have created an instance of PrivilegedAction
                          // instead of  PrivilegedExceptionAction here
                          AccessController.checkPermission(perm);
                            File = new File("/tmp/test");
                            return null;
                      }
                 });
             }
   }


            

In this example, the AccessController is checking the application’s current policy implementation. If any permission defined in the policy file implies the requested permission, the method will simply return; otherwise an AccessControlException will be thrown. The check is actually redundant in this example, because the constructor for the default File implementation performs the same check. The sample is meant to illustrate the flow.

How the JS2E Access Controller Works

AccessController works with the java.security.Policy implementation to securely process application requests. In JS2E, a typical checkPermission(Permission p) method call on the AccessController class might result in the following sequence:

  1. The AccessController invokes the getPermisisons() method of the javax.security.auth policy passing in the subject and the code source.

  2. The getPermissions() method returns a PermissionCollection class instance, which represents a collection of same types of permissions.

  3. The elements() method of the returned PermissionCollection gets called, which returns an enumeration of the permissions held in this PermissionCollection.

  4. For each of the permissions returned in the enumeration (in step 3), the perm.newPermissionCollection() method gets called to obtain the PermissionCollection used to store the permission.

  5. PermissionCollection.add(perm) gets called by the J2SE internal code to store the permission in its PermissionCollection.

  6. The AccessController calls the implies(Permission p) method of the PermissionCollection returned in step 2.

  7. Once the implies() of PermissionCollection is called, it in turn triggers the calling of implies(Permission p) of the individual permission objects contained in the PermissionCollection . These methods return true if the current permission object in the collection implies the specified permission; the methods return false the current permission object in the collection does not imply the specified permission. This outcome is implementation dependent and can be changed.