/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.harmony.auth.internal.kerberos.v5;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;

import org.apache.harmony.auth.internal.nls.Messages;
import org.apache.harmony.security.asn1.DerInputStream;

/**
 * @see http://www.ietf.org/rfc/rfc4120.txt
 */
public class KrbClient {

    // default kdc server
    private static final String DEFAULT_KDC = "java.security.krb5.kdc"; //$NON-NLS-1$

    // default realm
    private static final String DEFAULT_REALM = "java.security.krb5.realm"; //$NON-NLS-1$

    private static String kdc;

    private static String realm;

    private static int port = 88;//default

    private static final int BUF_SIZE = 1024;

    private static boolean isInitialized = false;
    
    private KrbClient() {
        // no objects
    }

    public static synchronized String getRealm() throws KerberosException {
        if (!isInitialized) {
            setEnv();
        }
        return realm;
    }

    private static void setEnv() throws KerberosException {
        if (isInitialized) {
            return;
        }

        //TODO put in doPrivileged
        kdc = System.getProperty(DEFAULT_KDC);
        realm = System.getProperty(DEFAULT_REALM);
        if (kdc == null && realm != null || kdc != null && realm == null) {
            // both properties should be set or unset together
            throw new KerberosException();//FIXME message
        } else if (kdc == null && realm == null) {

            // reading config from configuration file 'krb5.conf'
            KrbConfig config = null;
            try {
                config = KrbConfig.getSystemConfig();
            } catch (IOException e) {
                throw new KerberosException(e.getMessage());
            }

            if (config == null) {
                // no config file was found
                throw new KerberosException();//FIXME err msg
            }
            realm = config.getValue("libdefaults", //$NON-NLS-1$
                    "default_realm"); //$NON-NLS-1$
            
            //TODO set KDC
            return;
        }

        int pos = kdc.indexOf(':');
        if (pos != -1) {
            port = Integer.parseInt(kdc.substring(pos + 1));
            kdc = kdc.substring(0, pos);
        }
        
        isInitialized = true;
    }

    /**
     * Get credentials from Authentication Service.
     * 
     * @param address - service host
     * @param port - service port
     * @param cname - client's principal identifier
     * @param realm - client's realm
     * @return - ticket
     */
    public static KDCReply doAS(PrincipalName cname, char[] password)
            throws KerberosException {

        setEnv();

        PrincipalName sname = new PrincipalName(PrincipalName.NT_SRV_XHST,
                new String[] { "krbtgt", realm }); //$NON-NLS-1$

        KDCRequest request = new KDCRequest(KDCRequest.AS_REQ, cname, realm,
                sname);

        try {
            DatagramSocket socket = request.send(InetAddress.getByName(kdc),
                    port);

            ByteArrayOutputStream out = new ByteArrayOutputStream(BUF_SIZE);

            byte[] buf = new byte[BUF_SIZE];

            DatagramPacket resp = new DatagramPacket(buf, buf.length);

            int bytesRead = BUF_SIZE;
            while (bytesRead == BUF_SIZE) {
                socket.receive(resp);

                bytesRead = resp.getLength();
                out.write(buf, resp.getOffset(), bytesRead);
            }
            DerInputStream in = new DerInputStream(out.toByteArray());

            if (in.tag == KDCReply.AS_REP_ASN1.constrId) { //TODO AS reply
                KDCReply reply = (KDCReply) KDCReply.AS_REP_ASN1.decode(in);

                KerberosKey key = new KerberosKey(new KerberosPrincipal(cname
                        .getName()[0]
                        + '@' + realm, cname.getType()), password, "DES");

                reply.decrypt(key);

                return reply;
            } else if (in.tag == KerberosErrorMessage.ASN1.constrId) {
                KerberosErrorMessage errMsg = KerberosErrorMessage.decode(in);
                // auth.52=Error code: {0}
                throw new KerberosException(Messages.getString(
                        "auth.52", errMsg.getErrorCode())); //$NON-NLS-1$
            } else {
                new KerberosException(); //FIXME
            }

        } catch (IOException e) {
            new KerberosException(e.getMessage()); //FIXME 
        }

        return null;
    }

    public static KDCReply doTGS() throws KerberosException {
        setEnv();

        return null;
    }
}

@@ -5360,32 +5360,38 @@
                 
+throw 
 new KerberosExce
@@ -5464,24 +5464,30 @@
             
+throw 
 new Kerberos
@@ -5531,38 +5531,16 @@
        %7D
-%0A%0A        return null;
 %0A    %7D%0A%0A

Ensure the exceptions are thrown when things go wrong.