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

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

Reviewed-by: mbalao
上级 03313f0a
......@@ -33,6 +33,22 @@ class JavaxSecurityAuthKerberosAccessImpl
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;
}
public KerberosTicket kerberosTicketGetProxy(KerberosTicket t) {
return t.proxy;
}
......
......@@ -194,6 +194,10 @@ public class KerberosTicket implements Destroyable, Refreshable,
private InetAddress[] clientAddresses;
transient KerberosPrincipal clientAlias = null;
transient KerberosPrincipal serverAlias = null;
/**
* Evidence ticket if proxy_impersonator. This field can be accessed
* by KerberosSecrets. It's serialized.
......@@ -563,7 +567,11 @@ public class KerberosTicket implements Destroyable, Refreshable,
try {
krb5Creds = new sun.security.krb5.Credentials(asn1Encoding,
client.toString(),
(clientAlias != null ?
clientAlias.getName() : null),
server.toString(),
(serverAlias != null ?
serverAlias.getName() : null),
sessionKey.getEncoded(),
sessionKey.getKeyType(),
flags,
......
......@@ -713,14 +713,14 @@ class Krb5Context implements GSSContextSpi {
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() {
......
......@@ -60,7 +60,9 @@ public class Krb5InitCredential
private Krb5InitCredential(Krb5NameElement name,
byte[] asn1Encoding,
KerberosPrincipal client,
KerberosPrincipal clientAlias,
KerberosPrincipal server,
KerberosPrincipal serverAlias,
byte[] sessionKey,
int keyType,
boolean[] flags,
......@@ -81,14 +83,21 @@ public class Krb5InitCredential
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,
......@@ -111,7 +120,9 @@ public class Krb5InitCredential
Credentials delegatedCred,
byte[] asn1Encoding,
KerberosPrincipal client,
KerberosPrincipal clientAlias,
KerberosPrincipal server,
KerberosPrincipal serverAlias,
byte[] sessionKey,
int keyType,
boolean[] flags,
......@@ -132,7 +143,10 @@ public class Krb5InitCredential
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.
......@@ -154,10 +168,18 @@ public class Krb5InitCredential
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
}
KerberosPrincipal clientAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetClientAlias(tgt);
KerberosPrincipal serverAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetServerAlias(tgt);
Krb5InitCredential result = new Krb5InitCredential(name,
tgt.getEncoded(),
tgt.getClient(),
clientAlias,
tgt.getServer(),
serverAlias,
tgt.getSessionKey().getEncoded(),
tgt.getSessionKeyType(),
tgt.getFlags(),
......@@ -183,10 +205,14 @@ public class Krb5InitCredential
*/
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;
......@@ -197,6 +223,10 @@ public class Krb5InitCredential
client = new KerberosPrincipal(fullName);
}
if (cAPrinc != null) {
clientAlias = new KerberosPrincipal(cAPrinc.getName());
}
// XXX Compare name to credName
if (sPrinc != null) {
......@@ -205,11 +235,17 @@ public class Krb5InitCredential
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(),
......
......@@ -228,7 +228,7 @@ public class Krb5Util {
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(),
......@@ -241,14 +241,35 @@ public class Krb5Util {
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(),
......
/*
* 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 @@ class SubjectComber {
}
} 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));
}
......
......@@ -48,7 +48,9 @@ public class Credentials {
Ticket ticket;
PrincipalName client;
PrincipalName clientAlias;
PrincipalName server;
PrincipalName serverAlias;
EncryptionKey key;
TicketFlags flags;
KerberosTime authTime;
......@@ -78,7 +80,9 @@ public class Credentials {
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,
......@@ -87,14 +91,17 @@ public class Credentials {
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,
......@@ -104,7 +111,9 @@ public class Credentials {
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;
......@@ -116,7 +125,9 @@ public class Credentials {
public Credentials(byte[] encoding,
String client,
String clientAlias,
String server,
String serverAlias,
byte[] keyBytes,
int keyType,
boolean[] flags,
......@@ -127,7 +138,11 @@ public class Credentials {
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)),
......@@ -152,10 +167,18 @@ public class Credentials {
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;
}
......@@ -271,6 +294,7 @@ public class Credentials {
return new KrbTgsReq(options,
this,
server,
serverAlias,
null, // from
null, // till
null, // rtime
......@@ -488,7 +512,11 @@ public class Credentials {
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());
......@@ -516,7 +544,11 @@ public class Credentials {
public String toString() {
StringBuffer buffer = new StringBuffer("Credentials:");
buffer.append( "\n client=").append(client);
if (clientAlias != null)
buffer.append( "\n clientAlias=").append(clientAlias);
buffer.append( "\n server=").append(server);
if (serverAlias != null)
buffer.append( "\n serverAlias=").append(serverAlias);
if (authTime != null) {
buffer.append("\n authTime=").append(authTime);
}
......
......@@ -25,6 +25,7 @@
package sun.security.krb5;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KeyTab;
......@@ -39,6 +40,14 @@ public interface JavaxSecurityAuthKerberosAccess {
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);
/**
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -361,7 +361,9 @@ public class KrbApReq {
creds = new Credentials(
apReqMessg.ticket,
authenticator.cname,
null,
apReqMessg.ticket.sname,
null,
enc_ticketPart.key,
enc_ticketPart.flags,
enc_ticketPart.authtime,
......
......@@ -118,7 +118,7 @@ class KrbAsRep extends KrbKdcRep {
"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 @@ class KrbAsRep extends KrbKdcRep {
password,
encPartKeyType,
PAData.getSaltAndParams(encPartKeyType, rep.pAData));
decrypt(dkey, asReq);
decrypt(dkey, asReq, cname);
}
/**
......@@ -144,7 +144,8 @@ class KrbAsRep extends KrbKdcRep {
* @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 @@ class KrbAsRep extends KrbKdcRep {
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,
......
......@@ -68,6 +68,7 @@ public final class KrbAsReqBuilder {
// 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 @@ public final class KrbAsReqBuilder {
private void init(PrincipalName cname)
throws KrbException {
this.cname = cname;
this.refCname = cname;
state = State.INIT;
}
......@@ -284,7 +286,7 @@ public final class KrbAsReqBuilder {
}
return new KrbAsReq(key,
options,
cname,
refCname,
sname,
from,
till,
......@@ -334,7 +336,7 @@ public final class KrbAsReqBuilder {
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 @@ public final class KrbAsReqBuilder {
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 @@ public final class KrbAsReqBuilder {
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;
......
/*
* 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
......@@ -82,7 +82,9 @@ public class KrbCred {
sAddrs= new HostAddresses(server);
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);
obuf = credMessg.asn1Encode();
......@@ -157,7 +159,7 @@ public class KrbCred {
+ " 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);
}
......
......@@ -86,9 +86,20 @@ public class KrbTgsRep extends KrbKdcRep {
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 @@ public class KrbTgsRep extends KrbKdcRep {
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;
}
}
......@@ -45,7 +45,9 @@ import java.util.Arrays;
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 @@ public class KrbTgsReq {
// 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 @@ public class KrbTgsReq {
KDCOptions options,
Credentials asCreds,
PrincipalName sname,
PrincipalName serverAlias,
KerberosTime from,
KerberosTime till,
KerberosTime rtime,
......@@ -90,16 +96,18 @@ public class KrbTgsReq {
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 @@ public class KrbTgsReq {
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
......@@ -363,6 +373,14 @@ public class KrbTgsReq {
return secondTicket;
}
PrincipalName getClientAlias() {
return clientAlias;
}
PrincipalName getServerAlias() {
return serverAlias;
}
private static void debug(String message) {
// System.err.println(">>> KrbTgsReq: " + message);
}
......
......@@ -553,7 +553,9 @@ public class PrincipalName implements Cloneable {
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());
......
......@@ -284,8 +284,9 @@ public class CredentialsUtil {
// 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 @@ public class CredentialsUtil {
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 @@ public class CredentialsUtil {
// 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 @@ public class CredentialsUtil {
*/
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 @@ public class CredentialsUtil {
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) {
......
......@@ -139,7 +139,7 @@ public class KRBError implements java.io.Serializable {
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 @@ public class KRBError implements java.io.Serializable {
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;
......
......@@ -45,8 +45,27 @@ import sun.security.krb5.PrincipalName;
*/
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 @@ final class ReferralsCache {
}
/*
* 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 @@ final class ReferralsCache {
* 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 @@ final class ReferralsCache {
}
/*
* 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 @@ final class ReferralsCache {
/*
* 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()) {
......
......@@ -192,8 +192,9 @@ public class Credentials {
// 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() {
......
/*
* 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
......@@ -418,7 +418,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
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;
......@@ -432,7 +432,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
krbcredsConstructor,
ticket,
clientPrincipal,
NULL,
targetPrincipal,
NULL,
encryptionKey,
ticketFlags,
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.
*
* 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
"(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;"
......@@ -665,7 +667,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
krbcredsConstructor,
ticket,
clientPrincipal,
NULL,
targetPrincipal,
NULL,
encryptionKey,
ticketFlags,
authTime, // mdu
......
......@@ -804,8 +804,10 @@ public class KDC {
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(
......@@ -813,6 +815,9 @@ public class KDC {
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
referral.getRealm(), PrincipalName.KRB_NT_SRV_INST,
this.getRealm());
System.out.println(realm + "> referral to " +
referral.getRealm());
isReferral = true;
}
}
......@@ -912,7 +917,8 @@ public class KDC {
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);
......@@ -1073,8 +1079,7 @@ public class KDC {
}
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) {
......
......@@ -29,9 +29,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 {
......@@ -40,39 +49,32 @@ public class ReferralsTest {
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 serviceName = "http" +
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
"server.dev.rabbit.hole";
// Alias
private static final String clientAlias = clientName +
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 + 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;
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();
}
......@@ -107,6 +109,11 @@ public class ReferralsTest {
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);
......@@ -119,50 +126,123 @@ public class ReferralsTest {
}
}
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 (tgt == null) {
throw new Exception("TGT is null");
if (!clientPrincipal.getName().equals(clientKDC1Name)) {
throw new Exception("Unexpected client subject principal.");
}
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.");
}
}
private static void getTGS() throws Exception {
tgs = CredentialsUtil.acquireServiceCreds(serviceName +
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, tgt);
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("TGS");
System.out.println("----------------------");
System.out.println(tgs);
System.out.println("----------------------");
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.");
}
if (tgs == null) {
throw new Exception("TGS is null");
}
/*
* 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.getClient().getName().equals(clientKDC2Name)) {
throw new Exception("Unexpected TGS client");
// 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) ||
!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");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册