Java Security and JAAS Lab - Dr. Godfrey C. Muganda

10 downloads 112 Views 149KB Size Report
May 19, 2013 ... JAVA SECURITY LAB AND INTRODUCTION TO JAAS ... For example, the following program prints the Operating system name and version,.
JAVA SECURITY LAB AND INTRODUCTION TO JAAS GODFREY MUGANDA

1. Introduction This lab will introduce you to some of the mechanisms that are built into Java Security, and the Java mechanisms available to support authentication and authorization. After doing this lab, you are expected be able to write Java programs that can use a security policy to protect access to file resources and to sockets on the local machine. You are also expected to have an overall understanding of JAAS, the Java Authorization and Authentication Service. You do not have to actually write programs that use the JAAS, but you should understand the role of JAAS main components. Note: Most of this is distilled from Oracle’s documentation and from various websites. No claim is being made as to originality. 2. Java Security Policy Earlier in the term we discussed the importance of establishing a security policy. Indeed, authorization can only be enforced in the context of a known security policy. In Java, a security policy is specified using one or more policy configuration files. The configuration file(s) specify what permissions are allowed for code from a specified code source, and executed by a specified principal. Permissions are specified within a program using Permission objects, which we study later. A principal can be considered to be a subject who has already been authenticated. Each configuration file must be encoded in UTF-8. The default system policy file for the Java Virtual Machine can be found in directories such as C:\Program Files\Java\jre7\lib\security\java.policy C:\Program Files\Java\jdk1.7.0_17\jre\lib\security\java.policy Find one of the default policy files on your system and open it in a text editor. You will find entries such as grant { // allows anyone to listen on un-privileged ports permission java.net.SocketPermission "localhost:1024-", "listen"; // "standard" properties that can be read by anyone permission java.util.PropertyPermission "java.version", "read"; permission java.util.PropertyPermission "java.vendor", "read"; 1

2

permission permission permission permission permission permission permission permission

GODFREY MUGANDA

java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission

"java.vendor.url", "read"; "java.class.version", "read"; "os.name", "read"; "os.version", "read"; "os.arch", "read"; "file.separator", "read"; "path.separator", "read"; "line.separator", "read";

permission java.util.PropertyPermission "java.specification.version", "read"; permission java.util.PropertyPermission "java.specification.vendor", "read"; permission java.util.PropertyPermission "java.specification.name", "read"; permission permission permission permission permission permission };

java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission java.util.PropertyPermission

"java.vm.specification.version", "read"; "java.vm.specification.vendor", "read"; "java.vm.specification.name", "read"; "java.vm.version", "read"; "java.vm.vendor", "read"; "java.vm.name", "read";

Basically, all this policy does it to allow any program running in the Java Virtual Machine to start a server and listen for connections at any socket on the local machine at any port 1024 and above. The security policy also allows any code to read any of the standard system properties. For example, a Java program can find out what operating system it is running under by reading the the os.name and os.version properties. For example, the following program prints the Operating system name and version, and and user home directory of the person running the program. package javaperms; import java.util.Properties; public class JavaPerms { public static void main(String[] args) { Properties props = System.getProperties(); System.out.println(props.get("os.name")); System.out.println(props.get("os.version")); System.out.println(props.get("user.home")); } } Allowing read access to these properties may be appear harmless, however, you may not want to allow an applet running in a web page from an untrusted site to read this information, as an attacker might be able to take advantage of that information to attack your system. Recall that the user home directory is the default place where the keytool utility for creating certificates and public keys places the keystore. It is also the place where you should place your user policy file. A user policy file specifies a security policy for programs run by users.

JAVA SECURITY LAB AND INTRODUCTION TO JAAS

3

3. The Security Properties File When the Policy is initialized, the system policy is loaded in first, and then the user policy is added to it. If neither policy is present, a built-in policy is used. This built-in policy is the same as the java.policy file installed with the JRE. Policy file locations are specified in the security properties file, which is located in the same directory as the security policy file, except its name is java.security Locate this file and open it with a text editor. You will find that it specifies default values for many security parameters, including the location of the policy files policy.provider=sun.security.provider.PolicyFile # The default is to have a single system-wide policy file, # and a policy file in the user’s home directory. policy.url.1=file:${java.home}/lib/security/java.policy policy.url.2=file:${user.home}/.java.policy This entry says that the system and user security files will by default reside in the lib/security subdirectory of the Java home directory and in the user’s home directory, respectively. You can actually specify a number of URLs (including ones of the form "http://"), and all the designated policy files will get loaded. You can also comment out or change the second one to disable reading the default user policy file. The algorithm starts at policy.url.1, and keeps incrementing until it does not find a URL. Thus if you have policy.url.1 and policy.url.3, policy.url.3 will never be read. 4. Specifying an Additional Policy File at Runtime It is also possible to specify an additional or a different policy file when invoking execution of an application. This can be done via the "-Djava.security.policy" command line argument, which sets the value of the java.security.policy property. For example, if you use java -Djava.security.manager -Djava.security.policy=someURL myProg where someURL is a URL specifying the location of a policy file, then the specified policy file will be loaded in addition to all the policy files that are specified in the security properties file. Notes: The URL can be any regular URL or simply the name of a policy file in the current directory, as in java -Djava.security.manager -Djava.security.policy=mypolicy myProg The "-Djava.security.manager" argument ensures that the default security manager is installed, and thus the application is subject to policy checks. If you use java -Djava.security.manager -Djava.security.policy==someURL myProg

4

GODFREY MUGANDA

(note the double equals) then just the specified policy file will be used; all the ones indicated in the security properties file will be ignored. 5. An Example Program We are going to create a file with only a read permission, and then write a program that checks various types of permissions on the file. First, open a command box to your home director, and then type the command policytool This will invoke a took that comes with the JDK to create or edit policy files (you can also edit a policy file using a simple text editor, as long as you use the correct syntax. The policytool provides a GUI tool where you do not have to remember the required syntax. Once the policy tool is open, select Add policy entry. In the ensuing dialog, press the Add New Permission button. This opens up another dialog. See that the fields of this dialog are filled in as follows FilePermission Target Name read

java.File.Permission permsExample1.txt read

and click OK. This takes you back to the Policy Entry dialog: Ignore all the other field and press Done. Finally, go to Files and save the file as permsExample1.policy. Close the policy tool. Now use Windows explorer to open the policy file you have just created in a text editor such as Notepad++. You should see the following contents /* AUTOMATICALLY GENERATED ON Sun May 19 21:00:25 CDT 2013*/ /* DO NOT EDIT */ grant { permission java.io.FilePermission "permsExample1.txt", "read"; }; Next, use a text editor to create the file permsExample1.txt in your home directory with the contents This is a protected file. Next, Fire up Netbeans and write the following program: package javapermsexample1; import java.io.File; public class JavaPermsExample1 { public static void main(String[] args) { File f = new File(args[0]); System.out.println("The name of the file is " + f.getName()); System.out.println("Read permission? " + f.canRead());

JAVA SECURITY LAB AND INTRODUCTION TO JAAS

5

System.out.println("Write permission? " + f.canWrite()); System.out.println("Execute permission? " + f.canExecute()); } } Build the program to create a jar file. Then using Windows explorer, copy the jar file from the dist folder to your home directory, where both the test file and the security policy are. Finally run the program with the command line: C:\Users\Administrator>java -jar -Djava.security.manager -Djava.security.policy=permsExample1.policy JavaPermsExample1.jar permsExample1.txt This command invokes the execution of a jar file that takes a single command-line argument. The results of executing this program are as follows: The name of the file is permsExample1.txt Read permission? true Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "permsExample1.txt" "write") at java.security.AccessControlContext.checkPermission(Unknown Source) at java.security.AccessController.checkPermission(Unknown Source) at java.lang.SecurityManager.checkPermission(Unknown Source) at java.lang.SecurityManager.checkWrite(Unknown Source) at java.io.File.canWrite(Unknown Source) at javapermsexample1.JavaPermsExample1.main(JavaPermsExample1.java:13) Why did this happen? Point Google to java 7 File and look up the methods of the File class. Among them, you will find this entry for the canWrite() method: public boolean canWrite() Tests whether the application can modify the file denoted by this abstract pathname. Returns: true if and only if the file system actually contains a file denoted by this abstract pathname and the application is allowed to write to the file; false otherwise. Throws: SecurityException - If a security manager exists and its SecurityManager.checkWrite(java.lang.String) method denies write access to the file. This is consistent with what we expected from a file that has read permission but not write permission.

6. Modifying the Security Policy Now open the policy tool, and use the file menu to open the security file. Using the mouse, select the only policy entry in the file, which is the one that reads CodeBase

6

GODFREY MUGANDA

and then click the Edit Policy Entry button. Select the only permission there, and then click Edit Permission. Use the last drop-down list on the left to add the write permission. Click Ok, then Done, and then Save on the File menu. Open the policy file with Notepad ++ and verify that the file permissions for the file have been changed: grant { permission java.io.FilePermission "permsExample1.txt", "read, write"; }; Now run the program again, using the same command as before. Note that this time, the read and write permissions are granted, but the execute permission fails. 7. Guard public interface Guard This interface represents a guard, which is an object that is used to protect access to another object. This interface contains a single method, checkGuard, with a single object argument. checkGuard is invoked (by the GuardedObject getObject method) to determine whether or not to allow access to the object. Has a single method void checkGuard(Object object) throws SecurityException which determines whether or not to allow access to the guarded object object. Returns silently if access is allowed. Otherwise, throws a SecurityException. The Guard interface is implemented by various subclasses of the Permission class. 8. Permission Permission Abstract class for representing access to a system resource. All permissions have a name (whose interpretation depends on the subclass), as well as abstract functions for defining the semantics of the particular Permission subclass. Most Permission objects also include an “actions” list that tells the actions that are permitted for the object. For example, for a java.io.FilePermission object, the permission name is the pathname of a file (or directory), and the actions list (such as “read, write”) specifies which actions are granted for the specified file (or for files in the specified directory). The actions list is optional for Permission objects, such as java.lang.RuntimePermission, that don’t need such a list; you either have the named permission (such as “system.exit”) or you don’t. An important method that must be implemented by each subclass is the implies method to compare Permissions. Basically, “permission p1 implies permission p2” means that if one is granted permission p1, one is naturally granted permission p2. Thus, this is not an equality test, but rather more of a subset test. Permission objects are similar to String objects in that they are immutable once they have been created. Subclasses should not provide methods that can change the state of a permission once it has been created.

JAVA SECURITY LAB AND INTRODUCTION TO JAAS

7

Methods are (1) Permission(String name) Constructs a permission with the specified name. (2) void checkGuard(Object object) Implements the guard interface for a permission. (3) public abstract String getActions() Returns the actions as a String. This is abstract so subclasses can defer creating a String representation until one is needed. Subclasses should always return actions in what they consider to be their canonical form. For example, two FilePermission objects created via the following: perm1 = new FilePermission(p1,"read,write"); perm2 = new FilePermission(p2,"write,read"); both return ”read,write” when the getActions method is invoked. (4) public abstract boolean implies(Permission permission) Checks if the specified permission’s actions are ”implied by” this object’s actions. This must be implemented by subclasses of Permission, as they are the only ones that can impose semantics on a Permission object. The implies method is used by the AccessController to determine whether or not a requested permission is implied by another permission that is known to be valid in the current execution context

9. FilePermission public final class FilePermission extends Permission This class represents access to a file or directory. A FilePermission consists of a pathname and a set of actions valid for that pathname. Pathname is the pathname of the file or directory granted the specified actions. A pathname that ends in "/*" (where "/" is the file separator character, File.separatorChar) indicates all the files and directories contained in that directory. A pathname that ends with "/-" indicates (recursively) all files and subdirectories contained in that directory. A pathname consisting of the special token ” matches any file. Note: A pathname consisting of a single "*" indicates all the files in the current directory, while a pathname consisting of a single "-" indicates all the files in the current directory and (recursively) all files and subdirectories contained in the current directory. The actions to be granted are passed to the constructor in a string containing a list of one or more comma-separated keywords. The possible keywords are “read”, “write”, “execute”, “delete”, and “readlink”. Their meaning is defined as follows: (1) read read permission (2) write write permission (3) execute execute permission. Allows Runtime.exec to be called. Corresponds to SecurityManager.checkExec. (4) delete delete permission. Allows File.delete to be called. Corresponds to SecurityManager.checkDelete. The actions string is converted to lowercase before processing. Be careful when granting FilePermissions. Think about the implications of granting read and especially write access to various files and directories.

8

GODFREY MUGANDA

Please note: Code can always read a file from the same directory it’s in (or a subdirectory of that directory); it does not need explicit permission to do so. 10. SocketPermission Actions for SocketPermission are accept connect listen resolve The ”listen” action is only meaningful when used with ”localhost”. The ”resolve” action is implied when any of the other actions are present. The action ”resolve” refers to host/ip name service lookups. The actions string is converted to lowercase before processing. As an example of the creation and meaning of SocketPermissions, note that if the following permission: p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept"); is granted to some code, it allows that code to connect to port 7777 on puffin.eng.sun.com, and to accept connections on that port. Similarly, if the following permission: p2 = new SocketPermission("localhost:1024-", "accept,connect,listen"); is granted to some code, it allows that code to accept connections on, connect to, or listen on any port between 1024 and 65535 on the local host. 11. Pluggable Aunthentication Module A pluggable authentication module (PAM) is a mechanism to integrate multiple lowlevel authentication schemes into a high-level application programming interface (API). It allows programs that rely on authentication to be written independently of the underlying authentication scheme. So PAM is a way of accessing different implementations of authentication schemes through a single interface. JAAS is Java’s implementation of PAM. 12. Introduction to JAAS We now look at JAAS. JAAS is fairly complicated, and we will not have enough time to explore the writing of programs that use it. I have assembled the following information to provide an overview of the service. You need to have an overall understanding of the following classes and interfaces, and be able to explain how they work together to authenticate a subject. (1) (2) (3) (4) (5)

Subject Principal LoginContext LoginModule Configuration

JAVA SECURITY LAB AND INTRODUCTION TO JAAS

9

The following is largely taken from the Oracle website, but is sequenced to make it easier to assimilate the information and get the big picture. The notes are not polished: If I manage to improve them before the term is over, I will post a new version and send the class an email. However, all you need to know for the final exam is here, so don’t wait. We will start with the following two classes: (1) Subject (javax.security.auth.Subject) (2) Principal (java.security.Principal) 13. Principal Let us start with Principal. This interface represents the abstract notion of a principal, which can be used to represent any entity, such as an individual, a corporation, and a login id. Has a method (1) String getName() Returns the name of this principal. A principal is like an identity. 14. Subject A Subject represents a grouping of related information for a single entity, such as a person. Such information includes the Subject’s identities as well as its securityrelated attributes (passwords and cryptographic keys, for example). Subjects may potentially have multiple identities. Each identity is represented as a Principal within the Subject. Principals simply bind names to a Subject. For example, a Subject that happens to be a person, Alice, might have two Principals: one which binds "Alice Bar", the name on her driver license, to the Subject, and another which binds, "999-99-9999", the number on her student identification card, to the Subject. Both Principals refer to the same Subject even though each has a different name. A Subject may also own security-related attributes, which are referred to as credentials. Sensitive credentials that require special protection, such as private cryptographic keys, are stored within a private credential Set. Credentials intended to be shared, such as public key certificates or Kerberos server tickets are stored within a public credential Set. Different permissions are required to access and modify the different credential Sets. So a principal is like a login name, and a subject is like a person? Note that the only “useful” method in a Principal is a name, but a Subject has credentials that can be used to authenticate the subject. So a principal is like an identity. Here are some Subject methods (1) Set getPrincipals() Return the Set of Principals associated with this Subject. (2) Set getPrincipals(Class c) Return a Set of Principals associated with this Subject that are instances or subclasses of the specified Class. (3) Set getPrivateCredentials() Return the Set of private credentials held by this Subject.

10

GODFREY MUGANDA

(4) Set getPrivateCredentials(Class c) Return a Set of private credentials associated with this Subject that are instances or subclasses of the specified Class. (5) Set getPublicCredentials() Return the Set of public credentials held by this Subject. (6) Set getPublicCredentials(Class c) Return a Set of public credentials associated with this Subject that are instances or subclasses of the specified Class.

15. LoginModule public interface LoginModule LoginModule describes the interface implemented by authentication technology providers. LoginModules are plugged in under applications to provide a particular type of authentication. While applications write to the LoginContext API, authentication technology providers implement the LoginModule interface. A Configuration specifies the LoginModule(s) to be used with a particular login application. Therefore different LoginModules can be plugged in under the application without requiring any modifications to the application itself. The LoginContext is responsible for reading the Configuration and instantiating the appropriate LoginModules. Each LoginModule is initialized with a Subject, a CallbackHandler, shared LoginModule state, and LoginModule-specific options. The Subject represents the Subject currently being authenticated and is updated with relevant Credentials if authentication succeeds.LoginModules use the CallbackHandler to communicate with users. The CallbackHandler may be used to prompt for usernames and passwords, for example. Note that the CallbackHandler may be null. LoginModules which absolutely require a CallbackHandler to authenticate the Subject may throw a LoginException. LoginModules optionally use the shared state to share information or data among themselves. The LoginModule-specific options represent the options configured for this LoginModule by an administrator or user in the login Configuration. The options are defined by the LoginModule itself and control the behavior within it. For example, a LoginModule may define options to support debugging/testing capabilities. Options are defined using a key-value syntax, such as debug=true. The LoginModule stores the options as a Map so that the values may be retrieved using the key. Note that there is no limit to the number of options a LoginModule chooses to define. The calling application sees the authentication process as a single operation. However, the authentication process within the LoginModule proceeds in two distinct phases. In the first phase, the LoginModule’s login method gets invoked by the LoginContext’s login method. The login method for the LoginModule then performs the actual authentication (prompt for and verify a password for example) and saves its authentication status as private state information. Once finished, the LoginModule’s login method either returns true (if it succeeded) or false (if it should be ignored), or throws a LoginException to specify a failure. In the failure case, the LoginModule must not retry the authentication or introduce delays. The responsibility of such tasks belongs to the application. If the application attempts to retry the authentication, the LoginModule’s login method will be called again.

JAVA SECURITY LAB AND INTRODUCTION TO JAAS

11

In the second phase, if the LoginContext’s overall authentication succeeded (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules succeeded), then the commit method for the LoginModule gets invoked. The commit method for a LoginModule checks its privately saved state to see if its own authentication succeeded. If the overall LoginContext authentication succeeded and the LoginModule’s own authentication succeeded, then the commit method associates the relevant Principals (authenticated identities) and Credentials (authentication data such as cryptographic keys) with the Subject located within the LoginModule. If the LoginContext’s overall authentication failed (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules did not succeed), then the abort method for each LoginModule gets invoked. In this case, the LoginModule removes/destroys any authentication state originally saved. Logging out a Subject involves only one phase. The LoginContext invokes the LoginModule’s logout method. The logout method for the LoginModule then performs the logout procedures, such as removing Principals or Credentials from the Subject or logging session information. A LoginModule implementation must have a constructor with no arguments. This allows classes which load the LoginModule to instantiate it. (1) boolean abort() Method to abort the authentication process (phase 2). (2) boolean commit() Method to commit the authentication process (phase 2). (3) void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) Initialize this LoginModule. (4) boolean login() Method to authenticate a Subject (phase 1). (5) boolean logout() Method which logs out a Subject.

16. Configuration A Configuration object is responsible for specifying which LoginModules should be used for a particular application, and in what order the LoginModules should be invoked. A login configuration contains the following information. Note that this example only represents the default syntax for the Configuration. Subclass implementations of this class may implement alternative syntaxes and may retrieve the Configuration from any source such as files, databases, or servers. Name { ModuleClass ModuleClass ModuleClass }; Name { ModuleClass ModuleClass };

Flag Flag Flag

ModuleOptions; ModuleOptions; ModuleOptions;

Flag Flag

ModuleOptions; ModuleOptions;

12

GODFREY MUGANDA

other { ModuleClass ModuleClass };

Flag Flag

ModuleOptions; ModuleOptions;

Each entry in the Configuration is indexed via an application name, Name, and contains a list of LoginModules configured for that application. Each LoginModule is specified via its fully qualified class name. Authentication proceeds down the module list in the exact order specified. If an application does not have specific entry, it defaults to the specific entry for ”other”. The Flag value controls the overall behavior as authentication proceeds down the stack. The following represents a description of the valid values for Flag and their respective semantics: (1) Required : The LoginModule is required to succeed. If it succeeds or fails, authentication still continues to proceed down the LoginModule list. (2) Requisite : The LoginModule is required to succeed. If it succeeds, authentication continues down the LoginModule list. If it fails, control immediately returns to the application (authentication does not proceed down the LoginModule list). (3) Sufficient : The LoginModule is not required to succeed. If it does succeed, control immediately returns to the application (authentication does not proceed down the LoginModule list). If it fails, authentication continues down the LoginModule list. (4) Optional : The LoginModule is not required to succeed. If it succeeds or fails, authentication still continues to proceed down the LoginModule list. The overall authentication succeeds only if all Required and Requisite LoginModules succeed. If a Sufficient LoginModule is configured and succeeds, then only the Required and Requisite LoginModules prior to that Sufficient LoginModule need to have succeeded for the overall authentication to succeed. If no Required or Requisite LoginModules are configured for an application, then at least one Sufficient or Optional LoginModule must succeed. ModuleOptions is a space separated list of LoginModule-specific values which are passed directly to the underlying LoginModules. Options are defined by the LoginModule itself, and control the behavior within it. For example, a LoginModule may define options to support debugging/testing capabilities. The correct way to specify options in the Configuration is by using the following key-value pairing: debug=”true”. The key and value should be separated by an ’equals’ symbol, and the value should be surrounded by double quotes. If a String in the form, $system.property, occurs in the value, it will be expanded to the value of the system property. Note that there is no limit to the number of options a LoginModule may define. The following represents an example Configuration entry based on the syntax above: Login { com.sun.security.auth.module.Unix\texttt{LoginModule} required; com.sun.security.auth.module.Krb5LoginModule optional useTicketCache="true" ticketCache="${user.home}${/}tickets"; };

JAVA SECURITY LAB AND INTRODUCTION TO JAAS

13

This Configuration specifies that an application named, ”Login”, requires users to first authenticate to the com.sun.security.auth.module.UnixLoginModule, which is required to succeed. Even if the UnixLoginModule authentication fails, the com.sun.security.auth.module.Krb5LoginModule still gets invoked. This helps hide the source of failure. Since the Krb5LoginModule is Optional, the overall authentication succeeds only if the UnixLoginModule (Required) succeeds. Also note that the LoginModule-specific options, useTicketCache="true" and ticketCache="${user.home}${/}tickets" are passed to the Krb5LoginModule. These options instruct the Krb5LoginModule to use the ticket cache at the specified location. The system properties, user.home and / (file.separator), are expanded to their respective values. There is only one Configuration object installed in the runtime at any given time. A Configuration object can be installed by calling the setConfiguration method. The installed Configuration object can be obtained by calling the getConfiguration method. If no Configuration object has been installed in the runtime, a call to getConfiguration installs an instance of the default Configuration implementation (a default subclass implementation of this abstract class). The default Configuration implementation can be changed by setting the value of the ”login.configuration.provider” security property (in the Java security properties file) to the fully qualified name of the desired Configuration subclass implementation. The Java security properties file is located in the file named /lib/security/java.security. refers to the value of the java.home system property, and specifies the directory where the JRE is installed. Application code can directly subclass Configuration to provide a custom implementation. In addition, an instance of a Configuration object can be constructed by invoking one of the getInstance factory methods with a standard type. The default policy type is ”JavaLoginConfig”. See the Configuration section in the Java Cryptography Architecture Standard Algorithm Name Documentation for a list of standard Configuration types. 17. LoginContext The LoginContext class describes the basic methods used to authenticate Subjects and provides a way to develop an application independent of the underlying authentication technology. A Configuration specifies the authentication technology, or LoginModule, to be used with a particular application. Different LoginModules can be plugged in under an application without requiring any modifications to the application itself. In addition to supporting pluggable authentication, this class also supports the notion of stacked authentication. Applications may be configured to use more than

14

GODFREY MUGANDA

one LoginModule. For example, one could configure both a Kerberos LoginModule and a smart card LoginModule under an application. A typical caller instantiates a LoginContext with a name and a CallbackHandler. LoginContext uses the name as the index into a Configuration to determine which LoginModules should be used, and which ones must succeed in order for the overall authentication to succeed. The CallbackHandler is passed to the underlying LoginModules so they may communicate and interact with users (prompting for a username and password via a graphical user interface, for example). Once the caller has instantiated a LoginContext, it invokes the login method to authenticate a Subject. The login method invokes the configured modules to perform their respective types of authentication (username/password, smart card pin verification, etc.). Note that the LoginModules will not attempt authentication retries nor introduce delays if the authentication fails. Such tasks belong to the LoginContext caller. If the login method returns without throwing an exception, then the overall authentication succeeded. The caller can then retrieve the newly authenticated Subject by invoking the getSubject method. Principals and Credentials associated with the Subject may be retrieved by invoking the Subject’s respective getPrincipals, getPublicCredentials, and getPrivateCredentials methods. To logout the Subject, the caller calls the logout method. As with the login method, this logout method invokes the logout method for the configured modules. A LoginContext should not be used to authenticate more than one Subject. A separate LoginContext should be used to authenticate each different Subject. The following documentation applies to all LoginContext constructors: (1) Subject If the constructor has a Subject input parameter, the LoginContext uses the caller-specified Subject object. If the caller specifies a null Subject and a null value is permitted, the LoginContext instantiates a new Subject. If the constructor does not have a Subject input parameter, the LoginContext instantiates a new Subject. (2) Configuration If the constructor has a Configuration input parameter and the caller specifies a non-null Configuration, the LoginContext uses the caller-specified Configuration. If the constructor does not have a Configuration input parameter, or if the caller specifies a null Configuration object, the constructor uses the following call to get the installed Configuration: config = Configuration.getConfiguration(); For both cases, the name argument given to the constructor is passed to the Configuration.getAppConfigurationEntry method. If the Configuration has no entries for the specified name, then the LoginContext calls getAppConfigurationEntry with the name, ”other” (the default entry name). If there is no entry for ”other”, then a LoginException is thrown. When LoginContext uses the installed Configuration, the caller requires the createLoginContext.name and possibly createLoginContext.other AuthPermissions. Furthermore, the LoginContext will invoke configured modules from within an AccessController.doPrivileged call so that modules that

JAVA SECURITY LAB AND INTRODUCTION TO JAAS

15

perform security-sensitive tasks (such as connecting to remote hosts, and updating the Subject) will require the respective permissions, but the callers of the LoginContext will not require those permissions. When LoginContext uses a caller-specified Configuration, the caller does not require any createLoginContext AuthPermission. The LoginContext saves the AccessControlContext for the caller, and invokes the configured modules from within an AccessController.doPrivileged call constrained by that context. This means the caller context (stored when the LoginContext was created) must have sufficient permissions to perform any securitysensitive tasks that the modules may perform. (3) CallbackHandler If the constructor has a CallbackHandler input parameter, the LoginContext uses the caller-specified CallbackHandler object. If the constructor does not have a CallbackHandler input parameter, or if the caller specifies a null CallbackHandler object (and a null value is permitted), the LoginContext queries the auth.login.defaultCallbackHandler security property for the fully qualified class name of a default handler implementation. If the security property is not set, then the underlying modules will not have a CallbackHandler for use in communicating with users. The caller thus assumes that the configured modules have alternative means for authenticating the user. When the LoginContext uses the installed Configuration (instead of a caller-specified Configuration, see above), then this LoginContext must wrap any caller-specified or default CallbackHandler implementation in a new CallbackHandler implementation whose handle method implementation invokes the specified CallbackHandler’s handle method in a java.security.AccessController.doPrivileged call constrained by the caller’s current AccessControlContext. Note that Security Properties (such as auth.login.defaultCallbackHandler) can be set programmatically via the java.security.Security class, or statically in the Java security properties file located in the file named /lib/security/java.security. refers to the value of the java.home system property, and specifies the directory where the JRE is installed. Constructors for LoginContext are (1) LoginContext(String name) Instantiate a new LoginContext object with a name. (2) LoginContext(String name, CallbackHandler callbackHandler) Instantiate a new LoginContext object with a name and a CallbackHandler object. (3) LoginContext(String name, Subject subject) Instantiate a new LoginContext object with a name and a Subject object. (4) LoginContext(String name, Subject subject, CallbackHandler callbackHandler) Instantiate a new LoginContext object with a name, a Subject to be authenticated, and a CallbackHandler object. (5) LoginContext(String name, Subject subject, CallbackHandler callbackHandler, Configuration config) Instantiate a new LoginContext object with a name, a Subject to be authenticated, a CallbackHandler object, and a login Configuration.

16

GODFREY MUGANDA

Methods of LoginContext are (1) Subject getSubject() Return the authenticated Subject. (2) void login() Perform the authentication. (3) void logout() Logout the Subject.