/*
 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug 6659990
 * @summary test the immutability of the Date fields in KerberosTicket class.
 * @ignore Must set up KDC and setup Kerberos configuration file
 */

import java.net.InetAddress;
import java.util.Date;
import java.io.*;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KerberosTicket;
import java.util.Base64;

public class KerberosTixDateTest {

    // Serialized KerberosTicket from JDK6 (encoded in BASE64)
    // Note: the KerberosTicket object is created using the same values as
    // the KerberosTicket 't' in main(). Deserialization should succeed
    // and the deserialized object should equal to 't'.
    static String serializedKerberosTix =
"rO0ABXNyACtqYXZheC5zZWN1cml0eS5hdXRoLmtlcmJlcm9zLktlcmJlcm9zVGlja2V0ZqGBbXB3" +
"w7sCAApbAAxhc24xRW5jb2Rpbmd0AAJbQkwACGF1dGhUaW1ldAAQTGphdmEvdXRpbC9EYXRlO0wA" +
"BmNsaWVudHQAMExqYXZheC9zZWN1cml0eS9hdXRoL2tlcmJlcm9zL0tlcmJlcm9zUHJpbmNpcGFs" +
"O1sAD2NsaWVudEFkZHJlc3Nlc3QAF1tMamF2YS9uZXQvSW5ldEFkZHJlc3M7TAAHZW5kVGltZXEA" +
"fgACWwAFZmxhZ3N0AAJbWkwACXJlbmV3VGlsbHEAfgACTAAGc2VydmVycQB+AANMAApzZXNzaW9u" +
"S2V5dAAmTGphdmF4L3NlY3VyaXR5L2F1dGgva2VyYmVyb3MvS2V5SW1wbDtMAAlzdGFydFRpbWVx" +
"AH4AAnhwdXIAAltCrPMX+AYIVOACAAB4cAAAAARhc24xc3IADmphdmEudXRpbC5EYXRlaGqBAUtZ" +
"dBkDAAB4cHcIAAAAAAC8YU54c3IALmphdmF4LnNlY3VyaXR5LmF1dGgua2VyYmVyb3MuS2VyYmVy" +
"b3NQcmluY2lwYWyZp31dDx4zKQMAAHhwdXEAfgAIAAAAEzARoAMCAQGhCjAIGwZjbGllbnR1cQB+" +
"AAgAAAAVGxNKTEFCUy5TRkJBWS5TVU4uQ09NeHBxAH4AC3VyAAJbWlePIDkUuF3iAgAAeHAAAAAg" +
"AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxAH4AC3NxAH4ADHVxAH4ACAAAABMwEaAD" +
"AgEBoQowCBsGc2VydmVydXEAfgAIAAAAFRsTSkxBQlMuU0ZCQVkuU1VOLkNPTXhzcgAkamF2YXgu" +
"c2VjdXJpdHkuYXV0aC5rZXJiZXJvcy5LZXlJbXBskoOG6DyvS9cDAAB4cHVxAH4ACAAAABUwE6AD" +
        "AgEBoQwECnNlc3Npb25LZXl4cQB+AAs=";

    public static void main(String[] args) throws Exception {
        byte[] asn1Bytes = "asn1".getBytes();
        KerberosPrincipal client = new KerberosPrincipal("client");
        KerberosPrincipal server = new KerberosPrincipal("server");
        byte[] keyBytes = "sessionKey".getBytes();
        long originalTime = 12345678L;
        Date inDate = new Date(originalTime);
        boolean[] flags = new boolean[9];
        flags[8] = true; // renewable
        KerberosTicket t = new KerberosTicket(asn1Bytes, client, server,
                keyBytes, 1 /*keyType*/, flags, inDate /*authTime*/,
                inDate /*startTime*/, inDate /*endTime*/,
                inDate /*renewTill*/, null /*clientAddresses*/);
        inDate.setTime(0); // for testing the constructor

        testDateImmutability(t, originalTime);
        testS11nCompatibility(t); // S11n: Serialization
    }

    private static void checkTime(KerberosTicket kt, long timeValue) {
        if (kt.getAuthTime().getTime() != timeValue) {
            throw new RuntimeException("authTime check fails!");
        }
        if (kt.getStartTime().getTime() != timeValue) {
            throw new RuntimeException("startTime check fails!");
        }
        if (kt.getEndTime().getTime() != timeValue) {
            throw new RuntimeException("endTime check fails!");
        }
        if (kt.getRenewTill().getTime() != timeValue) {
            throw new RuntimeException("renewTill check fails!");
        }
    }

    private static void testDateImmutability(KerberosTicket t, long origTime)
        throws Exception {
        // test the constructor
        System.out.println("Testing constructor...");
        checkTime(t, origTime);

        // test the getAuth/Start/EndTime() & getRenewTill() methods
        System.out.println("Testing getAuth/Start/EndTime() & getRenewTill()...");
        t.getAuthTime().setTime(0);
        t.getStartTime().setTime(0);
        t.getEndTime().setTime(0);
        t.getRenewTill().setTime(0);
        checkTime(t, origTime);

        System.out.println("DateImmutability Test Passed");
    }

    private static void checkEqualsAndHashCode(byte[] bytes, KerberosTicket t)
        throws IOException, ClassNotFoundException {
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        KerberosTicket deserializedTicket = (KerberosTicket)
                (new ObjectInputStream(bais).readObject());
        if (!deserializedTicket.equals(t)) {
            throw new RuntimeException("equals() check fails!");
        }
        if (deserializedTicket.hashCode() != t.hashCode()) {
            throw new RuntimeException("hashCode() check fails!");
        }
    }

    private static void testS11nCompatibility(KerberosTicket t)
        throws Exception {

        System.out.println("Testing against KerberosTicket from JDK6...");
        byte[] serializedBytes =
            Base64.getMimeDecoder().decode(serializedKerberosTix);
        checkEqualsAndHashCode(serializedBytes, t);

        System.out.println("Testing against KerberosTicket from current rel...");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new ObjectOutputStream(baos).writeObject(t);
        checkEqualsAndHashCode(baos.toByteArray(), t);

        System.out.println("S11nCompatibility Test Passed");
    }
}
