mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-20 15:25:27 +00:00
8168518: rcache interop with krb5-1.15
Reviewed-by: xuelei
This commit is contained in:
parent
d9bc8cbcdb
commit
e10da9956f
@ -301,12 +301,13 @@ public class KrbApReq {
|
||||
if (!authenticator.ctime.inClockSkew())
|
||||
throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
|
||||
|
||||
String alg = AuthTimeWithHash.DEFAULT_HASH_ALG;
|
||||
byte[] hash;
|
||||
try {
|
||||
hash = MessageDigest.getInstance("MD5")
|
||||
hash = MessageDigest.getInstance(AuthTimeWithHash.realAlg(alg))
|
||||
.digest(apReqMessg.authenticator.cipher);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new AssertionError("Impossible");
|
||||
throw new AssertionError("Impossible " + alg);
|
||||
}
|
||||
|
||||
char[] h = new char[hash.length * 2];
|
||||
@ -319,6 +320,7 @@ public class KrbApReq {
|
||||
apReqMessg.ticket.sname.toString(),
|
||||
authenticator.ctime.getSeconds(),
|
||||
authenticator.cusec,
|
||||
alg,
|
||||
new String(h));
|
||||
rcache.checkAndStore(KerberosTime.now(), time);
|
||||
|
||||
|
||||
@ -116,14 +116,14 @@ public class AuthTime {
|
||||
if (st.countTokens() != 6) {
|
||||
throw new IOException("Incorrect rcache style");
|
||||
}
|
||||
st.nextToken();
|
||||
String hashAlg = st.nextToken();
|
||||
String hash = st.nextToken();
|
||||
st.nextToken();
|
||||
client = st.nextToken();
|
||||
st.nextToken();
|
||||
server = st.nextToken();
|
||||
return new AuthTimeWithHash(
|
||||
client, server, ctime, cusec, hash);
|
||||
client, server, ctime, cusec, hashAlg, hash);
|
||||
} else {
|
||||
return new AuthTime(
|
||||
client, server, ctime, cusec);
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package sun.security.krb5.internal.rcache;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -34,14 +36,39 @@ import java.util.Objects;
|
||||
public class AuthTimeWithHash extends AuthTime
|
||||
implements Comparable<AuthTimeWithHash> {
|
||||
|
||||
// The hash algorithm can be "HASH" or "SHA256".
|
||||
public static final String DEFAULT_HASH_ALG;
|
||||
|
||||
static {
|
||||
if (GetPropertyAction.privilegedGetProperty(
|
||||
"jdk.krb5.rcache.useMD5", "false").equals("true")) {
|
||||
DEFAULT_HASH_ALG = "HASH";
|
||||
} else {
|
||||
DEFAULT_HASH_ALG = "SHA256";
|
||||
}
|
||||
}
|
||||
|
||||
public static String realAlg(String alg) {
|
||||
switch (alg) {
|
||||
case "HASH":
|
||||
return "MD5";
|
||||
case "SHA256":
|
||||
return "SHA-256";
|
||||
default:
|
||||
throw new AssertionError(alg + " is not HASH or SHA256");
|
||||
}
|
||||
}
|
||||
|
||||
final String hashAlg;
|
||||
final String hash;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>AuthTimeWithHash</code>.
|
||||
*/
|
||||
public AuthTimeWithHash(String client, String server,
|
||||
int ctime, int cusec, String hash) {
|
||||
int ctime, int cusec, String hashAlg, String hash) {
|
||||
super(client, server, ctime, cusec);
|
||||
this.hashAlg = hashAlg;
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
@ -56,6 +83,7 @@ public class AuthTimeWithHash extends AuthTime
|
||||
if (!(o instanceof AuthTimeWithHash)) return false;
|
||||
AuthTimeWithHash that = (AuthTimeWithHash)o;
|
||||
return Objects.equals(hash, that.hash)
|
||||
&& Objects.equals(hashAlg, that.hashAlg)
|
||||
&& Objects.equals(client, that.client)
|
||||
&& Objects.equals(server, that.server)
|
||||
&& ctime == that.ctime
|
||||
@ -88,6 +116,19 @@ public class AuthTimeWithHash extends AuthTime
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares with a possibly old style object. Used
|
||||
* in DflCache$Storage#loadAndCheck.
|
||||
* @return true if all AuthTime fields are the same but different hash
|
||||
*/
|
||||
public boolean sameTimeDiffHash(AuthTimeWithHash old) {
|
||||
if (!this.isSameIgnoresHash(old)) {
|
||||
return false;
|
||||
}
|
||||
return this.hashAlg.equals(old.hashAlg) &&
|
||||
!this.hash.equals(old.hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares with a possibly old style object. Used
|
||||
* in DflCache$Storage#loadAndCheck.
|
||||
@ -112,7 +153,7 @@ public class AuthTimeWithHash extends AuthTime
|
||||
String sstring;
|
||||
if (withHash) {
|
||||
cstring = "";
|
||||
sstring = String.format("HASH:%s %d:%s %d:%s", hash,
|
||||
sstring = String.format("%s:%s %d:%s %d:%s", hashAlg, hash,
|
||||
client.length(), client,
|
||||
server.length(), server);
|
||||
} else {
|
||||
|
||||
@ -96,6 +96,8 @@ import sun.security.krb5.internal.ReplayCache;
|
||||
* Java also does this way.
|
||||
*
|
||||
* See src/lib/krb5/rcache/rc_io.c and src/lib/krb5/rcache/rc_dfl.c.
|
||||
*
|
||||
* Update: New version can use other hash algorithms.
|
||||
*/
|
||||
public class DflCache extends ReplayCache {
|
||||
|
||||
@ -300,7 +302,7 @@ public class DflCache extends ReplayCache {
|
||||
if (time.equals(a)) {
|
||||
// Exact match, must be a replay
|
||||
throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);
|
||||
} else if (time.isSameIgnoresHash(a)) {
|
||||
} else if (time.sameTimeDiffHash((AuthTimeWithHash)a)) {
|
||||
// Two different authenticators in the same second.
|
||||
// Remember it
|
||||
seeNewButNotSame = true;
|
||||
|
||||
@ -243,16 +243,23 @@ public class Proc {
|
||||
// Starts the proc
|
||||
public Proc start() throws IOException {
|
||||
List<String> cmd = new ArrayList<>();
|
||||
boolean hasModules;
|
||||
if (launcher != null) {
|
||||
cmd.add(launcher);
|
||||
File base = new File(launcher).getParentFile().getParentFile();
|
||||
hasModules = new File(base, "modules").exists() ||
|
||||
new File(base, "jmods").exists();
|
||||
} else {
|
||||
cmd.add(new File(new File(System.getProperty("java.home"), "bin"),
|
||||
"java").getPath());
|
||||
hasModules = true;
|
||||
}
|
||||
|
||||
Stream.of(jdk.internal.misc.VM.getRuntimeArguments())
|
||||
.filter(arg -> arg.startsWith("--add-exports="))
|
||||
.forEach(cmd::add);
|
||||
if (hasModules) {
|
||||
Stream.of(jdk.internal.misc.VM.getRuntimeArguments())
|
||||
.filter(arg -> arg.startsWith("--add-exports="))
|
||||
.forEach(cmd::add);
|
||||
}
|
||||
|
||||
Collections.addAll(cmd, splitProperty("test.vm.opts"));
|
||||
Collections.addAll(cmd, splitProperty("test.java.opts"));
|
||||
|
||||
@ -47,15 +47,15 @@ public class ReplayCacheExpunge {
|
||||
int count = Integer.parseInt(args[0]);
|
||||
ReplayCache cache = ReplayCache.getInstance("dfl:./");
|
||||
AuthTimeWithHash a1 =
|
||||
new AuthTimeWithHash(client, server, time(-400), 0, hash("1"));
|
||||
new AuthTimeWithHash(client, server, time(-400), 0, "HASH", hash("1"));
|
||||
AuthTimeWithHash a2 =
|
||||
new AuthTimeWithHash(client, server, time(0), 0, hash("4"));
|
||||
new AuthTimeWithHash(client, server, time(0), 0, "HASH", hash("4"));
|
||||
KerberosTime now = new KerberosTime(time(0)*1000L);
|
||||
KerberosTime then = new KerberosTime(time(-300)*1000L);
|
||||
|
||||
// Once upon a time, we added a lot of events
|
||||
for (int i=0; i<count; i++) {
|
||||
a1 = new AuthTimeWithHash(client, server, time(-400), 0, hash(""));
|
||||
a1 = new AuthTimeWithHash(client, server, time(-400), 0, "HASH", hash(""));
|
||||
cache.checkAndStore(then, a1);
|
||||
}
|
||||
|
||||
|
||||
@ -48,9 +48,9 @@ public class ReplayCachePrecise {
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
AuthTimeWithHash a1 = new AuthTimeWithHash(client, server, time(0), 0,
|
||||
"1111111111111111");
|
||||
"HASH", "1111111111111111");
|
||||
AuthTimeWithHash a2 = new AuthTimeWithHash(client, server, time(0), 0,
|
||||
"2222222222222222");
|
||||
"HASH", "2222222222222222");
|
||||
KerberosTime now = new KerberosTime(time(0)*1000L);
|
||||
|
||||
// When all new styles, must exact match
|
||||
|
||||
@ -23,11 +23,10 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7152176
|
||||
* @bug 7152176 8168518
|
||||
* @summary More krb5 tests
|
||||
* @library ../../../../java/security/testlibrary/
|
||||
* @compile -XDignore.symbol.file ReplayCacheTestProc.java
|
||||
* @run main/othervm/timeout=100 ReplayCacheTestProc
|
||||
* @library ../../../../java/security/testlibrary/ /test/lib
|
||||
* @run main/othervm/timeout=300 ReplayCacheTestProc
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
@ -38,17 +37,40 @@ import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.test.lib.Platform;
|
||||
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.
|
||||
/**
|
||||
* This test runs multiple acceptor Procs to mimic AP-REQ replays.
|
||||
* These system properties are supported:
|
||||
*
|
||||
* - test.libs on what types of acceptors to use
|
||||
* Format: CSV of (J|N|N<suffix>=<libname>|J<suffix>=<launcher>)
|
||||
* Default: J,N on Solaris and Linux where N is available, or J
|
||||
* Example: J,N,N14=/krb5-1.14/lib/libgssapi_krb5.so,J8=/java8/bin/java
|
||||
*
|
||||
* - test.runs on manual runs. If empty, a iterate through all pattern
|
||||
* Format: (req# | client# service#) acceptor# expected, ...
|
||||
* Default: null
|
||||
* Example: c0s0Jav,c1s1N14av,r0Jbx means 0th req is new c0->s0 sent to Ja,
|
||||
* 1st req is new c1 to s1 sent to N14a,
|
||||
* 2nd req is old (0th replayed) sent to Jb.
|
||||
* a/b at the end of acceptor is different acceptors of the same lib
|
||||
*
|
||||
* - test.autoruns on number of automatic runs
|
||||
* Format: number
|
||||
* Default: 100
|
||||
*/
|
||||
public class ReplayCacheTestProc {
|
||||
|
||||
private static Proc[] ps;
|
||||
private static Proc pc;
|
||||
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";
|
||||
|
||||
@ -59,119 +81,193 @@ public class ReplayCacheTestProc {
|
||||
"/var/krb5/rcache/" :
|
||||
System.getProperty("user.dir");
|
||||
|
||||
private static MessageDigest md5, sha256;
|
||||
|
||||
static {
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
sha256 = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new AssertionError("Impossible", nsae);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
int nc = 5; // number of clients
|
||||
int ns = 5; // number of services
|
||||
String[] libs; // available acceptor types:
|
||||
// J: java
|
||||
// J<suffix>=<java launcher>: another java
|
||||
// N: default native lib
|
||||
// N<suffix>=<libname>: another native lib
|
||||
Ex[] result;
|
||||
int numPerType = 2; // number of acceptors 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);
|
||||
for (int i=0; i<nc; i++) {
|
||||
kdc.addPrincipal(client(i), OneKDC.PASS);
|
||||
}
|
||||
kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
|
||||
for (int i=0; i<np; i++) {
|
||||
kdc.addPrincipalRandKey(peer(i));
|
||||
for (int i=0; i<ns; i++) {
|
||||
kdc.addPrincipalRandKey(service(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;
|
||||
}
|
||||
}
|
||||
// User-provided libs
|
||||
String userLibs = System.getProperty("test.libs");
|
||||
|
||||
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);
|
||||
if (userLibs != null) {
|
||||
libs = userLibs.split(",");
|
||||
} 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;
|
||||
if (Platform.isOSX() || Platform.isWindows()) {
|
||||
// macOS uses Heimdal and Windows has no native lib
|
||||
libs = new String[]{"J"};
|
||||
} else {
|
||||
if (acceptor("N", "sanity").waitFor() != 0) {
|
||||
Proc.d("Native mode sanity check failed, only java");
|
||||
libs = new String[]{"J"};
|
||||
} else {
|
||||
Proc.d("Console resue old");
|
||||
old = r.nextInt(reqs.size());
|
||||
expected = false;
|
||||
libs = new String[]{"J", "N"};
|
||||
}
|
||||
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");
|
||||
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++) {
|
||||
pa[i] = acceptor(libs[i/numPerType],
|
||||
"" + (char)('a' + i%numPerType));
|
||||
}
|
||||
System.out.println("Result\n======");
|
||||
|
||||
// Manual runs
|
||||
String userRuns = System.getProperty("test.runs");
|
||||
|
||||
if (userRuns == null) {
|
||||
result = new Ex[Integer.parseInt(
|
||||
System.getProperty("test.autoruns", "100"))];
|
||||
Random r = new Random();
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
boolean expected = reqs.isEmpty() || r.nextBoolean();
|
||||
result[i] = new Ex(
|
||||
i,
|
||||
expected ?
|
||||
req(r.nextInt(nc), r.nextInt(ns)) :
|
||||
r.nextInt(reqs.size()),
|
||||
pa[r.nextInt(na)],
|
||||
expected);
|
||||
}
|
||||
} else if (userRuns.isEmpty()) {
|
||||
int count = 0;
|
||||
result = new Ex[libs.length * libs.length];
|
||||
for (int i = 0; i < libs.length; i++) {
|
||||
result[count] = new Ex(
|
||||
count,
|
||||
req(0, 0),
|
||||
pa[i * numPerType],
|
||||
true);
|
||||
count++;
|
||||
for (int j = 0; j < libs.length; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
result[count] = new Ex(
|
||||
count,
|
||||
i,
|
||||
pa[j * numPerType],
|
||||
false);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String[] runs = userRuns.split(",");
|
||||
result = new Ex[runs.length];
|
||||
for (int i = 0; i < runs.length; i++) {
|
||||
UserRun run = new UserRun(runs[i]);
|
||||
result[i] = new Ex(
|
||||
i,
|
||||
run.req() == -1 ?
|
||||
req(run.client(), run.service()) :
|
||||
result[run.req()].req,
|
||||
Arrays.stream(pa)
|
||||
.filter(p -> p.debug().equals(run.acceptor()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new Exception(
|
||||
"no acceptor named " + run.acceptor())),
|
||||
run.success());
|
||||
}
|
||||
}
|
||||
|
||||
for (Ex x : result) {
|
||||
x.run();
|
||||
}
|
||||
|
||||
pi.println("END");
|
||||
for (int i=0; i<na; i++) {
|
||||
pa[i].println("END");
|
||||
}
|
||||
System.out.println("\nAll Test Results\n================");
|
||||
boolean finalOut = true;
|
||||
for (int i=0; i<nx; i++) {
|
||||
System.out.println(" req** client service acceptor Result");
|
||||
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: %s (%2d): u%d h%d %s %s %s %2d\n",
|
||||
System.out.printf("%3d: %3d%s c%d s%d %4s %8s %s %s\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);
|
||||
result[i].req,
|
||||
result[i].expected ? "**" : " ",
|
||||
reqs.get(result[i].req).client,
|
||||
reqs.get(result[i].req).service,
|
||||
"(" + result[i].csize + ")",
|
||||
result[i].acceptor.debug(),
|
||||
result[i].actual ? "++" : "--",
|
||||
out ? " " : "xxx");
|
||||
}
|
||||
|
||||
System.out.println("\nPath of Reqs\n============");
|
||||
for (int j=0; ; j++) {
|
||||
boolean found = false;
|
||||
for (int i=0; i<result.length; i++) {
|
||||
if (result[i].req == j) {
|
||||
if (!found) {
|
||||
System.out.printf("%3d (c%s -> s%s): ", j,
|
||||
reqs.get(j).client, reqs.get(j).service);
|
||||
}
|
||||
System.out.printf("%s%s(%d)%s",
|
||||
found ? " -> " : "",
|
||||
result[i].acceptor.debug(),
|
||||
i,
|
||||
result[i].actual != result[i].expected ?
|
||||
"xxx" : "");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
if (!found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!finalOut) throw new Exception();
|
||||
} else if (args[0].equals("N-1")) {
|
||||
} else if (args[0].equals("Nsanity")) {
|
||||
// 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")) {
|
||||
} else if (args[0].equals("initiator")) {
|
||||
while (true) {
|
||||
String title = Proc.textIn();
|
||||
Proc.d("Client see " + title);
|
||||
@ -185,22 +281,26 @@ public class ReplayCacheTestProc {
|
||||
Proc.binOut(token);
|
||||
}
|
||||
} else {
|
||||
Proc.d(System.getProperty("java.vm.version"));
|
||||
Proc.d(System.getProperty("sun.security.jgss.native"));
|
||||
Proc.d(System.getProperty("sun.security.jgss.lib"));
|
||||
Proc.d("---------------------------------\n");
|
||||
Proc.d("Server start");
|
||||
Context s = Context.fromUserKtab("*", OneKDC.KTAB, true);
|
||||
Proc.d("Server login");
|
||||
while (true) {
|
||||
String title = Proc.textIn();
|
||||
Proc.d("Server " + args[0] + " sees " + title);
|
||||
Proc.d("Server sees " + title);
|
||||
if (title.equals("END")) break;
|
||||
s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
|
||||
byte[] token = Proc.binIn();
|
||||
try {
|
||||
s.take(token);
|
||||
Proc.textOut("true");
|
||||
Proc.d(args[0] + " Good");
|
||||
Proc.d("Good");
|
||||
} catch (Exception e) {
|
||||
Proc.textOut("false");
|
||||
Proc.d(args[0] + " Bad");
|
||||
Proc.d("Bad");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -215,79 +315,90 @@ public class ReplayCacheTestProc {
|
||||
}
|
||||
}
|
||||
|
||||
// returns the user name
|
||||
private static String user(int p) {
|
||||
return "USER" + p;
|
||||
// returns the client name
|
||||
private static String client(int p) {
|
||||
return "client" + p;
|
||||
}
|
||||
// returns the peer name
|
||||
private static String peer(int p) {
|
||||
return "host" + p + "/" + HOST;
|
||||
|
||||
// returns the service name
|
||||
private static String service(int p) {
|
||||
return "service" + p + "/" + HOST;
|
||||
}
|
||||
// returns the dfl name for a host
|
||||
|
||||
// returns the dfl name for a service
|
||||
private static String dfl(int p) {
|
||||
return cwd + "host" + p + (uid == -1 ? "" : ("_"+uid));
|
||||
return "service" + 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());
|
||||
private static int req(int client, int service) throws Exception {
|
||||
pi.println(client(client) + " " + service(service));
|
||||
Req req = new Req(client, service, pi.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);
|
||||
|
||||
// create a acceptor
|
||||
private static Proc acceptor(String type, String suffix) throws Exception {
|
||||
Proc p;
|
||||
String label;
|
||||
String lib;
|
||||
int pos = type.indexOf('=');
|
||||
if (pos < 0) {
|
||||
label = type;
|
||||
lib = null;
|
||||
} else {
|
||||
label = type.substring(0, pos);
|
||||
lib = type.substring(pos + 1);
|
||||
}
|
||||
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();
|
||||
if (type.startsWith("J")) {
|
||||
if (lib == null) {
|
||||
p = Proc.create("ReplayCacheTestProc");
|
||||
} else {
|
||||
p = Proc.create("ReplayCacheTestProc", lib);
|
||||
}
|
||||
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 = Proc.create("ReplayCacheTestProc")
|
||||
.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 (lib != null) {
|
||||
String libDir = lib.substring(0, lib.lastIndexOf('/'));
|
||||
p.prop("sun.security.jgss.lib", lib)
|
||||
.env("DYLD_LIBRARY_PATH", libDir)
|
||||
.env("LD_LIBRARY_PATH", libDir);
|
||||
}
|
||||
}
|
||||
Proc.d(label+suffix+" started");
|
||||
return p.args(label+suffix).debug(label+suffix).start();
|
||||
}
|
||||
|
||||
// generates hash of authenticator inside ap-req inside initsectoken
|
||||
private static String hash(String req) throws Exception {
|
||||
byte[] data = Base64.getDecoder().decode(req);
|
||||
private static void record(String label, Req req) throws Exception {
|
||||
byte[] data = Base64.getDecoder().decode(req.msg);
|
||||
data = Arrays.copyOfRange(data, 17, data.length);
|
||||
byte[] hash = MessageDigest.getInstance("MD5").digest(new APReq(data).authenticator.getBytes());
|
||||
|
||||
try (PrintStream ps = new PrintStream(
|
||||
new FileOutputStream("log.txt", true))) {
|
||||
ps.printf("%s:\nmsg: %s\nMD5: %s\nSHA-256: %s\n\n",
|
||||
label,
|
||||
req.msg,
|
||||
hex(md5.digest(data)),
|
||||
hex(sha256.digest(data)));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a compact hexdump for a byte array
|
||||
private static String hex(byte[] hash) {
|
||||
char[] h = new char[hash.length * 2];
|
||||
char[] hexConst = "0123456789ABCDEF".toCharArray();
|
||||
for (int i=0; i<hash.length; i++) {
|
||||
@ -296,10 +407,11 @@ public class ReplayCacheTestProc {
|
||||
}
|
||||
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)) {
|
||||
Paths.get(cwd, dfl(p)), StandardOpenOption.READ)) {
|
||||
chan.position(6);
|
||||
int cc = 0;
|
||||
while (true) {
|
||||
@ -314,27 +426,73 @@ public class ReplayCacheTestProc {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// models an experiement
|
||||
private static class Ex {
|
||||
int i; // #
|
||||
int req; // which ap-req to send
|
||||
Proc acceptor; // which acceptor to send to
|
||||
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
|
||||
String hash; // the hash of req
|
||||
|
||||
Ex(int i, int req, Proc acceptor, boolean expected) {
|
||||
this.i = i;
|
||||
this.req = req;
|
||||
this.acceptor = acceptor;
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
void run() throws Exception {
|
||||
Req r = reqs.get(req);
|
||||
acceptor.println("TEST");
|
||||
acceptor.println(r.msg);
|
||||
String reply = acceptor.readData();
|
||||
|
||||
actual = Boolean.valueOf(reply);
|
||||
csize = csize(r.service);
|
||||
|
||||
String label = String.format("%03d-CLIENT%d-SERVICE%d-%s-%s",
|
||||
i, r.client, r.service, acceptor.debug(), actual);
|
||||
|
||||
record(label, r);
|
||||
if (new File(cwd, dfl(r.service)).exists()) {
|
||||
Files.copy(Paths.get(cwd, dfl(r.service)), Paths.get(label),
|
||||
StandardCopyOption.COPY_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
int client; // which client
|
||||
int service; // which service
|
||||
Req(int client, int service, String msg) {
|
||||
this.msg = msg;
|
||||
this.user= user;
|
||||
this.peer = peer;
|
||||
this.client= client;
|
||||
this.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
private static class UserRun {
|
||||
static final Pattern p
|
||||
= Pattern.compile("(c(\\d)+s(\\d+)|r(\\d+))(.*)(.)");
|
||||
final Matcher m;
|
||||
|
||||
UserRun(String run) { m = p.matcher(run); m.find(); }
|
||||
|
||||
int req() { return group(4); }
|
||||
int client() { return group(2); }
|
||||
int service() { return group(3); }
|
||||
String acceptor() { return m.group(5); }
|
||||
boolean success() { return m.group(6).equals("v"); }
|
||||
|
||||
int group(int i) {
|
||||
String g = m.group(i);
|
||||
return g == null ? -1 : Integer.parseInt(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
jdk/test/sun/security/krb5/auto/rcache_usemd5.sh
Normal file
30
jdk/test/sun/security/krb5/auto/rcache_usemd5.sh
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (c) 2016, 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 8168518
|
||||
# @library ../../../../java/security/testlibrary/ /test/lib
|
||||
# @run main/othervm/timeout=300 -Djdk.krb5.rcache.useMD5=true ReplayCacheTestProc
|
||||
# @summary testing jdk.krb5.rcache.useMD5. This action is put in a separate
|
||||
# test so that ReplayCacheTestProc.java can be launched with special
|
||||
# test.* system properties easily.
|
||||
Loading…
x
Reference in New Issue
Block a user