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.
src/GssSpNegoClient.javaCode listing for GssSpNegoClient.java.
static class GssSpnegoClientAction implements
PrivilegedExceptionAction {... public Object run() throws Exception
{ // Create socket to
server Socket socket = new
Socket(hostName, port); DataInputStream inStream = new
DataInputStream(socket.getInputStream()); DataOutputStream outStream = new
DataOutputStream(socket.getOutputStream()); // Get service's principal
name GSSManager manager =
GSSManager.getInstance(); Oid spnegoOid = new
Oid("1.3.6.1.5.5.2"); GSSName serverName =
manager.createName(serverPrinc, GSSName.NT_HOSTBASED_SERVICE,
spnegoOid); // Get the context for
authentication GSSContext context =
manager.createContext(serverName, spnegoOid,
null,
GSSContext.DEFAULT_LIFETIME); context.requestMutualAuth(true);
// Request mutual authentication context.requestConf(true); //
Request confidentiality // Do the context establishment
loop byte[] token = new
byte[0]; while
(!context.isEstablished()) { token =
context.initSecContext(token, 0, token.length); outStream.writeInt(token.length); outStream.write(token); outStream.flush(); // Check if we're
done if
(!context.isEstablished()) { token =
new byte[inStream.readInt()]; inStream.readFully(token); } } // Context
established! // Create MessageProp for use
with unwrap (true means request confidentiality) MessageProp prop = new
MessageProp(0, true); // Create encrypted message and
send to server byte[] reply = ...; token =
context.wrap(reply, 0, reply.length, prop); outStream.writeInt(token.length); outStream.write(token); outStream.flush(); // Read token from
server token = new
byte[inStream.readInt()]; inStream.readFully(token); // Unwrap (decrypt) token sent by
server byte[] input =
context.unwrap(token, 0, token.length, prop); ... context.dispose(); socket.close(); return null; }}% javac GssSpNegoClient.java
src/GssSpNegoServer.javaCode listing for GssSpNegoServer.java.
static class GssSpNegoServerAction implements
PrivilegedExceptionAction {... public Object run() throws Exception
{ // Create server socket for
accepting connections ServerSocket ss = new
ServerSocket(localPort); // Get own Kerberos credentials
for accepting connection GSSManager manager =
GSSManager.getInstance(); Oid
spnegoOid = new Oid("1.3.6.1.5.5.2"); GSSCredential serverCreds =
manager.createCredential(null, GSSCredential.DEFAULT_LIFETIME,
spnegoOid, GSSCredential.ACCEPT_ONLY); while (true) { Socket socket =
ss.accept(); DataInputStream
inStream = new
DataInputStream(socket.getInputStream()); DataOutputStream
outStream = new
DataOutputStream(socket.getOutputStream()); GSSContext
context =
manager.createContext((GSSCredential)serverCreds); // Do the context
establishment loop byte[] token =
null; while
(!context.isEstablished()) { // Read
token token =
new byte[inStream.readInt()]; inStream.readFully(token); //
Process token token
= context.acceptSecContext(token, 0,
token.length); // Send a
token to the peer if one was generated by
acceptSecContext outStream.writeInt(token.length); outStream.write(token); outStream.flush(); } // Context
established! // Create MessageProp
for use with unwrap (will be set upon return from
unwrap) MessageProp prop =
new MessageProp(0, false); // Read token from
client token = new
byte[inStream.readInt()]; inStream.readFully(token); // Unwrap (decrypt)
token sent by client byte[] input
= context.unwrap(token, 0, token.length,
prop); ... // Create new token
and send to client byte[] reply =
...; token =
context.wrap(reply, 0, reply.length, prop); outStream.writeInt(token.length); outStream.write(token); outStream.flush(); context.dispose(); socket.close(); } }}% javac GssSpNegoServer.java
% xterm & % java -Djava.security.auth.login.config=jaas-krb5.conf GssSpNegoServer
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.
Authenticated principal:
[host/j1hol-001@J1LABS.EXAMPLE.COM]Waiting for incoming connections...Got connection from client /129.145.128.102Context Established!Client principal is test@J1LABS.EXAMPLE.COMServer principal is
host/j1hol-001@J1LABS.EXAMPLE.COMMutual authentication took place!Received data "Hello There!" of length 12Confidentiality applied: trueSending: Hello There! Thu May 06 12:11:15 PDT
2005Output for running the GssSpNegoClient example.
Kerberos password for test: changeitAuthenticated principal:
[test@J1LABS.EXAMPLE.COM]Connected to address
j1hol-001/129.145.128.102Context Established!Client principal is test@J1LABS.EXAMPLE.COMServer principal is host@j1hol-001Mutual authentication took place!Sending message: Hello There!Will read token of size 93Received 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".