// Copyright 1997 The Open Group Research Institute.  All rights reserved.
// Copyright 1999 Memesoft.  All rights reserved.

package krb5.lib.ccache;

import krb5.lib.*;

import krb5.lib.*;
import java.util.*;
import java.io.*;
import java.net.*;

/** 
 * Credentials cache implementation
 */
public abstract class CCacheImpl implements CredentialsCache {

	/**
	 * Sets primary principal
	 *
	 * @param principal is of type String
	 * @exception RealmException an exception
	 * @see krb5.lib.RealmException
	 */
	public void setPrimaryPrincipal(String principal) throws RealmException {
	    setPrimaryPrincipal(new PrincipalName(principal));
	}

	/**
	 * Returns enumerator for the credentials cache
	 *
	 * @return CCacheEnumerator is a result
	 * @param filter is of type CredentialsFilter
	 * @see krb5.lib.ccache.CCacheEnumerator
	 * @see krb5.lib.ccache.CredentialsFilter
	 */
	public synchronized CCacheEnumerator lookupCredentials(CredentialsFilter filter) {
	    CredentialsFilter[] filters = { filter };
	    return lookupCredentials(filters);
	}

	/**
	 * Returns a single credential
	 *
	 * @return Credentials is a result
	 * @param filter is of type CredentialsFilter
	 * @see krb5.lib.ccache.Credentials
	 * @see krb5.lib.ccache.CredentialsFilter
	 */
	public synchronized Credentials lookupSingleCredentials(CredentialsFilter filter) {
	    CredentialsFilter[] filters = { filter };
	    return lookupSingleCredentials(filters);
	}

	/**
	 * Returns the TGT service name
	 *
	 * @return PrincipalName is a result
	 * @see krb5.lib.PrincipalName
	 */
    public synchronized PrincipalName getTGTServiceName() {
	    if (getPrimaryPrincipal() == null)
	        return null;
	    PrincipalName tgtServiceName = null;
	    try {
	    //XXX replace with something better
	        tgtServiceName = new PrincipalName(
	            new String[] {
	                Krb5.TGS_DEFAULT_SRV_NAME,
	                getPrimaryPrincipal().getRealm().toString()
	            }, Krb5.KRB_NT_UNKNOWN);
	        tgtServiceName.setRealm(getPrimaryPrincipal().getRealm().toString());
	    } catch (RealmException e) {
	        tgtServiceName = null;
	    }
	    return tgtServiceName;
    }

	/**
	 * Returns initial credentials
	 *
	 * @return Credentials is a result
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @exception UnknownHostException an exception
	 * @see krb5.lib.KrbException
     * @see krb5.lib.ccache.Credentials
     * @see java.net.UnknownHostException
     * @see java.io.IOException
	 */
	public synchronized Credentials getInitialCredentials()
	    throws KrbException, IOException, UnknownHostException {
	    return getServiceCredentials(getTGTServiceName());
	}

	/**
	 * Returns a single valid credentials
	 *
	 * @return Credentials is a result
	 * @param serviceName is of type PrincipalName
	 * @see krb5.lib.PrincipalName
     * @see krb5.lib.ccache.Credentials
	 */
	public synchronized Credentials lookupSingleValidCredentials(PrincipalName serviceName) {
        CCacheEnumerator credsEnum = lookupCredentials(
            new CredentialsFilter[] {
                new MatchPrincipalCredsFilter(getPrimaryPrincipal()),
                new MatchServiceCredsFilter(serviceName),
                new UnexpiredCredsFilter()
            }
        );
        if (credsEnum.hasMoreCredentials())
            return credsEnum.nextCredential();
        return null;
	}

	/**
	 * Returns service credentials
	 *
	 * @return Credentials is a result
	 * @param serviceName is of type PrincipalName
	 * @exception RealmException an exception
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @exception UnknownHostException an exception
	 * @see krb5.lib.PrincipalName
     * @see krb5.lib.ccache.Credentials
     * @see krb5.lib.RealmException
     * @see krb5.lib.KrbException
     * @see java.net.UnknownHostException
     * @see java.io.IOException
	 */
	public synchronized Credentials getServiceCredentials(PrincipalName serviceName)
	    throws RealmException, KrbException, IOException, UnknownHostException {
        Credentials creds = lookupSingleValidCredentials(serviceName);
        if (creds != null)
            return creds;
        
        Credentials initialCreds = getInitialCredentials();
        if (initialCreds == null)
            return null;
        
		KrbTgsReq tgs_req = new KrbTgsReq(
			new KDCOptions(),
			initialCreds,
			serviceName,
			null, //KerberosTime from
			null, //KerberosTime till
			null, //KerberosTime rtime
			null, //int[] eTypes
			null, //HostAddresses addresses
			null, //AuthorizationData authorizationData
			null, //Ticket[] additionalTickets
			null //EncryptionKey subSessionKey
		);

		tgs_req.send(Config.KDC_HOST_NAME);
		KrbTgsRep tgs_rep = tgs_req.getKrbTgsRep(initialCreds);

		add(tgs_rep.creds());
			
		return tgs_rep.creds();
    }

	/**
	 * Returns initial credentials
	 *
	 * @return Credentials is a result
	 * @param principal is of type String
	 * @param pw is of type StringBuffer
	 * @exception RealmException an exception
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @exception UnknownHostException an exception
	 * @see krb5.lib.ccache.Credentials
	 * @see krb5.lib.RealmException
     * @see krb5.lib.KrbException
     * @see java.net.UnknownHostException
     * @see java.io.IOException
	 */
	public synchronized Credentials getInitialCredentials(String principal, StringBuffer pw)
	    throws RealmException, KrbException, IOException, UnknownHostException {
	    setPrimaryPrincipal(principal);
    	return getInitialCredentials(pw);
	}

	/**
	 * Returns initial credentials
	 *
	 * @return Credentials is a result
	 * @param pw is of type StringBuffer
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @exception UnknownHostException an exception
	 * @see krb5.lib.ccache.Credentials
     * @see krb5.lib.KrbException
     * @see java.net.UnknownHostException
     * @see java.io.IOException
	 */
	public synchronized Credentials getInitialCredentials(StringBuffer pw)
	    throws KrbException, IOException, UnknownHostException {
		KrbAsReq as_req = new KrbAsReq(
			new KDCOptions(),
			getPrimaryPrincipal(),
			null, // PrincipalName sname
			null, //KerberosTime from
			null, //KerberosTime till
			null, //KerberosTime rtime
			null, //int[] eTypes
			new HostAddresses(),
			null //Ticket[] additionalTickets
		);

		as_req.send(Config.KDC_HOST_NAME);
		KrbAsRep as_rep = as_req.getKrbAsRep(pw);

		add(as_rep.creds());
		    
	    return as_rep.creds();
	}

	/**
	 * Returns initial credentials
	 *
	 * @return Credentials is a result
	 * @param principal is of type String
	 * @param key is of type EncryptionKey
	 * @exception RealmException an exception
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @exception UnknownHostException an exception
	 * @see krb5.lib.ccache.Credentials
	 * @see krb5.lib.EncryptionKey
	 * @see krb5.lib.RealmException
     * @see krb5.lib.KrbException
     * @see java.net.UnknownHostException
     * @see java.io.IOException
	 */
	public synchronized Credentials getInitialCredentials(String principal, EncryptionKey key)
	    throws RealmException, KrbException, IOException, UnknownHostException {
	    setPrimaryPrincipal(principal);
    	return getInitialCredentials(key);
	}

	/**
	 * Returns initial credentials
	 *
	 * @return Credentials is a result
	 * @param key is of type EncryptionKey
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @exception UnknownHostException an exception
	 * @see krb5.lib.ccache.Credentials
	 * @see krb5.lib.EncryptionKey
     * @see krb5.lib.KrbException
     * @see java.net.UnknownHostException
     * @see java.io.IOException
	 */
	public synchronized Credentials getInitialCredentials(EncryptionKey key)
	    throws KrbException, IOException, UnknownHostException {
		KrbAsReq as_req = new KrbAsReq(
			new KDCOptions(),
			getPrimaryPrincipal(),
			null, // PrincipalName sname
			null, //KerberosTime from
			null, //KerberosTime till
			null, //KerberosTime rtime
			null, //int[] eTypes
			new HostAddresses(),
			null //Ticket[] additionalTickets
		);

		as_req.send(Config.KDC_HOST_NAME);
		KrbAsRep as_rep = as_req.getKrbAsRep(key);

		add(as_rep.creds());
		    
	    return as_rep.creds();
	}

	/**
	 * Returns service credentials
	 *
	 * @return Credentials is a result
	 * @param serviceName is of type String
	 * @exception RealmException an exception
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @exception UnknownHostException an exception
	 * @see krb5.lib.ccache.Credentials
	 * @see krb5.lib.RealmException
     * @see krb5.lib.KrbException
     * @see java.net.UnknownHostException
     * @see java.io.IOException
	 */
	public synchronized Credentials getServiceCredentials(String serviceName)
	    throws RealmException, KrbException, IOException, UnknownHostException {
    	return getServiceCredentials(new PrincipalName(serviceName));
	}

	/**
	 * Destroys
	 */
	public synchronized void destroy() {
	}

	/**
	 * Finalizes
	 */
	public void finalize() {
	    destroy();
	}
}