// Copyright 1997 The Open Group Research Institute.  All rights reserved.
// Copyright 1999 Memesoft.  All rights reserved.

package krb5.lib.ccache;

import krb5.lib.*;

/**
 * Credentials
 */
public class Credentials implements Cloneable {

	/**
	 * PA data
	 */
	public PAData[] pAData; //optional; may contain proper salt

	/**
	 * Client realm
	 */
	public Realm crealm;

	/**
	 * Client name
	 */
	public PrincipalName cname;

	/**
	 * Ticket
	 */
	public Ticket ticket;

	/**
	 * Key
	 */
	public EncryptionKey key;

	/**
	 * Key expiration time
	 */
	public KerberosTime keyExpiration; //optional; for initial tickets only

	/**
	 * Ticket flags
	 */
	public TicketFlags flags;

	/**
	 * Authentication time
	 */
	public KerberosTime authtime;

	/**
	 * Start time
	 */
	public KerberosTime starttime; //optional

	/**
	 * End time
	 */
	public KerberosTime endtime;

	/**
	 * Renew till
	 */
	public KerberosTime renewTill; //optional

	/**
	 * Server realm
	 */
	public Realm srealm;

	/**
	 * Server name
	 */
	public PrincipalName sname;

	/**
	 * Address
	 */
	public HostAddresses caddr; //optional; for proxied tickets only

	/**
	 * Second ticket
	 */
    public Ticket secondTicket; //optional

	/**
	 * Authorization data
	 */
    public AuthorizationData authorizationData; //optional

	/**
	 * Is encryption in server key
	 */
    public boolean isEncInSKey;

	/**
	 * Class constructor
	 */
	Credentials() {
	}

	/**
	 * Class constructor
	 *
	 * @param kdcRep is of type KDCRep
	 * @param new_secondTicket is of type Ticket
	 * @param new_authorizationData is of type AuthorizationData
	 * @param new_isEncInSKey is of type boolean
	 * @see krb5.lib.KDCRep
	 * @see krb5.lib.Ticket
	 * @see krb5.lib.AuthorizationData
	 */
	public Credentials(
		KDCRep kdcRep,
		Ticket new_secondTicket,
		AuthorizationData new_authorizationData,
		boolean new_isEncInSKey
	) {
		if (kdcRep.encKDCRepPart == null) //can't store while encrypted
			//XXX should raise exception
			return;
		if (kdcRep.pAData != null) {
			pAData = new PAData[kdcRep.pAData.length];
			for (int i = 0; i < kdcRep.pAData.length; i++)
				pAData[i] = (PAData)kdcRep.pAData[i].clone();
		}
		crealm = (Realm)kdcRep.crealm.clone();
		cname = (PrincipalName)kdcRep.cname.clone();
		ticket = (Ticket)kdcRep.ticket.clone();
		key = (EncryptionKey)kdcRep.encKDCRepPart.key.clone();
		if (kdcRep.encKDCRepPart.keyExpiration != null)
    		keyExpiration = (KerberosTime)kdcRep.encKDCRepPart.keyExpiration.clone();
		flags = (TicketFlags)kdcRep.encKDCRepPart.flags.clone();
		authtime = (KerberosTime)kdcRep.encKDCRepPart.authtime.clone();
		//XXX need to check for existence first!!!
		if (kdcRep.encKDCRepPart.starttime != null)
		    starttime = (KerberosTime)kdcRep.encKDCRepPart.starttime.clone();
		endtime = (KerberosTime)kdcRep.encKDCRepPart.endtime.clone();
		if (kdcRep.encKDCRepPart.renewTill != null)
		    renewTill = (KerberosTime)kdcRep.encKDCRepPart.renewTill.clone();
		srealm = (Realm)kdcRep.encKDCRepPart.srealm.clone();
		sname = (PrincipalName)kdcRep.encKDCRepPart.sname.clone();
		if (kdcRep.encKDCRepPart.caddr != null)
		    caddr = (HostAddresses)kdcRep.encKDCRepPart.caddr.clone();
		if (new_secondTicket != null)
		    secondTicket = (Ticket)new_secondTicket.clone();
		if (new_authorizationData != null)
		    authorizationData =
			    (AuthorizationData)new_authorizationData.clone();
		isEncInSKey = new_isEncInSKey;
	}

	/**
	 * Clones a copy of the object
	 *
	 * @return Object is a result
	 */
	public Object clone()
	{
	    Credentials myClone = null;
	    // Everything above and within Credentials is Cloneable
	    // so we should *never* see a CloneNotSupportedException
	    try {
    	    myClone = (Credentials)super.clone();
    	    if (pAData != null) {
    		    myClone.pAData = new PAData[pAData.length];
    		    for (int i = 0; i < pAData.length; i++)
    			    myClone.pAData[i] = (PAData)pAData[i].clone();
    	    }
    		myClone.crealm = (Realm)crealm.clone();
    		myClone.cname = (PrincipalName)cname.clone();
    		myClone.ticket = (Ticket)ticket.clone();
    		myClone.key = (EncryptionKey)key.clone();
    	    if (keyExpiration != null)
    		    myClone.keyExpiration = (KerberosTime)keyExpiration.clone();
    		myClone.flags = (TicketFlags)flags.clone();
    		myClone.authtime = (KerberosTime)authtime.clone();
    	    if (starttime != null)
    		    myClone.starttime = (KerberosTime)starttime.clone();
    		myClone.endtime = (KerberosTime)endtime.clone();
    	    if (renewTill != null)
    		    myClone.renewTill = (KerberosTime)renewTill.clone();
    		myClone.srealm = (Realm)srealm.clone();
    		myClone.sname = (PrincipalName)sname.clone();
    	    if (caddr != null)
    		    myClone.caddr = (HostAddresses)caddr.clone();
    	    if (secondTicket != null)
    		    myClone.secondTicket = (Ticket)secondTicket.clone();
    	    if (authorizationData != null)
    		    myClone.authorizationData =
    			    (AuthorizationData)authorizationData.clone();
    	    myClone.isEncInSKey = isEncInSKey;
	    } catch (CloneNotSupportedException e) {
	        myClone = null;
	    }
	    return myClone;
	}

	/**
	 * Returns client name
	 *
	 * @return PrincipalName is a result
	 * @see krb5.lib.PrincipalName
	 */
	public PrincipalName client() {
	    PrincipalName name = (PrincipalName)cname.clone();
	    name.setRealm((Realm)crealm.clone());
	    return name;
	}

	/**
	 * Returns server name
	 *
	 * @return PrincipalName is a result
	 * @see krb5.lib.PrincipalName
	 */
	public PrincipalName server() {
	    PrincipalName name = (PrincipalName)sname.clone();
	    name.setRealm((Realm)srealm.clone());
	    return name;
	}

    // zero out any sensitive fields in the credential
	// (session keys, encrypted fields, etc)
	/**
	 * Destroys
	 */
	public void destroy() {
	}

	/**
	 * Returns KRB credentials
	 *
	 * @return KrbCreds is a result
	 * @exception RealmException an exception
	 * @see krb5.lib.KrbCreds
	 * @see krb5.lib.RealmException
	 */
	public KrbCreds getKrbCreds() throws RealmException {
	    PrincipalName client = (PrincipalName)cname.clone();
	    client.setRealm((Realm)crealm.clone());
	    PrincipalName server = (PrincipalName)sname.clone();
	    server.setRealm((Realm)srealm.clone());
	    return new KrbCreds(
	        (Ticket)ticket.clone(),
	        client,
	        server,
	        (EncryptionKey)key.clone()
	    );
	}

}