Return-Path: Received: from fort-point-station.mit.edu by po10.mit.edu (8.9.2/4.7) id AAA05899; Sat, 28 Jul 2001 00:16:11 -0400 (EDT) Received: from hermes.java.sun.com (hermes.java.sun.com [204.160.241.85]) by fort-point-station.mit.edu (8.9.2/8.9.2) with SMTP id AAA27947 for ; Sat, 28 Jul 2001 00:16:10 -0400 (EDT) Message-Id: <200107280416.AAA27947@fort-point-station.mit.edu> Date: Fri, 27 Jul 2001 21:16:10 PDT From: "JDC Tech Tips" To: alexp@mit.edu Subject: JDC Tech Tips July 27, 2001 Precedence: junk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: Beyond Email 2.2 J D C T E C H T I P S TIPS, TECHNIQUES, AND SAMPLE CODE WELCOME to the Java Developer Connection(sm) (JDC) Tech Tips, July 27, 2001. This issue covers the Java(tm) Authentication and Authorization Service (JAAS). It introduces some key concepts in JAAS and shows you how to make use of these concepts. The tips are: * Introduction to JAAS * Using JAAS In order to run the code in this tip you will need access to JAAS version 1.0, which is available at: http://java.sun.com/products/jaas These tips were developed using Java 2 SDK, Standard Edition, v 1.3. This issue of the JDC Tech Tips is written by Stuart Halloway, a Java specialist at DevelopMentor (http://www.develop.com/java). You can view this issue of the Tech Tips on the Web at http://java.sun.com/jdc/JDCTechTips/2001/tt0727.html - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INTRODUCTION TO JAAS The Java Authentication and Authorization Service (JAAS) extends the Java security model to perform checks based on the identity of the caller. Before you use JAAS, you need to understand some key concepts. These are: o Subject o Principal o Client and LoginContext o Configuration File o Provider o Java Policy File o JAAS Policy File Subject In JAAS, a subject is some identity in a system that you want to authenticate and to which you want to assign permissions. For example, a subject can be a human user, a machine, or a process. Subjects are represented by the javax.security.auth.Subject class. Principal Just as in the real world, a Subject can have relationships with several different authorities. For example, you might have one password and set of privileges at your bank, and a different password and set for of privileges for your voice mail. In this example, the authorities are the bank and the voice mail system. In JAAS, a subject's multiple interactions with authorities are are represented by classes that implement the java.security.Principal interface. So a Principal is a class that represents a Subject's interactions with an authority. A Principal simply knows its name and provides sensible overrides for the Object methods, as the following SimplePrincipal class demonstrates. Note: You'll use this class and other components in an application that uses JAAS. Don't try to compile and use this class individually. Instructions for building and running the application are in the tip that follows this one, titled "Using JAAS." import java.security.Principal; public final class SimplePrincipal implements Principal { private final String name; public SimplePrincipal(String name) { if (name == null) { throw new IllegalArgumentException( "Name cannot be null"); } this.name = name; } public int hashCode() { return name.hashCode(); } public java.lang.String getName() { return name; } public java.lang.String toString() { return "SimplePrincipal: " + name; } public boolean equals(java.lang.Object obj) { if (obj == null) return false; if (!(obj instanceof SimplePrincipal)) return false; SimplePrincipal other = (SimplePrincipal) obj; return name.equals(other.getName()); } } Client and LoginContext In order to associate a Principal with a Subject, clients must login. JAAS provides a concrete class, LoginContext, that acts as a session with a group of one or more authentication providers. The following JAASClient class demonstrates using a LoginContext: import java.util.Iterator; import java.security.PrivilegedAction; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; public class JAASClient { public static void main(String [] args) { try { loginAndDoSomething(); } catch (Exception e) { e.printStackTrace(); } } public static void loginAndDoSomething() throws Exception { LoginContext ctx = new LoginContext("SimpleLogin"); ctx.login(); Subject subj = ctx.getSubject(); System.out.println("Login assigned these principals: "); Iterator it = subj.getPrincipals().iterator(); while (it.hasNext()) System.out.println("\t" + it.next()); Subject.doAs(subj, new PrivilegedAction() { public Object run() { System.out.println("You live at " + System.getProperty("user.home")); return null; } }); ctx.logout(); } } The LoginContext constructor prepares to authenticate based on a named configuration. In this case, the configuration is named SimpleLogin (more on this in a moment). The call to login then causes the LoginContext to call one or more authentication providers. The call to getSubject returns a Subject that contains any Principals that the authenticators chose to assign. The doAs method then attempts a secured operation, which will succeed if one of the Principals has the appropriate Permission. The call to getPrincipals is for debugging; it prints the Principals that login assigned to the Subject. Configuration File The LoginContext finds the named configuration from a configuration file that looks like this: //File conf/simple.conf SimpleLogin { SimpleLoginModule required; }; This file tells the LoginContext to load a class named SimpleLoginModule, which is a service provider for some authentication strategy. The "required" means that this class's approval is necessary for login to succeed. The LoginContext allows multiple authentication providers to be used in tandem, in which case, additional entries would appear inside the SimpleLogin block. Provider A JAAS authentication provider provides the authentication strategy. In JAAS, an authentication strategy is implemented through the LoginModule interface. So the SimpleLoginModule must implement the LoginModule interface: package java.security.auth.spi; public interface LoginModule { boolean abort(); boolean commit(); void initialize(Subject s, CallbackHandler ch, Map shared, Map options); boolean login(); boolean logout(); } The LoginContext will call these methods in the following sequence: 1. initialize gives the service provider a Subject, to which it can later attach Principals to if login succeeds. The CallbackHandler is a client-provided set of interfaces for entering authentication information. These interfaces decouple the service provider from the particular input devices being used, such as a computer keyboard or cell phone. The shared map contains general configuration information, and the options map contains a provider-specific configuration. 2. login tells the provider to authenticate the Subject. Principals are not assigned at this time. 3. commit tells the provider that the LoginContext accepts the results from all the other providers, and so the provider can assign Principals. 4. abort tells the provider that even though it may have authenticated the Subject, some other Provider failed and the overall login should fail. The provider forgets that it ever saw the login succeed and does not assign Principals to the Subject. 5. logout cancels the assignment of Principals to the Subject. Now let's look at the content of SimpleLoginModule. In this example, it provides a rudimentary implementation of LoginModule that tests the user's knowledge of movie trivia: import java.io.*; import java.util.*; import java.security.Principal; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.spi.LoginModule; public class SimpleLoginModule implements LoginModule { private static final int NOT_AUTHENTICATED = 0; private static final int AUTHENTICATED = 1; private static final int AUTHENTICATE_COMMITTED = 2; private int state; private SimplePrincipal sp; private Subject sub; public boolean abort() { if ((sub != null) && (sp != null)) { Set prins = sub.getPrincipals(); if (prins.contains(sp)) { prins.remove(sp); } } sub = null; sp = null; state = NOT_AUTHENTICATED; return true; } public boolean commit() { if (state < AUTHENTICATED) { return false; } if (sub == null) { return false; } Set prins = sub.getPrincipals(); if (!prins.contains(sp)) { prins.add(sp); } state = AUTHENTICATE_COMMITTED; return true; } public void initialize(Subject s, CallbackHandler ch, Map shared, Map options) { state = NOT_AUTHENTICATED; sp = null; sub = s; } public boolean login() { BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); System.err.println("What can Jack Burton see? "); try { String resp = br.readLine(); if (!resp.equalsIgnoreCase("things no one else can see")) { return false; } } catch (IOException ioe) { return false; } sp = new SimplePrincipal("Jack"); state = AUTHENTICATED; return true; } public boolean logout() { state = NOT_AUTHENTICATED; sp = null; sub = null; return true; } } The SimpleLogin module is indeed very simple, recognizing only one Principal ("Jack") and only one authentication string, both of which are hard-coded. Java Policy File A JAAS authentication provider is a highly-trusted part of the system, and needs special permissions. To grant these permissions, you will need to specify a Java 2 policy file like this one: //file conf/JAASProvider.policy //trust the provider grant codeBase "file:./provider/" { permission java.security.AllPermission; }; //trust JAAS grant codeBase "file:/java/jaas1_0/lib/jaas.jar" { permission java.security.AllPermission; }; //these permissions are needed by the client grant codeBase "file:./client/" { permission javax.security.auth.AuthPermission "createLoginContext"; permission javax.security.auth.AuthPermission "doAs"; permission java.util.PropertyPermission "user.home", "read"; }; Make sure to edit the jaas.jar codeBase entry to point to the location of jaas.jar on your local system. The other URLs are relative and do not need to be edited. The provider files and the the JAAS API files are completely trusted. The client code has the permissions it needs to bootstrap a LoginContext and to perform an authentication check. The client can also read the "user.home" property, which is the "sensitive operation" being demonstrated in this example. JAAS Policy File JAAS defines a policy file format for assigning permissions to authenticated clients. The format looks very similar to the normal Java 2 policy file. In fact, Java 2 SDK version 1.4 will support both formats from a single file. For JAAS 1.0, the JAAS-specific sections are in a separate file that looks like this: //file conf/SimpleJAAS.policy grant Principal SimplePrincipal "Jack" { permission java.util.PropertyPermission "user.home", "read"; }; The permission settings look exactly like Java 2 security permission settings. The only difference is in the grant declaration, which can list a Principal instead of, or in addition to, the normal codeBase and signedBy settings. This simple example gives Jack permission to read the user.home property. In the 1.4 version of the Java 2 SDK, a separate JAAS policy file will not be necessary. All settings will be controlled by the standard policy. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - USING JAAS Let's build and run a JAAS application using the components described in the "Introduction to JAAS," above. All you need to do is start the client in a virtual machine with the correct configuration. Specifically, you: o Compile the Java classes. Remember to first ensure that your class path includes the jaas.jar file. Compile the client class (JAASClient) to a subdirectory named "client." Compile all the other classes to a subdirectory named "provider." o Place the configuration file (simple.conf) in a subdirectory named "conf." o Place the policy files (JAASProvider.policy and SimpleJAAS.policy) in the "conf" subdirectory. With those files in place, issue the following command. Make sure to edit the command to specify the correct location of jaas.jar. On Windows systems (this is shown in multiple lines for readibility. You should enter the command as a single line): java -cp client;provider;d:\java\jaas1_0\lib\jaas.jar -Djava.security.manager -Djava.security.policy=conf/JAASProvider.policy -Djava.security.auth.policy=conf/SimpleJAAS.policy -Djava.security.auth.login.config=conf/simple.conf JAASClient On UNIX systems: java -cp client:provider:/java/jaas1_0/lib/jaas.jar \ -Djava.security.manager \ -Djava.security.policy=conf/JAASProvider.policy \ -Djava.security.auth.policy=conf/SimpleJAAS.policy \ -Djava.security.auth.login.config=conf/simple.conf JAASClient If you examine the command, you'll see that it: o Turns on Java 2 security (-Djava.security.manager) o Gives the provider the Java 2 permissions it needs (-Djava.security.policy=JAASProvider.policy) o Gives the client the JAAS permissions it needs (-Djava.security.auth.policy=SimpleJAAS.policy o Tells the LoginContext where to find the configuration file (-Djava.security.auth.login.config=simple.conf) You should see a session like the following (assuming you enter the correct answer to the question): What can Jack Burton see? things no one else can see Login assigned these principals: SimplePrincipal: Jack You live at {your home directory} In general, you do not need to write your own providers or Principals. Instead, you can use a standard provider and Principals that integrate with your OS login, smart card, or other authentication provider. Otherwise, what you do to build and run an application that uses JAAS is very similar to what was shown above. Specifically, you need to: o Create a LoginContext that refers to a named JAAS policy entry. o Configure your provider in the Java 2 security policy. o Configure your JAAS policy. o Use Subject.doAs to control sensitive operations. The example code shown above is quite simple. Here are some other experiments you could try: o A real authentication provider should not use System.in and System.err. The CallbackHandler interface is provided for this purpose. Rewrite the SimpleLoginModule to use a CallbackHandler provided by the client. o Providers do not actually need AllPermission. To discover the permissions that are really needed, remove the AllPermission entries from the JAASProvider.policy file. Then, run the application with the -Djava.security.debug=access,failure flag to dump the name of permission checks that are failing. When you see a permission fail, add it back to the security file and try again. Warning: This will take a while! But, if you investigate each permission as you go, you will gain an intimate understanding of how JAAS works. To learn more about JAAS 1.0, see the Java Authentication and Authorization Service (JAAS) 1.0 page: ( http://java.sun.com/products/jaas/index-10.html ). Scroll down on that page to the "More Info" section for several useful links. The 1.4 version of Java 2 Platform, Standard Edition incorporates JAAS. A beta version of J2SE(tm) version 1.4 is available for download at http://java.sun.com/j2se/1.4/ . . . . . . . . . . . . . . . . . . . . . . - NOTE Sun respects your online time and privacy. The Java Developer Connection mailing lists are used for internal Sun Microsystems(tm) purposes only. You have received this email because you elected to subscribe. To unsubscribe, go to the Subscriptions page (http://developer.java.sun.com/subscription/), uncheck the appropriate checkbox, and click the Update button. As of May 22, 2001, Sun Microsystems updated its Privacy Policy (http://sun.com/privacy) to give you a better understanding of Sun's Privacy Policy and Practice. If you have any questions, contact privacy@sun.com. - SUBSCRIBE To subscribe to a JDC newsletter mailing list, go to the Subscriptions page (http://developer.java.sun.com/subscription/), choose the newsletters you want to subscribe to, and click Update. - FEEDBACK Comments? Send your feedback on the JDC Tech Tips to: jdc-webmaster@sun.com - ARCHIVES You'll find the JDC Tech Tips archives at: http://java.sun.com/jdc/TechTips/index.html - COPYRIGHT Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA. This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html - LINKS TO NON-SUN SITES The JDC Tech Tips may provide, or third parties may provide, links to other Internet sites or resources. Because Sun has no control over such sites and resources, You acknowledge and agree that Sun is not responsible for the availability of such external sites or resources, and does not endorse and is not responsible or liable for any Content, advertising, products, or other materials on or available from such sites or resources. Sun will not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such Content, goods or services available on or through any such site or resource. JDC Tech Tips July 27, 2001 Sun, Sun Microsystems, Java, Java Developer Connection, and J2SE are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. To use our one-click unsubscribe facility, select the following URL: http://hermes.java.sun.com/unsubscribe?623340616925952587