Acquiring a Service Ticket

A Kerberos service ticket authenticates a request by a particular client to a particular service. As such, a service ticket represents the credentials of the client in a way that the credentials can only be understood by a single service.

Acquiring a service ticket involves the following steps:

  1. Create a class that implements PrivilegedExceptionAction
  2. Implement the GSSAPI operations to create a service ticket within the PrivilegedExceptionAction
  3. Acquire the client’s credentials as a Subject
  4. Call the PrivilegedExceptionAction using the Subject.doAs() operation

Step 1) involves the creation of a PrivilegedExceptionAction. The java.security.PrivilegedExceptionAction interface is similar to a Runnable interface, because it simply requires the implementation of a run() method. The intent of a PrivilegedExceptionAction, however, is that it can be run by an AccessController, which can grant or deny access based on credentials. In the case of creating a service ticket, the AccessController will actually be called by a Subject, which provides its credentials in the form of a TGT, or Ticket-Granting Ticket. This layer of Java security can be very confusing and obscure because all of these operations are hidden from the Java developer. So don’t worry about what is happening underneath – just create a class that implements PrivilegedExceptionAction, and be prepared to implement the run() method.

Step 2) involves implementing GSSAPI operations within the PrivilegedExceptionAction. GSSAPI is the API that the Java runtime provides for creating and decrypting service tickets. Because GSSAPI is intended for general purpose usage and does not make specific reference to the Kerberos protocol, it creates a certain level of abstraction and obscurity that can be confusing. The following code example shows how to create a Kerberos service ticket with GSSAPI, and the comments in the code relate the generic GSSAPI operations to specific elements of Kerberos security.

Example Java code (PrivilegedExceptionAction to create a Kerberos service ticket)

public class ServiceTicketGenerator implements PrivilegedExceptionAction
{
	public Object run() throws Exception
	{
		try
		{
			// GSSAPI is generic, but if you give it the following Object ID,
			// it will create Kerberos 5 service tickets
			Oid kerberos5Oid = new Oid("1.2.840.113554.1.2.2");

			// create a GSSManager, which will do the work
			GSSManager gssManager = GSSManager.getInstance();

			// tell the GSSManager the Kerberos name of the client and service (substitute your appropriate names here)
			GSSName clientName = gssManager.createName("client@DOMAIN.COM", GSSName.NT_USER_NAME);
			GSSName serviceName = gssManager.createName("service/server.domain.com@DOMAIN.COM", null);

			// get the client's credentials. note that this run() method was called by Subject.doAs(),
			// so the client's credentials (Kerberos TGT or Ticket-Granting Ticket) are already available in the Subject
			GSSCredential clientCredentials = gssManager.createCredential(clientName, 8*60*60, kerberos5Oid, GSSCredential.INITIATE_ONLY);

			// create a security context between the client and the service
			GSSContext gssContext = gssManager.createContext(serviceName, kerberos5Oid, clientCredentials, GSSContext.DEFAULT_LIFETIME);

			// initialize the security context
			// this operation will cause a Kerberos request of Active Directory,
			// to create a service ticket for the client to use the service
			byte[] serviceTicket = gssContext.initSecContext(new byte[0], 0, 0);
			gssContext.dispose();

			// return the Kerberos service ticket as an array of encrypted bytes
			return serviceTicket;
		}
		catch (Exception ex)
		{
			throw new PrivilegedActionException(ex);
		}
	}

}

Now that you have a class that can generate a service ticket, you need client credentials to invoke the generator (step 3). The simplest and most common way to get client credentials is to use the credentials of the signed-on user. See Acquiring the Signed-On User’s TGT for details. Note that the credentials of the signed-on user are called the TGT, or Ticket-Granting Ticket, which is exactly what is needed to grant the right to create a service ticket.

Example Java code

      // create a LoginContext based on the entry in the login.conf file
      LoginContext lc = new LoginContext("SignedOnUserLoginContext");

      // login (effectively populating the Subject)
      lc.login();

      // get the Subject that represents the signed-on user
      Subject clientSubject = lc.getSubject();

Step 4) is the final step, where the service ticket is actually generated. Using the client Subject obtained in step 3), make the following call:

Example Java code

byte[] serviceTicket = (byte[]) Subject.doAs(clientSubject, new ServiceTicketGenerator());

The resulting byte[] contains the Kerberos service ticket, which can be passed to the service to authenticate the identity of the client. For details of what happens on the service side, see Authenticating the User from a Service Ticket.

Java developers should exercise caution in handling and transporting service tickets. Since the GSSAPI does not provide any facility for passing the service ticket from the client to the service, and the transport mechanism is left up to the Java developer. (The standards-based mechanism for passing Kerberos service tickets between client and service is SASL (Simple Authentication and Security Layer), which is also supported by Java, but out of the scope of this discussion.) Even though service tickets are encrypted, if they are stolen and communicated to the service by malicious software, they convey the rights of the authenticated client. In particular, the Java developer should:

  1. Never persist service tickets in memory or on the file system
  2. Always use secure (e.g., SSL) transports for communication across networks

Precaution 2) is necessary to prevent man-in-the-middle attacks, where the man-in-the-middle would present the service ticket to the service, and then issue requests and receive responses that were not authorized by the client.