Verifying HTTPS Hosts The HTTPS Protocol Handler

This last step has an important ramification. Because there are now two sets of policy files, you must be very careful when you set up a program to run with JAAS. The initial code must be granted certain privileges: in addition to the required JAAS−specific permissions, depending on the underlying module used to authenticate the user, other permissions such as connecting to a nameserver may come into play. In practice, this means that the setup code runs with a large set of permissions, and its usually easiest to grant that code all permissions. The code that runs on behalf of a user, of course, cannot have such broad permissions; we probably dont want it to be able to make arbitrary socket calls or many of the other actions that the setup code performs. To prevent this code from being granted all the permissions of the setup code, you must load it from a different codebase. Hence, a JAAS−enabled program should be partitioned into at least two jar files or directories, each of which can be used to specify a different codebase and can therefore have different sets of permissions. Depending on the type of authentication youre performing and the type of activities you want to prevent users from performing, this partitioning is not strictly required, but its usually necessary. For developers, then, there are two steps to using JAAS: they must make a call to authenticate the user and execute particular methods on behalf of that user. For administrators, there are three steps: they must configure a set of login modules, configure a set of JAAS policy files, and set up the programs environment correctly. In the next few sections, well look at how all this works with a simple example. Well start with the programmatic steps required to JAAS−enable code, then well look at the administrative steps required to run such code.

15.2 Simple JAAS programming

The JAAS−enabled code is partitioned into two groups: the setup code and the user−specific code.

15.2.1 The JAAS Setup Code

The setup code looks like this: package javasec.samples.ch15; import javax.security.auth.; import javax.security.auth.callback.; import javax.security.auth.login.; public class CountFiles { static class NullCallbackHandler implements CallbackHandler { public void handleCallback[] cb { throw new IllegalArgumentExceptionNot implemented yet; } } static LoginContext lc = null; public static void mainString[] args { use the configured LoginModules for the CountFiles entry try { lc = new LoginContextCountFiles, new NullCallbackHandler ; } catch LoginException le { le.printStackTrace ; System.exit−1; } log in the user try { lc.login ; if we return with no exception, authentication succeeded } catch Exception e { System.out.printlnLogin failed: + e; System.exit−1; } now execute the code as the authenticated user Object o = Subject.doAslc.getSubject, new CountFilesAction ; System.out.printlnUser + lc.getSubject + found + o + files.; System.exit0; } } There are three important steps here: first, we construct a LoginContext object; second, we use that object to log in a user; and third, we pass that user as one of the parameters to the doAs method.

15.2.1.1 The LoginContext class

The first two of these activities are based on the LoginContext class javax.security.auth.login.LoginContext . There are four ways to construct a LoginContext object: public LoginContextString name public LoginContextString name, CallbackHandler cb public LoginContextString name, Subject s public LoginContextString name, Subject s, CallbackHandler cb Establish a context by which a user can be authenticated. The details of that authentication are handled by an external configuration file; the name passed to the constructor of this object is referenced from that configuration file. Certain ways of authenticating users may require callbacks e.g., to allow the user to type in a password, which we will explore after our simple example. If you use a constructor that does not require a callback and then configure the program to use an authentication method that does require a callback, a LoginException is thrown. That exception also is thrown if there is an error in the external configuration files. The purpose of a login context is to allow retrieval of an authenticated user, which is represented as a subject object. You can pass a preexisting subject to the login context if you want to add credentials to the subject. For now, well treat subjects as opaque objects; well examine them in detail later in this chapter. Creating the login context does not authenticate the user; that is done via the login method, as our sample code demonstrates. That method is one of three available to this class: public void login Authenticate the current user and carry out the steps listed in the login configuration file. This method throws a LoginException if the login fails. 294 public void logout Log the current user out. This invalidates the subject object. This method throws a LoginException if the logout operation fails. public Subject getSubject Return the subject object that represents the authenticated user.

15.2.1.2 The Subject class

The Subject class javax.security.auth.Subject is used to represent an authenticated user. In essence, each user is represented as an array of Principal objects stored by this class. There is an array of objects because each user is likely to have several identifying characteristics. For example, on my Sun system I have a principal that represents me by username sdo, one that represents me by user ID 6058, and many that represent me by the groups to which I belong group 20, group 45. In addition, I may have other identities such as a database login with a name of scott. Since a principal contains only a single name, my identity is modeled as a set of these principals. For the most part, subjects are opaque objects. You can retrieve the entire set of principals from the subject object as well as private and public credentials i.e., keys and certificates if they are set by the login system. Unless youre implementing your own authentication system, you really use the subject object only as an argument to one of the following static methods of the Subject class: public static Object doAsSubject s, PrivilegedAction pa public static Object doAsSubject s, PrivilegedExceptionAction pea public static Object doAsPrivilegedSubject s, PrivilegedAction pa, AccessControlContext acc public static Object doAsPrivilegedSubject s, PrivilegedExceptionAction pa, AccessControlContext acc Execute the run method of the given object on behalf of the given subject possibly with the given access control context. If the run method can throw an exception, you must use a method that requires a PrivilegedExceptionAction parameter; the exception will be wrapped into a PrivilegedExecption . The doAs method looks remarkably similar to the doPrivileged method of the access controller. This is not an accident: the doAs method sets up special checking that the access controller uses to perform permission checking. The details of how that works are coming up next.

15.2.2 The JAAS User−Specific Code

The code that well execute in our simple example looks like this: package javasec.samples.ch15; import java.io.; import java.security.; class CountFilesAction implements PrivilegedAction { public Object run { File f = new FileFile.separatorChar + files; File fArray[] = f.listFiles ; return new IntegerfArray.length; } }