Java Authentication and Authorization Service (JAAS)


Authentication is the process of verifying the identity of a user or a device to determine its accuracy and trustworthiness. Authorization provides access rights and privileges depending on the requesting identity's granted permissions to access a resource or execute a required functionality.

JAAS provides API mechanisms and services for enabling authentication and authorization in Java-based application solutions. JAAS is the Java implementation of the Pluggable Authentication Module (PAM) framework originally developed for Sun's Solaris operating system. PAM enables the plugging in of authentication mechanisms, which allows applications to remain independent from the underlying authentication technologies. Using PAM, JAAS Authentication modules allow integrating authentication technologies such as Kerberos, RSA, smart cards, and biometric authentication systems. Figure 4-5 illustrates JAAS-based authentication and authorization using pluggable authentication modules.

Figure 4-5. JAAS architectural model and pluggable authentication


In an end-to-end application security model, JAAS provides authentication and authorization mechanisms to the Java applications and also enables them to remain independent from JAAS provider implementations. The JAAS API framework features can be categorized into two concepts:

  • Authentication: JAAS provides reliable and secure API mechanisms to verify and determine the identity of who is executing the code.

  • Authorization: Based on an authenticated identity, JAAS applies access control rights and privileges to execute the required functions. JAAS extends the Java platform access control based on code signers and codebases with fine-grained access control mechanisms based on identities.

Like other security packages, JAAS also features a provider architecture and service-provider interface that allows different JAAS-based authentication and authorization provider modules to be plugged into a J2SE environment.

JAAS Classes and Interfaces

In J2SE, the core classes and interfaces of the JAAS framework are available in the following packages:

  • javax.security.auth.*: Contains the base classes and interfaces for authentication and authorization mechanisms.

  • javax.security.auth.callback.*: Contains the classes and interfaces for defining authentication credentials of the application.

  • javax.security.auth.login.*: Contains the classes for logging in and out of an application domain.

  • javax.security.auth.spi.*: Contains interfaces for a JAAS provider for implementing JAAS modules.

The classes and interfaces are further classified into three categories: Common, Authentication, and Authorization. Let's take a look at some of the important classes and interfaces from these categories.

Common Classes
  • Subject (javax.security.auth.Subject): Represents a group of related entities, such as people, organizations, or services with a set of security credentials. Once authenticated, a Subject is populated with associated identities, or Principals. The authorization actions will be made based on the Subject.

  • Principal (java.security.Principal): An interface that represents an authenticated entity, such as an individual, organization, service, and so forth.

Authentication Classes
  • LoginContext (javax.security.auth.login.LoginContext): Provides the basic methods to authenticate Subjects. Once the caller has instantiated a LoginContext, the LoginContext invokes the login method to authenticate a Subject. It is also responsible for loading the Configuration and instantiating the appropriate LoginModules.

  • LoginModule (javax.security.auth.spi.LoginModule): This interface is primarily meant for JAAS providers. It allows JAAS providers to implement and plug in authentication mechanisms as login modules. LoginModules are plugged into an application environment to provide a particular type of authentication. In an authentication process, each LoginModule is initialized with a Subject, a CallbackHandler, shared LoginModule state, and LoginModule-specific options. The LoginModule uses the CallbackHandler to communicate with the user. J2SE 1.4 provides a number of LoginModules bundled under the com.sun.security.auth.module package.

  • Configuration (javax.security.auth.login.Configuration): Represents the configuration of LoginModule(s) for use with a particular login application.

  • CallbackHandler (javax.security.auth.callback.CallbackHandler): Defines an interface that allows interaction with a user identity to retrieve authentication-related data such as username/password, biometric samples, smart card-based credentials, and so forth. Applications implement the CallbackHandler and pass it to the LoginContext, which forwards it directly to the underlying LoginModule.

Authorization Classes
  • Policy (java.security.Policy): Represents the system-wide access control policy for authorization based on an authenticated subject.

  • AuthPermission (javax.security.auth.AuthPermission): Encapsulates the basic permissions required for a JAAS authorization and guards the access to the Policy, Subject, LoginContext, and Configuration objects.

  • PrivateCredentialsPermission (javax.security.auth.PrivateCredentialsPermission): Encapsulates the permissions for accessing the private credentials of a Subject.

Understanding the JAAS API Programming Model

To understand the JAAS API programming model and the steps involved, let's take a look at some common JAAS authentication and authorization usage scenarios.

JAAS Authentication

In a JAAS authentication process, the client applications initiate authentication by instantiating a LoginContext object. The LoginContext then communicates with the LoginModule, which performs the actual authentication process. As the LoginContext uses the generic interface provided by a LoginModule, changing authentication providers during runtime becomes simpler without any changes in the LoginContext. A typical LoginModule will prompt for and verify a username and password or interface with authentication providers such as RSA SecureID, smart cards, and biometrics. LoginModules use a CallbackHandler to communicate with the clients to perform user interaction to obtain authentication information and to notify login process and authentication events.

Implementing a JAAS LoginModule

The following programming steps are required for implementing a JAAS LoginModule:

1.

Define a class that represents your LoginModule (for example, MyTestLoginModule). The LoginModule class implements the LoginModule interface (see Example 4-27).

Example 4-27. Implementing a JAAS LoginModule
import javax.security.auth.*;    import javax.security.auth.login.*;       import javax.security.auth.callback.*;       import javax.security.auth.spi.*;    import java.security.*;       import java.io.*;       import java.util.*; public class MyTestLoginModule implements                                LoginModule { Boolean loginVerification = false; Subject  subject;       CallbackHandler CallbackHandler;       Map sharedState;       Map options;       String myName;       String myPassword;       DemoPrincipal myNamePrincipal; ... . // LoginModule methods } 

2.

Implement the LoginModule interface methods:

  • initialize(): The initialize() method initializes the authentication scheme and its state information (see Example 4-28).

    Example 4-28. Implementing a JAAS LoginModuleinitialize() method
    /** Implement the LoginModule initialize() method */     public void         initialize(Subject subject,                     CallbackHandler callbackHandler,                      Map sharedState,                      Map options) {         this.subject = subject;         this.callbackHandler = callbackHandler;         this.sharedState = sharedState;         this.options = options;     } 

  • login(): The login() method performs the actual authentication process. For example, the login() method is responsible for prompting the client for a username and password, and then attempting to verify the password against a password repository. It makes use of callbacks to prompt the client user to provide the username and password information. The login() method (see Example 4-29) returns a Boolean value of true if the requested authentication is successful; if authentication is not successful, it returns false with a LoginExeption such as FailedLoginException.

    Example 4-29. Implementing a JAAS LoginModulelogin() method
            /** Implement LoginModule login() method */          public boolean login() throws LoginException {             boolean loginVerification = false;             try {          // Setup the callbacks to obtain          // user authentication information            Callback myCallback[] = new Callback[2];            myCallback[0] =                  new NameCallback(" Enter Username:" );            myCallback[1] =            new PasswordCallback("Enter Password:", false);          // Invoke the handle() method          // in the Callbackhandler            CallbackHandler.handle(myCallback);           // Get the username and password from the callback           // populate them            myName = ((NameCallback) myCallback[0]).getName();            myPassword              = new String ((PasswordCallback)                             myCallback[1]).getPassword());        // Perform a simple verification              If (( myName.equals("ramesh"))                       && (myPassword.equals("javaguy"))) {                     loginVerification = true;                 }               else {                     loginVerification = false;                }              }  catch (Exception e) {                    throw new LoginException("Login failed")               }           } 

  • commit(): If the user is successfully authenticated (see Example 4-30), the commit() method adds the Principal from the corresponding authentication state information and populates the Subject with the Principal. If the authentication fails, the commit() method returns false and destroys the authentication state information.

    Example 4-30. Implementing a JAAS LoginModulecommit() method
      /** Implement LoginModule commit() method */     public boolean commit() throws LoginException {    if (loginVerification) {        // Add Principal to the Subject         myNamePrincipal = new DemoPrincipal();         myNamePrincipal = setName(myName);         subject.getPrincipals().add(myNamePrincipal);       }         myName = null;         myPassword = null;        return loginVerification;    } 

  • abort(): If the authentication fails, the abort() method exits the LoginModule and cleans up all the corresponding user state information (see Example 4-31).

    Example 4-31. Implementing a JAAS LoginModuleabort() method
      /** Implement LoginModule abort() method */     public boolean abort() throws LoginException {     boolean myReturnValue = false;    if (!(loginVerification)) {        // Clear out all state information         myName = null;         myPassword = null;         loginVerification = false;    }     else { subject.getPrincipals().remove(myNamePrincipal); myName = null; myPassword = null; myReturnValue = true; } return myReturnValue;        } 

  • logout(): The logout() clears the subject and cleans up all Principal settings of the subject in the LoginModule. It returns true if the logout() process succeeds (see Example 4-32).

    Example 4-32. Implementing a JAAS LoginModulelogout() method
    /** Implement LoginModule logout() method */     public boolean logout() throws LoginException {     boolean myReturnValue = false;    // Clear all    if (loginVerification) { subject.getPrincipals().remove(myNamePrincipal); myName = null; myPassword = null; myReturnValue = false; } return true;        } } // End of LoginModule 

Configuring JAAS LoginModule Providers

JAAS LoginModules are configured in the java.security properties file, which is located in the <java.home>/jre/lib/security directory. To configure JAAS LoginModules in a J2SE environment, the following security properties are required:

  • Authentication configuration Properties

    login.configuration.provider login.config.url.n 

    The login.configuration.provider identifies the JAAS LoginModule provider, and the login.config.url.n identifies the JAAS LoginModule configuration file.

For example (see Example 4-33), the JAAS provider can be represented in the java.security properties.

Example 4-33. Configuring a JAAS Provider in java.security properties
login.configuration.provider=com.csp.JAASprovider login.config.url.1=/export/home/my-jaas.conf 

To enable the JAAS LoginModule at runtime, the JAAS configuration file can also be specified as Java command-line options (see Example 4-34).

Example 4-34. Enabling a JAAS Provider as Java runtime options
java  -Djava.security.auth.login.config==/export/home/my-jaas.conf Myapplication 

Configuring JAAS LoginModule for an application

The JAAS LoginModules are configured with an application using a JAAS configuration file (e.g., my-jaas.conf), which identifies one or more JAAS LoginModules intended for authentication. Each entry in the configuration file is identified by an application name, and contains a list of LoginModules configured for that application. Each LoginModule is specified via its fully qualified class name and an authentication Flag value that controls the overall authentication behavior. The authentication process proceeds down the specified list of entries in the configuration file. The following is the list of authentication flag values:

  • Required: Defines that the associated login module must succeed with authentication. Even if it succeeds or fails, the authentication still continues to proceed down the LoginModule list.

  • Requisite: Defines that the associated login module must succeed for the overall authentication to be considered as successful. If it succeeds, the authentication still continues to proceed down the LoginModule list; otherwise, it terminates authentication and returns to the application.

  • Sufficient: Defines the associated login module's successful authentication sufficient for the overall authentication. If the authentication is successful, the control is returned back to the application and it is not required to proceed down the LoginModule list. If the authentication fails, then the authentication still continues down the list of other login modules.

  • Optional: Defines that the associated login module authentication is not required to succeed. Even if the authentication succeeds or fails, the authentication still continues down the list of other login modules.

If the Sufficient flag value is not specified, the overall authentication succeeds only if all Required and Requisite LoginModules are successful. If no Required or Requisite LoginModules are specified, then at least one Sufficient or Optional LoginModule must succeed. In addition to flags, you can also specify module-specific options as name-value pairs that can be passed directly to the underlying LoginModules.

Example 4-35 shows an example configuration file based on the preceding syntax.

Example 4-35. JAAS Authentication configuration file
BiometricLogin {    com.csp.jaasmodule.BioLoginModule sufficient;    com.csp.jaasmodule.JavaCardLoginModule                               required matchOnCard="true"; }; 

The preceding example specifies that an application named BiometricLogin requires users to first authenticate using the com.csp.jaasmodule.BioLoginModule, which is required to succeed. Even if the BioLoginModule authentication fails, the com.csp.jaasmodule.JavaCardLoginModule still gets invoked. This helps hide the source of failure during authentication. Also note that the LoginModule-specific option, matchOnCache="true" is passed to the JavaCardLoginModule as a custom attribute required for processing.

Implementing JAAS Authentication in a Client

To implement JAAS-based authentication in a client application, the following steps are required:

1.

The client application instantiates a LoginContext.

2.

The LoginContext loads the LoginModule(s) specified in the JAAS Configuration file.

3.

The client application invokes the LoginContext's login() method. The login() method calls the loaded LoginModule and then attempts to authenticate the Subject. Upon success, the LoginModule associates the initiating client credentials (such as username/password or tokens) with the Subject.

4.

Finally, the LoginContext returns the authentication status to the application. If the authentication succeeds, the application retrieves the authenticated Subject from the LoginContext.

Let's walk through the steps for building a client using JAAS authentication when a username and password are required to grant access to an application.

  • Create a LoginContext: To instantiate a new LoginContext, a JAAS configuration file is required. The JAAS configuration file specifies the class that implements the authentication mechanisms and has a reference to its CallbackHandler. The LoginContext instantiates the configured LoginModule (see Example 4-36, MyTestLoginModule) and initializes it with this new Subject and a CallbackHandler (in our example, MyTestCallbackHandler).

    Example 4-36. Creating the JAAS LoginContext
       LoginContext loginContext = null;          try {           loginContext              = new LoginContext("MyTestLoginModule",                               new MyTestCallbackHandler());        } catch (LoginException le) {             System.err.println("Cannot create                           LoginContext. " + le.getMessage());             System.exit(-1);         } catch (SecurityException se) {             System.err.println("Cannot create LoginContext. "                 + se.getMessage());             System.exit(-1);         } 

    The following JAAS configuration file MyTestLoginModule.conf specifies the authentication module MyTestLoginModule from the com.csp.jaasmodule package that implements the authentication mechanisms.

       MyTestLoginApp {        com.csp.jaasmodule.MyTestLoginModule required;   }; 

  • Logging In: After instantiating the LoginContext, the login process is performed by invoking the login() method (see Example 4-37).

    Example 4-37. Invoking the login() method
    try {       loginContext.login();      } catch (LoginException le) {         System.err.println("Authentication failed:");         System.err.println("  " + le.getMessage());  } 

    The LoginContext's login method calls methods in the MyTestLoginModule to perform the login and authentication.

  • Implement the CallbackHandler: The LoginModule invokes a CallbackHandler to perform the user interaction and to obtain the authentication credentials (such as username/password, smart-card tokens). In the following example (see Example 4-38), the MyTestLoginModule utilizes the handle() method of TextCallbackHandler to obtain the username and password. The MyTestLoginModule passes the CallbackHandler handle() method with an array of appropriate Callbacks such as NameCallback for the username and a PasswordCallback for the password, which allows the CallbackHandler to perform the client interaction for authentication data and then set appropriate values in the Callbacks.

    Example 4-38. Implementing the Callbackhandler handle() method
    public void handle(Callback[] callbacks)     throws IOException, UnsupportedCallbackException {    for (int i = 0; i < callbacks.length; i++) {      if (callbacks[i] instanceof TextOutputCallback) {     // Display the message according     // to the specified type          //..     }   } else if (callbacks[i] instanceof NameCallback) {     // prompt the user for a User Name     NameCallback nc = (NameCallback)callbacks[i];     System.err.print(nc.getPrompt());     System.err.flush();     nc.setName((new BufferedReader        (new InputStreamReader(System.in))).readLine());      } else if (callbacks[i] instanceof                                 PasswordCallback) {         // prompt the user for Password information         PasswordCallback pc                    = (PasswordCallback)callbacks[i];         System.err.print(pc.getPrompt());         System.err.flush();         // Uses readPassword method         pc.setPassword(readPassword(System.in));      } else {         throw new UnsupportedCallbackException            (callbacks[i], " Callback Unrecognized ");           }      } } 

    The MyTestLoginModule then authenticates the user by verifying the user inputs. If authentication is successful, MyTestLoginModule populates the Subject with a Principal representing the user. The calling application can retrieve the authenticated Subject by calling the LoginContext's getSubject method.

  • Logging Out: It is always good practice to log out the user as soon as the user-specific actions have been performed, or at least before exiting the application. To perform logout, invoke the logout() method in the LoginContext. The logout() method of the LoginContext calls the logout() method of the login module being used. (see Example 4-39).

    Example 4-39. Invoking the logout() method
    try {    loginContext.logout(); } catch (LoginException e) {     System.out.println(e.getMessage()); } 

To run the client application, it is necessary to specify the login module configuration with the following:

-Djava.security.auth.login.config==MyTestLoginModule.conf 

This option can be set as a command-line option or a system property. For authorization policies, it is necessary to specify a policy file that defines a security policy. For example:

java -Djava.security.auth.login.config==MyTestLoginModule.conf     -Djava.security.policy==security.policy                             MyTestAuthenticationClient 

JAAS Authorization

JAAS authorization enhances the Java security model by adding user, group, and role-based access control mechanisms. It allows setting user and operational level privileges for enforcing access control on who is executing the code.

When a Subject is created as a result of an authentication process, the Subject represents an authenticated entity. A Subject usually contains a set of Principals, where each Principal represents a caller of an application. Permissions are granted using the policy for selective Principals. Once the user logged in is authenticated, the application associates the Subject with the Principal based on the user's access control context.

Implementing JAAS Authorization

To implement JAAS-based client authorization, the following is required:

  • The caller must be successfully authenticated with a Subject.

  • A policy file has to be configured with Principal-based entries and allowed permissions.

  • The caller's Subject must be associated with the current access control object.

Now, let's walk through the steps involved in implementing authorization.

  • Configuring a Principal-based policy file: The JAAS Principal-based policy file provides grant statements to include one or more Principal fields. Adding Principal fields in the policy file defines the user or entities with designated permissions to execute the specific application code or other privileges associated with the application or resources. The basic format of a grant statement (see Example 4-40) is as follows.

    Example 4-40. JAAS authorization policy filegrant statement
    grant <signer(s) field>, <codeBase URL>   <Principal field(s)> {      permission class_name "target_name", "action1";       ....      permission class_name "target_name", "action2";   }; 

    The signer field usually defines the application codebase and is followed by a codebase location. The Principal field defines the Principal_class defined by the authentication module and the associated user name. If multiple Principal fields are provided, then the Permissions in that grant statement are granted only if the Subject associated with the current access control context contains all of those as authenticated Principals. To grant the same set of Permissions to multiple Principals, create multiple grant statements listing all the permissions and containing a single Principal field designating one of the Principals. Example 4-41 is a sample JAAS Principal-based policy file defining the access control policies.

    Example 4-41. Sample JAAS authorization policy file
    grant codebase "file:/export/rn/MyTestLoginModule.jar" {     permission javax.security.auth.AuthPermission                                     "modifyPrincipals"; }; grant codebase "file:/export/rn/MyTestAction.jar" {    permission javax.security.auth.AuthPermission                                   "MyTestAction.class";    permission javax.security.auth.AuthPermission                                   "doAsPrivileged"; }; /** User-Based Access Control Policy grant   codebase "file:/export/rn/MyTestAction.jar",       Principal sample.principal.SamplePrincipal                                         "testUser" {   permission java.util.PropertyPermission "java.home",                                                 "read";   permission java.util.PropertyPermission "user.home",                                                 "read";   permission java.io.FilePermission "cspaction.txt",                                                 "read"; }; 

  • Associating the Subject with access control: To associate a Subject with the access control context (see Example 4-42), we need to authenticate the user with JAAS authentication.

   Subject mySubject = loginContext.getSubject(); 

Example 4-42 will find out the Principals part of the authenticated Subject.

Example 4-42. Obtaining the user principal information from the subject
 Iterator principalIterator            = mySubject.getPrincipals().iterator();  System.out.println("Authenticated user                                 has Principals:");  while (principalIterator.hasNext()) {      Principal p = (Principal)principalIterator.next();      System.out.println("\t" + p.toString());   } 

Then we can call the doAs() method available in the Subject class, passing the authenticated subject and either a java.security.PrivilegedAction or java.security. PrivilegedExceptionAction object. The doAs() method associates the Subject with the current access control context and invokes the run() method from the action, which contains all the necessary code to be executed. The doAsPrivileged() method from the Subject class can be called instead of the doAs() method, with the AccessControlContext as an additional parameter. This enables the Subject to associate with only the AccessControlContext provided.

Example 4-43. Using doAs() and doAsPrivileged()
  // Authorize the execution of TestAction   //as the authenticated Subject     PrivilegedAction action = new MyTestAction();     Subject.doAs(mySubject, action);     // To associate with an AccessControlContext     //   Subject.doAsPrivileged(mySubject, action,                                 accessControlContext); 

Example 4-44 is sample code for the PrivilegedAction to be executed after associating the Subject with the current access control context. Upon successful authentication, the action defined in the MyTestAction class will be executed based on the user access privileges defined in the policy file providing grant permissions.

Example 4-44. MyTestAction.java
  import java.security.PrivilegedAction;       public class MyTestAction implements                                PrivilegedAction {       public Object run() {       try {         FileOutputStream fos                = new FileOutputStream("cspaction.txt");         fos.write("Java Rules");         fos.close();         } catch (IOException ioe) {        }        }     } 

To run the client application using JAAS-based authentication and authorization, it is necessary to include the CLASSPATH containing the LoginModule and to specify the login module configuration file and JAAS principal-based policy file as command-line options or as system properties (see Example 4-45).

Example 4-45. Representing JAAS authentication and authorization policies
 java    -Djava.security.auth.login.config                                ==MyTestLoginModule.conf    -Djava.security.policy==MyJaasAction.policy                                            MyTestClient 

Single Sign-On (SSO) Using the JAAS Shared State

The JAAS shared state provides sharing of security credentials (such as username/password, shared secrets, and so forth) across multiple authentication modules. This enables SSO access to multiple applications by sharing of security credentials between the LoginModules used for multiple applications. JAAS provides a shared state mechanism that allows a login module to put the authentication credentials into a shared map and then pass it to other login modules defined in the configuration file. In a typical SSO scenario, multiple applications are required to have a unified authentication solution that enables a user to log in once to access multiple applications. In JAAS, to achieve SSO, all corresponding login modules of the applications participating in an SSO must be defined in the JAAS configuration file. The LoginModules can make use of a sharedState parameter specified in the configuration file, which ensures the authentication result of a LoginModule will be shared with other configured login modules. For example, when LoginModules are configured with sharedState, it allows username and password to be shared with multiple LoginModules, thus ensuring the user only enters the password once though authenticating to multiple LoginModules.

In a JAAS client authentication process, the login() method in the LoginContext iterates through the configured list of LoginModules by calling the login() method implemented in each LoginModule. Example 4-46 shows instantiating a LoginModule.

Example 4-46. Initializing the LoginModule with shared state
  // Instantiate  the module    LoginModule loginmodule =   (LoginModule)(Class.forName(moduleName).newInstance());    loginmodule.initialize(subject_,             callbackHandler_, sharedStateMap, options); 

The Subject is populated with principal and credential information by the login module, CallBackHandler is used by the login module for capturing user credential information (such as username/password), sharedStateMap will be used for passing user security information between login modules, and options are additional name/value pairs defined in the configuration file and are meaningful only for that particular login module. The LoginContext determines the authentication result by consulting the configuration file and also combining the returned results of each LoginModule. For example (see Example 4-47), the JAAS configuration file that lists multiple LoginModules will look like the following.

Example 4-47. Setting SharedState attribute in the JAAS configuration file
MyTestLoginModule {        com.csp.jaasmodule.MyPortalLoginModule required;        com.csp.jaasmodule.MyApplicationLoginModule                           required useSharedState=true;   }; 

If the useSharedState attribute is specified, the LoginModule stores and retrieves the username and password from the shared state, using javax.security.auth.login.name and javax.security.auth.login.password as the respective keys. The retrieved values, such as username and password, can be used again by other listed LoginModules.

So far we have looked at JAAS and how to use its authentication and authorization services. Now, let's explore Java Generic Secure Services (JGSS), which enables uniform access to security services over a variety of underlying authentication mechanisms.




Core Security Patterns. Best Practices and Strategies for J2EE, Web Services, and Identity Management
Core Security Patterns: Best Practices and Strategies for J2EE, Web Services, and Identity Management
ISBN: 0131463071
EAN: 2147483647
Year: 2005
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net