< prev index next >

test/sun/security/krb5/auto/ReplayCacheTestProc.java

Print this page
rev 15878 : 8168518: rcache interop with krb5-1.15

*** 23,35 **** /* * @test * @bug 7152176 * @summary More krb5 tests ! * @library ../../../../java/security/testlibrary/ * @compile -XDignore.symbol.file ReplayCacheTestProc.java ! * @run main/othervm/timeout=100 ReplayCacheTestProc */ import java.io.*; import java.nio.BufferUnderflowException; import java.nio.channels.SeekableByteChannel; --- 23,36 ---- /* * @test * @bug 7152176 * @summary More krb5 tests ! * @library ../../../../java/security/testlibrary/ /test/lib * @compile -XDignore.symbol.file ReplayCacheTestProc.java ! * @run main/othervm/timeout=300 ReplayCacheTestProc ! * @run main/othervm/timeout=300 -Djdk.krb5.rcache.usemd5=true ReplayCacheTestProc */ import java.io.*; import java.nio.BufferUnderflowException; import java.nio.channels.SeekableByteChannel;
*** 38,56 **** import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.security.MessageDigest; import java.util.*; import sun.security.jgss.GSSUtil; import sun.security.krb5.internal.APReq; import sun.security.krb5.internal.rcache.AuthTime; ! // This test runs multiple acceptor Procs to mimin AP-REQ replays. public class ReplayCacheTestProc { ! private static Proc[] ps; ! private static Proc pc; private static List<Req> reqs = new ArrayList<>(); private static String HOST = "localhost"; // Where should the rcache be saved. It seems KRB5RCACHEDIR is not // recognized on Solaris. Maybe version too low? I see 1.6. --- 39,77 ---- import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.security.MessageDigest; import java.util.*; + import jdk.test.lib.Platform; import sun.security.jgss.GSSUtil; import sun.security.krb5.internal.APReq; import sun.security.krb5.internal.rcache.AuthTime; + import sun.security.krb5.internal.rcache.AuthTimeWithHash; ! /** ! * This test runs multiple acceptor Procs to mimin AP-REQ replays. ! * It can either run with automatic (random) test runs or user can provide ! * these system properties: ! * ! * - test.libs on what types of acceptors to use ! * Format: CSV of (J|N|N<libname>) ! * Example: J,N,N/krb5-1.14/lib/libgssapi_krb5.so ! * ! * - test.runs on runs ! * Format: (req# | client# service#) acceptor# expected... ! * Example: c0h0J0v,c1h1N0v,r0J1x means 1st req is new c0 to h0 sent to J0, ! * 2nd req is new c1 to h1 sent to N0, ! * 3rd req is old (1st replayed) sent to J1. ! * For all old reqs, client# and service# MUST be - ! * ! * - test.autoruns on how many autoruns ! * Format: number ! */ public class ReplayCacheTestProc { ! private static Proc[] pa; // all acceptors ! private static Proc pi; // the single initiator private static List<Req> reqs = new ArrayList<>(); private static String HOST = "localhost"; // Where should the rcache be saved. It seems KRB5RCACHEDIR is not // recognized on Solaris. Maybe version too low? I see 1.6.
*** 63,179 **** private static long uid; public static void main0(String[] args) throws Exception { System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF); if (args.length == 0) { // The controller - int ns = 5; // number of servers int nu = 5; // number of users ! int nx = 50; // number of experiments ! int np = 5; // number of peers (services) ! int mode = 0; // native(1), random(0), java(-1) ! boolean random = true; // random experiments choreograph ! ! // Do not test interop with native GSS on some platforms ! String os = System.getProperty("os.name", "???"); ! if (!os.startsWith("SunOS") && !os.startsWith("Linux")) { ! mode = -1; ! } uid = jdk.internal.misc.VM.geteuid(); KDC kdc = KDC.create(OneKDC.REALM, HOST, 0, true); for (int i=0; i<nu; i++) { kdc.addPrincipal(user(i), OneKDC.PASS); } kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM); ! for (int i=0; i<np; i++) { ! kdc.addPrincipalRandKey(peer(i)); } kdc.writeKtab(OneKDC.KTAB); KDC.saveConfig(OneKDC.KRB5_CONF, kdc); ! if (mode != -1) { ! // A special native server to check basic sanity ! if (ns(-1).waitFor() != 0) { Proc.d("Native mode sanity check failed, revert to java"); ! mode = -1; } } ! pc = Proc.create("ReplayCacheTestProc").debug("C") ! .args("client") .start(); - ps = new Proc[ns]; - Ex[] result = new Ex[nx]; ! if (!random) { ! // 2 experiments, 2 server, 1 peer, 1 user ! nx = 2; ns = 2; np = 1; nu = 1; ! ! // Creates reqs from user# to peer# ! req(0, 0); ! ! // Creates server# ! ps[0] = ns(0); ! ps[1] = js(1); ! ! // Runs ex# using req# to server# with expected result ! result[0] = round(0, 0, 0, true); ! result[1] = round(1, 0, 1, false); } else { ! Random r = new Random(); ! for (int i=0; i<ns; i++) { ! boolean useNative = (mode == 1) ? true ! : (mode == -1 ? false : r.nextBoolean()); ! ps[i] = useNative?ns(i):js(i); } ! for (int i=0; i<nx; i++) { ! result[i] = new Ex(); int old; // which req to send boolean expected; if (reqs.isEmpty() || r.nextBoolean()) { ! Proc.d("Console get new AP-REQ"); ! old = req(r.nextInt(nu), r.nextInt(np)); expected = true; } else { - Proc.d("Console resue old"); old = r.nextInt(reqs.size()); expected = false; } ! int s = r.nextInt(ns); ! Proc.d("Console send to " + s); ! result[i] = round(i, old, s, expected); ! Proc.d("Console sees " + result[i].actual); } } ! pc.println("END"); ! for (int i=0; i<ns; i++) { ! ps[i].println("END"); } System.out.println("Result\n======"); boolean finalOut = true; ! for (int i=0; i<nx; i++) { boolean out = result[i].expected==result[i].actual; finalOut &= out; ! System.out.printf("%3d: %s (%2d): u%d h%d %s %s %s %2d\n", i, result[i].expected?"----":" ", ! result[i].old, ! result[i].user, result[i].peer, result[i].server, result[i].actual?"Good":"Bad ", out?" ":"xxx", result[i].csize); } if (!finalOut) throw new Exception(); ! } else if (args[0].equals("N-1")) { // Native mode sanity check Proc.d("Detect start"); Context s = Context.fromUserKtab("*", OneKDC.KTAB, true); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); ! } else if (args[0].equals("client")) { while (true) { String title = Proc.textIn(); Proc.d("Client see " + title); if (title.equals("END")) break; String[] cas = title.split(" "); --- 84,254 ---- private static long uid; public static void main0(String[] args) throws Exception { System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF); if (args.length == 0) { // The controller int nu = 5; // number of users ! int nh = 5; // number of hosts (services) ! String[] libs; // available acceptor types: ! // J: java ! // N: default native lib ! // N<libname>: native lib with the given name ! Ex[] result; ! int numPerType = 2; // number of servers per type uid = jdk.internal.misc.VM.geteuid(); KDC kdc = KDC.create(OneKDC.REALM, HOST, 0, true); for (int i=0; i<nu; i++) { kdc.addPrincipal(user(i), OneKDC.PASS); } kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM); ! for (int i=0; i<nh; i++) { ! kdc.addPrincipalRandKey(host(i)); } kdc.writeKtab(OneKDC.KTAB); KDC.saveConfig(OneKDC.KRB5_CONF, kdc); ! // User-provided libs ! String userLibs = System.getProperty("test.libs"); ! ! if (userLibs != null) { ! libs = userLibs.split(","); ! } else { ! if (Platform.isOSX() || Platform.isWindows()) { ! // macOS uses Heimdal and Windows has no native lib ! libs = new String[]{"J"}; ! } else { ! // Test interop between Java and native (if available) ! if (acceptor("N", "sanity").waitFor() != 0) { Proc.d("Native mode sanity check failed, revert to java"); ! libs = new String[]{"J"}; ! } else { ! libs = new String[]{"J", "N"}; ! } } } ! pi = Proc.create("ReplayCacheTestProc").debug("C") ! .args("initiator") .start(); ! int na = libs.length * numPerType; // total number of acceptors ! pa = new Proc[na]; ! ! // Acceptors, numPerType for 1st, numForType for 2nd, ... ! for (int i=0; i<na; i++) { ! int type = i / numPerType; ! String label; // N/J for N/J, ABC... for N<lib> ! if (libs[type].length() == 1) { ! label = libs[type]; } else { ! label = "" + (char)('A' + type); ! } ! pa[i] = acceptor(libs[type], label + i % numPerType); ! } ! ! String userRuns = System.getProperty("test.runs"); ! ! if (userRuns != null) { ! String[] runs = userRuns.split(","); ! result = new Ex[runs.length]; ! for (int i = 0; i < runs.length; i++) { ! boolean expected = false; ! int req = -1; ! int client = -1; ! int host = -1; ! UserRun run = new UserRun(runs[i]); ! while (true) { ! char type = run.nextAction(); ! if (type == ' ') { ! break; ! } ! switch (type) { ! case 'r': ! req = result[run.nextValue()].req; ! break; ! case 'c': ! client = run.nextValue(); ! break; ! case 'h': ! req = req(client, run.nextValue()); ! break; ! case 'J': ! case 'N': ! for (int j = 0; j < libs.length; j++) { ! if (libs[j].equals("" + type)) { ! host = j * numPerType + run.nextValue(); ! break; ! } ! } ! break; ! case 'v': ! expected = true; ! break; ! case 'x': ! expected = false; ! break; ! default: // ABC... ! host = (type - 'A') * numPerType + run.nextValue(); ! } } ! result[i] = new Ex(i, req, host, expected); ! } ! } else { ! result = new Ex[Integer.parseInt( ! System.getProperty("test.autoruns", "100"))]; ! Random r = new Random(); ! for (int i = 0; i < result.length; i++) { int old; // which req to send boolean expected; if (reqs.isEmpty() || r.nextBoolean()) { ! old = req(r.nextInt(nu), r.nextInt(nh)); expected = true; } else { old = r.nextInt(reqs.size()); expected = false; } ! int s = r.nextInt(na); ! result[i] = new Ex(i, old, s, expected); ! } } + + for (Ex x : result) { + x.run(); } ! pi.println("END"); ! for (int i=0; i<na; i++) { ! pa[i].println("END"); } System.out.println("Result\n======"); boolean finalOut = true; ! System.out.println(" #: expected (req): client host acceptor Result size"); ! System.out.println("---- -------- ------ ------ ---- -------- ------ ----"); ! for (int i=0; i<result.length; i++) { boolean out = result[i].expected==result[i].actual; finalOut &= out; ! System.out.printf("%3d: %8s (%3d): u%d h%d %8s %s %s %4d\n", i, result[i].expected?"----":" ", ! result[i].req, ! reqs.get(result[i].req).user, ! reqs.get(result[i].req).peer, ! pa[result[i].acceptor].debug(), result[i].actual?"Good":"Bad ", out?" ":"xxx", result[i].csize); } if (!finalOut) throw new Exception(); ! } else if (args[0].equals("sanity")) { // Native mode sanity check Proc.d("Detect start"); Context s = Context.fromUserKtab("*", OneKDC.KTAB, true); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); ! } else if (args[0].equals("initiator")) { while (true) { String title = Proc.textIn(); Proc.d("Client see " + title); if (title.equals("END")) break; String[] cas = title.split(" ");
*** 215,307 **** } } // returns the user name private static String user(int p) { ! return "USER" + p; } ! // returns the peer name ! private static String peer(int p) { return "host" + p + "/" + HOST; } // returns the dfl name for a host private static String dfl(int p) { ! return cwd + "host" + p + (uid == -1 ? "" : ("_"+uid)); } // generates an ap-req and save into reqs, returns the index private static int req(int user, int peer) throws Exception { ! pc.println(user(user) + " " + peer(peer)); ! Req req = new Req(user, peer, pc.readData()); reqs.add(req); return reqs.size() - 1; } ! // carries out a round of experiment ! // i: ex#, old: which req, server: which server, expected: result? ! private static Ex round(int i, int old, int server, boolean expected) ! throws Exception { ! ps[server].println("TEST"); ! ps[server].println(reqs.get(old).msg); ! String reply = ps[server].readData(); ! Ex result = new Ex(); ! result.i = i; ! result.expected = expected; ! result.server = ps[server].debug(); ! result.actual = Boolean.valueOf(reply); ! result.user = reqs.get(old).user; ! result.peer = reqs.get(old).peer; ! result.old = old; ! result.csize = csize(result.peer); ! result.hash = hash(reqs.get(old).msg); ! if (new File(dfl(result.peer)).exists()) { ! Files.copy(Paths.get(dfl(result.peer)), Paths.get( ! String.format("%03d-USER%d-host%d-%s-%s", ! i, result.user, result.peer, result.server, ! result.actual) ! + "-" + result.hash), ! StandardCopyOption.COPY_ATTRIBUTES); ! } ! return result; } ! // create a native server ! private static Proc ns(int i) throws Exception { ! return Proc.create("ReplayCacheTestProc") ! .args("N"+i) ! .env("KRB5_CONFIG", OneKDC.KRB5_CONF) .env("KRB5_KTNAME", OneKDC.KTAB) .env("KRB5RCACHEDIR", cwd) .prop("sun.security.jgss.native", "true") .prop("javax.security.auth.useSubjectCredsOnly", "false") ! .prop("sun.security.nativegss.debug", "true") ! .debug("N"+i) ! .start(); } - // creates a java server - private static Proc js(int i) throws Exception { - return Proc.create("ReplayCacheTestProc") - .debug("S"+i) - .args("S"+i) - .prop("sun.security.krb5.rcache", "dfl") - .prop("java.io.tmpdir", cwd) - .start(); } // generates hash of authenticator inside ap-req inside initsectoken private static String hash(String req) throws Exception { byte[] data = Base64.getDecoder().decode(req); data = Arrays.copyOfRange(data, 17, data.length); ! byte[] hash = MessageDigest.getInstance("MD5").digest(new APReq(data).authenticator.getBytes()); char[] h = new char[hash.length * 2]; char[] hexConst = "0123456789ABCDEF".toCharArray(); for (int i=0; i<hash.length; i++) { h[2*i] = hexConst[(hash[i]&0xff)>>4]; h[2*i+1] = hexConst[hash[i]&0xf]; } return new String(h); } // return size of dfl file, excluding the null hash ones private static int csize(int p) throws Exception { try (SeekableByteChannel chan = Files.newByteChannel( ! Paths.get(dfl(p)), StandardOpenOption.READ)) { chan.position(6); int cc = 0; while (true) { try { if (AuthTime.readFrom(chan) != null) cc++; --- 290,370 ---- } } // returns the user name private static String user(int p) { ! return "user" + p; } ! ! // returns the host name ! private static String host(int p) { return "host" + p + "/" + HOST; } + // returns the dfl name for a host private static String dfl(int p) { ! return "host" + p + (uid == -1 ? "" : ("_"+uid)); } + // generates an ap-req and save into reqs, returns the index private static int req(int user, int peer) throws Exception { ! pi.println(user(user) + " " + host(peer)); ! Req req = new Req(user, peer, pi.readData()); reqs.add(req); return reqs.size() - 1; } ! ! // create a acceptor ! private static Proc acceptor(String type, String label) throws Exception { ! Proc p = Proc.create("ReplayCacheTestProc") ! .args(label) ! .debug(label); ! if (type.equals("J")) { ! p.prop("sun.security.krb5.rcache", "dfl") ! .prop("java.io.tmpdir", cwd); ! String useMD5 = System.getProperty("jdk.krb5.rcache.usemd5"); ! if (useMD5 != null) { ! p.prop("jdk.krb5.rcache.usemd5", useMD5); } ! } else { ! p.env("KRB5_CONFIG", OneKDC.KRB5_CONF) .env("KRB5_KTNAME", OneKDC.KTAB) .env("KRB5RCACHEDIR", cwd) .prop("sun.security.jgss.native", "true") .prop("javax.security.auth.useSubjectCredsOnly", "false") ! .prop("sun.security.nativegss.debug", "true"); ! if (type.length() > 1) { ! String lib = type.substring(1); ! String libDir = lib.substring(0, lib.lastIndexOf('/')); ! p.prop("sun.security.jgss.lib", lib) ! .env("DYLD_LIBRARY_PATH", libDir) ! .env("LD_LIBRARY_PATH", libDir); } } + return p.start(); + } + // generates hash of authenticator inside ap-req inside initsectoken private static String hash(String req) throws Exception { byte[] data = Base64.getDecoder().decode(req); data = Arrays.copyOfRange(data, 17, data.length); ! byte[] hash = MessageDigest.getInstance( ! AuthTimeWithHash.realAlg(AuthTimeWithHash.DEFAULT_HASH_ALG)) ! .digest(new APReq(data).authenticator.getBytes()); char[] h = new char[hash.length * 2]; char[] hexConst = "0123456789ABCDEF".toCharArray(); for (int i=0; i<hash.length; i++) { h[2*i] = hexConst[(hash[i]&0xff)>>4]; h[2*i+1] = hexConst[hash[i]&0xf]; } return new String(h); } + // return size of dfl file, excluding the null hash ones private static int csize(int p) throws Exception { try (SeekableByteChannel chan = Files.newByteChannel( ! Paths.get(cwd, dfl(p)), StandardOpenOption.READ)) { chan.position(6); int cc = 0; while (true) { try { if (AuthTime.readFrom(chan) != null) cc++;
*** 312,340 **** return cc; } catch (IOException ioe) { return 0; } } // models an experiement private static class Ex { int i; // # boolean expected; // expected result boolean actual; // actual output - int old; // which ap-req to send - String server; // which server to send to - String hash; // the hash of req - int user; // which initiator - int peer; // which acceptor int csize; // size of rcache after test } // models a saved ap-req msg private static class Req { String msg; // based64-ed req ! int user; // which initiator ! int peer; // which accceptor Req(int user, int peer, String msg) { this.msg = msg; this.user= user; this.peer = peer; } } } --- 375,452 ---- return cc; } catch (IOException ioe) { return 0; } } + // models an experiement private static class Ex { int i; // # + int req; // which ap-req to send + int acceptor; // which acceptor to send to boolean expected; // expected result + boolean actual; // actual output int csize; // size of rcache after test + String hash; // the hash of req + + Ex(int i, int req, int acceptor, boolean expected) { + this.i = i; + this.req = req; + this.acceptor = acceptor; + this.expected = expected; + } + + void run() throws Exception { + Req r = reqs.get(req); + pa[acceptor].println("TEST"); + pa[acceptor].println(r.msg); + String reply = pa[acceptor].readData(); + + actual = Boolean.valueOf(reply); + csize = csize(r.peer); + hash = hash(r.msg); + if (new File(cwd, dfl(r.peer)).exists()) { + Files.copy(Paths.get(cwd, dfl(r.peer)), Paths.get( + String.format("%03d-USER%d-host%d-%s-%s", + i, r.user, r.peer, acceptor, + actual) + + "-" + hash), + StandardCopyOption.COPY_ATTRIBUTES); + } + } } + // models a saved ap-req msg private static class Req { String msg; // based64-ed req ! int user; // which client ! int peer; // which service Req(int user, int peer, String msg) { this.msg = msg; this.user= user; this.peer = peer; } } + + private static class UserRun { + String run; + int pos = 0; + UserRun(String run) { + this.run = run; + } + char nextAction() { + return pos < run.length() ? run.charAt(pos++) : ' '; + } + int nextValue() { + int result = 0; + for (; pos < run.length(); pos++) { + char c = run.charAt(pos); + if (!Character.isDigit(c)) { + break; + } + result = result * 10 + (c - '0'); + } + return result; + } + } }
< prev index next >