/**************************************************************************
 * 
 * Copyright 1997 The Open Group.
 * 
 * This software was developed by The Open Group Research Institute
 * ("TOG/RI").  This software, both binary and source (hereafter,
 * Software) is copyrighted by The Open Group and ownership remains with
 * The Open Group.
 * 
 * TOG/RI grants you (hereafter, Licensee) a license to use this software.
 * By obtaining, using and/or copying this software, you agree that you
 * have read, understood, and will comply with these terms and conditions:
 *
 * Export of this software from the United States of America may
 * require a specific license from the United States Government.
 * It is the responsibility of any person or organization contemplating
 * export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute
 * this software and its documentation for any purpose and without fee or
 * royalty is hereby granted, provided that you agree to comply with the
 * following copyright notice and statements, including the disclaimer, and
 * that the same appear on ALL copies of the software and documentation,
 * including modifications that you make for internal use or for
 * distribution:
 *
 * THE TOG/RI MAKES NO REPRESENTATIONS ABOUT THE SERVICEABILITY OF
 * THIS SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT
 * EXPRESS OR IMPLIED WARRANTY.  By way of example, but not limitation,
 * TOG/RI MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR
 * FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED
 * SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY
 * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.  THE TOG/RI SHALL
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE USERS OF THIS SOFTWARE.
 * 
 * By using or copying this Software, Licensee agrees to abide by the
 * copyright law and all other applicable laws of the U.S. including, but
 * not limited to, export control laws, and the terms of this license.
 *
 * The name of The Open Group Research Institue, or TOG/RI may NOT be used
 * in advertising or publicity pertaining to distribution of the software.
 * Title to copyright in this software and any associated documentation
 * shall at all times remain with TOG/RI, and the Licensee agrees to
 * preserve same.
 * 
 * Comments and questions and can be sent to ri-software@opengroup.org.
 * 
 **************************************************************************/

//KrbApplet.java -- Java-Kerberos Demo Applet

import java.awt.*;
import java.applet.*;
import java.io.*;
import java.net.*;
import krb5.lib.*;
import krb5.lib.asn1.*;
import krb5.lib.crypto.*;

public class KrbApplet extends Applet {

	private final String PARAM_realm_parm = "realm";
	private final String PARAM_kdc_parm = "kdc";
	private final String PARAM_principal_parm = "principal";
	private final String PARAM_password_parm = "password";
	private final String PARAM_service_parm = "service";
	private final String PARAM_message_parm = "message";
	private final String PARAM_appHost_parm = "appHost";
	private final String PARAM_appPort_parm = "appPort";

	private boolean logged_in;
	private boolean authenticated;
	private KrbTgsRep tgs_rep;
	private LocalSeqNumber seqNumber;
	private EncryptionKey subSessionKey;
	private TCPClient client;
	private String kdc;
	private String appHost;
	private int appPort;

	public String getAppletInfo()
	{
		return "Name: KrbApplet\r\n" +
		       "Author: Tom Sanfilippo\r\n" +
		       "Created with Visual Cafe Version 1.0";
	}

	public String[][] getParameterInfo()
	{
		String[][] info =
		{
			{ PARAM_realm_parm, "String", "Realm name" },
			{ PARAM_kdc_parm, "String", "KDC hostname" },
			{ PARAM_principal_parm, "String", "Principal name" },
			{ PARAM_password_parm, "String", "Password" },
			{ PARAM_service_parm, "String", "Service name" },
			{ PARAM_message_parm, "String", "Message text" },
			{ PARAM_appHost_parm, "String", "Application hostname" },
			{ PARAM_appPort_parm, "int", "Application port" },
		};
		return info;
	}

	void button1_Clicked(Event event) {

		//{{CONNECTION
		// Clear the text for TextArea
		textArea1.setText("");
		//}}

		String principal = txtPrincipal.getText();
		String realm = txtRealm.getText();
		String password = txtPassword.getText();
		String service = txtService.getText();
		kdc = txtKDC.getText();

		logged_in = false;
		authenticated = false;
		tgs_rep = null;
		seqNumber = null;
		subSessionKey = null;
		try {
		    if (client != null) {
		        client.close();
		        client = null;
		    }
		}
		catch (IOException e) {
		}

		try {

			//as_req

			KrbAsReq as_req = new KrbAsReq(
				new KDCOptions(),
				new PrincipalName(principal, realm),
				null, //PrincipalName sname
				null, //KerberosTime from
				null, //KerberosTime till
				null, //KerberosTime rtime
				null, //int[] eTypes
				new HostAddresses(),
				null //Ticket[] additionalTickets
			);

			textArea1.appendText("send as_req for " + principal + "@" +
			    realm + " to " + kdc + "\n");

			as_req.send(kdc);

			textArea1.appendText("receive as_rep from " + kdc + "\n");

			KrbAsRep as_rep = as_req.getKrbAsRep(new StringBuffer(password));

			//tgs_req

			KrbTgsReq tgs_req = new KrbTgsReq(
				new KDCOptions(),
				as_rep.creds(),
				new ServiceName(service, realm),
				null, //KerberosTime from
				null, //KerberosTime till
				null, //KerberosTime rtime
				null, //int[] eTypes
				null, //HostAddresses addresses
				null, //EncryptedData encAuthorizationData
				null, //Ticket[] additionalTickets,
				null //EncryptionKey subSessionKey
			);

			textArea1.appendText("send tgs_req for " + service + "@" +
			    realm + " to " + kdc + "\n");

			tgs_req.send(kdc);

			textArea1.appendText("receive tgs_req from " + kdc + "\n");

			tgs_rep = tgs_req.getKrbTgsRep(as_rep.creds());
			logged_in = true;

			textArea1.appendText("ok\n");

		} catch (KrbException e) {
			logged_in = false;
			textArea1.appendText(e.krbErrorMessage() + "\n");
		} catch (Exception e) {
			logged_in = false;
			textArea1.appendText(e + "\n");
		}
	}

    void button2_Clicked(Event event) {

		if (!logged_in)
			return;

		//{{CONNECTION
		// Clear the text for TextField
		txtResponse.setText("");
		//}}
		try {

    		if (!authenticated) {
    			client = new TCPClient(appHost, appPort);

    			seqNumber = new LocalSeqNumber();

    			KrbApReq ap_req = new KrbApReq(
    				new APOptions(Krb5.AP_OPTS_MUTUAL_REQUIRED),
    				tgs_rep.creds(),
    				null, //Checksum cksum
    				subSessionKey,
    				seqNumber,
    				null  //AuthorizationData authzData
    			);

    			textArea1.appendText("send ap_req\n");

    			client.send(ap_req.msg());
    			byte[] ibuf = client.receive();

    			textArea1.appendText("received ap_rep\n");

    			KrbApRep ap_rep = new KrbApRep(
    				ibuf,
    				tgs_rep.creds()
    			);
    			ap_rep.authenticate(ap_req);
    			authenticated = true;
    			if (ap_rep.getSubKey() != null)
    				subSessionKey = ap_rep.getSubKey();

    			textArea1.appendText("authenticated; ");
    			textArea1.appendText("server=" + tgs_rep.creds().server() + "\n");
    		}

    		if (authenticated) {
    			String str = txtMessage.getText();
    			byte[] userData = new byte[str.length()];
    			str.getBytes(0, str.length(), userData, 0);

				KrbMkPriv krb_priv = new KrbMkPriv(
					userData,
					tgs_rep.creds(),
					subSessionKey,
					new KerberosTime(KerberosTime.NOW),
					seqNumber,
					new HostAddress(),
					new HostAddress(client.getInetAddress())
				);

				textArea1.appendText("sending \"" + str + "\"\n");

				client.send(krb_priv.msg());
				byte[] ibuf = client.receive();

				textArea1.appendText("received response\n");

				KrbRdPriv krb_priv_reply = new KrbRdPriv(
					ibuf,
					tgs_rep.creds(),
					subSessionKey,
					seqNumber,
					new HostAddress(client.getInetAddress()),
					new HostAddress(),
					true, //boolean timestampRequired
					true //boolean seqNumberRequired
				);

				textArea1.appendText("decrypted\n");

				byte[] replyData = krb_priv_reply.data();
				String response = new String(replyData, 0);

				textArea1.appendText("response=\"" + response + "\"\n");
				txtResponse.setText(response);
			}

		} catch (KrbException e) {
			authenticated = false;
			seqNumber = null;
			subSessionKey = null;
			try {
			    if (client != null) {
			        client.close();
			        client = null;
			    }
			}
			catch (IOException f) {
			}
			textArea1.appendText(e.krbErrorMessage() + "\n");
		} catch (Exception e) {
			authenticated = false;
			seqNumber = null;
			subSessionKey = null;
			try {
			    if (client != null) {
			        client.close();
			        client = null;
			    }
			}
			catch (IOException f) {
			}
			textArea1.appendText(e + "\n");
		}

	}

	void button3_Clicked(Event event) {

		authenticated = false;
		seqNumber = null;
		subSessionKey = null;
		try {
		    if (client != null) {
		        client.close();
		        client = null;
		        textArea1.appendText("closed\n");
		    }
		}
		catch (IOException f) {
		}
	}

	public void init() {
		super.init();

		//{{INIT_CONTROLS
		setLayout(null);
		setBackground(java.awt.Color.lightGray);
		setSize(479,435);
		add(txtPrincipal);
		txtPrincipal.setBounds(108,12,116,29);
		add(txtRealm);
		txtRealm.setBounds(108,84,192,30);
		add(txtService);
		txtService.setBounds(108,156,192,30);
		label1.setText("Principal");
		add(label1);
		label1.setBounds(24,12,72,20);
		label2.setText("Password");
		add(label2);
		label2.setBounds(24,48,72,20);
		label3.setText("Realm");
		add(label3);
		label3.setBounds(24,84,72,20);
		label4.setText("KDC");
		add(label4);
		label4.setBounds(24,120,72,24);
		label5.setText("Service");
		add(label5);
		label5.setBounds(24,156,72,20);
		button1.setLabel("Login");
		add(button1);
		button1.setBounds(336,12,75,29);
		textArea1.setEditable(false);
		add(textArea1);
		textArea1.setBounds(24,204,432,132);
		txtPassword.setEchoChar('*');
		add(txtPassword);
		txtPassword.setBounds(108,48,116,30);
		add(txtKDC);
		txtKDC.setBounds(108,120,192,30);
		add(txtMessage);
		txtMessage.setBounds(108,348,192,30);
		label6.setText("Message");
		add(label6);
		label6.setBounds(24,348,72,20);
		button2.setLabel("Send");
		add(button2);
		button2.setBounds(336,348,75,29);
		txtResponse.setEditable(false);
		add(txtResponse);
		txtResponse.setBounds(108,384,192,30);
		label7.setText("Response");
		add(label7);
		label7.setBounds(24,384,72,20);
		button3.setLabel("Close");
		add(button3);
		button3.setBounds(336,384,75,29);
		//}}

		String param;
		param = getParameter(PARAM_realm_parm);
		if (param != null)
			txtRealm.setText(param);
		param = getParameter(PARAM_kdc_parm);
		if (param != null)
			txtKDC.setText(param);
		param = getParameter(PARAM_principal_parm);
		if (param != null)
			txtPrincipal.setText(param);
		param = getParameter(PARAM_password_parm);
		if (param != null)
			txtPassword.setText(param);
		param = getParameter(PARAM_service_parm);
		if (param != null)
			txtService.setText(param);
		param = getParameter(PARAM_message_parm);
		if (param != null)
			txtMessage.setText(param);
		param = getParameter(PARAM_appHost_parm);
		if (param != null)
			appHost = param;
		param = getParameter(PARAM_appPort_parm);
		if (param != null)
			appPort = Integer.parseInt(param);

	}

	public boolean handleEvent(Event event) {
		if (event.target == button1 && event.id == Event.ACTION_EVENT) {
			button1_Clicked(event);
			return true;
		}
		if (event.target == button2 && event.id == Event.ACTION_EVENT) {
			button2_Clicked(event);
			return true;
		}
		if (event.target == button3 && event.id == Event.ACTION_EVENT) {
			button3_Clicked(event);
			return true;
		}
		return super.handleEvent(event);
	}

	//{{DECLARE_CONTROLS
	java.awt.TextField txtPrincipal = new java.awt.TextField();
	java.awt.TextField txtRealm = new java.awt.TextField();
	java.awt.TextField txtService = new java.awt.TextField();
	java.awt.Label label1 = new java.awt.Label();
	java.awt.Label label2 = new java.awt.Label();
	java.awt.Label label3 = new java.awt.Label();
	java.awt.Label label4 = new java.awt.Label();
	java.awt.Label label5 = new java.awt.Label();
	java.awt.Button button1 = new java.awt.Button();
	java.awt.TextArea textArea1 = new java.awt.TextArea();
	java.awt.TextField txtPassword = new java.awt.TextField();
	java.awt.TextField txtKDC = new java.awt.TextField();
	java.awt.TextField txtMessage = new java.awt.TextField();
	java.awt.Label label6 = new java.awt.Label();
	java.awt.Button button2 = new java.awt.Button();
	java.awt.TextField txtResponse = new java.awt.TextField();
	java.awt.Label label7 = new java.awt.Label();
	java.awt.Button button3 = new java.awt.Button();
	//}}
}
