//SecureTCPServer.java

import java.io.*;
import java.net.*;
import krb5.lib.*;
import krb5.lib.util.*;

class SecureTCPServer extends Thread {
	TCPClient client;
	static KeytabFile keytab = new KeytabFile("d:\\jkrb5\\myserver.keytab");
	static String principal = "myserver@MEMESOFT.COM";
	static int port = 8891;
    
	public SecureTCPServer(Socket newSocket) throws IOException {
		client = new TCPClient(newSocket);
	}

	public static void main(String[] args) throws IOException {
		ServerSocket server = new ServerSocket(port);
		try {
			System.out.println("listening...");
			do {
				SecureTCPServer client = new SecureTCPServer(server.accept());
				client.start();
			}
			while(true);
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			try {
				server.close();
			}
			catch (IOException e) {
			}
		}
	}

	public void run() {
		try {
			byte[] ibuf = client.receive();
			if (ibuf == null || ibuf.length == 0)
				//client disconnected
				return;

			System.out.println("received ap_req");

			KrbApReq ap_req = new KrbApReq(ibuf);
			ServiceName servName = new ServiceName(principal);
			ap_req.authenticate(
				keytab.getEncryptionKey(servName),
				new HostAddress(client.getInetAddress())
			);
			System.out.println("authenticated");
			System.out.println("client=\"" + ap_req.creds().client + "\"");
			System.out.println();

			EncryptionKey subSessionKey = null;
			if (ap_req.getSubKey() != null) {
				subSessionKey = ap_req.getSubKey();
			//or...
				//provide an alternate subSessionKey
				//String subKeyString = "eruithsa";
				//byte[] subKeyData = new byte[subKeyString.length()];
				//subKeyString.getBytes(0, subKeyString.length(), subKeyData, 0);
				//subSessionKey = new EncryptionKey(subKeyData);
			}

			LocalSeqNumber seqNumber = new LocalSeqNumber(
				ap_req.getSeqNumber());

			KrbApRep ap_rep = new KrbApRep(
				ap_req,
				subSessionKey,
				null //Integer startingSeqNumber
			);

			System.out.println("sending ap_rep");
			client.send(ap_rep.msg());

			do {
				ibuf = client.receive();
				if (ibuf == null || ibuf.length == 0)
					//client disconnected
					return;

				System.out.println("received");

				KrbRdPriv krb_priv = new KrbRdPriv(
					ibuf,
					ap_req.creds(),
					subSessionKey,
					seqNumber,
					new HostAddress(client.getInetAddress()),
					new HostAddress(),
					true, //boolean timestampRequired
					true //boolean seqNumberRequired
				);

				System.out.println("decrypted");

				byte[] userData = krb_priv.data();

				System.out.println("userData=\"" + new String(userData, 0) + "\"");

				String str = "<" + new String(userData, 0) + ">";
				byte[] userData2 = new byte[str.length()];
				str.getBytes(0, str.length(), userData2, 0);
				
				KrbMkPriv krb_priv_reply = new KrbMkPriv(
					userData2,
					ap_req.creds(),
					subSessionKey,
					new KerberosTime(KerberosTime.NOW),
					seqNumber,
					new HostAddress(),
					new HostAddress(client.getInetAddress())
				);

				System.out.println("sending");
				client.send(krb_priv_reply.msg());
				System.out.println();
			}
			while(true);
		}
		catch (IOException e) {
		}
		catch (KrbException e) {
			e.printStackTrace();
			System.out.println(e.krbErrorMessage());
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			try {
				client.close();
			}
			catch (IOException e) {
			}
		}
	}

}
