提交 32e7a542 编写于 作者: A andrew

8227437: S4U2proxy cannot continue because server's TGT cannot be found

Reviewed-by: mbalao
上级 03313f0a
...@@ -33,6 +33,22 @@ class JavaxSecurityAuthKerberosAccessImpl ...@@ -33,6 +33,22 @@ class JavaxSecurityAuthKerberosAccessImpl
KeyTab ktab) { KeyTab ktab) {
return ktab.takeSnapshot(); 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;
}
public KerberosTicket kerberosTicketGetProxy(KerberosTicket t) { public KerberosTicket kerberosTicketGetProxy(KerberosTicket t) {
return t.proxy; return t.proxy;
} }
......
...@@ -194,6 +194,10 @@ public class KerberosTicket implements Destroyable, Refreshable, ...@@ -194,6 +194,10 @@ public class KerberosTicket implements Destroyable, Refreshable,
private InetAddress[] clientAddresses; private InetAddress[] clientAddresses;
transient KerberosPrincipal clientAlias = null;
transient KerberosPrincipal serverAlias = null;
/** /**
* Evidence ticket if proxy_impersonator. This field can be accessed * Evidence ticket if proxy_impersonator. This field can be accessed
* by KerberosSecrets. It's serialized. * by KerberosSecrets. It's serialized.
...@@ -563,7 +567,11 @@ public class KerberosTicket implements Destroyable, Refreshable, ...@@ -563,7 +567,11 @@ public class KerberosTicket implements Destroyable, Refreshable,
try { try {
krb5Creds = new sun.security.krb5.Credentials(asn1Encoding, krb5Creds = new sun.security.krb5.Credentials(asn1Encoding,
client.toString(), client.toString(),
(clientAlias != null ?
clientAlias.getName() : null),
server.toString(), server.toString(),
(serverAlias != null ?
serverAlias.getName() : null),
sessionKey.getEncoded(), sessionKey.getEncoded(),
sessionKey.getKeyType(), sessionKey.getKeyType(),
flags, flags,
......
...@@ -715,9 +715,9 @@ class Krb5Context implements GSSContextSpi { ...@@ -715,9 +715,9 @@ class Krb5Context implements GSSContextSpi {
/* /*
* Store the service credentials as * Store the service credentials as
* javax.security.auth.kerberos.KerberosTicket in * javax.security.auth.kerberos.KerberosTicket in
* the Subject. We could wait till the context is * the Subject. We could wait until the context is
* succesfully established; however it is easier * successfully established; however it is easier
* to do here and there is no harm indoing it here. * to do it here and there is no harm.
*/ */
final KerberosTicket kt = final KerberosTicket kt =
Krb5Util.credsToTicket(serviceCreds); Krb5Util.credsToTicket(serviceCreds);
......
...@@ -60,7 +60,9 @@ public class Krb5InitCredential ...@@ -60,7 +60,9 @@ public class Krb5InitCredential
private Krb5InitCredential(Krb5NameElement name, private Krb5InitCredential(Krb5NameElement name,
byte[] asn1Encoding, byte[] asn1Encoding,
KerberosPrincipal client, KerberosPrincipal client,
KerberosPrincipal clientAlias,
KerberosPrincipal server, KerberosPrincipal server,
KerberosPrincipal serverAlias,
byte[] sessionKey, byte[] sessionKey,
int keyType, int keyType,
boolean[] flags, boolean[] flags,
...@@ -81,14 +83,21 @@ public class Krb5InitCredential ...@@ -81,14 +83,21 @@ public class Krb5InitCredential
endTime, endTime,
renewTill, renewTill,
clientAddresses); clientAddresses);
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketSetClientAlias(this, clientAlias);
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketSetServerAlias(this, serverAlias);
this.name = name; this.name = name;
try { try {
// Cache this for later use by the sun.security.krb5 package. // Cache this for later use by the sun.security.krb5 package.
krb5Credentials = new Credentials(asn1Encoding, krb5Credentials = new Credentials(asn1Encoding,
client.getName(), client.getName(),
(clientAlias != null ?
clientAlias.getName() : null),
server.getName(), server.getName(),
(serverAlias != null ?
serverAlias.getName() : null),
sessionKey, sessionKey,
keyType, keyType,
flags, flags,
...@@ -111,7 +120,9 @@ public class Krb5InitCredential ...@@ -111,7 +120,9 @@ public class Krb5InitCredential
Credentials delegatedCred, Credentials delegatedCred,
byte[] asn1Encoding, byte[] asn1Encoding,
KerberosPrincipal client, KerberosPrincipal client,
KerberosPrincipal clientAlias,
KerberosPrincipal server, KerberosPrincipal server,
KerberosPrincipal serverAlias,
byte[] sessionKey, byte[] sessionKey,
int keyType, int keyType,
boolean[] flags, boolean[] flags,
...@@ -132,7 +143,10 @@ public class Krb5InitCredential ...@@ -132,7 +143,10 @@ public class Krb5InitCredential
endTime, endTime,
renewTill, renewTill,
clientAddresses); clientAddresses);
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketSetClientAlias(this, clientAlias);
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketSetServerAlias(this, serverAlias);
this.name = name; this.name = name;
// A delegated cred does not have all fields set. So do not try to // A delegated cred does not have all fields set. So do not try to
// creat new Credentials out of the delegatedCred. // creat new Credentials out of the delegatedCred.
...@@ -154,10 +168,18 @@ public class Krb5InitCredential ...@@ -154,10 +168,18 @@ public class Krb5InitCredential
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
} }
KerberosPrincipal clientAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetClientAlias(tgt);
KerberosPrincipal serverAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetServerAlias(tgt);
Krb5InitCredential result = new Krb5InitCredential(name, Krb5InitCredential result = new Krb5InitCredential(name,
tgt.getEncoded(), tgt.getEncoded(),
tgt.getClient(), tgt.getClient(),
clientAlias,
tgt.getServer(), tgt.getServer(),
serverAlias,
tgt.getSessionKey().getEncoded(), tgt.getSessionKey().getEncoded(),
tgt.getSessionKeyType(), tgt.getSessionKeyType(),
tgt.getFlags(), tgt.getFlags(),
...@@ -183,10 +205,14 @@ public class Krb5InitCredential ...@@ -183,10 +205,14 @@ public class Krb5InitCredential
*/ */
PrincipalName cPrinc = delegatedCred.getClient(); PrincipalName cPrinc = delegatedCred.getClient();
PrincipalName cAPrinc = delegatedCred.getClientAlias();
PrincipalName sPrinc = delegatedCred.getServer(); PrincipalName sPrinc = delegatedCred.getServer();
PrincipalName sAPrinc = delegatedCred.getServerAlias();
KerberosPrincipal client = null; KerberosPrincipal client = null;
KerberosPrincipal clientAlias = null;
KerberosPrincipal server = null; KerberosPrincipal server = null;
KerberosPrincipal serverAlias = null;
Krb5NameElement credName = null; Krb5NameElement credName = null;
...@@ -197,6 +223,10 @@ public class Krb5InitCredential ...@@ -197,6 +223,10 @@ public class Krb5InitCredential
client = new KerberosPrincipal(fullName); client = new KerberosPrincipal(fullName);
} }
if (cAPrinc != null) {
clientAlias = new KerberosPrincipal(cAPrinc.getName());
}
// XXX Compare name to credName // XXX Compare name to credName
if (sPrinc != null) { if (sPrinc != null) {
...@@ -205,11 +235,17 @@ public class Krb5InitCredential ...@@ -205,11 +235,17 @@ public class Krb5InitCredential
KerberosPrincipal.KRB_NT_SRV_INST); KerberosPrincipal.KRB_NT_SRV_INST);
} }
if (sAPrinc != null) {
serverAlias = new KerberosPrincipal(sAPrinc.getName());
}
return new Krb5InitCredential(credName, return new Krb5InitCredential(credName,
delegatedCred, delegatedCred,
delegatedCred.getEncoded(), delegatedCred.getEncoded(),
client, client,
clientAlias,
server, server,
serverAlias,
sessionKey.getBytes(), sessionKey.getBytes(),
sessionKey.getEType(), sessionKey.getEType(),
delegatedCred.getFlags(), delegatedCred.getFlags(),
......
...@@ -228,7 +228,7 @@ public class Krb5Util { ...@@ -228,7 +228,7 @@ public class Krb5Util {
public static KerberosTicket credsToTicket(Credentials serviceCreds) { public static KerberosTicket credsToTicket(Credentials serviceCreds) {
EncryptionKey sessionKey = serviceCreds.getSessionKey(); EncryptionKey sessionKey = serviceCreds.getSessionKey();
return new KerberosTicket( KerberosTicket kt = new KerberosTicket(
serviceCreds.getEncoded(), serviceCreds.getEncoded(),
new KerberosPrincipal(serviceCreds.getClient().getName()), new KerberosPrincipal(serviceCreds.getClient().getName()),
new KerberosPrincipal(serviceCreds.getServer().getName(), new KerberosPrincipal(serviceCreds.getServer().getName(),
...@@ -241,14 +241,35 @@ public class Krb5Util { ...@@ -241,14 +241,35 @@ public class Krb5Util {
serviceCreds.getEndTime(), serviceCreds.getEndTime(),
serviceCreds.getRenewTill(), serviceCreds.getRenewTill(),
serviceCreds.getClientAddresses()); 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) public static Credentials ticketToCreds(KerberosTicket kerbTicket)
throws KrbException, IOException { throws KrbException, IOException {
KerberosPrincipal clientAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetClientAlias(kerbTicket);
KerberosPrincipal serverAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetServerAlias(kerbTicket);
return new Credentials( return new Credentials(
kerbTicket.getEncoded(), kerbTicket.getEncoded(),
kerbTicket.getClient().getName(), kerbTicket.getClient().getName(),
(clientAlias != null ? clientAlias.getName() : null),
kerbTicket.getServer().getName(), kerbTicket.getServer().getName(),
(serverAlias != null ? serverAlias.getName() : null),
kerbTicket.getSessionKey().getEncoded(), kerbTicket.getSessionKey().getEncoded(),
kerbTicket.getSessionKeyType(), kerbTicket.getSessionKeyType(),
kerbTicket.getFlags(), kerbTicket.getFlags(),
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
package sun.security.jgss.krb5; package sun.security.jgss.krb5;
import sun.security.krb5.KerberosSecrets;
import javax.security.auth.kerberos.KerberosTicket; import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KerberosKey; import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.Subject; import javax.security.auth.Subject;
...@@ -182,24 +184,45 @@ class SubjectComber { ...@@ -182,24 +184,45 @@ class SubjectComber {
} }
} else { } else {
KerberosPrincipal serverAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetServerAlias(ticket);
if (serverPrincipal == null || 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 || if (clientPrincipal == null ||
clientPrincipal.equals( clientPrincipal.equals(
ticket.getClient().getName())) { ticket.getClient().getName()) ||
(clientAlias != null &&
clientPrincipal.equals(
clientAlias.getName()))) {
if (oneOnly) { if (oneOnly) {
return ticket; return ticket;
} else { } else {
// Record names so that tickets will // Record names so that tickets will
// all belong to same principals // all belong to same principals
if (clientPrincipal == null) { if (clientPrincipal == null) {
if (clientAlias == null) {
clientPrincipal = clientPrincipal =
ticket.getClient().getName(); ticket.getClient().getName();
} else {
clientPrincipal =
clientAlias.getName();
}
} }
if (serverPrincipal == null) { if (serverPrincipal == null) {
if (serverAlias == null) {
serverPrincipal = serverPrincipal =
ticket.getServer().getName(); ticket.getServer().getName();
} else {
serverPrincipal =
serverAlias.getName();
}
} }
answer.add(credClass.cast(ticket)); answer.add(credClass.cast(ticket));
} }
......
...@@ -48,7 +48,9 @@ public class Credentials { ...@@ -48,7 +48,9 @@ public class Credentials {
Ticket ticket; Ticket ticket;
PrincipalName client; PrincipalName client;
PrincipalName clientAlias;
PrincipalName server; PrincipalName server;
PrincipalName serverAlias;
EncryptionKey key; EncryptionKey key;
TicketFlags flags; TicketFlags flags;
KerberosTime authTime; KerberosTime authTime;
...@@ -78,7 +80,9 @@ public class Credentials { ...@@ -78,7 +80,9 @@ public class Credentials {
public Credentials(Ticket new_ticket, public Credentials(Ticket new_ticket,
PrincipalName new_client, PrincipalName new_client,
PrincipalName new_client_alias,
PrincipalName new_server, PrincipalName new_server,
PrincipalName new_server_alias,
EncryptionKey new_key, EncryptionKey new_key,
TicketFlags new_flags, TicketFlags new_flags,
KerberosTime authTime, KerberosTime authTime,
...@@ -87,14 +91,17 @@ public class Credentials { ...@@ -87,14 +91,17 @@ public class Credentials {
KerberosTime renewTill, KerberosTime renewTill,
HostAddresses cAddr, HostAddresses cAddr,
AuthorizationData authzData) { AuthorizationData authzData) {
this(new_ticket, new_client, new_server, new_key, new_flags, this(new_ticket, new_client, new_client_alias, new_server,
authTime, new_startTime, new_endTime, renewTill, cAddr); new_server_alias, new_key, new_flags, authTime,
new_startTime, new_endTime, renewTill, cAddr);
this.authzData = authzData; this.authzData = authzData;
} }
public Credentials(Ticket new_ticket, public Credentials(Ticket new_ticket,
PrincipalName new_client, PrincipalName new_client,
PrincipalName new_client_alias,
PrincipalName new_server, PrincipalName new_server,
PrincipalName new_server_alias,
EncryptionKey new_key, EncryptionKey new_key,
TicketFlags new_flags, TicketFlags new_flags,
KerberosTime authTime, KerberosTime authTime,
...@@ -104,7 +111,9 @@ public class Credentials { ...@@ -104,7 +111,9 @@ public class Credentials {
HostAddresses cAddr) { HostAddresses cAddr) {
ticket = new_ticket; ticket = new_ticket;
client = new_client; client = new_client;
clientAlias = new_client_alias;
server = new_server; server = new_server;
serverAlias = new_server_alias;
key = new_key; key = new_key;
flags = new_flags; flags = new_flags;
this.authTime = authTime; this.authTime = authTime;
...@@ -116,7 +125,9 @@ public class Credentials { ...@@ -116,7 +125,9 @@ public class Credentials {
public Credentials(byte[] encoding, public Credentials(byte[] encoding,
String client, String client,
String clientAlias,
String server, String server,
String serverAlias,
byte[] keyBytes, byte[] keyBytes,
int keyType, int keyType,
boolean[] flags, boolean[] flags,
...@@ -127,7 +138,11 @@ public class Credentials { ...@@ -127,7 +138,11 @@ public class Credentials {
InetAddress[] cAddrs) throws KrbException, IOException { InetAddress[] cAddrs) throws KrbException, IOException {
this(new Ticket(encoding), this(new Ticket(encoding),
new PrincipalName(client, PrincipalName.KRB_NT_PRINCIPAL), 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), new PrincipalName(server, PrincipalName.KRB_NT_SRV_INST),
(serverAlias == null? null : new PrincipalName(serverAlias,
PrincipalName.KRB_NT_SRV_INST)),
new EncryptionKey(keyType, keyBytes), new EncryptionKey(keyType, keyBytes),
(flags == null? null: new TicketFlags(flags)), (flags == null? null: new TicketFlags(flags)),
(authTime == null? null: new KerberosTime(authTime)), (authTime == null? null: new KerberosTime(authTime)),
...@@ -152,10 +167,18 @@ public class Credentials { ...@@ -152,10 +167,18 @@ public class Credentials {
return client; return client;
} }
public final PrincipalName getClientAlias() {
return clientAlias;
}
public final PrincipalName getServer() { public final PrincipalName getServer() {
return server; return server;
} }
public final PrincipalName getServerAlias() {
return serverAlias;
}
public final EncryptionKey getSessionKey() { public final EncryptionKey getSessionKey() {
return key; return key;
} }
...@@ -271,6 +294,7 @@ public class Credentials { ...@@ -271,6 +294,7 @@ public class Credentials {
return new KrbTgsReq(options, return new KrbTgsReq(options,
this, this,
server, server,
serverAlias,
null, // from null, // from
null, // till null, // till
null, // rtime null, // rtime
...@@ -488,7 +512,11 @@ public class Credentials { ...@@ -488,7 +512,11 @@ public class Credentials {
public static void printDebug(Credentials c) { public static void printDebug(Credentials c) {
System.out.println(">>> DEBUG: ----Credentials----"); System.out.println(">>> DEBUG: ----Credentials----");
System.out.println("\tclient: " + c.client.toString()); 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()); 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()); System.out.println("\tticket: sname: " + c.ticket.sname.toString());
if (c.startTime != null) { if (c.startTime != null) {
System.out.println("\tstartTime: " + c.startTime.getTime()); System.out.println("\tstartTime: " + c.startTime.getTime());
...@@ -516,7 +544,11 @@ public class Credentials { ...@@ -516,7 +544,11 @@ public class Credentials {
public String toString() { public String toString() {
StringBuffer buffer = new StringBuffer("Credentials:"); StringBuffer buffer = new StringBuffer("Credentials:");
buffer.append( "\n client=").append(client); buffer.append( "\n client=").append(client);
if (clientAlias != null)
buffer.append( "\n clientAlias=").append(clientAlias);
buffer.append( "\n server=").append(server); buffer.append( "\n server=").append(server);
if (serverAlias != null)
buffer.append( "\n serverAlias=").append(serverAlias);
if (authTime != null) { if (authTime != null) {
buffer.append("\n authTime=").append(authTime); buffer.append("\n authTime=").append(authTime);
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package sun.security.krb5; package sun.security.krb5;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KerberosTicket; import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KeyTab; import javax.security.auth.kerberos.KeyTab;
...@@ -39,6 +40,14 @@ public interface JavaxSecurityAuthKerberosAccess { ...@@ -39,6 +40,14 @@ public interface JavaxSecurityAuthKerberosAccess {
public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot(
KeyTab ktab); 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);
/** /**
* Returns the proxy for a KerberosTicket. * Returns the proxy for a KerberosTicket.
*/ */
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -361,7 +361,9 @@ public class KrbApReq { ...@@ -361,7 +361,9 @@ public class KrbApReq {
creds = new Credentials( creds = new Credentials(
apReqMessg.ticket, apReqMessg.ticket,
authenticator.cname, authenticator.cname,
null,
apReqMessg.ticket.sname, apReqMessg.ticket.sname,
null,
enc_ticketPart.key, enc_ticketPart.key,
enc_ticketPart.flags, enc_ticketPart.flags,
enc_ticketPart.authtime, enc_ticketPart.authtime,
......
...@@ -118,7 +118,7 @@ class KrbAsRep extends KrbKdcRep { ...@@ -118,7 +118,7 @@ class KrbAsRep extends KrbKdcRep {
"Cannot find key for type/kvno to decrypt AS REP - " + "Cannot find key for type/kvno to decrypt AS REP - " +
EType.toString(encPartKeyType) + "/" + encPartKvno); EType.toString(encPartKeyType) + "/" + encPartKvno);
} }
decrypt(dkey, asReq); decrypt(dkey, asReq, cname);
} }
/** /**
...@@ -136,7 +136,7 @@ class KrbAsRep extends KrbKdcRep { ...@@ -136,7 +136,7 @@ class KrbAsRep extends KrbKdcRep {
password, password,
encPartKeyType, encPartKeyType,
PAData.getSaltAndParams(encPartKeyType, rep.pAData)); PAData.getSaltAndParams(encPartKeyType, rep.pAData));
decrypt(dkey, asReq); decrypt(dkey, asReq, cname);
} }
/** /**
...@@ -144,7 +144,8 @@ class KrbAsRep extends KrbKdcRep { ...@@ -144,7 +144,8 @@ class KrbAsRep extends KrbKdcRep {
* @param dkey the decryption key to use * @param dkey the decryption key to use
* @param asReq the original AS-REQ sent, used to validate AS-REP * @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 { throws KrbException, Asn1Exception, IOException {
byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey, byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey,
KeyUsage.KU_ENC_AS_REP_PART); KeyUsage.KU_ENC_AS_REP_PART);
...@@ -157,10 +158,16 @@ class KrbAsRep extends KrbKdcRep { ...@@ -157,10 +158,16 @@ class KrbAsRep extends KrbKdcRep {
ASReq req = asReq.getMessage(); ASReq req = asReq.getMessage();
check(true, req, rep, dkey); check(true, req, rep, dkey);
PrincipalName clientAlias = cname;
if (clientAlias.equals(rep.cname))
clientAlias = null;
creds = new Credentials( creds = new Credentials(
rep.ticket, rep.ticket,
rep.cname, rep.cname,
clientAlias,
enc_part.sname, enc_part.sname,
null, // No server alias expected in a TGT
enc_part.key, enc_part.key,
enc_part.flags, enc_part.flags,
enc_part.authtime, enc_part.authtime,
......
...@@ -68,6 +68,7 @@ public final class KrbAsReqBuilder { ...@@ -68,6 +68,7 @@ public final class KrbAsReqBuilder {
// Common data for AS-REQ fields // Common data for AS-REQ fields
private KDCOptions options; private KDCOptions options;
private PrincipalName cname; private PrincipalName cname;
private PrincipalName refCname; // May be changed by referrals
private PrincipalName sname; private PrincipalName sname;
private KerberosTime from; private KerberosTime from;
private KerberosTime till; private KerberosTime till;
...@@ -100,6 +101,7 @@ public final class KrbAsReqBuilder { ...@@ -100,6 +101,7 @@ public final class KrbAsReqBuilder {
private void init(PrincipalName cname) private void init(PrincipalName cname)
throws KrbException { throws KrbException {
this.cname = cname; this.cname = cname;
this.refCname = cname;
state = State.INIT; state = State.INIT;
} }
...@@ -284,7 +286,7 @@ public final class KrbAsReqBuilder { ...@@ -284,7 +286,7 @@ public final class KrbAsReqBuilder {
} }
return new KrbAsReq(key, return new KrbAsReq(key,
options, options,
cname, refCname,
sname, sname,
from, from,
till, till,
...@@ -334,7 +336,7 @@ public final class KrbAsReqBuilder { ...@@ -334,7 +336,7 @@ public final class KrbAsReqBuilder {
ReferralsState referralsState = new ReferralsState(); ReferralsState referralsState = new ReferralsState();
while (true) { while (true) {
if (referralsState.refreshComm()) { if (referralsState.refreshComm()) {
comm = new KdcComm(cname.getRealmAsString()); comm = new KdcComm(refCname.getRealmAsString());
} }
try { try {
req = build(pakey, referralsState); req = build(pakey, referralsState);
...@@ -384,7 +386,7 @@ public final class KrbAsReqBuilder { ...@@ -384,7 +386,7 @@ public final class KrbAsReqBuilder {
ReferralsState() throws KrbException { ReferralsState() throws KrbException {
if (Config.DISABLE_REFERRALS) { 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" + throw new KrbException("NT-ENTERPRISE principals only allowed" +
" when referrals are enabled."); " when referrals are enabled.");
} }
...@@ -402,15 +404,15 @@ public final class KrbAsReqBuilder { ...@@ -402,15 +404,15 @@ public final class KrbAsReqBuilder {
if (req.getMessage().reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) && if (req.getMessage().reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) &&
referredRealm != null && referredRealm.toString().length() > 0 && referredRealm != null && referredRealm.toString().length() > 0 &&
count < Config.MAX_REFERRALS) { count < Config.MAX_REFERRALS) {
cname = new PrincipalName(cname.getNameType(), refCname = new PrincipalName(refCname.getNameType(),
cname.getNameStrings(), referredRealm); refCname.getNameStrings(), referredRealm);
refreshComm = true; refreshComm = true;
count++; count++;
return true; return true;
} }
} }
if (count < Config.MAX_REFERRALS && 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. // Server may raise an error if CANONICALIZE is true.
// Try CANONICALIZE false. // Try CANONICALIZE false.
enabled = false; enabled = false;
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -82,7 +82,9 @@ public class KrbCred { ...@@ -82,7 +82,9 @@ public class KrbCred {
sAddrs= new HostAddresses(server); sAddrs= new HostAddresses(server);
KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService, KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService,
null, null, null, null, sAddrs, null, null, null); null, null, null, null, null,
sAddrs, // Only non-null for KRB_NT_SRV_HST, see JDK-8132111
null, null, null);
credMessg = createMessage(tgsReq.sendAndGetCreds(), key); credMessg = createMessage(tgsReq.sendAndGetCreds(), key);
obuf = credMessg.asn1Encode(); obuf = credMessg.asn1Encode();
...@@ -157,7 +159,7 @@ public class KrbCred { ...@@ -157,7 +159,7 @@ public class KrbCred {
+ " endtime=" + endtime + " endtime=" + endtime
+ "renewTill=" + renewTill); + "renewTill=" + renewTill);
} }
creds = new Credentials(ticket, pname, sname, credInfoKey, creds = new Credentials(ticket, pname, null, sname, null, credInfoKey,
flags, authtime, starttime, endtime, renewTill, caddr); flags, authtime, starttime, endtime, renewTill, caddr);
} }
......
...@@ -86,9 +86,20 @@ public class KrbTgsRep extends KrbKdcRep { ...@@ -86,9 +86,20 @@ public class KrbTgsRep extends KrbKdcRep {
check(false, req, rep, tgsReq.tgsReqKey); 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, this.creds = new Credentials(rep.ticket,
rep.cname, rep.cname,
tgsReq.getClientAlias(),
enc_part.sname, enc_part.sname,
serverAlias,
enc_part.key, enc_part.key,
enc_part.flags, enc_part.flags,
enc_part.authtime, enc_part.authtime,
...@@ -111,4 +122,16 @@ public class KrbTgsRep extends KrbKdcRep { ...@@ -111,4 +122,16 @@ public class KrbTgsRep extends KrbKdcRep {
sun.security.krb5.internal.ccache.Credentials setCredentials() { sun.security.krb5.internal.ccache.Credentials setCredentials() {
return new sun.security.krb5.internal.ccache.Credentials(rep, secondTicket); 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;
}
} }
...@@ -45,7 +45,9 @@ import java.util.Arrays; ...@@ -45,7 +45,9 @@ import java.util.Arrays;
public class KrbTgsReq { public class KrbTgsReq {
private PrincipalName princName; private PrincipalName princName;
private PrincipalName clientAlias;
private PrincipalName servName; private PrincipalName servName;
private PrincipalName serverAlias;
private TGSReq tgsReqMessg; private TGSReq tgsReqMessg;
private KerberosTime ctime; private KerberosTime ctime;
private Ticket secondTicket = null; private Ticket secondTicket = null;
...@@ -59,13 +61,16 @@ public class KrbTgsReq { ...@@ -59,13 +61,16 @@ public class KrbTgsReq {
// Used in CredentialsUtil // Used in CredentialsUtil
public KrbTgsReq(KDCOptions options, Credentials asCreds, public KrbTgsReq(KDCOptions options, Credentials asCreds,
PrincipalName cname, PrincipalName sname, PrincipalName cname, PrincipalName clientAlias,
PrincipalName sname, PrincipalName serverAlias,
Ticket[] additionalTickets, PAData[] extraPAs) Ticket[] additionalTickets, PAData[] extraPAs)
throws KrbException, IOException { throws KrbException, IOException {
this(options, this(options,
asCreds, asCreds,
cname, cname,
clientAlias,
sname, sname,
serverAlias,
null, // KerberosTime from null, // KerberosTime from
null, // KerberosTime till null, // KerberosTime till
null, // KerberosTime rtime null, // KerberosTime rtime
...@@ -82,6 +87,7 @@ public class KrbTgsReq { ...@@ -82,6 +87,7 @@ public class KrbTgsReq {
KDCOptions options, KDCOptions options,
Credentials asCreds, Credentials asCreds,
PrincipalName sname, PrincipalName sname,
PrincipalName serverAlias,
KerberosTime from, KerberosTime from,
KerberosTime till, KerberosTime till,
KerberosTime rtime, KerberosTime rtime,
...@@ -90,16 +96,18 @@ public class KrbTgsReq { ...@@ -90,16 +96,18 @@ public class KrbTgsReq {
AuthorizationData authorizationData, AuthorizationData authorizationData,
Ticket[] additionalTickets, Ticket[] additionalTickets,
EncryptionKey subKey) throws KrbException, IOException { EncryptionKey subKey) throws KrbException, IOException {
this(options, asCreds, asCreds.getClient(), sname, this(options, asCreds, asCreds.getClient(), asCreds.getClientAlias(),
from, till, rtime, eTypes, addresses, sname, serverAlias, from, till, rtime, eTypes,
authorizationData, additionalTickets, subKey, null); addresses, authorizationData, additionalTickets, subKey, null);
} }
private KrbTgsReq( private KrbTgsReq(
KDCOptions options, KDCOptions options,
Credentials asCreds, Credentials asCreds,
PrincipalName cname, PrincipalName cname,
PrincipalName clientAlias,
PrincipalName sname, PrincipalName sname,
PrincipalName serverAlias,
KerberosTime from, KerberosTime from,
KerberosTime till, KerberosTime till,
KerberosTime rtime, KerberosTime rtime,
...@@ -111,7 +119,9 @@ public class KrbTgsReq { ...@@ -111,7 +119,9 @@ public class KrbTgsReq {
PAData[] extraPAs) throws KrbException, IOException { PAData[] extraPAs) throws KrbException, IOException {
princName = cname; princName = cname;
this.clientAlias = clientAlias;
servName = sname; servName = sname;
this.serverAlias = serverAlias;
ctime = KerberosTime.now(); ctime = KerberosTime.now();
// check if they are valid arguments. The optional fields // check if they are valid arguments. The optional fields
...@@ -363,6 +373,14 @@ public class KrbTgsReq { ...@@ -363,6 +373,14 @@ public class KrbTgsReq {
return secondTicket; return secondTicket;
} }
PrincipalName getClientAlias() {
return clientAlias;
}
PrincipalName getServerAlias() {
return serverAlias;
}
private static void debug(String message) { private static void debug(String message) {
// System.err.println(">>> KrbTgsReq: " + message); // System.err.println(">>> KrbTgsReq: " + message);
} }
......
...@@ -553,7 +553,9 @@ public class PrincipalName implements Cloneable { ...@@ -553,7 +553,9 @@ public class PrincipalName implements Cloneable {
for (int i = 0; i < nameStrings.length; i++) { for (int i = 0; i < nameStrings.length; i++) {
if (i > 0) if (i > 0)
str.append("/"); str.append("/");
str.append(nameStrings[i]); String n = nameStrings[i];
n = n.replace("@", "\\@");
str.append(n);
} }
str.append("@"); str.append("@");
str.append(nameRealm.toString()); str.append(nameRealm.toString());
......
...@@ -284,8 +284,9 @@ public class CredentialsUtil { ...@@ -284,8 +284,9 @@ public class CredentialsUtil {
// Try CANONICALIZE false. // Try CANONICALIZE false.
} }
} }
return serviceCredsSingle(options, asCreds, return serviceCredsSingle(options, asCreds, cname,
cname, sname, additionalTickets, extraPAs); asCreds.getClientAlias(), sname, sname, additionalTickets,
extraPAs);
} }
/* /*
...@@ -300,26 +301,29 @@ public class CredentialsUtil { ...@@ -300,26 +301,29 @@ public class CredentialsUtil {
options = new KDCOptions(options.toBooleanArray()); options = new KDCOptions(options.toBooleanArray());
options.set(KDCOptions.CANONICALIZE, true); options.set(KDCOptions.CANONICALIZE, true);
PrincipalName cSname = sname; PrincipalName cSname = sname;
PrincipalName refSname = sname; // May change with referrals
Credentials creds = null; Credentials creds = null;
boolean isReferral = false; boolean isReferral = false;
List<String> referrals = new LinkedList<>(); List<String> referrals = new LinkedList<>();
PrincipalName clientAlias = asCreds.getClientAlias();
while (referrals.size() <= Config.MAX_REFERRALS) { while (referrals.size() <= Config.MAX_REFERRALS) {
ReferralsCache.ReferralCacheEntry ref = ReferralsCache.ReferralCacheEntry ref =
ReferralsCache.get(sname, cSname.getRealmString()); ReferralsCache.get(cname, sname, refSname.getRealmString());
String toRealm = null; String toRealm = null;
if (ref == null) { if (ref == null) {
creds = serviceCredsSingle(options, asCreds, creds = serviceCredsSingle(options, asCreds, cname,
cname, cSname, additionalTickets, extraPAs); clientAlias, refSname, cSname, additionalTickets,
extraPAs);
PrincipalName server = creds.getServer(); PrincipalName server = creds.getServer();
if (!cSname.equals(server)) { if (!refSname.equals(server)) {
String[] serverNameStrings = server.getNameStrings(); String[] serverNameStrings = server.getNameStrings();
if (serverNameStrings.length == 2 && if (serverNameStrings.length == 2 &&
serverNameStrings[0].equals( serverNameStrings[0].equals(
PrincipalName.TGS_DEFAULT_SRV_NAME) && PrincipalName.TGS_DEFAULT_SRV_NAME) &&
!cSname.getRealmAsString().equals(serverNameStrings[1])) { !refSname.getRealmAsString().equals(serverNameStrings[1])) {
// Server Name (sname) has the following format: // Server Name (sname) has the following format:
// krbtgt/TO-REALM.COM@FROM-REALM.COM // krbtgt/TO-REALM.COM@FROM-REALM.COM
ReferralsCache.put(sname, server.getRealmString(), ReferralsCache.put(cname, sname, server.getRealmString(),
serverNameStrings[1], creds); serverNameStrings[1], creds);
toRealm = serverNameStrings[1]; toRealm = serverNameStrings[1];
isReferral = true; isReferral = true;
...@@ -336,8 +340,8 @@ public class CredentialsUtil { ...@@ -336,8 +340,8 @@ public class CredentialsUtil {
// Referrals loop detected // Referrals loop detected
return null; return null;
} }
cSname = new PrincipalName(cSname.getNameString(), refSname = new PrincipalName(refSname.getNameString(),
cSname.getNameType(), toRealm); refSname.getNameType(), toRealm);
referrals.add(toRealm); referrals.add(toRealm);
isReferral = false; isReferral = false;
continue; continue;
...@@ -356,14 +360,15 @@ public class CredentialsUtil { ...@@ -356,14 +360,15 @@ public class CredentialsUtil {
*/ */
private static Credentials serviceCredsSingle( private static Credentials serviceCredsSingle(
KDCOptions options, Credentials asCreds, KDCOptions options, Credentials asCreds,
PrincipalName cname, PrincipalName sname, PrincipalName cname, PrincipalName clientAlias,
PrincipalName refSname, PrincipalName sname,
Ticket[] additionalTickets, PAData[] extraPAs) Ticket[] additionalTickets, PAData[] extraPAs)
throws KrbException, IOException { throws KrbException, IOException {
Credentials theCreds = null; Credentials theCreds = null;
boolean[] okAsDelegate = new boolean[]{true}; boolean[] okAsDelegate = new boolean[]{true};
String[] serverAsCredsNames = asCreds.getServer().getNameStrings(); String[] serverAsCredsNames = asCreds.getServer().getNameStrings();
String tgtRealm = serverAsCredsNames[1]; String tgtRealm = serverAsCredsNames[1];
String serviceRealm = sname.getRealmString(); String serviceRealm = refSname.getRealmString();
if (!serviceRealm.equals(tgtRealm)) { if (!serviceRealm.equals(tgtRealm)) {
// This is a cross-realm service request // This is a cross-realm service request
if (DEBUG) { if (DEBUG) {
...@@ -390,8 +395,8 @@ public class CredentialsUtil { ...@@ -390,8 +395,8 @@ public class CredentialsUtil {
System.out.println(">>> Credentials serviceCredsSingle:" + System.out.println(">>> Credentials serviceCredsSingle:" +
" same realm"); " same realm");
} }
KrbTgsReq req = new KrbTgsReq(options, asCreds, KrbTgsReq req = new KrbTgsReq(options, asCreds, cname, clientAlias,
cname, sname, additionalTickets, extraPAs); refSname, sname, additionalTickets, extraPAs);
theCreds = req.sendAndGetCreds(); theCreds = req.sendAndGetCreds();
if (theCreds != null) { if (theCreds != null) {
if (DEBUG) { if (DEBUG) {
......
...@@ -139,7 +139,7 @@ public class KRBError implements java.io.Serializable { ...@@ -139,7 +139,7 @@ public class KRBError implements java.io.Serializable {
sTime = new_sTime; sTime = new_sTime;
suSec = new_suSec; suSec = new_suSec;
errorCode = new_errorCode; errorCode = new_errorCode;
crealm = new_cname.getRealm(); crealm = new_cname != null ? new_cname.getRealm() : null;
cname = new_cname; cname = new_cname;
sname = new_sname; sname = new_sname;
eText = new_eText; eText = new_eText;
...@@ -168,7 +168,7 @@ public class KRBError implements java.io.Serializable { ...@@ -168,7 +168,7 @@ public class KRBError implements java.io.Serializable {
sTime = new_sTime; sTime = new_sTime;
suSec = new_suSec; suSec = new_suSec;
errorCode = new_errorCode; errorCode = new_errorCode;
crealm = new_cname.getRealm(); crealm = new_cname != null ? new_cname.getRealm() : null;
cname = new_cname; cname = new_cname;
sname = new_sname; sname = new_sname;
eText = new_eText; eText = new_eText;
......
...@@ -45,8 +45,27 @@ import sun.security.krb5.PrincipalName; ...@@ -45,8 +45,27 @@ import sun.security.krb5.PrincipalName;
*/ */
final class ReferralsCache { final class ReferralsCache {
private static Map<PrincipalName, Map<String, ReferralCacheEntry>> referralsMap = private static Map<ReferralCacheKey, Map<String, ReferralCacheEntry>>
new HashMap<>(); 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 { static final class ReferralCacheEntry {
private final Credentials creds; private final Credentials creds;
...@@ -64,8 +83,9 @@ final class ReferralsCache { ...@@ -64,8 +83,9 @@ final class ReferralsCache {
} }
/* /*
* Add a new referral entry to the cache, including: service principal, * Add a new referral entry to the cache, including: client principal,
* source KDC realm, destination KDC realm and referral TGT. * 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 * If a loop is generated when adding the new referral, the first hop is
* automatically removed. For example, let's assume that adding a * automatically removed. For example, let's assume that adding a
...@@ -73,16 +93,17 @@ final class ReferralsCache { ...@@ -73,16 +93,17 @@ final class ReferralsCache {
* REALM-1.COM -> REALM-2.COM -> REALM-3.COM -> REALM-1.COM. Then, * 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. * 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) { String fromRealm, String toRealm, Credentials creds) {
pruneExpired(service); ReferralCacheKey k = new ReferralCacheKey(cname, service);
pruneExpired(k);
if (creds.getEndTime().before(new Date())) { if (creds.getEndTime().before(new Date())) {
return; return;
} }
Map<String, ReferralCacheEntry> entries = referralsMap.get(service); Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
if (entries == null) { if (entries == null) {
entries = new HashMap<String, ReferralCacheEntry>(); entries = new HashMap<String, ReferralCacheEntry>();
referralsMap.put(service, entries); referralsMap.put(k, entries);
} }
entries.remove(fromRealm); entries.remove(fromRealm);
ReferralCacheEntry newEntry = new ReferralCacheEntry(creds, toRealm); ReferralCacheEntry newEntry = new ReferralCacheEntry(creds, toRealm);
...@@ -103,13 +124,14 @@ final class ReferralsCache { ...@@ -103,13 +124,14 @@ final class ReferralsCache {
} }
/* /*
* Obtain a referral entry from the cache given a service principal and a * Obtain a referral entry from the cache given a client principal,
* source KDC realm. * service principal and a source KDC realm.
*/ */
static synchronized ReferralCacheEntry get(PrincipalName service, static synchronized ReferralCacheEntry get(PrincipalName cname,
String fromRealm) { PrincipalName service, String fromRealm) {
pruneExpired(service); ReferralCacheKey k = new ReferralCacheKey(cname, service);
Map<String, ReferralCacheEntry> entries = referralsMap.get(service); pruneExpired(k);
Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
if (entries != null) { if (entries != null) {
ReferralCacheEntry toRef = entries.get(fromRealm); ReferralCacheEntry toRef = entries.get(fromRealm);
if (toRef != null) { if (toRef != null) {
...@@ -122,9 +144,9 @@ final class ReferralsCache { ...@@ -122,9 +144,9 @@ final class ReferralsCache {
/* /*
* Remove referral entries from the cache when referral TGTs expire. * 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(); Date now = new Date();
Map<String, ReferralCacheEntry> entries = referralsMap.get(service); Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
if (entries != null) { if (entries != null) {
for (Entry<String, ReferralCacheEntry> mapEntry : for (Entry<String, ReferralCacheEntry> mapEntry :
entries.entrySet()) { entries.entrySet()) {
......
...@@ -192,8 +192,9 @@ public class Credentials { ...@@ -192,8 +192,9 @@ public class Credentials {
// is most likely to be the one in Authenticator in PA-TGS-REQ encoded // 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 TGS-REQ, therefore only stored with a service ticket. Currently
// in Java, we only reads TGTs. // in Java, we only reads TGTs.
return new sun.security.krb5.Credentials(ticket, return new sun.security.krb5.Credentials(ticket, cname, null, sname,
cname, sname, key, flags, authtime, starttime, endtime, renewTill, caddr); null, key, flags, authtime, starttime, endtime, renewTill,
caddr);
} }
public KerberosTime getStartTime() { public KerberosTime getStartTime() {
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -418,7 +418,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ ...@@ -418,7 +418,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
if (krbcredsConstructor == 0) { if (krbcredsConstructor == 0) {
krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>", 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) { if (krbcredsConstructor == 0) {
printf("Couldn't find sun.security.krb5.internal.Ticket constructor\n"); printf("Couldn't find sun.security.krb5.internal.Ticket constructor\n");
break; break;
...@@ -432,7 +432,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ ...@@ -432,7 +432,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
krbcredsConstructor, krbcredsConstructor,
ticket, ticket,
clientPrincipal, clientPrincipal,
NULL,
targetPrincipal, targetPrincipal,
NULL,
encryptionKey, encryptionKey,
ticketFlags, ticketFlags,
authTime, authTime,
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -404,6 +404,8 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ ...@@ -404,6 +404,8 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
"(Lsun/security/krb5/internal/Ticket;" "(Lsun/security/krb5/internal/Ticket;"
"Lsun/security/krb5/PrincipalName;" "Lsun/security/krb5/PrincipalName;"
"Lsun/security/krb5/PrincipalName;" "Lsun/security/krb5/PrincipalName;"
"Lsun/security/krb5/PrincipalName;"
"Lsun/security/krb5/PrincipalName;"
"Lsun/security/krb5/EncryptionKey;" "Lsun/security/krb5/EncryptionKey;"
"Lsun/security/krb5/internal/TicketFlags;" "Lsun/security/krb5/internal/TicketFlags;"
"Lsun/security/krb5/internal/KerberosTime;" "Lsun/security/krb5/internal/KerberosTime;"
...@@ -665,7 +667,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ ...@@ -665,7 +667,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
krbcredsConstructor, krbcredsConstructor,
ticket, ticket,
clientPrincipal, clientPrincipal,
NULL,
targetPrincipal, targetPrincipal,
NULL,
encryptionKey, encryptionKey,
ticketFlags, ticketFlags,
authTime, // mdu authTime, // mdu
......
...@@ -804,8 +804,10 @@ public class KDC { ...@@ -804,8 +804,10 @@ public class KDC {
PrincipalName cname = null; PrincipalName cname = null;
boolean allowForwardable = true; boolean allowForwardable = true;
boolean isReferral = false;
if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
System.out.println(realm + "> verifying referral for " +
body.sname.getNameString());
KDC referral = aliasReferrals.get(body.sname.getNameString()); KDC referral = aliasReferrals.get(body.sname.getNameString());
if (referral != null) { if (referral != null) {
service = new PrincipalName( service = new PrincipalName(
...@@ -813,6 +815,9 @@ public class KDC { ...@@ -813,6 +815,9 @@ public class KDC {
PrincipalName.NAME_COMPONENT_SEPARATOR_STR + PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
referral.getRealm(), PrincipalName.KRB_NT_SRV_INST, referral.getRealm(), PrincipalName.KRB_NT_SRV_INST,
this.getRealm()); this.getRealm());
System.out.println(realm + "> referral to " +
referral.getRealm());
isReferral = true;
} }
} }
...@@ -912,7 +917,8 @@ public class KDC { ...@@ -912,7 +917,8 @@ public class KDC {
if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) { if (body.kdcOptions.get(KDCOptions.ALLOW_POSTDATE)) {
bFlags[Krb5.TKT_OPTS_MAY_POSTDATE] = true; 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)) { if (!options.containsKey(Option.ALLOW_S4U2PROXY)) {
// Don't understand CNAME_IN_ADDL_TKT // Don't understand CNAME_IN_ADDL_TKT
throw new KrbException(Krb5.KDC_ERR_BADOPTION); throw new KrbException(Krb5.KDC_ERR_BADOPTION);
...@@ -1073,8 +1079,7 @@ public class KDC { ...@@ -1073,8 +1079,7 @@ public class KDC {
} }
int eType = eTypes[0]; int eType = eTypes[0];
if (body.kdcOptions.get(KDCOptions.CANONICALIZE) && if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
PrincipalName principal = alias2Principals.get( PrincipalName principal = alias2Principals.get(
body.cname.getNameString()); body.cname.getNameString());
if (principal != null) { if (principal != null) {
......
...@@ -29,9 +29,18 @@ ...@@ -29,9 +29,18 @@
*/ */
import java.io.File; import java.io.File;
import sun.security.krb5.Credentials; import java.security.Principal;
import sun.security.krb5.internal.CredentialsUtil; import java.util.Arrays;
import sun.security.krb5.KrbAsReqBuilder; 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; import sun.security.krb5.PrincipalName;
public class ReferralsTest { public class ReferralsTest {
...@@ -40,39 +49,32 @@ public class ReferralsTest { ...@@ -40,39 +49,32 @@ public class ReferralsTest {
private static final String realmKDC1 = "RABBIT.HOLE"; private static final String realmKDC1 = "RABBIT.HOLE";
private static final String realmKDC2 = "DEV.RABBIT.HOLE"; private static final String realmKDC2 = "DEV.RABBIT.HOLE";
private static final char[] password = "123qwe@Z".toCharArray(); private static final char[] password = "123qwe@Z".toCharArray();
// Names
private static final String clientName = "test"; private static final String clientName = "test";
private static final String serviceName = "http" +
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
"server.dev.rabbit.hole";
// Alias
private static final String clientAlias = clientName + private static final String clientAlias = clientName +
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
private static final String clientKDC1QueryName = clientAlias.replaceAll( // Names + realms
private static final String clientKDC1Name = clientAlias.replaceAll(
PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" + PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
PrincipalName.NAME_REALM_SEPARATOR_STR) + PrincipalName.NAME_REALM_SEPARATOR_STR) +
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; 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 + private static final String clientKDC2Name = clientName +
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2; PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
private static final String serviceKDC2Name = serviceName +
private static final String serviceName = "http" + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
"server.dev.rabbit.hole";
private static Credentials tgt;
private static Credentials tgs;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
try { try {
initializeKDCs(); initializeKDCs();
getTGT(); testSubjectCredentials();
getTGS(); testDelegated();
} finally { } finally {
cleanup(); cleanup();
} }
...@@ -107,6 +109,11 @@ public class ReferralsTest { ...@@ -107,6 +109,11 @@ public class ReferralsTest {
kdc1.registerAlias(serviceName, kdc2); kdc1.registerAlias(serviceName, kdc2);
kdc2.registerAlias(clientAlias, clientKDC2Name); 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, KDC.saveConfig(krbConfigName, kdc1, kdc2,
"forwardable=true"); "forwardable=true");
System.setProperty("java.security.krb5.conf", krbConfigName); System.setProperty("java.security.krb5.conf", krbConfigName);
...@@ -119,50 +126,123 @@ public class ReferralsTest { ...@@ -119,50 +126,123 @@ public class ReferralsTest {
} }
} }
private static void getTGT() throws Exception { /*
KrbAsReqBuilder builder = new KrbAsReqBuilder(clientKDC1QueryPrincipal, * The client subject (whose principal is
password); * test@RABBIT.HOLE@RABBIT.HOLE) will obtain a TGT after
tgt = builder.action().getCreds(); * realm referral and name canonicalization (TGT cname
builder.destroy(); * 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) { if (DEBUG) {
System.out.println("TGT"); System.out.println("Client subject principal: " +
System.out.println("----------------------"); clientPrincipal.getName());
System.out.println(tgt); }
System.out.println("----------------------"); if (!clientPrincipal.getName().equals(clientKDC1Name)) {
throw new Exception("Unexpected client subject principal.");
}
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 (tgt == null) {
throw new Exception("TGT is null");
} }
if (!tgt.getClient().getName().equals(clientKDC2Name)) { if (DEBUG) {
throw new Exception("Unexpected TGT client"); 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();
private static void getTGS() throws Exception { clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
tgs = CredentialsUtil.acquireServiceCreds(serviceName + clientContext.take(new byte[0]);
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, tgt); clientContext.status();
int newNumOfTickets =
clientSubject.getPrivateCredentials(KerberosTicket.class).size();
if (DEBUG) { if (DEBUG) {
System.out.println("TGS"); System.out.println("client subject number of tickets: " +
System.out.println("----------------------"); numOfTickets);
System.out.println(tgs); System.out.println("client subject new number of tickets: " +
System.out.println("----------------------"); newNumOfTickets);
}
if (numOfTickets != newNumOfTickets) {
throw new Exception("Useless client subject TGS request because" +
" TGS was not found in private credentials.");
} }
if (tgs == null) {
throw new Exception("TGS is null");
} }
if (!tgs.getClient().getName().equals(clientKDC2Name)) {
throw new Exception("Unexpected TGS client"); /*
* 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");
}
// 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.getServer().getNameString().equals(serviceName) || if (!contextInitiatorName.toString().equals(clientKDC2Name) ||
!tgs.getServer().getRealmString().equals(realmKDC2)) { !contextAcceptorName.toString().equals(serviceName)) {
throw new Exception("Unexpected TGS server"); throw new Exception("Unexpected initiator or acceptor names");
} }
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册