//SecureTCPServer.java

import java.io.*;
import java.net.*;
import krb5.lib.*;

class SecureTCPServer extends Thread {
	TCPClient client;
	static byte[] keyData = { 1, 2, 3, 4, 5, 6, 7, 8 };
    static EncryptionKey key = new EncryptionKey(keyData);
	static String principal =
		"jkrbsvc/firenze.ee.osf.org@jambalaya.ee.osf.org";
	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);
			ap_req.authenticate(
				key,
				new HostAddress(client.getInetAddress())
			);
			System.out.println("authenticated");
                        
            String client_name =
                   ap_req.creds().client.getNameString();
            String client_realm =
                   ap_req.creds().client.getRealmString();
			System.out.println("client_name=\"" +
				client_name + "\" client_realm=\"" +
				client_realm + "\"");
			//or...
			//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) {
			}
		}
	}

}
