*
===========================================================================
* Licensed Materials - Property of IBM
* IBM Security Software Development Kit, Java
(tm) Technology Edition
*
* (C) Copyright IBM Corp. 2002, 2005 All
Rights Reserved.
*
* US Government
Users Restricted Rights - Use, duplication or
*
disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
===========================================================================
package
com.ibm.security.jgss.test;
import org.ietf.jgss.*;
import com.ibm.security.jgss.Debug;
import java.io.*;
import
java.net.*;
import java.util.*;
/**
* A JGSS sample client;
* to be used in conjunction with the JGSS
sample server.
* The client first establishes a context with
the server
* and then sends wrapped message followed by a
MIC to the server.
* The MIC is calculated over the plain text
that was wrapped.
* The client requires to server to
authenticate itself
* (mutual authentication) during context
establishment.
* It also delegates its credentials to the
server.
* <p>
* It sets the JAVA variable
* <code>javax.security.auth.useSubjectCredsOnly</code>
to <code>false</code>
* so that JGSS will not acquire credentials
through JAAS.
* <p>
* The client takes input parameters, and
complements it
* with information from the jgss.ini file; any
required input not
* supplied on the command line is taking from
the jgss.ini file.
* <p>
* Usage: Client [options]
* <p>
* The -? option produces a help message
including supported options.
* <p>
* This sample client does not use JAAS.
* The client can be run against the JAAS
sample client and server.
* See {@link JAASClient
JAASClient} for a sample client that uses JAAS.
*
* @author Thomas Owusu
* @version %I%, %G%
*/
class
Client
{
private Util testUtil = null;
private String myName = null;
private GSSName gssName = null;
private String serverName = null;
private int servicePort = 0;
private GSSManager
mgr = GSSManager.getInstance();
private GSSName
service = null;
private GSSContext
context = null;
private String program = "Client";
private String debugPrefix=
"Client: ";
private TCPComms tcp = null;
private String data = null;
private byte[] dataBytes = null;
private String serviceHostname=
null;
private GSSCredential
gssCred = null;
private boolean useStreams;
private static Debug debug
= new Debug();
private static final String usageString =
"\t[-?] [-n name] [-s
serverName]"
+ "\n\t[-h serverHost
[:port]] [-p port] [-m msg]"
+ "\n"
+ "\n -?\t\t\thelp;
produces this message"
+ "\n -n name\t\tthe
client's principal name (without realm)"
+ "\n -s serverName\t\tthe
server's principal name (without realm)"
+ "\n -h serverHost[:port]\tthe server's hostname"
+ " (and optional port
number)"
+ "\n -p port\t\tthe port
on which the server will be listening"
+ "\n -m msg\t\tmessage
to send to the server";
// Caller must call initialize (may need to
call processArgs first).
public Client (String programName)
throws Exception
{
testUtil =
new Util();
if (programName
!= null)
{
program = programName;
debugPrefix
= programName + ": ";
}
}
// Caller must call initialize (may need to
call processArgs first).
Client (String programName,
boolean useSubjectCredsOnly)
throws Exception
{
this(programName);
setUseSubjectCredsOnly(useSubjectCredsOnly);
}
public Client(GSSCredential
myCred,
String serverNameWithoutRealm,
String serverHostname,
int
serverPort,
String message,
boolean
useStreams)
throws Exception
{
if (useStreams)
{
this.useStreams
= useStreams;
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+
"Using streams");
}
testUtil =
new Util();
if (myCred !=
null)
{
gssCred =
myCred;
}
else
{
throw new GSSException(GSSException.NO_CRED, 0,
"Null input credential");
}
init(serverNameWithoutRealm,
serverHostname, serverPort,
message);
}
void setUseSubjectCredsOnly(boolean useSubjectCredsOnly)
{
final String subjectOnly
= useSubjectCredsOnly ? "true" :
"false";
final String property = "javax.security.auth.useSubjectCredsOnly";
String temp = (String)java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(property));
if (temp == null)
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "setting useSubjectCredsOnly property to "
+ useSubjectCredsOnly);
// Property not set. Set it to the
specified value.
java.security.AccessController.doPrivileged(
new
java.security.PrivilegedAction() {
public Object run() {
System.setProperty(property,
subjectOnly);
return null;
}
});
}
else
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "useSubjectCredsOnly
property already set "
+ "in JVM to " + temp);
}
}
private void init(String myNameWithoutRealm,
String serverNameWithoutRealm,
String serverHostname,
int serverPort,
String message) throws
Exception
{
myName = myNameWithoutRealm;
init(serverNameWithoutRealm,
serverHostname, serverPort,
message);
}
private void init(String serverNameWithoutRealm,
String serverHostname,
int serverPort,
String message) throws Exception
{
// peer's name
if (serverNameWithoutRealm
!= null)
{
this.serverName
= serverNameWithoutRealm;
}
else
{
this.serverName
= testUtil.getDefaultServicePrincipalWithoutRealm();
}
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "server name=" + this.serverName);
// peer's host
if (serverHostname
!= null)
{
this.serviceHostname
= serverHostname;
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "server host=" + this.serviceHostname);
}
else
{
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix +
"server host=<local host>");
//this.serviceHostname
= testUtil.getDefaultServiceHostname();
}
// peer's port
if (serverPort
> 0)
{
this.servicePort
= serverPort;
}
else
{
this.servicePort
= testUtil.getDefaultServicePort();
}
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "server port=" + this.servicePort);
// message for peer
if (message != null)
{
this.data
= message;
}
else
{
this.data
= "I think. Therefore I am?";
}
this.dataBytes
= this.data.getBytes();
tcp = new TCPComms(serviceHostname, servicePort);
}
void initialize() throws Exception
{
Oid
krb5MechanismOid = new Oid("1.2.840.113554.1.2.2");
if (gssCred
== null)
{
if (myName != null)
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+
"creating GSSName USER_NAME for "
+ myName);
gssName
= mgr.createName(
myName,
GSSName.NT_USER_NAME,
krb5MechanismOid);
//GSSManagerImpl.MECH_TYPE_KRB5);
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "Canonicalized GSSName="
+ gssName);
}
else
gssName
= null; // for default credentials
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "creating"
+ ((gssName
== null)? " default " : " ")
+ "credential");
gssCred =
mgr.createCredential(
gssName,
GSSCredential.DEFAULT_LIFETIME,
(Oid)null,
GSSCredential.INITIATE_ONLY);
if (gssName
== null)
{
gssName
= gssCred.getName();
myName = gssName.toString();
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "default credential principal=" + myName);
}
int
lifetime = gssCred.getRemainingLifetime();
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "lifetime
remaining on cred: " + lifetime + " secs");
Oid[] mechs = gssCred.getMechs();
lifetime = gssCred.getRemainingInitLifetime(mechs[0]);
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "Init lifetime
remaining on cred for mech
" + mechs[0]
+ ": " +
lifetime + " secs");
}
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ gssCred);
String serviceStr
= serverName;
if (serviceHostname
!= null) {
serviceStr +=
"@" + serviceHostname;
}
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "creating canonicalized GSSName for serverName " + serviceStr);
service = mgr.createName(serviceStr,
GSSName.NT_HOSTBASED_SERVICE,
krb5MechanismOid);
//GSSManagerImpl.MECH_TYPE_KRB5);
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "Canonicalized server name =
" + service);
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "Raw data=" + data);
}
void establishContext(BitSet flags) throws Exception
{
try {
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "creating GSScontext");
Oid defaultMech = null;
context = mgr.createContext(service,
defaultMech, gssCred,
GSSContext.INDEFINITE_LIFETIME);
if (flags != null)
{
if (flags.get(Util.CONTEXT_OPTS_MUTUAL))
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "requesting mutualAuthn");
context.requestMutualAuth(true);
}
if (flags.get(Util.CONTEXT_OPTS_INTEG))
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "requesting
integrity");
context.requestInteg(true);
}
if (flags.get(Util.CONTEXT_OPTS_CONF))
{
context.requestConf(true);
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "requesting
confidentiality");
}
if (flags.get(Util.CONTEXT_OPTS_DELEG))
{
context.requestCredDeleg(true);
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "requesting delegation");
}
if (flags.get(Util.CONTEXT_OPTS_REPLAY))
{
context.requestReplayDet(true);
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "requesting replay detection");
}
if (flags.get(Util.CONTEXT_OPTS_SEQ))
{
context.requestSequenceDet(true);
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "requesting out-of-sequence
detection");
}
// Add more later!
}
byte[] response = null;
byte[] request = null;
int len = 0;
boolean
done = false;
ByteArrayInputStream
bis = null;
ByteArrayOutputStream
bos = null;
do {
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "Calling initSecContext");
if (!useStreams)
{
request = context.initSecContext(response,
0, len);
} else {
bos
= new ByteArrayOutputStream();
if (response == null) {
context.initSecContext((InputStream)null, bos);
} else {
bis
= new ByteArrayInputStream(response);
context.initSecContext(bis, bos);
}
request = bos.toByteArray();
}
if (request != null && request.length != 0)
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "Sending context
token");
tcp.send(request);
}
done = context.isEstablished();
if (!done)
{
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "Receiving response token");
byte[] temp = tcp.receive();
response = temp;
len = response.length;
}
} while(!done);
if (debug.on(Debug.OPTS_CAT_APPLICATION)) {
String msg
= "established context with acceptor "
+
context.getTargName();
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ msg);
boolean
delegationState = context.getCredDelegState();
msg =
"getCredDelegState=" + delegationState;
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ msg);
}
} catch (Exception exc)
{
exc.printStackTrace();
throw exc;
}
}
void doMIC()
throws Exception
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "generating MIC");
byte[] mic =
null;
if (!useStreams)
{
mic = context.getMIC(dataBytes, 0, dataBytes.length, null);
} else {
ByteArrayInputStream
bis = new ByteArrayInputStream(dataBytes);
ByteArrayOutputStream
bos = new ByteArrayOutputStream();
context.getMIC(bis, bos, null);
mic = bos.toByteArray();
}
if (mic !=
null)
{
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "sending MIC");
tcp.send(mic);
}
else
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix + "getMIC
Failed");
}
void doWrap()
throws Exception
{
MessageProp
mp = new MessageProp(true);
mp.setPrivacy(context.getConfState());
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "wrapping message");
byte[] wrapped = null;
if (!useStreams)
{
wrapped = context.wrap(dataBytes, 0, dataBytes.length,
mp);
} else {
ByteArrayInputStream
bis = new ByteArrayInputStream(dataBytes);
ByteArrayOutputStream
bos = new ByteArrayOutputStream();
context.wrap(bis, bos, mp);
wrapped = bos.toByteArray();
}
if (wrapped != null)
{
debug.out(Debug.OPTS_CAT_APPLICATION,
debugPrefix
+ "sending wrapped message");
tcp.send(wrapped);
}
else
debug.out(Debug.OPTS_CAT_APPLICATION, debugPrefix
+ "wrap Failed");
}
void printUsage()
{
System.out.println(program
+ usageString);
}
void processArgs(String[]
args) throws Exception {
String port = null;
String myName = null;
int servicePort = 0;
String serviceHostname = null;
String sHost
= null;
String msg =
null;
int ch = -1;
if (args !=
null && args.length > 0) {
for (int i=0; i<args.length;
i++) {
if ("-?".equals(args[i])) {
printUsage();
System.exit(1);
} else if ("-h".equals(args[i])) {
if (sHost
== null) {
if (i+1 >= args.length) {
noArgForOptionError("-h");
}
sHost
= args[++i];
int
p = sHost.indexOf(':');
if (p != -1) {
String temp1 = sHost.substring(0, p);
if (port == null)
port = sHost.substring(p+1,
sHost.length()).trim();
sHost
= temp1;
}
continue;
} else {
duplicateOptionError("-h");
}
} else if ("-p".equals(args[i])) {
if (port == null) {
if (i+1 >= args.length)
{
noArgForOptionError("-p");
}
port = args[++i];
continue;
} else {
duplicateOptionError("-p");
}
} else if ("-m".equals(args[i])) {
if (msg
== null) {
if (i+1 >= args.length) {
noArgForOptionError("-m");
}
msg
= args[++i];
continue;
} else {
duplicateOptionError("-m");
}
} else if ("-n".equals(args[i])) {
if (myName == null) {
if (i+1 >= args.length) {
noArgForOptionError("-n");
}
myName = args[++i];
continue;
} else {
duplicateOptionError("-n");
}
} else if ("-s".equals(args[i])) {
if (serverName == null) {
if (i+1 >= args.length) {
noArgForOptionError("-n");
}
serverName = args[++i];
continue;
} else {
duplicateOptionError("-s");
}
}
}
}
if ((port != null) && (port.length() > 0))
{
int p =
-1;
try {
p = Integer.parseInt(port);
} catch (Exception exc) {
System.out.println("Bad
port input: "+port);
}
if (p != -1)
servicePort
= p;
}
if ((sHost !=
null) && (sHost.length() > 0)) {
serviceHostname
= sHost;
}
init(myName, serverName, serviceHostname, servicePort, msg);
}
private void duplicateOptionError(String
option) {
System.out.println("Duplicate
option: " + option);
printUsage();
System.exit(1);
}
private void noArgForOptionError(String
option) {
System.out.println("Missing
argument for option: " + option);
printUsage();
System.exit(1);
}
void interactWithAcceptor(BitSet flags) throws Exception
{
establishContext(flags);
doWrap();
doMIC();
}
void interactWithAcceptor()
throws Exception
{
BitSet flags
= new BitSet();
flags.set(Util.CONTEXT_OPTS_MUTUAL);
flags.set(Util.CONTEXT_OPTS_CONF);
flags.set(Util.CONTEXT_OPTS_INTEG);
flags.set(Util.CONTEXT_OPTS_DELEG);
interactWithAcceptor(flags);
}
void dispose() throws Exception
{
if (tcp !=
null)
{
tcp.close();
}
}
public static void main(String args[]) throws Exception
{
System.out.println(debug.toString()); // XXXXXXX
String programName
= "Client";
Client client
= null;
try {
client = new Client(programName,
false); //
don't use Subject creds.
client.processArgs(args);
client.initialize();
client.interactWithAcceptor();
} catch (Exception exc)
{
debug.out(Debug.OPTS_CAT_APPLICATION,
programName
+ " Exception: " + exc.toString());
exc.printStackTrace();
throw exc;
} finally {
try {
if (client != null)
client.dispose();
} catch (Exception exc) {}
}
debug.out(Debug.OPTS_CAT_APPLICATION,
programName + ": done");
}
}