8227437: S4U2proxy cannot continue because server's TGT cannot be found
Reviewed-by: weijun
--- a/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -345,7 +345,7 @@
if (krbcredsConstructor == 0) {
krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>",
- "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V");
+ "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V");
if (krbcredsConstructor == 0) {
printf("Couldn't find sun.security.krb5.internal.Ticket constructor\n");
break;
@@ -359,7 +359,9 @@
krbcredsConstructor,
ticket,
clientPrincipal,
+ NULL,
targetPrincipal,
+ NULL,
encryptionKey,
ticketFlags,
authTime,
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -26,8 +26,6 @@
package javax.security.auth.kerberos;
import sun.security.krb5.JavaxSecurityAuthKerberosAccess;
-import sun.security.krb5.EncryptionKey;
-import sun.security.krb5.PrincipalName;
class JavaxSecurityAuthKerberosAccessImpl
implements JavaxSecurityAuthKerberosAccess {
@@ -35,4 +33,20 @@
KeyTab ktab) {
return ktab.takeSnapshot();
}
+
+ public KerberosPrincipal kerberosTicketGetClientAlias(KerberosTicket t) {
+ return t.clientAlias;
+ }
+
+ public void kerberosTicketSetClientAlias(KerberosTicket t, KerberosPrincipal a) {
+ t.clientAlias = a;
+ }
+
+ public KerberosPrincipal kerberosTicketGetServerAlias(KerberosTicket t) {
+ return t.serverAlias;
+ }
+
+ public void kerberosTicketSetServerAlias(KerberosTicket t, KerberosPrincipal a) {
+ t.serverAlias = a;
+ }
}
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -195,6 +195,10 @@
private transient boolean destroyed = false;
+ transient KerberosPrincipal clientAlias = null;
+
+ transient KerberosPrincipal serverAlias = null;
+
/**
* Constructs a {@code KerberosTicket} using credentials information that a
* client either receives from a KDC or reads from a cache.
@@ -591,7 +595,11 @@
try {
krb5Creds = new sun.security.krb5.Credentials(asn1Encoding,
client.getName(),
+ (clientAlias != null ?
+ clientAlias.getName() : null),
server.getName(),
+ (serverAlias != null ?
+ serverAlias.getName() : null),
sessionKey.getEncoded(),
sessionKey.getKeyType(),
flags,
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -713,14 +713,14 @@
if (subject != null &&
!subject.isReadOnly()) {
/*
- * Store the service credentials as
- * javax.security.auth.kerberos.KerberosTicket in
- * the Subject. We could wait till the context is
- * succesfully established; however it is easier
- * to do here and there is no harm indoing it here.
- */
+ * Store the service credentials as
+ * javax.security.auth.kerberos.KerberosTicket in
+ * the Subject. We could wait until the context is
+ * successfully established; however it is easier
+ * to do it here and there is no harm.
+ */
final KerberosTicket kt =
- Krb5Util.credsToTicket(serviceCreds);
+ Krb5Util.credsToTicket(serviceCreds);
AccessController.doPrivileged (
new java.security.PrivilegedAction<Void>() {
public Void run() {
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -59,7 +59,9 @@
private Krb5InitCredential(Krb5NameElement name,
byte[] asn1Encoding,
KerberosPrincipal client,
+ KerberosPrincipal clientAlias,
KerberosPrincipal server,
+ KerberosPrincipal serverAlias,
byte[] sessionKey,
int keyType,
boolean[] flags,
@@ -80,14 +82,21 @@
endTime,
renewTill,
clientAddresses);
-
+ KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketSetClientAlias(this, clientAlias);
+ KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketSetServerAlias(this, serverAlias);
this.name = name;
try {
// Cache this for later use by the sun.security.krb5 package.
krb5Credentials = new Credentials(asn1Encoding,
client.getName(),
+ (clientAlias != null ?
+ clientAlias.getName() : null),
server.getName(),
+ (serverAlias != null ?
+ serverAlias.getName() : null),
sessionKey,
keyType,
flags,
@@ -110,7 +119,9 @@
Credentials delegatedCred,
byte[] asn1Encoding,
KerberosPrincipal client,
+ KerberosPrincipal clientAlias,
KerberosPrincipal server,
+ KerberosPrincipal serverAlias,
byte[] sessionKey,
int keyType,
boolean[] flags,
@@ -131,7 +142,10 @@
endTime,
renewTill,
clientAddresses);
-
+ KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketSetClientAlias(this, clientAlias);
+ KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketSetServerAlias(this, serverAlias);
this.name = name;
// A delegated cred does not have all fields set. So do not try to
// creat new Credentials out of the delegatedCred.
@@ -153,10 +167,18 @@
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
}
+ KerberosPrincipal clientAlias = KerberosSecrets
+ .getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketGetClientAlias(tgt);
+ KerberosPrincipal serverAlias = KerberosSecrets
+ .getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketGetServerAlias(tgt);
return new Krb5InitCredential(name,
tgt.getEncoded(),
tgt.getClient(),
+ clientAlias,
tgt.getServer(),
+ serverAlias,
tgt.getSessionKey().getEncoded(),
tgt.getSessionKeyType(),
tgt.getFlags(),
@@ -179,10 +201,14 @@
*/
PrincipalName cPrinc = delegatedCred.getClient();
+ PrincipalName cAPrinc = delegatedCred.getClientAlias();
PrincipalName sPrinc = delegatedCred.getServer();
+ PrincipalName sAPrinc = delegatedCred.getServerAlias();
KerberosPrincipal client = null;
+ KerberosPrincipal clientAlias = null;
KerberosPrincipal server = null;
+ KerberosPrincipal serverAlias = null;
Krb5NameElement credName = null;
@@ -193,6 +219,10 @@
client = new KerberosPrincipal(fullName);
}
+ if (cAPrinc != null) {
+ clientAlias = new KerberosPrincipal(cAPrinc.getName());
+ }
+
// XXX Compare name to credName
if (sPrinc != null) {
@@ -201,11 +231,17 @@
KerberosPrincipal.KRB_NT_SRV_INST);
}
+ if (sAPrinc != null) {
+ serverAlias = new KerberosPrincipal(sAPrinc.getName());
+ }
+
return new Krb5InitCredential(credName,
delegatedCred,
delegatedCred.getEncoded(),
client,
+ clientAlias,
server,
+ serverAlias,
sessionKey.getBytes(),
sessionKey.getEType(),
delegatedCred.getFlags(),
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java Wed Jul 17 12:26:56 2019 -0300
@@ -132,7 +132,7 @@
public static KerberosTicket credsToTicket(Credentials serviceCreds) {
EncryptionKey sessionKey = serviceCreds.getSessionKey();
- return new KerberosTicket(
+ KerberosTicket kt = new KerberosTicket(
serviceCreds.getEncoded(),
new KerberosPrincipal(serviceCreds.getClient().getName()),
new KerberosPrincipal(serviceCreds.getServer().getName(),
@@ -145,14 +145,35 @@
serviceCreds.getEndTime(),
serviceCreds.getRenewTill(),
serviceCreds.getClientAddresses());
+ PrincipalName clientAlias = serviceCreds.getClientAlias();
+ PrincipalName serverAlias = serviceCreds.getServerAlias();
+ if (clientAlias != null) {
+ KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketSetClientAlias(kt, new KerberosPrincipal(
+ clientAlias.getName(), clientAlias.getNameType()));
+ }
+ if (serverAlias != null) {
+ KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketSetServerAlias(kt, new KerberosPrincipal(
+ serverAlias.getName(), serverAlias.getNameType()));
+ }
+ return kt;
};
public static Credentials ticketToCreds(KerberosTicket kerbTicket)
throws KrbException, IOException {
+ KerberosPrincipal clientAlias = KerberosSecrets
+ .getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketGetClientAlias(kerbTicket);
+ KerberosPrincipal serverAlias = KerberosSecrets
+ .getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketGetServerAlias(kerbTicket);
return new Credentials(
kerbTicket.getEncoded(),
kerbTicket.getClient().getName(),
+ (clientAlias != null ? clientAlias.getName() : null),
kerbTicket.getServer().getName(),
+ (serverAlias != null ? serverAlias.getName() : null),
kerbTicket.getSessionKey().getEncoded(),
kerbTicket.getSessionKeyType(),
kerbTicket.getFlags(),
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/SubjectComber.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/SubjectComber.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, 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
@@ -25,6 +25,8 @@
package sun.security.jgss.krb5;
+import sun.security.krb5.KerberosSecrets;
+
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.Subject;
@@ -182,24 +184,45 @@
}
} else {
+ KerberosPrincipal serverAlias = KerberosSecrets
+ .getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketGetServerAlias(ticket);
if (serverPrincipal == null ||
- ticket.getServer().getName().equals(serverPrincipal)) {
-
+ ticket.getServer().getName().equals(serverPrincipal) ||
+ (serverAlias != null &&
+ serverPrincipal.equals(
+ serverAlias.getName()))) {
+ KerberosPrincipal clientAlias = KerberosSecrets
+ .getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketGetClientAlias(ticket);
if (clientPrincipal == null ||
clientPrincipal.equals(
- ticket.getClient().getName())) {
+ ticket.getClient().getName()) ||
+ (clientAlias != null &&
+ clientPrincipal.equals(
+ clientAlias.getName()))) {
if (oneOnly) {
return ticket;
} else {
// Record names so that tickets will
// all belong to same principals
if (clientPrincipal == null) {
- clientPrincipal =
- ticket.getClient().getName();
+ if (clientAlias == null) {
+ clientPrincipal =
+ ticket.getClient().getName();
+ } else {
+ clientPrincipal =
+ clientAlias.getName();
+ }
}
if (serverPrincipal == null) {
- serverPrincipal =
- ticket.getServer().getName();
+ if (serverAlias == null) {
+ serverPrincipal =
+ ticket.getServer().getName();
+ } else {
+ serverPrincipal =
+ serverAlias.getName();
+ }
}
answer.add(credClass.cast(ticket));
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -49,7 +49,9 @@
Ticket ticket;
PrincipalName client;
+ PrincipalName clientAlias;
PrincipalName server;
+ PrincipalName serverAlias;
EncryptionKey key;
TicketFlags flags;
KerberosTime authTime;
@@ -69,7 +71,9 @@
public Credentials(Ticket new_ticket,
PrincipalName new_client,
+ PrincipalName new_client_alias,
PrincipalName new_server,
+ PrincipalName new_server_alias,
EncryptionKey new_key,
TicketFlags new_flags,
KerberosTime authTime,
@@ -78,14 +82,17 @@
KerberosTime renewTill,
HostAddresses cAddr,
AuthorizationData authzData) {
- this(new_ticket, new_client, new_server, new_key, new_flags,
- authTime, new_startTime, new_endTime, renewTill, cAddr);
+ this(new_ticket, new_client, new_client_alias, new_server,
+ new_server_alias, new_key, new_flags, authTime,
+ new_startTime, new_endTime, renewTill, cAddr);
this.authzData = authzData;
}
public Credentials(Ticket new_ticket,
PrincipalName new_client,
+ PrincipalName new_client_alias,
PrincipalName new_server,
+ PrincipalName new_server_alias,
EncryptionKey new_key,
TicketFlags new_flags,
KerberosTime authTime,
@@ -95,7 +102,9 @@
HostAddresses cAddr) {
ticket = new_ticket;
client = new_client;
+ clientAlias = new_client_alias;
server = new_server;
+ serverAlias = new_server_alias;
key = new_key;
flags = new_flags;
this.authTime = authTime;
@@ -107,7 +116,9 @@
public Credentials(byte[] encoding,
String client,
+ String clientAlias,
String server,
+ String serverAlias,
byte[] keyBytes,
int keyType,
boolean[] flags,
@@ -118,7 +129,11 @@
InetAddress[] cAddrs) throws KrbException, IOException {
this(new Ticket(encoding),
new PrincipalName(client, PrincipalName.KRB_NT_PRINCIPAL),
+ (clientAlias == null? null : new PrincipalName(clientAlias,
+ PrincipalName.KRB_NT_PRINCIPAL)),
new PrincipalName(server, PrincipalName.KRB_NT_SRV_INST),
+ (serverAlias == null? null : new PrincipalName(serverAlias,
+ PrincipalName.KRB_NT_SRV_INST)),
new EncryptionKey(keyType, keyBytes),
(flags == null? null: new TicketFlags(flags)),
(authTime == null? null: new KerberosTime(authTime)),
@@ -143,10 +158,18 @@
return client;
}
+ public final PrincipalName getClientAlias() {
+ return clientAlias;
+ }
+
public final PrincipalName getServer() {
return server;
}
+ public final PrincipalName getServerAlias() {
+ return serverAlias;
+ }
+
public final EncryptionKey getSessionKey() {
return key;
}
@@ -262,6 +285,7 @@
return new KrbTgsReq(options,
this,
server,
+ serverAlias,
null, // from
null, // till
null, // rtime
@@ -484,7 +508,11 @@
public static void printDebug(Credentials c) {
System.out.println(">>> DEBUG: ----Credentials----");
System.out.println("\tclient: " + c.client.toString());
+ if (c.clientAlias != null)
+ System.out.println("\tclient alias: " + c.clientAlias.toString());
System.out.println("\tserver: " + c.server.toString());
+ if (c.serverAlias != null)
+ System.out.println("\tserver alias: " + c.serverAlias.toString());
System.out.println("\tticket: sname: " + c.ticket.sname.toString());
if (c.startTime != null) {
System.out.println("\tstartTime: " + c.startTime.getTime());
@@ -512,7 +540,11 @@
public String toString() {
StringBuilder sb = new StringBuilder("Credentials:");
sb.append( "\n client=").append(client);
+ if (clientAlias != null)
+ sb.append( "\n clientAlias=").append(clientAlias);
sb.append( "\n server=").append(server);
+ if (serverAlias != null)
+ sb.append( "\n serverAlias=").append(serverAlias);
if (authTime != null) {
sb.append("\n authTime=").append(authTime);
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -25,6 +25,8 @@
package sun.security.krb5;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KeyTab;
import sun.security.krb5.EncryptionKey;
import sun.security.krb5.PrincipalName;
@@ -39,4 +41,12 @@
*/
public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot(
KeyTab ktab);
+
+ public KerberosPrincipal kerberosTicketGetClientAlias(KerberosTicket t);
+
+ public void kerberosTicketSetClientAlias(KerberosTicket t, KerberosPrincipal a);
+
+ public KerberosPrincipal kerberosTicketGetServerAlias(KerberosTicket t);
+
+ public void kerberosTicketSetServerAlias(KerberosTicket t, KerberosPrincipal a);
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -363,7 +363,9 @@
creds = new Credentials(
apReqMessg.ticket,
authenticator.cname,
+ null,
apReqMessg.ticket.sname,
+ null,
enc_ticketPart.key,
enc_ticketPart.flags,
enc_ticketPart.authtime,
--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java Wed Jul 17 12:26:56 2019 -0300
@@ -118,7 +118,7 @@
"Cannot find key for type/kvno to decrypt AS REP - " +
EType.toString(encPartKeyType) + "/" + encPartKvno);
}
- decrypt(dkey, asReq);
+ decrypt(dkey, asReq, cname);
}
/**
@@ -136,7 +136,7 @@
password,
encPartKeyType,
PAData.getSaltAndParams(encPartKeyType, rep.pAData));
- decrypt(dkey, asReq);
+ decrypt(dkey, asReq, cname);
}
/**
@@ -144,7 +144,8 @@
* @param dkey the decryption key to use
* @param asReq the original AS-REQ sent, used to validate AS-REP
*/
- private void decrypt(EncryptionKey dkey, KrbAsReq asReq)
+ private void decrypt(EncryptionKey dkey, KrbAsReq asReq,
+ PrincipalName cname)
throws KrbException, Asn1Exception, IOException {
byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey,
KeyUsage.KU_ENC_AS_REP_PART);
@@ -157,10 +158,16 @@
ASReq req = asReq.getMessage();
check(true, req, rep, dkey);
+ PrincipalName clientAlias = cname;
+ if (clientAlias.equals(rep.cname))
+ clientAlias = null;
+
creds = new Credentials(
rep.ticket,
rep.cname,
+ clientAlias,
enc_part.sname,
+ null, // No server alias expected in a TGT
enc_part.key,
enc_part.flags,
enc_part.authtime,
--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java Wed Jul 17 12:26:56 2019 -0300
@@ -68,6 +68,7 @@
// Common data for AS-REQ fields
private KDCOptions options;
private PrincipalName cname;
+ private PrincipalName refCname; // May be changed by referrals
private PrincipalName sname;
private KerberosTime from;
private KerberosTime till;
@@ -100,6 +101,7 @@
private void init(PrincipalName cname)
throws KrbException {
this.cname = cname;
+ this.refCname = cname;
state = State.INIT;
}
@@ -284,7 +286,7 @@
}
return new KrbAsReq(key,
options,
- cname,
+ refCname,
sname,
from,
till,
@@ -334,7 +336,7 @@
ReferralsState referralsState = new ReferralsState();
while (true) {
if (referralsState.refreshComm()) {
- comm = new KdcComm(cname.getRealmAsString());
+ comm = new KdcComm(refCname.getRealmAsString());
}
try {
req = build(pakey, referralsState);
@@ -384,7 +386,7 @@
ReferralsState() throws KrbException {
if (Config.DISABLE_REFERRALS) {
- if (cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
+ if (refCname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
throw new KrbException("NT-ENTERPRISE principals only allowed" +
" when referrals are enabled.");
}
@@ -402,15 +404,15 @@
if (req.getMessage().reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) &&
referredRealm != null && referredRealm.toString().length() > 0 &&
count < Config.MAX_REFERRALS) {
- cname = new PrincipalName(cname.getNameType(),
- cname.getNameStrings(), referredRealm);
+ refCname = new PrincipalName(refCname.getNameType(),
+ refCname.getNameStrings(), referredRealm);
refreshComm = true;
count++;
return true;
}
}
if (count < Config.MAX_REFERRALS &&
- cname.getNameType() != PrincipalName.KRB_NT_ENTERPRISE) {
+ refCname.getNameType() != PrincipalName.KRB_NT_ENTERPRISE) {
// Server may raise an error if CANONICALIZE is true.
// Try CANONICALIZE false.
enabled = false;
--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -76,7 +76,7 @@
options.set(KDCOptions.FORWARDABLE, true);
KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService,
- null, null, null, null,
+ null, null, null, null, null,
null, // No easy way to get addresses right
null, null, null);
credMessg = createMessage(tgsReq.sendAndGetCreds(), key);
@@ -152,7 +152,7 @@
+ " endtime=" + endtime
+ "renewTill=" + renewTill);
}
- creds = new Credentials(ticket, pname, sname, credInfoKey,
+ creds = new Credentials(ticket, pname, null, sname, null, credInfoKey,
flags, authtime, starttime, endtime, renewTill, caddr);
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsRep.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsRep.java Wed Jul 17 12:26:56 2019 -0300
@@ -86,9 +86,20 @@
check(false, req, rep, tgsReq.tgsReqKey);
+ PrincipalName serverAlias = tgsReq.getServerAlias();
+ if (serverAlias != null) {
+ PrincipalName repSname = enc_part.sname;
+ if (serverAlias.equals(repSname) ||
+ isReferralSname(repSname)) {
+ serverAlias = null;
+ }
+ }
+
this.creds = new Credentials(rep.ticket,
rep.cname,
+ tgsReq.getClientAlias(),
enc_part.sname,
+ serverAlias,
enc_part.key,
enc_part.flags,
enc_part.authtime,
@@ -111,4 +122,16 @@
sun.security.krb5.internal.ccache.Credentials setCredentials() {
return new sun.security.krb5.internal.ccache.Credentials(rep, secondTicket);
}
+
+ private static boolean isReferralSname(PrincipalName sname) {
+ if (sname != null) {
+ String[] snameStrings = sname.getNameStrings();
+ if (snameStrings.length == 2 &&
+ snameStrings[0].equals(
+ PrincipalName.TGS_DEFAULT_SRV_NAME)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java Wed Jul 17 12:26:56 2019 -0300
@@ -45,7 +45,9 @@
public class KrbTgsReq {
private PrincipalName princName;
+ private PrincipalName clientAlias;
private PrincipalName servName;
+ private PrincipalName serverAlias;
private TGSReq tgsReqMessg;
private KerberosTime ctime;
private Ticket secondTicket = null;
@@ -59,13 +61,16 @@
// Used in CredentialsUtil
public KrbTgsReq(KDCOptions options, Credentials asCreds,
- PrincipalName cname, PrincipalName sname,
+ PrincipalName cname, PrincipalName clientAlias,
+ PrincipalName sname, PrincipalName serverAlias,
Ticket[] additionalTickets, PAData[] extraPAs)
throws KrbException, IOException {
this(options,
asCreds,
cname,
+ clientAlias,
sname,
+ serverAlias,
null, // KerberosTime from
null, // KerberosTime till
null, // KerberosTime rtime
@@ -82,6 +87,7 @@
KDCOptions options,
Credentials asCreds,
PrincipalName sname,
+ PrincipalName serverAlias,
KerberosTime from,
KerberosTime till,
KerberosTime rtime,
@@ -90,16 +96,18 @@
AuthorizationData authorizationData,
Ticket[] additionalTickets,
EncryptionKey subKey) throws KrbException, IOException {
- this(options, asCreds, asCreds.getClient(), sname,
- from, till, rtime, eTypes, addresses,
- authorizationData, additionalTickets, subKey, null);
+ this(options, asCreds, asCreds.getClient(), asCreds.getClientAlias(),
+ sname, serverAlias, from, till, rtime, eTypes,
+ addresses, authorizationData, additionalTickets, subKey, null);
}
private KrbTgsReq(
KDCOptions options,
Credentials asCreds,
PrincipalName cname,
+ PrincipalName clientAlias,
PrincipalName sname,
+ PrincipalName serverAlias,
KerberosTime from,
KerberosTime till,
KerberosTime rtime,
@@ -111,7 +119,9 @@
PAData[] extraPAs) throws KrbException, IOException {
princName = cname;
+ this.clientAlias = clientAlias;
servName = sname;
+ this.serverAlias = serverAlias;
ctime = KerberosTime.now();
// check if they are valid arguments. The optional fields
@@ -365,6 +375,14 @@
return secondTicket;
}
+ PrincipalName getClientAlias() {
+ return clientAlias;
+ }
+
+ PrincipalName getServerAlias() {
+ return serverAlias;
+ }
+
private static void debug(String message) {
// System.err.println(">>> KrbTgsReq: " + message);
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java Wed Jul 17 12:26:56 2019 -0300
@@ -564,7 +564,9 @@
for (int i = 0; i < nameStrings.length; i++) {
if (i > 0)
str.append("/");
- str.append(nameStrings[i]);
+ String n = nameStrings[i];
+ n = n.replace("@", "\\@");
+ str.append(n);
}
str.append("@");
str.append(nameRealm.toString());
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java Wed Jul 17 12:26:56 2019 -0300
@@ -284,8 +284,9 @@
// Try CANONICALIZE false.
}
}
- return serviceCredsSingle(options, asCreds,
- cname, sname, additionalTickets, extraPAs);
+ return serviceCredsSingle(options, asCreds, cname,
+ asCreds.getClientAlias(), sname, sname, additionalTickets,
+ extraPAs);
}
/*
@@ -300,26 +301,29 @@
options = new KDCOptions(options.toBooleanArray());
options.set(KDCOptions.CANONICALIZE, true);
PrincipalName cSname = sname;
+ PrincipalName refSname = sname; // May change with referrals
Credentials creds = null;
boolean isReferral = false;
List<String> referrals = new LinkedList<>();
+ PrincipalName clientAlias = asCreds.getClientAlias();
while (referrals.size() <= Config.MAX_REFERRALS) {
ReferralsCache.ReferralCacheEntry ref =
- ReferralsCache.get(sname, cSname.getRealmString());
+ ReferralsCache.get(cname, sname, refSname.getRealmString());
String toRealm = null;
if (ref == null) {
- creds = serviceCredsSingle(options, asCreds,
- cname, cSname, additionalTickets, extraPAs);
+ creds = serviceCredsSingle(options, asCreds, cname,
+ clientAlias, refSname, cSname, additionalTickets,
+ extraPAs);
PrincipalName server = creds.getServer();
- if (!cSname.equals(server)) {
+ if (!refSname.equals(server)) {
String[] serverNameStrings = server.getNameStrings();
if (serverNameStrings.length == 2 &&
serverNameStrings[0].equals(
PrincipalName.TGS_DEFAULT_SRV_NAME) &&
- !cSname.getRealmAsString().equals(serverNameStrings[1])) {
+ !refSname.getRealmAsString().equals(serverNameStrings[1])) {
// Server Name (sname) has the following format:
// krbtgt/TO-REALM.COM@FROM-REALM.COM
- ReferralsCache.put(sname, server.getRealmString(),
+ ReferralsCache.put(cname, sname, server.getRealmString(),
serverNameStrings[1], creds);
toRealm = serverNameStrings[1];
isReferral = true;
@@ -336,8 +340,8 @@
// Referrals loop detected
return null;
}
- cSname = new PrincipalName(cSname.getNameString(),
- cSname.getNameType(), toRealm);
+ refSname = new PrincipalName(refSname.getNameString(),
+ refSname.getNameType(), toRealm);
referrals.add(toRealm);
isReferral = false;
continue;
@@ -356,14 +360,15 @@
*/
private static Credentials serviceCredsSingle(
KDCOptions options, Credentials asCreds,
- PrincipalName cname, PrincipalName sname,
+ PrincipalName cname, PrincipalName clientAlias,
+ PrincipalName refSname, PrincipalName sname,
Ticket[] additionalTickets, PAData[] extraPAs)
throws KrbException, IOException {
Credentials theCreds = null;
boolean[] okAsDelegate = new boolean[]{true};
String[] serverAsCredsNames = asCreds.getServer().getNameStrings();
String tgtRealm = serverAsCredsNames[1];
- String serviceRealm = sname.getRealmString();
+ String serviceRealm = refSname.getRealmString();
if (!serviceRealm.equals(tgtRealm)) {
// This is a cross-realm service request
if (DEBUG) {
@@ -390,8 +395,8 @@
System.out.println(">>> Credentials serviceCredsSingle:" +
" same realm");
}
- KrbTgsReq req = new KrbTgsReq(options, asCreds,
- cname, sname, additionalTickets, extraPAs);
+ KrbTgsReq req = new KrbTgsReq(options, asCreds, cname, clientAlias,
+ refSname, sname, additionalTickets, extraPAs);
theCreds = req.sendAndGetCreds();
if (theCreds != null) {
if (DEBUG) {
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java Wed Jul 17 12:26:56 2019 -0300
@@ -139,7 +139,7 @@
sTime = new_sTime;
suSec = new_suSec;
errorCode = new_errorCode;
- crealm = new_cname.getRealm();
+ crealm = new_cname != null ? new_cname.getRealm() : null;
cname = new_cname;
sname = new_sname;
eText = new_eText;
@@ -168,7 +168,7 @@
sTime = new_sTime;
suSec = new_suSec;
errorCode = new_errorCode;
- crealm = new_cname.getRealm();
+ crealm = new_cname != null ? new_cname.getRealm() : null;
cname = new_cname;
sname = new_sname;
eText = new_eText;
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ReferralsCache.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ReferralsCache.java Wed Jul 17 12:26:56 2019 -0300
@@ -45,8 +45,27 @@
*/
final class ReferralsCache {
- private static Map<PrincipalName, Map<String, ReferralCacheEntry>> referralsMap =
- new HashMap<>();
+ private static Map<ReferralCacheKey, Map<String, ReferralCacheEntry>>
+ referralsMap = new HashMap<>();
+
+ static private final class ReferralCacheKey {
+ private PrincipalName cname;
+ private PrincipalName sname;
+ ReferralCacheKey (PrincipalName cname, PrincipalName sname) {
+ this.cname = cname;
+ this.sname = sname;
+ }
+ public boolean equals(Object other) {
+ if (!(other instanceof ReferralCacheKey))
+ return false;
+ ReferralCacheKey that = (ReferralCacheKey)other;
+ return cname.equals(that.cname) &&
+ sname.equals(that.sname);
+ }
+ public int hashCode() {
+ return cname.hashCode() + sname.hashCode();
+ }
+ }
static final class ReferralCacheEntry {
private final Credentials creds;
@@ -64,8 +83,9 @@
}
/*
- * Add a new referral entry to the cache, including: service principal,
- * source KDC realm, destination KDC realm and referral TGT.
+ * Add a new referral entry to the cache, including: client principal,
+ * service principal, source KDC realm, destination KDC realm and
+ * referral TGT.
*
* If a loop is generated when adding the new referral, the first hop is
* automatically removed. For example, let's assume that adding a
@@ -73,16 +93,17 @@
* REALM-1.COM -> REALM-2.COM -> REALM-3.COM -> REALM-1.COM. Then,
* REALM-1.COM -> REALM-2.COM referral entry is removed from the cache.
*/
- static synchronized void put(PrincipalName service,
+ static synchronized void put(PrincipalName cname, PrincipalName service,
String fromRealm, String toRealm, Credentials creds) {
- pruneExpired(service);
+ ReferralCacheKey k = new ReferralCacheKey(cname, service);
+ pruneExpired(k);
if (creds.getEndTime().before(new Date())) {
return;
}
- Map<String, ReferralCacheEntry> entries = referralsMap.get(service);
+ Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
if (entries == null) {
entries = new HashMap<String, ReferralCacheEntry>();
- referralsMap.put(service, entries);
+ referralsMap.put(k, entries);
}
entries.remove(fromRealm);
ReferralCacheEntry newEntry = new ReferralCacheEntry(creds, toRealm);
@@ -103,13 +124,14 @@
}
/*
- * Obtain a referral entry from the cache given a service principal and a
- * source KDC realm.
+ * Obtain a referral entry from the cache given a client principal,
+ * service principal and a source KDC realm.
*/
- static synchronized ReferralCacheEntry get(PrincipalName service,
- String fromRealm) {
- pruneExpired(service);
- Map<String, ReferralCacheEntry> entries = referralsMap.get(service);
+ static synchronized ReferralCacheEntry get(PrincipalName cname,
+ PrincipalName service, String fromRealm) {
+ ReferralCacheKey k = new ReferralCacheKey(cname, service);
+ pruneExpired(k);
+ Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
if (entries != null) {
ReferralCacheEntry toRef = entries.get(fromRealm);
if (toRef != null) {
@@ -122,9 +144,9 @@
/*
* Remove referral entries from the cache when referral TGTs expire.
*/
- private static void pruneExpired(PrincipalName service) {
+ private static void pruneExpired(ReferralCacheKey k) {
Date now = new Date();
- Map<String, ReferralCacheEntry> entries = referralsMap.get(service);
+ Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
if (entries != null) {
for (Entry<String, ReferralCacheEntry> mapEntry :
entries.entrySet()) {
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java Wed Jul 17 12:26:56 2019 -0300
@@ -180,8 +180,9 @@
// is most likely to be the one in Authenticator in PA-TGS-REQ encoded
// in TGS-REQ, therefore only stored with a service ticket. Currently
// in Java, we only reads TGTs.
- return new sun.security.krb5.Credentials(ticket,
- cname, sname, key, flags, authtime, starttime, endtime, renewTill, caddr);
+ return new sun.security.krb5.Credentials(ticket, cname, null, sname,
+ null, key, flags, authtime, starttime, endtime, renewTill,
+ caddr);
}
public KerberosTime getStartTime() {
--- a/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c Wed Jul 17 16:13:26 2019 -0700
+++ b/src/java.security.jgss/windows/native/libw2k_lsa_auth/NativeCreds.c Wed Jul 17 12:26:56 2019 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -406,6 +406,8 @@
"(Lsun/security/krb5/internal/Ticket;"
"Lsun/security/krb5/PrincipalName;"
"Lsun/security/krb5/PrincipalName;"
+ "Lsun/security/krb5/PrincipalName;"
+ "Lsun/security/krb5/PrincipalName;"
"Lsun/security/krb5/EncryptionKey;"
"Lsun/security/krb5/internal/TicketFlags;"
"Lsun/security/krb5/internal/KerberosTime;"
@@ -667,7 +669,9 @@
krbcredsConstructor,
ticket,
clientPrincipal,
+ NULL,
targetPrincipal,
+ NULL,
encryptionKey,
ticketFlags,
authTime, // mdu
--- a/test/jdk/sun/security/krb5/auto/KDC.java Wed Jul 17 16:13:26 2019 -0700
+++ b/test/jdk/sun/security/krb5/auto/KDC.java Wed Jul 17 12:26:56 2019 -0300
@@ -808,8 +808,10 @@
PrincipalName cname = null;
boolean allowForwardable = true;
-
+ boolean isReferral = false;
if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
+ System.out.println(realm + "> verifying referral for " +
+ body.sname.getNameString());
KDC referral = aliasReferrals.get(body.sname.getNameString());
if (referral != null) {
service = new PrincipalName(
@@ -817,6 +819,9 @@
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
referral.getRealm(), PrincipalName.KRB_NT_SRV_INST,
this.getRealm());
+ System.out.println(realm + "> referral to " +
+ referral.getRealm());
+ isReferral = true;
}
}
@@ -918,7 +923,8 @@
if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) {
bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true;
}
- if (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT)) {
+ if (body.kdcOptions.get(KDCOptions.CNAME_IN_ADDL_TKT) &&
+ !isReferral) {
if (!options.containsKey(Option.ALLOW_S4U2PROXY)) {
// Don't understand CNAME_IN_ADDL_TKT
throw new KrbException(Krb5.KDC_ERR_BADOPTION);
@@ -1074,8 +1080,7 @@
}
int eType = eTypes[0];
- if (body.kdcOptions.get(KDCOptions.CANONICALIZE) &&
- body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
+ if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
PrincipalName principal = alias2Principals.get(
body.cname.getNameString());
if (principal != null) {
--- a/test/jdk/sun/security/krb5/auto/ReferralsTest.java Wed Jul 17 16:13:26 2019 -0700
+++ b/test/jdk/sun/security/krb5/auto/ReferralsTest.java Wed Jul 17 12:26:56 2019 -0300
@@ -30,9 +30,18 @@
*/
import java.io.File;
-import sun.security.krb5.Credentials;
-import sun.security.krb5.internal.CredentialsUtil;
-import sun.security.krb5.KrbAsReqBuilder;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.Subject;
+
+import org.ietf.jgss.GSSName;
+
+import sun.security.jgss.GSSUtil;
import sun.security.krb5.PrincipalName;
public class ReferralsTest {
@@ -41,39 +50,32 @@
private static final String realmKDC1 = "RABBIT.HOLE";
private static final String realmKDC2 = "DEV.RABBIT.HOLE";
private static final char[] password = "123qwe@Z".toCharArray();
+
+ // Names
private static final String clientName = "test";
-
- private static final String clientAlias = clientName +
- PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
-
- private static final String clientKDC1QueryName = clientAlias.replaceAll(
- PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
- PrincipalName.NAME_REALM_SEPARATOR_STR) +
- PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
- private static PrincipalName clientKDC1QueryPrincipal = null;
- static {
- try {
- clientKDC1QueryPrincipal = new PrincipalName(
- clientKDC1QueryName, PrincipalName.KRB_NT_ENTERPRISE,
- null);
- } catch (Throwable t) {}
- }
-
- private static final String clientKDC2Name = clientName +
- PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
-
private static final String serviceName = "http" +
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
"server.dev.rabbit.hole";
- private static Credentials tgt;
- private static Credentials tgs;
+ // Alias
+ private static final String clientAlias = clientName +
+ PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
+
+ // Names + realms
+ private static final String clientKDC1Name = clientAlias.replaceAll(
+ PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
+ PrincipalName.NAME_REALM_SEPARATOR_STR) +
+ PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
+ private static final String clientKDC2Name = clientName +
+ PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
+ private static final String serviceKDC2Name = serviceName +
+ PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
public static void main(String[] args) throws Exception {
try {
initializeKDCs();
- getTGT();
- getTGS();
+ testSubjectCredentials();
+ testDelegated();
} finally {
cleanup();
}
@@ -108,6 +110,11 @@
kdc1.registerAlias(serviceName, kdc2);
kdc2.registerAlias(clientAlias, clientKDC2Name);
+ Map<String,List<String>> mapKDC2 = new HashMap<>();
+ mapKDC2.put(serviceName + "@" + realmKDC2, Arrays.asList(
+ new String[]{serviceName + "@" + realmKDC2}));
+ kdc2.setOption(KDC.Option.ALLOW_S4U2PROXY, mapKDC2);
+
KDC.saveConfig(krbConfigName, kdc1, kdc2,
"forwardable=true");
System.setProperty("java.security.krb5.conf", krbConfigName);
@@ -120,50 +127,123 @@
}
}
- private static void getTGT() throws Exception {
- KrbAsReqBuilder builder = new KrbAsReqBuilder(clientKDC1QueryPrincipal,
- password);
- tgt = builder.action().getCreds();
- builder.destroy();
+ /*
+ * The client subject (whose principal is
+ * test@RABBIT.HOLE@RABBIT.HOLE) will obtain a TGT after
+ * realm referral and name canonicalization (TGT cname
+ * will be test@DEV.RABBIT.HOLE). With this TGT, the client will request
+ * a TGS for service http/server.dev.rabbit.hole@RABBIT.HOLE. After
+ * realm referral, a http/server.dev.rabbit.hole@DEV.RABBIT.HOLE TGS
+ * will be obtained.
+ *
+ * Assert that we get the proper TGT and TGS tickets, and that they are
+ * associated to the client subject.
+ *
+ * Assert that if we request a TGS for the same service again (based on the
+ * original service name), we don't get a new one but the previous,
+ * already in the subject credentials.
+ */
+ private static void testSubjectCredentials() throws Exception {
+ Subject clientSubject = new Subject();
+ Context clientContext = Context.fromUserPass(clientSubject,
+ clientKDC1Name, password, false);
+
+ Set<Principal> clientPrincipals = clientSubject.getPrincipals();
+ if (clientPrincipals.size() != 1) {
+ throw new Exception("Only one client subject principal expected");
+ }
+ Principal clientPrincipal = clientPrincipals.iterator().next();
if (DEBUG) {
- System.out.println("TGT");
- System.out.println("----------------------");
- System.out.println(tgt);
- System.out.println("----------------------");
+ System.out.println("Client subject principal: " +
+ clientPrincipal.getName());
+ }
+ if (!clientPrincipal.getName().equals(clientKDC1Name)) {
+ throw new Exception("Unexpected client subject principal.");
}
- if (tgt == null) {
- throw new Exception("TGT is null");
- }
- if (!tgt.getClient().getName().equals(clientKDC2Name)) {
- throw new Exception("Unexpected TGT client");
+
+ clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
+ clientContext.take(new byte[0]);
+ Set<KerberosTicket> clientTickets =
+ clientSubject.getPrivateCredentials(KerberosTicket.class);
+ boolean tgtFound = false;
+ boolean tgsFound = false;
+ for (KerberosTicket clientTicket : clientTickets) {
+ String cname = clientTicket.getClient().getName();
+ String sname = clientTicket.getServer().getName();
+ if (cname.equals(clientKDC2Name)) {
+ if (sname.equals(PrincipalName.TGS_DEFAULT_SRV_NAME +
+ PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
+ realmKDC2 + PrincipalName.NAME_REALM_SEPARATOR_STR +
+ realmKDC2)) {
+ tgtFound = true;
+ } else if (sname.equals(serviceKDC2Name)) {
+ tgsFound = true;
+ }
+ }
+ if (DEBUG) {
+ System.out.println("Client subject KerberosTicket:");
+ System.out.println(clientTicket);
+ }
}
- String[] tgtServerNames = tgt.getServer().getNameStrings();
- if (tgtServerNames.length != 2 || !tgtServerNames[0].equals(
- PrincipalName.TGS_DEFAULT_SRV_NAME) ||
- !tgtServerNames[1].equals(realmKDC2) ||
- !tgt.getServer().getRealmString().equals(realmKDC2)) {
- throw new Exception("Unexpected TGT server");
+ if (!tgtFound || !tgsFound) {
+ throw new Exception("client subject tickets (TGT/TGS) not found.");
+ }
+ int numOfTickets = clientTickets.size();
+ clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
+ clientContext.take(new byte[0]);
+ clientContext.status();
+ int newNumOfTickets =
+ clientSubject.getPrivateCredentials(KerberosTicket.class).size();
+ if (DEBUG) {
+ System.out.println("client subject number of tickets: " +
+ numOfTickets);
+ System.out.println("client subject new number of tickets: " +
+ newNumOfTickets);
+ }
+ if (numOfTickets != newNumOfTickets) {
+ throw new Exception("Useless client subject TGS request because" +
+ " TGS was not found in private credentials.");
}
}
- private static void getTGS() throws Exception {
- tgs = CredentialsUtil.acquireServiceCreds(serviceName +
- PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, tgt);
- if (DEBUG) {
- System.out.println("TGS");
- System.out.println("----------------------");
- System.out.println(tgs);
- System.out.println("----------------------");
+ /*
+ * The server (http/server.dev.rabbit.hole@DEV.RABBIT.HOLE)
+ * will authenticate on itself on behalf of the client
+ * (test@DEV.RABBIT.HOLE). Cross-realm referrals will occur
+ * when requesting different TGTs and TGSs (including the
+ * request for delegated credentials).
+ */
+ private static void testDelegated() throws Exception {
+ Context c = Context.fromUserPass(clientKDC2Name,
+ password, false);
+ c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
+ Context s = Context.fromUserPass(serviceKDC2Name,
+ password, true);
+ s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+ Context.handshake(c, s);
+ Context delegatedContext = s.delegated();
+ delegatedContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
+ delegatedContext.x().requestMutualAuth(false);
+ Context s2 = Context.fromUserPass(serviceKDC2Name,
+ password, true);
+ s2.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+
+ // Test authentication
+ Context.handshake(delegatedContext, s2);
+ if (!delegatedContext.x().isEstablished() || !s2.x().isEstablished()) {
+ throw new Exception("Delegated authentication failed");
}
- if (tgs == null) {
- throw new Exception("TGS is null");
+
+ // Test identities
+ GSSName contextInitiatorName = delegatedContext.x().getSrcName();
+ GSSName contextAcceptorName = delegatedContext.x().getTargName();
+ if (DEBUG) {
+ System.out.println("Context initiator: " + contextInitiatorName);
+ System.out.println("Context acceptor: " + contextAcceptorName);
}
- if (!tgs.getClient().getName().equals(clientKDC2Name)) {
- throw new Exception("Unexpected TGS client");
- }
- if (!tgs.getServer().getNameString().equals(serviceName) ||
- !tgs.getServer().getRealmString().equals(realmKDC2)) {
- throw new Exception("Unexpected TGS server");
+ if (!contextInitiatorName.toString().equals(clientKDC2Name) ||
+ !contextAcceptorName.toString().equals(serviceName)) {
+ throw new Exception("Unexpected initiator or acceptor names");
}
}
}