4102N/A/*
4102N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4102N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4102N/A *
4102N/A * This code is free software; you can redistribute it and/or modify it
4102N/A * under the terms of the GNU General Public License version 2 only, as
4102N/A * published by the Free Software Foundation.
4102N/A *
4102N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4102N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4102N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4102N/A * version 2 for more details (a copy is included in the LICENSE file that
4102N/A * accompanied this code).
4102N/A *
4102N/A * You should have received a copy of the GNU General Public License version
4102N/A * 2 along with this work; if not, write to the Free Software Foundation,
4102N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4102N/A *
4102N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4102N/A * or visit www.oracle.com if you need additional information or have any
4102N/A * questions.
4102N/A */
4102N/A
4102N/A/*
4102N/A * @test
4102N/A * @bug 6894072
4102N/A * @run main/othervm DynamicKeytab
4102N/A * @summary always refresh keytab
4102N/A */
4102N/A
4102N/Aimport java.io.File;
4102N/Aimport java.io.FileOutputStream;
4145N/Aimport java.nio.file.Files;
4145N/Aimport java.nio.file.Paths;
4102N/Aimport org.ietf.jgss.GSSException;
4102N/Aimport sun.security.jgss.GSSUtil;
4102N/Aimport sun.security.krb5.KrbException;
4102N/Aimport sun.security.krb5.internal.Krb5;
4102N/A
4102N/Apublic class DynamicKeytab {
4102N/A
4102N/A Context c, s;
4102N/A public static void main(String[] args)
4102N/A throws Exception {
4102N/A new DynamicKeytab().go();
4102N/A }
4102N/A
4102N/A void go() throws Exception {
4102N/A OneKDC k = new OneKDC(null);
4102N/A k.writeJAASConf();
4102N/A
4145N/A Files.delete(Paths.get(OneKDC.KTAB));
4102N/A
4102N/A // Starts with no keytab
4102N/A c = Context.fromJAAS("client");
4102N/A s = Context.fromJAAS("com.sun.security.jgss.krb5.accept");
4102N/A
4102N/A // Test 1: read new key 1 from keytab
4102N/A k.addPrincipal(OneKDC.SERVER, "pass1".toCharArray());
4102N/A k.writeKtab(OneKDC.KTAB);
4102N/A connect();
4102N/A
4102N/A // Test 2: service key cached, find 1 in keytab (now contains 1 and 2)
4102N/A k.addPrincipal(OneKDC.SERVER, "pass2".toCharArray());
4102N/A k.appendKtab(OneKDC.KTAB);
4102N/A connect();
4102N/A
4102N/A // Test 3: re-login. Now find 2 in keytab
4102N/A c = Context.fromJAAS("client");
4102N/A connect();
4102N/A
4102N/A // Test 4: re-login, KDC use 3 this time.
4102N/A c = Context.fromJAAS("client");
4102N/A // Put 3 and 4 into keytab but keep the real key back to 3.
4102N/A k.addPrincipal(OneKDC.SERVER, "pass3".toCharArray());
4102N/A k.appendKtab(OneKDC.KTAB);
4102N/A k.addPrincipal(OneKDC.SERVER, "pass4".toCharArray());
4102N/A k.appendKtab(OneKDC.KTAB);
4102N/A k.addPrincipal(OneKDC.SERVER, "pass3".toCharArray());
4102N/A connect();
4102N/A
4102N/A // Test 5: invalid keytab file, should ignore
4145N/A try (FileOutputStream fos = new FileOutputStream(OneKDC.KTAB)) {
4145N/A fos.write("BADBADBAD".getBytes());
4145N/A }
4102N/A connect();
4102N/A
4102N/A // Test 6: delete keytab file, identical to revoke all
4145N/A Files.delete(Paths.get(OneKDC.KTAB));
4102N/A try {
4102N/A connect();
4102N/A throw new Exception("Should not success");
4102N/A } catch (GSSException gsse) {
4102N/A System.out.println(gsse);
4102N/A KrbException ke = (KrbException)gsse.getCause();
4102N/A // KrbApReq.authenticate(*) if (dkey == null)...
4102N/A // This should have been Krb5.KRB_AP_ERR_NOKEY
4102N/A if (ke.returnCode() != Krb5.API_INVALID_ARG) {
4102N/A throw new Exception("Not expected failure code: " +
4102N/A ke.returnCode());
4102N/A }
4102N/A }
4102N/A
4102N/A // Test 7: 3 revoked, should fail (now contains only 5)
4102N/A k.addPrincipal(OneKDC.SERVER, "pass5".toCharArray());
4102N/A k.writeKtab(OneKDC.KTAB); // overwrite keytab, which means
4102N/A // old key is revoked
4102N/A try {
4102N/A connect();
4102N/A throw new Exception("Should not success");
4102N/A } catch (GSSException gsse) {
4102N/A System.out.println(gsse);
4102N/A KrbException ke = (KrbException)gsse.getCause();
4102N/A if (ke.returnCode() != Krb5.KRB_AP_ERR_BADKEYVER) {
4102N/A throw new Exception("Not expected failure code: " +
4102N/A ke.returnCode());
4102N/A }
4102N/A }
4102N/A
4102N/A // Test 8: an empty KDC means revoke all
4102N/A KDC.create("EMPTY.REALM").writeKtab(OneKDC.KTAB);
4102N/A try {
4102N/A connect();
4102N/A throw new Exception("Should not success");
4102N/A } catch (GSSException gsse) {
4102N/A System.out.println(gsse);
4102N/A KrbException ke = (KrbException)gsse.getCause();
4102N/A // KrbApReq.authenticate(*) if (dkey == null)...
4102N/A // This should have been Krb5.KRB_AP_ERR_NOKEY
4102N/A if (ke.returnCode() != Krb5.API_INVALID_ARG) {
4102N/A throw new Exception("Not expected failure code: " +
4102N/A ke.returnCode());
4102N/A }
4102N/A }
4102N/A }
4102N/A
4102N/A void connect() throws Exception {
4102N/A Thread.sleep(2000); // make sure ktab timestamp is different
4102N/A c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
4102N/A s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
4102N/A Context.handshake(c, s);
4102N/A }
4102N/A}