Level: Introductory Thomas Owusu, Software engineer, IBM
08 Nov 2002 In this article, software engineer Thomas Owusu describes how a Java GSSAPI can be enhanced with a login interface using the Java Authentication and Authorization Service (JAAS), a pluggable, modular authentication and authorization Java infrastructure. Using a Java GSSAPI Kerberos mechanism as an example, Thomas discusses a Kerberos JAAS login module that provides an interface for a Java GSSAPI principal to log into a Kerberos system. He also discusses how Java GSSAPI can use the JAAS Subject as a central repository for credentials including server secret keys.
The Generic Security Service Application Programming Interface (GSSAPI) is a standardized abstract interface that provides a generic authentication and secure messaging interface under which can be plugged actual security mechanisms. A common GSSAPI mechanism is the Kerberos mechanism that is based on secret-key cryptography.
GSSAPI offers a standard generic interface through which a secure application can use multiple underlying security mechanisms. Figure 1 shows how a secure application can call a standard GSSAPI framework to get security benefits, such as authentication, message integrity, and confidentiality, no matter what the underlying implementing security mechanism is, such as Kerberos, Distributed Computing Environment (DCE), or Simple Public-Key GSSAPI Mechanism (SPKM).
Figure 1. GSSAPI framework architecture
To fully appreciate the benefits of GSSAPI, consider Telnet with Kerberos, a secure telnet program that authenticates a telnet user and encrypts data, including passwords, exchanged over the network during the telnet session. The authentication and message protection features are provided using Kerberos. Telnet with Kerberos can use only Kerberos, which is based on secret-key technology. However, a telnet program written to the GSSAPI interface can use Kerberos as well as other security mechanisms supported by GSSAPI.
The main benefit of GSSAPI is that a secure application developed using GSSAPI can work over different security mechanisms without modification. A GSSAPI principal requires credentials as proof of identity. GSSAPI lacks a login interface for acquiring credentials; it merely queries the underlying security mechanism for credentials for the calling principal. Hence, a GSSAPI application must provide for credential acquisition before invoking GSSAPI.
GSSAPI can be enhanced with the provision of a login interface by leveraging the login architecture of the Java Authentication and Authorization Service (JAAS). The JAAS login process is akin to the two-phase commit process used in transaction processing systems where participants prepare their transactions in the first phase and commit the transactions during the second phase only when all participants were successful in the first, prepare phase. They abort and rollback the transaction if one or more participants failed in the prepare phase.
The participants in a JAAS login are login modules. In the first phase of the process, each login module performs a login. In the second phase, each login module commits the outcome of its login, updating the JAAS Subject of the current access control context with credentials acquired during the login phase. If the overall login was unsuccessful, the commit phase is skipped and each login module aborts, resetting its state.
A JAAS Subject represents a single security principal. It represents the originator of access to resources and forms the basis for access control decisions in the JAAS framework. A Subject embodies related information about the principal. This information includes the principal's identities, public security credentials, and private security credentials. The principal represented by a Subject may have multiple identities and multiple security credentials, all encapsulated in the one Subject. A Subject maintains a principal's identities and security credentials in the form of sets (of class java.util.Set). These sets may be added to or deleted from, given the proper access permission, by using the appropriate java.util.Set modification methods. As shown in Figure 2, a JAAS Subject exists within an AccessControlContext, which is the embodiment of a security context used by Java Security for access control decisions. A Java virtual machine may have more than one AccessControlContext.
Figure 2. JAAS Subject
The login modules to be used are listed in the application's JAAS configuration. Each login module is assigned a weighting regarding its affect on the overall success or failure of the application's login. Login modules with required or requisite weighting must succeed for the overall login to be deemed successful.
Some benefits of a JAAS login interface
Credential acquisition is security mechanism-specific. GSSAPI specifications do not prescribe how a principal acquires credentials, and implementations typically do not provide such a feature. A typical Kerberos GSSAPI implementation, for example, requires a user to acquire Kerberos credentials using the Kerberos kinit tool, which saves the credentials in a credentials cache file; a service principal is required to create a key table containing its secret key. A similar procedure needs to be performed for each mechanism in a multi-mechanism environment.
Using JAAS login in Java GSSAPI can simplify the acquisition of credentials by making the process an integral part of the GSSAPI application. There is no need for external tools such as kinit.
Because JAAS does not place any restrictions on the internal workings of its login modules, the features, functionality, and interface offered by a login module can be simple, elaborate, user-friendly, general, application-specific, or anything the module designer decides. The important thing is that after a successful login, the JAAS Subject in the current access control context of a Java GSSAPI application is populated with the identities and credentials of the principals that logged in. Subsequently, the Subject becomes the central place for GSSAPI credentials required by the application. This approach has the added benefit that by performing a JAAS logout and then login in again, a Java GSSAPI application can switch principals and credentials at run time without the application being terminated and restarted.
A Kerberos login module
Design goals and principles
The basic goal of a JAAS login module is to populate a given JAAS Subject with
authenticated login principal identities following a successful login attempt. For a
Kerberos login module, this means first authenticating a principal to the Kerberos system
by acquiring a ticket-granting ticket (TGT) from the Key Distribution Center (KDC) of
the principal's Kerberos realm. The identity of the principal is then installed in the JAAS
Subject.
For the Subject to serve as a central repository for GSSAPI credentials, the TGT acquired
during the authentication process is added to the private credentials set of the Subject.
Normally, a TGT is acquired for GSSAPI user principals and not service principals. The
TGT is required for the user principal to initiate GSSAPI context with one or more
service principals. A service principal, on the other hand, requires just its secret key to
accept GSSAPI contexts. A service's secret key is typically kept in a key table file from
where it is retrieved at run time.
However, a Java GSSAPI JAAS Kerberos login module can be extended to also cover
service principals. The secret key of a service principal can be added to the JAAS
Subject, furthering the objective of using the JAAS Subject as a central repository of
GSSAPI credentials. Although the creation of a secret key does not involve
authentication, the service principal using the secret key is authenticated when it accepts
a GSSAPI context involving mutual authentication, during which the service principal
authenticates itself to the client principal. A GSSAPI service principal may also initiate
context, in which case it requires a TGT. The login module can enable this, too.
The login module can be interactive and prompt for a principal's Kerberos name or
password. This information is needed to acquire a TGT for a user principal or to create a
secret key for a service principal. The login module can also use an existing TGT from a
credentials cache or an existing secret key from a key table. In this mode, no user input
(name or password) will be required.
The login module can also support default principals, that is, using default TGT or secret
key when no principal name is specified. In this scenario, the principal that is added to
the Subject is the principal that owns the default TGT or service key.
Where multiple credentials are available, for example, from a credentials cache or a key
table, the choice of default credentials can be based on a number of factors. For secret
keys, some reasonable factors are key version number and the time the key was added to
the key table. For TGTs, factors to take into consideration include the time the TGT was
issued (authentication time), the time it becomes effective (start time), the time it expires
(end time), and the time it was added to the credentials cache. It can be argued that the
most recent addition to a key table or a credential cache is the most reasonable choice as
a default; it is certainly one of the simplest choices.
The login module updates the JAAS Subject in the current login context only if the
application's overall login was successful. If the login is unsuccessful, it should rollback
operations performed in its login method (the first phase), resetting state, and discarding
any credentials acquired for the login principal. If the principal logs out, the login module
should again rollback and reset state; this time, it should also clear the JAAS Subject of
any principal identities and credentials it installed in the Subject on behalf of the
principal.
Let's recap the design goals outlined above:
- Authenticate a principal and install its identity in the given JAAS Subject if the
overall login was successful; rollback and reset if the login is aborted or if the
principal logs out. This is the overriding goal.
- Install the principal's credentials in the Subject.
- Support both user and service principals. The credentials for a user principal are
always a TGT. For a service principal, it is usually a secret key but can also be a
TGT.
- Support the use of TGTs obtained from a credentials cache and secret keys obtained
from key tables.
- Support default credentials; install the owner of the default TGT or secret key as the
principal in the Subject.
JAAS configuration options
Some JAAS configuration options are used to realize these design goals in a simple
text-based Kerberos login module. The options listed below should suffice:
-
principal. The name of the Kerberos principal.
-
credsType. The GSSAPI credentials type. It can be initiator, acceptor, or both.
-
ccache. The URL of the TGT cache. This option can also be used to indicate that a default TGT cache should be used by specifying, for example, the value
<<default>>.
-
keytab. The URL of the key table. Specify the value <<default>> to indicate the use of default key table.
Some of these options are incompatible with other options. An X in a cell in Table 1
shows two options that are incompatible. For example, it is invalid to specify ccache
when requesting acceptor credentials. The cells marked "N" indicate inapplicable
combination of options. For example, only one credential type can be specified.
Table 1. JAAS Kerberos login module configuration
options
|
credsType= initiator
|
credsType= acceptor
|
credsType= both
|
ccache (URL)
|
ccache (default)
|
keytab (URL)
|
keytab (default)
| |
credsType=initiator
|
| N | N |
|
| X | X | |
credsType=acceptor
| N |
| N | X | X |
|
| |
credsType=both
| N | N |
|
|
|
|
| |
ccache (URL)
|
| X |
|
| N |
|
| |
ccache (default)
|
| X |
| N |
|
|
| |
keytab (URL)
| X |
|
|
|
|
| N | |
keytab (default)
| X |
|
|
|
| N |
|
The login module can perform validity checks on the options according to the matrix in
Table 1. It should also provide meaningful and intuitive defaults. For example,
credentials type should default to initiator because user principals are more likely than
service principals to use the login interface.
Subject object types
The login module must install principals and their credentials in the JAAS Subject as
specific object types so that the installed information can be subsequently identified and
retrieved from the Subject. JAAS Subject holds principals and their credentials as
collections of type java.util.Set. These sets should not contain duplicates. They rely on the equals method of their constituent objects to avoid duplicates.
In addition, the object types must be such that a reasonable default instance can be
determined from among a set of different instances of the same type. Recall that one of
the design goals of the login module is to support the use of default credentials. Java
GSSAPI must be able to locate the default credentials installed by the login module in the
JAAS Subject using an algorithm or basis consistent with that used by the login module
to load default credentials and secret keys from credential caches and key tables into the
Subject.
Listing 1 illustrates these principles with the definition of two classes: KerberosTGT and KerberosSecretKey. The classes represent a Kerberos TGT and a secret key, respectively. They are both derived from the common ancestor KerberosCredentials. The classes Krb5Principal, Krb5TGT, and Krb5SecretKey are assumed to be defined in some available Kerberos V5 package.
Note: The code included in this article is for illustration purposes only and sacrifices good programming practices such as error checking, exception handling, and modularity for simplicity and brevity.
For simplicity, the login module chooses default credentials and secret keys based on the
time when they were added to the Subject; hence, the timestamp in KerberosCredentials.
Listing 1. Object types installed in Subject
public class KerberosCredentials {
private Krb5Principal principal;
private Krb5TGT tgt;
private Krb5SecretKey skey;
private java.util.Date timestamp;
KerberosCredentials(Krb5Principal principal, Krb5TGT tgt);
KerberosCredentials(Krb5Principal principal, Krb5SecretKey skey);
KerberosCredentials(Krb5Principal principal, Krb5TGT tgt, Krb5SecretKey skey);
public Krb5Principal getPrincipal();
public Krb5TGT getTGT();
public Krb5SecretKey getSecretKey();
public boolean isNewerThan(KerberosCredentials that);
public boolean equals(Object o);
public int hashCode();
}
public class KerberosTGT extends KerberosCredentials {
public KerberosTGT(KerberosPrincipal principal, Krb5TGT tgt) {
super(principal, tgt);
}
public String getIssuer();
}
public class KerberosSecretKey extends KerberosCredentials {
public KerberosSecretKey(Krb5Principal principal, Krb5SecretKey skey) {
super(principal, skey);
}
}
|
Updating Subject
Listing 2 illustrates how Subject may be updated by the login module during the commit
phase of the login process. The Subject to be updated is supplied by the JAAS
infrastructure when it initializes the login module. The objects to be added to Subject
(principal, tgt, and skey) are from the login phase. Note that the TGT and secret key are saved in the private credentials set.
Listing 2. Updating Subject
public boolean commit() throws LoginException {
java.security.AccessController.doPrivileged(
(new java.security.PrivilegedAction() {
public Object run() {
subject.getPrincipals().add(principal);
subject.getPrivateCredentials().add(tgt);
subject.getPrivateCredentials().add(skey);
}
});
}
|
Integrating JAAS login into Java GSSAPI
A Java GSSAPI Kerberos mechanism requires a context initiator's TGT to obtain a
service ticket for the context acceptor from the Kerberos Ticket-Granting
Service (TGS). The context acceptor, on the other hand, requires its secret key to decrypt
the service ticket received from the initiator, thus authenticating the initiator.
A Java GSSAPI security mechanism implementation that considers the JAAS Subject as
the sole repository of credentials and secret keys relies on a JAAS login module to
populate the JAAS Subject with these credentials and service secret keys. It obtains these
credentials and secret keys from the Subject and fails if the Subject does not contain the
necessary credentials and secret keys.
Listing 3 illustrates how a Java GSSAPI Kerberos mechanism may access a JAAS
Subject to retrieve TGTs and secret keys.
The method getInitiatorCredential() retrieves the TGT of the specified principal from Subject. It retrieves the default TGT if the specified principal is null. Likewise, the
method getAcceptorCredential() obtains the secret key of the specified principal from
Subject and returns the default secret key if the specified principal is null.
By themselves, both methods are short and simple. They each delegate the real work to
the run() method of a PrivilegedExceptionAction class that is invoked within a privileged block. The getInitiatorCredential() and getAcceptorCredential() methods respectively use the SubjectTgtTrawler and the SubjectSecretKeyTrawler PrivilegedExceptionAction classes.
The method getInitiatorAndAcceptorCredentials() returns a composite KerberosCredentials object containing both a TGT and a secret key for a service principal.
As their names suggest, SubjectTgtTrawler and SubjectSecretKeyTrawler comb Subject for TGTs and secret keys respectively. They look in the private, not the public, credentials set of Subject where the login module installed them.
For simplicity and brevity, SubjectTgtTrawler is shown to return a default TGT based on the time at which the TGT was added to the Subject. As discussed previously, other
factors could be used as the basis for choosing the default TGT.
Listing 3. Retrieving objects from Subject
KerborosCredentials getInitiatorCredential(Krb5Principal principal) throws Exception {
KerberosTGT tgt = null;
try {
tgt = (KerberosTGT) java.security.AccessController.doPrivileged
(new SubjectTgtTrawler(principal));
} catch (PrivilegedActionException exc) {
throw (Exception) exc.getException();
}
if (tgt == null) {
return null;
}
if (principal == null) {
principal = tgt.getPrincipal();
}
return new KerberosTGT(principal, tgt);
}
KerborosCredentials getAcceptorCredential(Krb5Principal principal) throws Exception {
KerberosSecretKey key = null;
try {
key = (KerberosSecretKey)
java.security.AccessController.doPrivileged
(new SubjectSecretkeyTrawler(principal));
} catch (PrivilegedActionException exc) {
throw (Exception) exc.getException();
}
if (key == null) {
return null;
}
if (principal == null) {
principal = key.getPrincipal();
}
return new KerberosSecretKey(principal, key);
}
KerberosCredentials getInitiatorAndAcceptorCredentials(Krb5Principal principal)
throws Exception {
Krb5Credentials initiatorCreds = null;
Krb5Credentials acceptorCreds = null;
if ((acceptorCreds = getAcceptorCredential(principal)) == null) {
return null;
}
if (principal == null) {
principal = acceptorCreds.getPrincipal();
}
if ((initiatorCreds = getInitiatorCredential(principal)) == null) {
return null;
}
return new KerberosCredentials(principal, initiatorCreds.getTGT(),
acceptorCreds.getSecretKey());
}
/**
* Trawls the JAAS Subject for a TGT belonging to the specified
* principal.
* Returns default TGT if no principal specified.
*/
class SubjectTgtTrawler implements PrivilgedExceptionAction {
private Krb5Princpal principal;
SubjectTgtTrawler(Krb5Principal principal) {
this.principal = principal;
}
public Object run() throws Exception {
AccessControlContext context = AccessController.getContext();
Subject subject = Subject.getSubject(context);
if (subject == null) {
throw new Exception
("No Subject in the current AccessControlContext");
}
Object credential = null;
KerberosTGT retTgt = null;
KerberosTGT tempTgt = null;
String tgtIssuer = null;
if (principal != null) {
String realm = principal.getRealm();
tgtIssuer = "krb5tgt/" + realm + "@" + realm;
}
Iterator iterator =
subject.getPrivateCredentials().iterator();
while (iterator.hasNext()) {
credential = iterator.next();
if (!(credential instanceof KerberosTGT)) {
continue;
}
tempTgt = (KerberosTGT)credential;
if (principal == null) {
if (retTgt == null) {
retTgt = tempTgt;
} else if (tempTgt.isNewerThan(regTgt)) {
retTgt = tempTgt;
}
} else if (principal.equals(tempTgt.getPrincipal()) &&
tgtIssuer.equals(tempTgt.getIssuer())) {
retTgt = tempTgt;
break;
}
}
return retTgt;
}
}
/**
* Trawls the JAAS Subject for a secret key belonging to the specified
* principal.
* Returns default secret key if no principal specified.
*/
class SubjectSecretkeyTrawler implements PrivilegedExceptionAction {
// Code similar to that for SubjectTgtTrawler
}
|
 |
Conclusion
A GSSAPI login interface is neither mandated by standards nor provided by typical
implementations. The JAAS login infrastructure can be leveraged to provide an
integrated login interface for Java GSSAPI. A JAAS login module can be designed to
load Java GSSAPI credentials and secret keys into the JAAS Subject. Such a login
module simplifies Java GSSAPI by making Subject the sole repository of credentials and
secret keys at run time.
However, a Java GSSAPI application can benefit from an integrated JAAS login feature
only if the application conforms to the programming model imposed by JAAS.
Resources
- Read the official GSSAPI RFC (version 2, update 1) at the Internet Engineering Task Force Web site.
- Check out RFC 2853, which specifies Java language bindings for the GSSAPI Version 2.
-
RFC 2025 defines protocols, procedures, and conventions to be employed by peers implementing the GSSAPI when using the Simple Public-Key Mechanism.
- Visit the IBM Research -- Security pages for information on the various projects in the works worldwide.
- Find other Java-related resources on the developerWorks Java zone.
About the author  | |  |
Thomas Owusu has been a consultant software engineer for many years. His assignments have included work on varied technologies at IBM Hursley, IBM Austin, and Transarc Corporation. He currently is working with IBM Software Group on Tivoli Java Security software products.
|
Rate this page
|