Skip to content

Instantly share code, notes, and snippets.

@ekoontz
Created November 18, 2010 17:30
Show Gist options
  • Save ekoontz/705316 to your computer and use it in GitHub Desktop.
Save ekoontz/705316 to your computer and use it in GitHub Desktop.
/*
* @(#)SampleClient.java
*
* Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* -Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduct the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Oracle or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
* DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR
* RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR
* ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
* FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
* SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
* THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that Software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*/
import org.ietf.jgss.*;
import java.net.Socket;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
/**
* A sample client application that uses JGSS to do mutual authentication
* with a server using Kerberos as the underlying mechanism. It then
* exchanges data securely with the server.
*
* Every message sent to the server includes a 4-byte application-level
* header that contains the big-endian integer value for the number
* of bytes that will follow as part of the JGSS token.
*
* The protocol is:
* 1. Context establishment loop:
* a. client sends init sec context token to server
* b. server sends accept sec context token to client
* ....
* 2. client sends a wrap token to the server.
* 3. server sends a MIC token to the client for the application
* message that was contained in the wrap token.
*/
public class SampleClient {
public static void main(String[] args)
throws IOException, GSSException {
// Obtain the command-line arguments and parse the port number
if (args.length < 3) {
System.err.println("Usage: java <options> Login SampleClient "
+ " <server> <hostName> <port>");
System.exit(-1);
}
String server = args[0];
String hostName = args[1];
int port = Integer.parseInt(args[2]);
Socket socket = new Socket(hostName, port);
DataInputStream inStream =
new DataInputStream(socket.getInputStream());
DataOutputStream outStream =
new DataOutputStream(socket.getOutputStream());
System.out.println("Connected to server "
+ socket.getInetAddress());
/*
* This Oid is used to represent the Kerberos version 5 GSS-API
* mechanism. It is defined in RFC 1964. We will use this Oid
* whenever we need to indicate to the GSS-API that it must
* use Kerberos for some purpose.
*/
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
GSSManager manager = GSSManager.getInstance();
/*
* Create a GSSName out of the server's name. The null
* indicates that this application does not wish to make
* any claims about the syntax of this name and that the
* underlying mechanism should try to parse it as per whatever
* default syntax it chooses.
*/
GSSName serverName = manager.createName(server, null);
/*
* Create a GSSContext for mutual authentication with the
* server.
* - serverName is the GSSName that represents the server.
* - krb5Oid is the Oid that represents the mechanism to
* use. The client chooses the mechanism to use.
* - null is passed in for client credentials
* - DEFAULT_LIFETIME lets the mechanism decide how long the
* context can remain valid.
* Note: Passing in null for the credentials asks GSS-API to
* use the default credentials. This means that the mechanism
* will look among the credentials stored in the current Subject
* to find the right kind of credentials that it needs.
*/
GSSContext context = manager.createContext(serverName,
krb5Oid,
null,
GSSContext.DEFAULT_LIFETIME);
// Set the desired optional features on the context. The client
// chooses these options.
context.requestMutualAuth(true); // Mutual authentication
context.requestConf(true); // Will use confidentiality later
context.requestInteg(true); // Will use integrity later
// Do the context eastablishment loop
byte[] token = new byte[0];
while (!context.isEstablished()) {
// token is ignored on the first call
token = context.initSecContext(token, 0, token.length);
// Send a token to the server if one was generated by
// initSecContext
if (token != null) {
System.out.println("Will send token of size "
+ token.length
+ " from initSecContext.");
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
}
// If the client is done with context establishment
// then there will be no more tokens to read in this loop
if (!context.isEstablished()) {
token = new byte[inStream.readInt()];
System.out.println("Will read input token of size "
+ token.length
+ " for processing by initSecContext");
inStream.readFully(token);
}
}
System.out.println("Context Established! ");
System.out.println("Client is " + context.getSrcName());
System.out.println("Server is " + context.getTargName());
/*
* If mutual authentication did not take place, then only the
* client was authenticated to the server. Otherwise, both
* client and server were authenticated to each other.
*/
if (context.getMutualAuthState())
System.out.println("Mutual authentication took place!");
byte[] messageBytes = "Hello There!\0".getBytes();
/*
* The first MessageProp argument is 0 to request
* the default Quality-of-Protection.
* The second argument is true to request
* privacy (encryption of the message).
*/
MessageProp prop = new MessageProp(0, true);
/*
* Encrypt the data and send it across. Integrity protection
* is always applied, irrespective of confidentiality
* (i.e., encryption).
* You can use the same token (byte array) as that used when
* establishing the context.
*/
token = context.wrap(messageBytes, 0, messageBytes.length, prop);
System.out.println("Will send wrap token of size " + token.length);
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
/*
* Now we will allow the server to decrypt the message,
* calculate a MIC on the decrypted message and send it back
* to us for verification. This is unnecessary, but done here
* for illustration.
*/
token = new byte[inStream.readInt()];
System.out.println("Will read token of size " + token.length);
inStream.readFully(token);
context.verifyMIC(token, 0, token.length,
messageBytes, 0, messageBytes.length,
prop);
System.out.println("Verified received MIC for message.");
System.out.println("Exiting...");
context.dispose();
socket.close();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment