Anda di halaman 1dari 9

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
o
o
o
o
o
o

Subject
Principal
Client and LoginContext
Configuration File
Provider
Java Policy File
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
import
import
import

java.util.Iterator;
java.security.PrivilegedAction;
javax.security.auth.Subject;
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
import
import
import
import
import

java.io.*;
java.util.*;
java.security.Principal;
javax.security.auth.Subject;
javax.security.auth.callback.CallbackHandler;
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
o
o
o

Create a LoginContext that refers to a named JAAS policy entry.


Configure your provider in the Java 2 security policy.
Configure your JAAS policy.
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.

Anda mungkin juga menyukai