Using JAAS and SPNEGO/Kerberos to single sign-on from fat java clients
Index
Introduction
This article describes how to use Kerberos in a Windows environment to single sign-on (SSO) from a fat java client.
JAAS is used to implement the SSO by getting the Kerberos tickets and generate an SPNEGO/Kerberos token. The SPNEGO/Kerberos token
is then sent to a SPNEGO/Kerberos server and validated. If validated ok, the user was authenticated.
Overview
Fat java programs can authenticate the logged on user using a JAAS login module. If logon is successful,
the authenticated user's Subject is returned from the LoginContext
The authentication process is designed around the principle of
being able to access a protected HTTP resource, a resource which is protected with SPNEGO/Kerberos.
If the resource can be accessed, the user is authenticated,
since this involves a correctly validated SPNEGO/Kerberos token.

The LoginModule generates a SPNEGO/Kerberos token based on the credentials from the local
Kerberos ticket cache, generates a HTTP request for a SPNEGO/Kerberos protected resource. The HTTP request
the Authorization header contains the SPNEGO/Kerberos token.

When the HTTP request is received by the server, the server validated the SPNEGO/Kerberos token and responds
with either a HTTP 200 OK or a HTTP 401 Unauthorized If HTTP 200 OK is returned from the server,
the server validated the SPNEGO/Kerberos token and the user was authenticated. The response from the
authentication server includes a WWW-Authenticate HTTP header, which contains the SPNEGO/Kerberos response,
the GSS NegTokenTarg message, which contains a SPNEGO/Kerberos negotiation status.
After the LoginModule has validated that the SPNEGO/Kerberos negotiation status is OK, it then
populates the Subject with the principal name and returns this to
the client program
This last message ensures that its not possible just to change the URL in the client program to
some URL that always returns 200 OK, since the LoginModule checks if the server responds with
a valid message.
JaasClient example code
A typical JAAS client could look like:
public class JaasClient {
public final static String copyright = "(c) 2004 IT Practice A/S. All Rights Reserved.";
public static void main(String[] args) throws Exception {
LoginContext lc = null;
System.setProperty("java.security.auth.login.config", "JaasClient.conf");
String spn = "HTTP/spnego@TEST.NET";
String authUrl = "http://spnego/protected.asp";
lc = new LoginContext("JaasClient", new SpnegoClientCallbackHandler(authUrl, spn));
lc.login();
System.out.println("Subject:" + lc.getSubject());
}
}
This small piece of code shows how to create a LoginContext and do a login.
This is perhaps the nicest feature of the whole JAAS design - the ease of use seen from client side programmers.
Looking closer at the code, the used login configuration points to a configuration
file which looks like this:
JaasClient {
dk.itp.spnego.jaas.SpnegoLoginModule required;
};
This tells the JAAS system that it must require a valid login using
SpnegoLoginModule to authenticate the user.
The SpnegoClientCallbackHandler set the URL of the SPNEGO authentication server and the service principal
name of that server. These information is used, when Kerberos service tickets are issued and wrapped into the SPNEGO/Kerberos token.
When login() is called, the SPNEGO/Kerberos tokens is sent over HTTP to the URL, the SPNEGO/Kerberos authentication server, which will
respond with a GSS NegTokenTarg message. This message contains information about authentication status. If returned status is "ok",
the login module sets the principal name on the subject and returns.
Using the Subject to access remote EJB's
Now that we hae authenticated, we want to use the authenticated user to access a remote and protected EJB.
Lets user WebLogic as an example. WebLogic implements its own version of the Subject.runAs() called
weblogic.security.Security.runAs(). Using this special implementation, WebLogic takes care of the tranaction between
the client java program and the weblogic server.
Lets take a look at the following example
Subject subject = lc.getSubject();
PrivilegedAction pa = new PrivilegedAction() {
public Object run() {
try {
Context ctx = null;
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, "t3://spnego.test.net:7001");
// Get a context for the JNDI lookup
ctx = new InitialContext(ht);
Object o = ctx.lookup("ejb/sample/SimpleRemoteBeanHome");
SimpleRemoteBeanHome home = (SimpleRemoteBeanHome)o;
SimpleRemoteBean bean = home.create();
String message = bean.sayHello();
System.out.println(message);
} catch (Exception e) {
e.printStackTrace();
}
return null;
};
};
weblogic.security.Security.runAs(subject, pa);
The SimpleRemoteBean is protected by a role at method level. This means that its not possible to execute the sayHello
method on the EJB without being authenticated on the EJB server.
Lets look at how its done:

The first part, the SPNEGO/Kerberos authentication using the JAAS login module, was explained in the previous section.
During authentication, the SPNEGO servlet also returns the authenticated subject. This subject is the then used
to authenticate the subject over the T3 protocol, which is used by the client program. Finally the subject is returned
to the client program by using LoginContext.getSubject().
The above code sample shows how the PrivilegedAction is created. It contains the EJB call. To execute this PrivilegedAction, the
weblogic implementation of runAs is executed. This takes care of sending the Subject, with the EJB request, to WebLogic. Server side maps the
Subject to the AuthenticatedSubject. Finally access to the EJB is handled by the installed server LoginModule, the Active Directory
authenticator.
Conclusion
We have shown how to implement Kerberos authentication over SPNEGO/Kerberos using a JAAS from java programs. Another way could be by
reading the system property "user.name", but this does not contain information about login at the KDC (domain). Using Kerberos
and SPNEGO/Kerberos proves that the user was valid user on the specified domain
The JAAS implementation makes it possible to transfer Subject from the client program to the server, if WebLogic is used. This
can be used for programmatic authorization or more tighter integration to WebLogic using the
weblogic.security.Security.runAs() method. If the PrivilegedAction run in the runAs contains JNDI code, like
EJB lookups, the JNDI code wil be executed, on the server, as the authenticated principal.
This brings a nice and transparent SSO mechanism to fat java clients, where EJB's can be executed using the windows domain logon
credentials.
For more information you can contact spnego_AT_it-practice.dk
About the author
Bo Friis is working as a security consultant for IT Practice
in Denmark. He has specialized in security protocols and
implementations. He is working on security solutions for various customers and is the co. architect of PortalProtect. He
has designed and developed the initial version of opensign and openlogon, a set of applets that supports digital
signature using X.509 certificates over the XMLDSIG standard. The result was donated to the open source
OpenOCES project.
Bo Friis holds a Masters degree in Cryptography from the University of Aarhus in Denmark. He also holds
a Master of Science degree in Electrical Engineering from the Technical University of Denmark.
He can be reached at email:jbf_AT_practice.dk
|