Part V : Secure Authentication using SPNEGO Java GSS mechanism (Java SE 6.0)

Exercise 8: Using the Java Generic Security Services (GSS) API with SPNEGO

Goal of this exercise:

Currently the only security mechansim available with Java GSS is "Kerberos". The goal of this exercise is to learn how to use other Java GSS mechanisms, such as SPNEGO, to secure the association. This feature is available from Java SE 6 onwards.

What is SPNEGO?

Java GSS is a framework that can support multiple security mechanisms; a way to negotiate a security mechanism underneath GSS-API is needed. This is available via SPNEGO.

SPNEGO is the Simple and Protected GSS-API Negotiation Mechanism, standardized at IETF in RFC 4178. It's a pseudo-security mechanism used to negotiate an underlying security mechanism. It provides the flexibility for client and server to securely negotiate a common GSS security mechanism.

Microsoft makes heavy use of SPNEGO. SPNEGO can be used to inter-operate with Microsoft Server over HTTP, to support HTTP-based Cross-Platform authentication via the Negotiate Protocol.

What do I need do to use SPNEGO in Java GSS?

Currently when using Java GSS with Kerberos, we specify the Kerberos OID to use Kerberos.

Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");

In order to use SPNEGO, you only need to specify the SPNEGO OID as follows:-

Oid spnegoOid = new Oid("1.3.6.1.5.5.2");

And henceforth use the SPNEGO OID when creating a GSSCredential, GSSContext, etc.

Steps to follow:

  1. Read the following code. This is located in src/GssSpNegoClient.java

Code listing for GssSpNegoClient.java.



  1. static class GssSpnegoClientAction implements PrivilegedExceptionAction {
  2. ...
  3.   public Object run() throws Exception {
  4.     // Create socket to server
  5.     Socket socket = new Socket(hostName, port);
  6.     DataInputStream inStream = new DataInputStream(socket.getInputStream());
  7.     DataOutputStream outStream = new DataOutputStream(socket.getOutputStream());

  8.     // Get service's principal name
  9.     GSSManager manager = GSSManager.getInstance();
  10.     Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
  11.     GSSName serverName = manager.createName(serverPrinc, GSSName.NT_HOSTBASED_SERVICE, spnegoOid);

  12.     // Get the context for authentication
  13.     GSSContext context = manager.createContext(serverName, spnegoOid, null,
  14.        GSSContext.DEFAULT_LIFETIME);
  15.     context.requestMutualAuth(true); // Request mutual authentication
  16.     context.requestConf(true); // Request confidentiality

  17.     // Do the context establishment loop
  18.     byte[] token = new byte[0];
  19.     while (!context.isEstablished()) {
  20.       token = context.initSecContext(token, 0, token.length);
  21.       outStream.writeInt(token.length);
  22.       outStream.write(token);
  23.       outStream.flush();

  24.       // Check if we're done
  25.       if (!context.isEstablished()) {
  26.         token = new byte[inStream.readInt()];
  27.         inStream.readFully(token);
  28.       }
  29.     }

  30.     // Context established!

  31.     // Create MessageProp for use with unwrap (true means request confidentiality)
  32.     MessageProp prop = new MessageProp(0, true);

  33.     // Create encrypted message and send to server
  34.     byte[] reply = ...;
  35.     token = context.wrap(reply, 0, reply.length, prop);

  36.     outStream.writeInt(token.length);
  37.     outStream.write(token);
  38.     outStream.flush();

  39.     // Read token from server
  40.     token = new byte[inStream.readInt()];
  41.     inStream.readFully(token);

  42.     // Unwrap (decrypt) token sent by server
  43.     byte[] input = context.unwrap(token, 0, token.length, prop);
  44.     ...
  45.     context.dispose();
  46.     socket.close();
  47.     return null;
  48.   }
  49. }


  1. Compile the sample code.
    % javac GssSpNegoClient.java
  2. Read the following code. This is located in src/GssSpNegoServer.java

Code listing for GssSpNegoServer.java.


  1. static class GssSpNegoServerAction implements PrivilegedExceptionAction {
  2. ...
  3.   public Object run() throws Exception {
  4.     // Create server socket for accepting connections
  5.     ServerSocket ss = new ServerSocket(localPort);

  6.     // Get own Kerberos credentials for accepting connection
  7.     GSSManager manager = GSSManager.getInstance();
  8.     Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
  9.     GSSCredential serverCreds = manager.createCredential(null,
  10.       GSSCredential.DEFAULT_LIFETIME, spnegoOid, GSSCredential.ACCEPT_ONLY);

  11.     while (true) {
  12.       Socket socket = ss.accept();
  13.       DataInputStream inStream = new DataInputStream(socket.getInputStream());
  14.       DataOutputStream outStream = new DataOutputStream(socket.getOutputStream());

  15.       GSSContext context = manager.createContext((GSSCredential)serverCreds);

  16.       // Do the context establishment loop
  17.       byte[] token = null;
  18.       while (!context.isEstablished()) {
  19.         // Read token
  20.         token = new byte[inStream.readInt()];
  21.         inStream.readFully(token);

  22.         // Process token
  23.         token = context.acceptSecContext(token, 0, token.length);

  24.         // Send a token to the peer if one was generated by acceptSecContext
  25.         outStream.writeInt(token.length);
  26.         outStream.write(token);
  27.         outStream.flush();
  28.       }

  29.       // Context established!

  30.       // Create MessageProp for use with unwrap (will be set upon return from unwrap)
  31.       MessageProp prop = new MessageProp(0, false);

  32.       // Read token from client
  33.       token = new byte[inStream.readInt()];
  34.       inStream.readFully(token);
  35.       // Unwrap (decrypt) token sent by client
  36.       byte[] input = context.unwrap(token, 0, token.length, prop);
  37.       ...
  38.       // Create new token and send to client
  39.       byte[] reply = ...;
  40.       token = context.wrap(reply, 0, reply.length, prop);

  41.       outStream.writeInt(token.length);
  42.       outStream.write(token);
  43.       outStream.flush();
  44.       context.dispose();
  45.       socket.close();
  46.     }
  47.   }
  48. }


  1. Compile the sample code.

    % javac GssSpNegoServer.java
  2. Launch a new window and start the server.

    % xterm &
    % java -Djava.security.auth.login.config=jaas-krb5.conf \
    GssSpNegoServer
  3. Run the client application. GssClient takes two parameters: the service name and the name of the server that the service is running on. For example, if the service is host running on the machine j1hol-001, you would enter the following. When prompted for the password, enter changeit.

    % java -Djava.security.auth.login.config=jaas-krb5.conf \
    GssSpNegoClient host j1hol-001

Output for running the GssSpNegoServer example.


  1. Authenticated principal: [host/j1hol-001@J1LABS.EXAMPLE.COM]
  2. Waiting for incoming connections...
  3. Got connection from client /129.145.128.102
  4. SPNEGO Negotiated Mechanism = 1.2.840.113554.1.2.2 Kerberos V5
  5. Context Established!
  6. Client principal is test@J1LABS.EXAMPLE.COM
  7. Server principal is host/j1hol-001@J1LABS.EXAMPLE.COM
  8. Mutual authentication took place!
  9. Received data "Hello There!" of length 12
  10. Confidentiality applied: true
  11. Sending: Hello There! Thu May 06 12:11:15 PDT 2005


Output for running the GssSpNegoClient example.


  1. Kerberos password for test: changeit
  2. Authenticated principal: [test@J1LABS.EXAMPLE.COM]
  3. Connected to address j1hol-001/129.145.128.102
  4. SPNEGO Negotiated Mechanism = 1.2.840.113554.1.2.2 Kerberos V5
  5. Context Established!
  6. Client principal is test@J1LABS.EXAMPLE.COM
  7. Server principal is host@j1hol-001
  8. Mutual authentication took place!
  9. Sending message: Hello There!
  10. Will read token of size 93
  11. Received message: Hello There! Thu May 06 12:11:15 PDT 2005


Summary:

In this exercise, you learned how to write a client-server application that uses the Java GSS API with SPNEGO to negotiate an underlying security mechanism, such as Kerberos, and communicate securely using Kerberos as the underlying authentication system.

Note: Microsoft has implemented certain variations of the SPNEGO protocol, hence to inter-operate with Microsoft, we have added an MS mode via a new system property "sun.security.spnego.msinterop". This property is enabled to "true" by default. To disable it, you need to explicitly set this property to "false". To enable SPNEGO debugging, you can set the system property "sun.security.spnego.debug=true".