mirror of
https://github.com/darlinghq/darling-openjdk.git
synced 2024-12-11 14:24:03 +00:00
8227437: S4U2proxy cannot continue because server's TGT cannot be found
Reviewed-by: weijun
This commit is contained in:
parent
5fd772a6f1
commit
3cd50f2666
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -345,7 +345,7 @@ 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;
|
||||
@ -359,7 +359,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
|
||||
krbcredsConstructor,
|
||||
ticket,
|
||||
clientPrincipal,
|
||||
NULL,
|
||||
targetPrincipal,
|
||||
NULL,
|
||||
encryptionKey,
|
||||
ticketFlags,
|
||||
authTime,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,8 +26,6 @@
|
||||
package javax.security.auth.kerberos;
|
||||
|
||||
import sun.security.krb5.JavaxSecurityAuthKerberosAccess;
|
||||
import sun.security.krb5.EncryptionKey;
|
||||
import sun.security.krb5.PrincipalName;
|
||||
|
||||
class JavaxSecurityAuthKerberosAccessImpl
|
||||
implements JavaxSecurityAuthKerberosAccess {
|
||||
@ -35,4 +33,20 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -195,6 +195,10 @@ public class KerberosTicket implements Destroyable, Refreshable,
|
||||
|
||||
private transient boolean destroyed = false;
|
||||
|
||||
transient KerberosPrincipal clientAlias = null;
|
||||
|
||||
transient KerberosPrincipal serverAlias = null;
|
||||
|
||||
/**
|
||||
* Constructs a {@code KerberosTicket} using credentials information that a
|
||||
* client either receives from a KDC or reads from a cache.
|
||||
@ -591,7 +595,11 @@ public class KerberosTicket implements Destroyable, Refreshable,
|
||||
try {
|
||||
krb5Creds = new sun.security.krb5.Credentials(asn1Encoding,
|
||||
client.getName(),
|
||||
(clientAlias != null ?
|
||||
clientAlias.getName() : null),
|
||||
server.getName(),
|
||||
(serverAlias != null ?
|
||||
serverAlias.getName() : null),
|
||||
sessionKey.getEncoded(),
|
||||
sessionKey.getKeyType(),
|
||||
flags,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -713,14 +713,14 @@ 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() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -59,7 +59,9 @@ public class Krb5InitCredential
|
||||
private Krb5InitCredential(Krb5NameElement name,
|
||||
byte[] asn1Encoding,
|
||||
KerberosPrincipal client,
|
||||
KerberosPrincipal clientAlias,
|
||||
KerberosPrincipal server,
|
||||
KerberosPrincipal serverAlias,
|
||||
byte[] sessionKey,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
@ -80,14 +82,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,
|
||||
@ -110,7 +119,9 @@ public class Krb5InitCredential
|
||||
Credentials delegatedCred,
|
||||
byte[] asn1Encoding,
|
||||
KerberosPrincipal client,
|
||||
KerberosPrincipal clientAlias,
|
||||
KerberosPrincipal server,
|
||||
KerberosPrincipal serverAlias,
|
||||
byte[] sessionKey,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
@ -131,7 +142,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.
|
||||
@ -153,10 +167,18 @@ public class Krb5InitCredential
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
}
|
||||
|
||||
KerberosPrincipal clientAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetClientAlias(tgt);
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(tgt);
|
||||
return new Krb5InitCredential(name,
|
||||
tgt.getEncoded(),
|
||||
tgt.getClient(),
|
||||
clientAlias,
|
||||
tgt.getServer(),
|
||||
serverAlias,
|
||||
tgt.getSessionKey().getEncoded(),
|
||||
tgt.getSessionKeyType(),
|
||||
tgt.getFlags(),
|
||||
@ -179,10 +201,14 @@ 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;
|
||||
|
||||
@ -193,6 +219,10 @@ public class Krb5InitCredential
|
||||
client = new KerberosPrincipal(fullName);
|
||||
}
|
||||
|
||||
if (cAPrinc != null) {
|
||||
clientAlias = new KerberosPrincipal(cAPrinc.getName());
|
||||
}
|
||||
|
||||
// XXX Compare name to credName
|
||||
|
||||
if (sPrinc != null) {
|
||||
@ -201,11 +231,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(),
|
||||
|
@ -132,7 +132,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(),
|
||||
@ -145,14 +145,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(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package sun.security.jgss.krb5;
|
||||
|
||||
import sun.security.krb5.KerberosSecrets;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import javax.security.auth.Subject;
|
||||
@ -182,24 +184,45 @@ 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));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -49,7 +49,9 @@ public class Credentials {
|
||||
|
||||
Ticket ticket;
|
||||
PrincipalName client;
|
||||
PrincipalName clientAlias;
|
||||
PrincipalName server;
|
||||
PrincipalName serverAlias;
|
||||
EncryptionKey key;
|
||||
TicketFlags flags;
|
||||
KerberosTime authTime;
|
||||
@ -69,7 +71,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,
|
||||
@ -78,14 +82,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,
|
||||
@ -95,7 +102,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;
|
||||
@ -107,7 +116,9 @@ public class Credentials {
|
||||
|
||||
public Credentials(byte[] encoding,
|
||||
String client,
|
||||
String clientAlias,
|
||||
String server,
|
||||
String serverAlias,
|
||||
byte[] keyBytes,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
@ -118,7 +129,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)),
|
||||
@ -143,10 +158,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;
|
||||
}
|
||||
@ -262,6 +285,7 @@ public class Credentials {
|
||||
return new KrbTgsReq(options,
|
||||
this,
|
||||
server,
|
||||
serverAlias,
|
||||
null, // from
|
||||
null, // till
|
||||
null, // rtime
|
||||
@ -484,7 +508,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());
|
||||
@ -512,7 +540,11 @@ public class Credentials {
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("Credentials:");
|
||||
sb.append( "\n client=").append(client);
|
||||
if (clientAlias != null)
|
||||
sb.append( "\n clientAlias=").append(clientAlias);
|
||||
sb.append( "\n server=").append(server);
|
||||
if (serverAlias != null)
|
||||
sb.append( "\n serverAlias=").append(serverAlias);
|
||||
if (authTime != null) {
|
||||
sb.append("\n authTime=").append(authTime);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package sun.security.krb5;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
import sun.security.krb5.EncryptionKey;
|
||||
import sun.security.krb5.PrincipalName;
|
||||
@ -39,4 +41,12 @@ public 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);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -363,7 +363,9 @@ 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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -76,7 +76,7 @@ public class KrbCred {
|
||||
options.set(KDCOptions.FORWARDABLE, true);
|
||||
|
||||
KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService,
|
||||
null, null, null, null,
|
||||
null, null, null, null, null,
|
||||
null, // No easy way to get addresses right
|
||||
null, null, null);
|
||||
credMessg = createMessage(tgsReq.sendAndGetCreds(), key);
|
||||
@ -152,7 +152,7 @@ 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
|
||||
@ -365,6 +375,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);
|
||||
}
|
||||
|
@ -564,7 +564,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()) {
|
||||
|
@ -180,8 +180,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() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -406,6 +406,8 @@ 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;"
|
||||
@ -667,7 +669,9 @@ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativ
|
||||
krbcredsConstructor,
|
||||
ticket,
|
||||
clientPrincipal,
|
||||
NULL,
|
||||
targetPrincipal,
|
||||
NULL,
|
||||
encryptionKey,
|
||||
ticketFlags,
|
||||
authTime, // mdu
|
||||
|
@ -808,8 +808,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(
|
||||
@ -817,6 +819,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -918,7 +923,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);
|
||||
@ -1074,8 +1080,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) {
|
||||
|
@ -30,9 +30,18 @@
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import sun.security.krb5.Credentials;
|
||||
import sun.security.krb5.internal.CredentialsUtil;
|
||||
import sun.security.krb5.KrbAsReqBuilder;
|
||||
import java.security.Principal;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.ietf.jgss.GSSName;
|
||||
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.krb5.PrincipalName;
|
||||
|
||||
public class ReferralsTest {
|
||||
@ -41,39 +50,32 @@ 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 clientAlias = clientName +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
|
||||
|
||||
private static final String clientKDC1QueryName = clientAlias.replaceAll(
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR) +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
|
||||
private static PrincipalName clientKDC1QueryPrincipal = null;
|
||||
static {
|
||||
try {
|
||||
clientKDC1QueryPrincipal = new PrincipalName(
|
||||
clientKDC1QueryName, PrincipalName.KRB_NT_ENTERPRISE,
|
||||
null);
|
||||
} catch (Throwable t) {}
|
||||
}
|
||||
|
||||
private static final String clientKDC2Name = clientName +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
|
||||
|
||||
private static final String serviceName = "http" +
|
||||
PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
|
||||
"server.dev.rabbit.hole";
|
||||
|
||||
private static Credentials tgt;
|
||||
private static Credentials tgs;
|
||||
// Alias
|
||||
private static final String clientAlias = clientName +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
|
||||
|
||||
// Names + realms
|
||||
private static final String clientKDC1Name = clientAlias.replaceAll(
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR) +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1;
|
||||
private static final String clientKDC2Name = clientName +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
|
||||
private static final String serviceKDC2Name = serviceName +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
initializeKDCs();
|
||||
getTGT();
|
||||
getTGS();
|
||||
testSubjectCredentials();
|
||||
testDelegated();
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
@ -108,6 +110,11 @@ 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);
|
||||
@ -120,50 +127,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.");
|
||||
}
|
||||
int numOfTickets = clientTickets.size();
|
||||
clientContext.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
clientContext.take(new byte[0]);
|
||||
clientContext.status();
|
||||
int newNumOfTickets =
|
||||
clientSubject.getPrivateCredentials(KerberosTicket.class).size();
|
||||
if (DEBUG) {
|
||||
System.out.println("client subject number of tickets: " +
|
||||
numOfTickets);
|
||||
System.out.println("client subject new number of tickets: " +
|
||||
newNumOfTickets);
|
||||
}
|
||||
if (numOfTickets != newNumOfTickets) {
|
||||
throw new Exception("Useless client subject TGS request because" +
|
||||
" TGS was not found in private credentials.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void getTGS() throws Exception {
|
||||
tgs = CredentialsUtil.acquireServiceCreds(serviceName +
|
||||
PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, tgt);
|
||||
/*
|
||||
* 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("TGS");
|
||||
System.out.println("----------------------");
|
||||
System.out.println(tgs);
|
||||
System.out.println("----------------------");
|
||||
System.out.println("Context initiator: " + contextInitiatorName);
|
||||
System.out.println("Context acceptor: " + contextAcceptorName);
|
||||
}
|
||||
if (tgs == null) {
|
||||
throw new Exception("TGS is null");
|
||||
}
|
||||
if (!tgs.getClient().getName().equals(clientKDC2Name)) {
|
||||
throw new Exception("Unexpected TGS client");
|
||||
}
|
||||
if (!tgs.getServer().getNameString().equals(serviceName) ||
|
||||
!tgs.getServer().getRealmString().equals(realmKDC2)) {
|
||||
throw new Exception("Unexpected TGS server");
|
||||
if (!contextInitiatorName.toString().equals(clientKDC2Name) ||
|
||||
!contextAcceptorName.toString().equals(serviceName)) {
|
||||
throw new Exception("Unexpected initiator or acceptor names");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user