JAAS authentication is done using principal-based access control and pluggable authentication. JAAS can also be used in conjunction with Java Servlets, Java Server Pages (JSPs), and Enterprise Java Beans (EJBs). The authentication part of JAAS provides the capability to reliably and securely maintain client identity. Understanding principal-based access controlJava 2 provides the ability to load the SecurityManager to enforce access to system resources. When JAAS is loaded, the SecurityManager should also be loaded for privileged actions. To use the SecurityManager , a policy file must be maintained , which follows the format of all policy files that use the Java 2 SecurityManager . The SecurityManager enforces the permissions based on the principal entries. Each permission entry protects a defined system resource. A permission set is called a grant entry. There could be many grant entries in a file or just one. When there are several grant entries in a file, there must be another defining entry, such as principal, codebase , or signed by, that gives a grant entry its uniqueness so that the SecurityManager can uniquely define several grant entries in the same policy file. Because the grant entry defines the principal, either explicitly or implicitly, to protect system resources, this form of access control is called Principal-Based Access Control. Before accessing a resource, the principal of the resource must be defined. The principal must be authenticated to guarantee its authenticity. Authentication is the matching of the principal with its associated credentials through the authentication mechanism to validate the principal's authenticity.
Sun is the service provider for these authentication modules. A service provider is any organization that distributes the authentication module that supports the JAAS API. After the principals and credentials have been authenticated through an authentication mechanism, through an encapsulating class called the subject , the JAAS can process the authorization. The principal can be a person, service, process, or group . When the subject is being authenticated, it is populated with Principal classes . The subject can have a collection of principals. The principal is a set of identities that separates it from other subjects. The Principal-Based Access Control defines access to a resource based on the policy file's principals. Only authorized principals can access the resources. To explicitly define the principal for the grant access, the principal follows the grant entry. The principal can take on many principal naming forms, such as Kerberos names, X.500 names, Solaris names, and Windows NT names . Different forms of the principal are needed to format the principal for particular authentication mechanisms. For example, the X.500 name is used when the principal is used with digital certificates. Listing 19-1 is an example of a grant entry. The grant entry, in this case, is a non-principal example that implicitly allows all principals and updates code from http://richware.com. This code is signed by the user rich for all principals to access ( read ) the resource (the cdrom ). Notice the use of the grant Codebase element instead of grant Principal element in the policy file. The user rich must be in the local keystore to verify the signature of the files in Listing 19-1. Listing 19-1: Grant entry // Java 2 codesource-based policy grant Codebase "http://richware.com", Signedby "rich" { permission java.io.FilePermission "/cdrom/-", "read"; }
Listing 19-2 shows a policy file that specifies a principal using JAAS. Listing 19-2: Grant entry with principal // Java 2 codesource-based policy grant Principal com.sun.security.auth.UnixPrincipal "rich" { permission java.io.FilePermission "/cdrom/-", "read"; } In this example, only a user associated with the UnixPrincipal principal type and associated with the name rich can have access to the cdrom . The com.sun.security.auth.UnixPrincipal is a Sun principal for a UNIX user. Recall that a subject is the source of the request to a resource, and that it is authenticated before it is authorized. A subject may have security- related attributes known as credentials . Credentials are security attributes that can be shared among subjects. An example of a credential is a public key that some subjects may share that is used to validate their principals. One of the easiest ways to execute the subject is to use the static method doAs , which associates a method with a javax.security.auth.Subject class. Listing 19-3 shows how the doAs method is used for access control. Listing 19-3: The doAs method class ExampleAction implements java.security.PrivilegedAction { public Object run() { java.io.File f = new java.io.File("/cdrom/-"); // the following call invokes a security check if (f.exists()) { System.out.println("cdrom exists"); } return null; } } public class Example1 { public static void main(String[] args) { // Authenticate the subject, "rich". // This process is described in the // LoginContext section. Subject rich; .... // perform "ExampleAction" as "rich" Subject.doAs(rich, new ExampleAction()); } The code in Listing 19-3 checks whether it can read the cdrom as the user rich . The line cdrom exists is printed out if the user rich is authenticated using the UNIX principal and is authorized with the permission set in a policy file in Listing 19-2. Understanding the Pluggable Authentication Module standardMany types of authentication mechanisms are available that organizations can implement. Some may be proprietary, and others may be standards such as RSA, Kerberos, and smart cards. JAAS was built with the idea of it being able to plug in to different authentication and keying mechanisms. The Pluggable Authentication Module (PAM) framework is a plug-and-play technology for using authentication mechanisms. Because many different technologies can be used to enter a system, new versions of authentication mechanisms are updated to an organization's authentication system, and new authentication modules are added inline for security enhancements. PAM technology is significant to understanding the pluggable authentication modules of JAAS and how they are configured. Before PAM, most authentication mechanisms were operating-system-specific, proprietary, or could not be changed, such as rlogin in UNIX or Kerberos authentication using a C language Software Development Kit (SDK), where the needed implementation is specific to the authentication mechanism. PAM allows an organization to use multiple, different authentication mechanisms and switch among them without code changes. The system administrator simply plugs in a new authentication module without modifying any coding in the services. The PAM model defines configuration modifications to change authentication mechanisms. The authentication mechanisms are pluggable in PAM, so the methods calling the authentication mechanisms must also become pluggable in order for the mechanisms to be dynamic. For instance, if the authentication mechanism is switched to Kerberos, the user's password and username should remain the same as it was before the switch of technology. In reality, there might be many authentication mechanisms throughout the underlying system that are hidden from the user, which perform the principals and credentials transformation. An extra authentication layer may be needed, for example, to provide the administration of permissions to access system resources. These resources, for instance, can be databases and property files. Some legacy systems have passwords that may be hard coded into the system. Making passwords and usernames static throughout a system creates a security risk and destroys the capability to change passwords dynamically. These passwords can be observed if an attacker of the system has the ability to desource the source code into readable form. PAM helps alleviate these issues and the gives the capability to layer authentications and allows a pluggable model to dynamically enhance a system. However, PAM does not address all the authentication issues, such as the single-sign-on problem of securely transferring the identity of the caller to a remote site. This issue arises when a user of an e-commerce system logs in once and its credentials are distributed throughout the system. The organization needs to distribute the credentials through an enterprise system using a form of delegation. What PAM does provide is the capability for the system administrator to install multiple authentication protocols for each application. PAM allows users to be authenticated from multiple protocols without retyping the password. The architecture provides a pluggable model for system authentication and related tasks such as password, account, and session management.
Figure 19-1 shows the PAM architecture and the pam.config file that is used to store and configure the authentication modules. The example shows the ftp, telnet, and login applications using Kerberos, UNIX authentication, and S/Key authentication mechanisms. There are four possible attributes in PAM that can be configured independently: authentication, password, session, and account. Figure 19-1: The Pluggable Authentication Module For instance, the system administrator may add a Kerberos and password module and reuse the same session and account modules. Just as PAM uses a configuration file to plug in different login modules, JAAS uses a policy file to specify the modules and permissions. Other classes that assist in using the authentication and authorization are the javax.security.auth.login.LoginContext and javax.security.auth.spi.LoginModule classes. Implementing the LoginContext and LoginModuleAs mentioned earlier, PAM provides the pluggable interface standard. PAM provides the underlying layer for pluggable authentication. That means that PAM is a separate protocol from JAAS; it is not a requirement that PAM be written in the Java language. In JAAS, the LoginContext class and LoginModule class represent the Java implementation of the PAM framework. The LoginContext class uses a configuration file, for which modules are configured to determine the LoginModule . A LoginModule can best be described as a wrapper around an authentication service provider such as Kerberos. JAAS client applications write to the LoginContext API, while authentication service providers implement the LoginModule interface. It is this LoginModule implementation that the configuration file calls to be used with the LoginContext so that multiple LoginModules can be plugged under the same application without modifications to the application. Only the configuration file needs to be changed. Listing 19-4 shows the LoginContext class and the LoginModule interface. Listing 19-4: The LoginContext class public final class LoginContext { public LoginContext(String name) { } public void login() { } // two phase process public void logout() { } public Subject getSubject() { } // get the authenticated } public interface LoginModule { public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options); boolean login(); // 1st authentication phase boolean commit(); // 2nd authentication phase boolean abort(); boolean logout(); } The LoginContext is responsible for reading the configuration file and installing the correct LoginModules . Each LoginContext has a subject that represents the subject currently being authenticated and is updated with the proper credentials if the authentication succeeds. For logging in, the LoginContext 's login method is invoked, which in turn invokes the appropriate LoginModule 's login method. The login method is dependent on which login modules the configuration loads. The login method executes the appropriate login procedure, such as adding principals and credentials to the subject and checking the password and principal. For logging out, the LoginContext 's logout method is invoked, which in turn invokes the LoginModule 's logout method. This logout method is executed from the LoginModule class that performs the logout procedure, such as removing principals and credentials from a subject and invalidating the login session. The login modules include many variations such as NTLoginModule , KeyStoreLoginModule, Krb5LoginModule, UnixLoginModule , and JNDILoginModule in the com.sun.security.auth.module package. The LoginContext class is an API that applications interface with to provide authentication. This authentication implements the LoginModule interface. Service providers that are technology vendors , such as Sun, provide many login modules. The modules are initialized based on the javax.security.auth.login.Configuration class that retrieves information from a configuration file. The configuration file in Listing 19-5 shows that the UnixLoginModule is always used, and the Krb5LoginModule is provided when a ticket is present. Listing 19-5: The login configuration file Login { com.sun.security.auth.module.UnixLoginModule required; com.sun.security.auth.module.Krb5LoginModule optional useTicketCache="true" ticketCache="${user.home}${/}tickets"; }; Not only does this technology provide pluggable authentication, but it also supports the notion of stacked authentication . This means that a single LoginContext can use multiple LoginModules in an authentication chain. In the Listing 19-5, the LoginContext could use both UNIX and Kerberos. The javax.security.auth.login.Configuration interface is used to read this configuration file and pass the specifics to the LoginContext . The Configuration interface uses an array of javax.security.auth.login.AppConfigurationEntry classes. In Listing 19-5, the AppConfigurationEntry contains two entries, one for the UnixLoginModule and one for the Krb5LoginModule . The AppConfigurationEntry array loads the LoginModules in the Configuration class. The javax.security.auth.login.ConfigFile is the default implementation of the Configuration interfaces. The ConfigFile interface looks for the java.security.auth.login.config= or java.security.auth.login.config== from the system properties. If the java.security.auth.login.config== is defined as the system property, then the ConfigFile ignores all other configuration files except for the one defined with this property. If the java.security.auth.login.config= is defined, other configuration files may still be used in conjunction. Listing 19-6 demonstrates defining the ConfigFile to read the configuration files and the configuration files defined by the login.config.url.1 that are URLs given sequentially. The excerpt is from the $[JRELIB] /security/java.security file. The ConfigFile loops through the sequence of login URLs and loads up the defined login files in these login configurations from the login.config.url.X entries. Listing 19-6: Defining the ConfigFile for reading login configurations # # Class to instantiate as the javax.security.auth.login.Configuration # provider. # login.configuration.provider=com.sun.security.auth.login.ConfigFile # # Default login configuration file # #login.config.url.1=file:${user.home}/.java.login.config Using the configuration file in this manner allows the login modules to be updated and changed without any modifications to the code itself. When a JAAS application is initialized, the login configuration file is defined using the java.security.auth.login.config system property. The entry in the login configuration for the login modules is defined when creating the LoginContext . The LoginContext loads the login modules when it is constructed through an internal init method, but it interfaces to the login modules directly through the javax.security.auth.callback.CallbackHandler interface. Listing 19-7 demonstrates the runtime definitions when running the JAAS application, and Listing 19-8 demonstrates JAAS application code. Listing 19-7: Runtime definitions java -Djava.security.manager - Djava.security.auth.login.config=jaas.config - Djava.security.policy=jaasapp.policy com.richware.chap19.JAASApp Listing 19-8: The JAASApp class: A JAAS application package com.richware.chap19; import java.security.*; import java.util.*; import javax.security.auth.*; import javax.security.auth.login.*; /** * Class JAASApp * Description: This is a Sample JAAS application * * Copyright: Copyright (c) 2002 Wiley Publishing, Inc. * @author Rich Helton <rhelton@richware.com> * @version 1.0 * DISCLAIMER: Please refer to the disclaimer at the beginning of this book. */ public class JAASApp { /** * Method main * Description: This is a Sample JAAS application * An example of running * java -Djava.security.manager * -Djava.security.auth.login.config =jaas.config * -Djava.security.policy=jaasapp.policy * * @param args none * */ public static void main(String[] args) { LoginContext loginContext = null; try { loginContext = new LoginContext("RichJAAS", new RichCallbackHandler()); loginContext.login(); System.out.println("\nLogin succeeded"); } catch (LoginException le) { le.printStackTrace(); System.out.println("\nLogin failed"); } try { // Now we're logged in, so we can get the current subject. Subject subject = loginContext.getSubject(); // Perform the example action as the authenticated subject. subject.doAs(subject, new JAASAction()); } catch (Exception ex) { ex.printStackTrace(); } } } The LoginContext initializes the LoginModules based on the entry in the configuration file and the type of CallbackHandler . If the CallbackHandler is not used, the parameters for the login module need to be defined in the login configuration file. Listing 19-9 shows the login configuration file for the JAAS application example. Listing 19-9: The JAAS login configuration RichJAAS { com.sun.security.auth.module.KeyStoreLoginModule required keyStoreURL="file:///C:/.keystore"; }; The RichJAAS entry is defined in the JAAS application's LoginContext when created. The RichCallbackHandler is an implementation of the CallbackHandler interface for the login module to get the input information for username, passwords, any text, and confirmations . The LoginContext could also pass in the username and password through the CallbackHandler to be grabbed by the login module at a later time. Listing 19-10 shows the RichCallbackHandler class. Listing 19-10: The RichCallbackHandler class: An example of runtime definitions package com.richware.chap19; import java.io.*; import java.security.*; import javax.security.auth.*; import javax.security.auth.callback.*; /** * Class RichCallbackHandler * Description: This is a Sample Callback Handler * * Copyright: Copyright (c) 2002 Wiley Publishing, Inc. * @author Rich Helton <rhelton@richware.com> * @version 1.0 * DISCLAIMER: Please refer to the disclaimer at the beginning of this book. */ public class RichCallbackHandler implements CallbackHandler { /** * Constructor RichCallbackHandler */ public RichCallbackHandler() {} /** * Method handle * Description: Retrieve or display the information requested in the * provided Callbacks. * * * @param callbacks - an array of Callback objects provided by an underlying * security service which contains the information requested to be retrieved * or displayed. * @throws IOException - if an input or output error occurs. * @throws UnsupportedCallbackException - if the implementation of this * method does not support one or more of the Callbacks specified in the * callbacks parameter. * */ 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 */ TextOutputCallback toc = (TextOutputCallback) callbacks[i]; switch (toc.getMessageType()) { case TextOutputCallback.INFORMATION : System.out.println(toc.getMessage()); break; case TextOutputCallback.ERROR : System.out.println("ERROR: " + toc.getMessage()); break; case TextOutputCallback.WARNING : System.out.println("WARNING: " + toc.getMessage()); break; default : throw new IOException("Unsupported message type: " + toc.getMessageType()); } } else if (callbacks[i] instanceof NameCallback) { // Prompt the user for the username 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 the username */ PasswordCallback pc = (PasswordCallback) callbacks[i]; System.err.print(pc.getPrompt()); System.err.flush(); /* * Note: JAAS specifies that the password is a char[] rather than a String */ String tmpPassword = (new BufferedReader(new InputStreamReader(System .in))).readLine(); int passLen = tmpPassword.length(); char[] password = new char[passLen]; for (int passIdx = 0; passIdx < passLen; passIdx++) { password[passIdx] = tmpPassword.charAt(passIdx); } pc.setPassword(password); } /* * Confirmation callbeack for KeyStore */ else if (callbacks[i] instanceof ConfirmationCallback) { // Prompt the user for the username ConfirmationCallback nc = (ConfirmationCallback) callbacks[i]; } else { throw new UnsupportedCallbackException( callbacks[i], "Unrecognized Callback"); } } } } Using the KeyStore login module, as defined in Listing 19-9, the login module requests information that it needs to log in a user using the RichCallbackHandler . The RichCallbackHandler prompts the user for the information that it requires. Listing 19-11 demonstrates the interaction for the alias richh and rich3 with the callback handler interaction. Listing 19-11: Callback handler interaction >ECHO ENSURE that richjaas.jar and jaasaction.jar are in the CLASSPATH ENSURE that richjaas.jar and jaasaction.jar are in the CLASSPATH >ECHO ENSURE that the keystore file is in the root drive of C:\ ENSURE that the keystore file is in the root drive of C:\ >java -Djava.security.manager - Djava.security.auth.login.config=jaas.config - Djava.security.policy=jaasapp.policy com.richware.chap19.JAASApp Please login to keystore Keystore alias: richh Keystore password: password Private key password (optional): password Login succeeded JAAS has many secrets. There is much to know. In Listing 19-11, the alias richh from the keystore is allowed to log in and access the file secretinfo.txt . The alias rich3 from the keystore receives a java.security.AccessControlException when trying to access the secretinfo.txt file, but is allowed to log in because the alias is listed in the keystore. If the alias were not in the keystore, a javax.security.auth.login.FailedLoginException would occur.
The user richh is allowed to access the resources because the permissions for the common name in the keystore are given access in Listing 19-12. Listing 19-12: The permissions /* AUTOMATICALLY GENERATED ON Sun Feb 03 23:56:54 MST 2002*/ /* DO NOT EDIT */ grant codeBase "file:./richjaas.jar" { permission java.security.AllPermission; }; grant codeBase "file:./jaasaction.jar", principal javax.security.auth.x500.X500Principal "CN=Rich Helton,OU=development,O=richware,L=denver,ST=co,C=us" { permission java.security.AllPermission; }; The policy file in Listing 19-12 is generated with the policytool utility. The security policy is defined at runtime in the system property -Djava.security.policy=jaasapp.policy . The principal is defined to have access to all system resources. The alias richh maps to the principal javax.security.auth.x500.X500Principal entry and allows the permission to all resources. Any other principal does not allow any permission to access any resources in the jaasaction.jar where the JAAS privileged action is defined. The privileged action contains the authorization components of JAAS that are executed by a subject. A subject is the implementation of the javax.security.auth.Subject class. The subject class is created with the associated principals, such as the username or the X500Principal in this example, and any credentials whether they are public or private. Public credentials are public keys such as the password for the user, and private credentials are the private keys such as the private key in the X.509 certificate in the keystore. The subject is created in the login module after a successful login has completed, and it is used by the login context to execute any privileged action using the subject's information. In the examples given so far, the login context uses the getSubject method to retrieve the subject from the login module and executes privileged code with the doAs method. The LoginContext completes a two-phase authentication process in order to create a subject. A two-phase authentication process means that after the login() method is initialized, either a commit() or abort() method is invoked. A commit() method finishes any processing after a valid login, and the abort() method performs cleanup after a login is invalid and the module needs to be returned to an initialized state. Since the LoginModule s are stackable , the LoginContext looks for a valid commit from all the modules to ensure that valid authentication takes place. Also, the higher module doesn't commit until the bottom module commits, so that if an abort happens for the last authentication, the LoginContext aborts the previous modules. After a valid authentication succeeds, the module populates the subject, and the LoginContext can now access the subject with the getSubject() method. This gives the LoginContext a valid subject to use for authorization. If a valid authentication has not succeeded, there is no subject for the LoginContext to use for the next phase of security in authorization. Figure 19-2 shows this class interaction. Figure 19-2: Java Authentication Class interaction
More detail for the CallbackHandler and CallbacksThe JAAS Callback is how information, such as username and password, is passed between the application and LoginModule . The list of Callbacks contains the information, and the CallbackHandler is the mechanism for passing the Callback information. When the LoginModule gets the login method, it requests the login and may request information such as the username and the password, from the CallbackHandler 's handle method that is defined in the login context. The requesting information is dependent on the login module that is defined. For instance, in the KeyStoreLoginModule there was a request for an alias name, a password for the keystore, a password for the alias, and a confirmation. Many other login modules may only require the username and password. The alias name and username were prompted for and sent back in the NameCallback. The passwords were prompted for and returned in the PasswordCallback. Listing 19-13 shows another example to populate the callback list. These callbacks are passed through an array of Callbacks; the array contains the various pieces of information to pass to the application depending on what is required from the LoginModule . Listing 19-13: Populating the callback list /* * Populate callback list */ Callback[] callbacks = new Callback[2]; callbacks[0] = new NameCallback("username: "); callbacks[1] = new PasswordCallback("password: ", false); try { /* * Prompt for username and password */ callbackHandler.handle(callbacks); /* * Retrieve username */ username = ((NameCallback) callbacks[0]).getName(); /* * Retrieve password, converting from char[] to String */ char[] charPassword = ((PasswordCallback) callbacks[1]).getPassword(); if (charPassword == null) { /* * Treat a NULL password as an empty password, not NULL */ charPassword = new char[0]; } password = new String(charPassword); } Following are several callback types that you can use:
More on the configuration file setupThe JAAS login configuration file defines the login modules to be used, and the entries to be used are defined in the creation of the LoginContext objects. The configuration file is defined by the property settings of the system environment in the java.security.auth.login.config definition. The associated login module class defines each login module in the configuration. Listing 19-14 defines an example configuration where two LoginModules are required to be used for the underlying login. This contains a list of login modules used for that application. The authentication proceeds down the list in the exact same order as the modules that have the REQUIRED field set. Listing 19-14: A configuration file example Login{ com.sun.security.auth.SampleLoginModule REQUIRED debug=true; com.sun.security.auth.NTLoginModule REQUIRED debug=true; } There are four flags to define when the associated login module is to be used: They are the REQUIRED , REQUISITE , SUFFICIENT , and OPTIONAL flags.
At least one of the OPTIONAL or SUFFICIENT modules must succeed in order for an authentication to succeed. Java Security Solutions ISBN: 0764549286
EAN: 2147483647 Year: 2001
Pages: 222 Authors: Rich Helton, Johennie Helton
flylib.com © 2008-2017. If you may any questions please contact us: flylib@qtcs.net |