--- a/src/java.base/share/conf/security/java.security Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.base/share/conf/security/java.security Fri Apr 19 10:22:20 2019 +0800
@@ -1213,3 +1213,32 @@
# if this property is not enabled.
#
jdk.security.caDistrustPolicies=SYMANTEC_TLS
+
+#
+# Policies for the proxy_impersonator Kerberos ccache configuration entry
+#
+# The proxy_impersonator ccache configuration entry indicates that the ccache
+# is a synthetic delegated credential for use with S4U2Proxy by an intermediate
+# server. The ccache file should also contain the TGT of this server and
+# an evidence ticket from the default principal of the ccache to this server.
+#
+# This security property determines how Java uses this configuration entry.
+# There are 3 possible values:
+#
+# no-impersonate - Ignore this configuration entry, and always act as
+# the owner of the TGT (if it exists).
+#
+# try-impersonate - Try impersonation when this configuration entry exists.
+# If no matching TGT or evidence ticket is found,
+# fallback to no-impersonate.
+#
+# always-impersonate - Always impersonate when this configuration entry exists.
+# If no matching TGT or evidence ticket is found,
+# no initial credential is read from the ccache.
+#
+# The default value is "always-impersonate".
+#
+# If a system property of the same name is also specified, it supersedes the
+# security property value defined here.
+#
+#jdk.security.krb5.default.initiate.credential=always-impersonate
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java Fri Apr 19 10:22:20 2019 +0800
@@ -49,4 +49,12 @@
public void kerberosTicketSetServerAlias(KerberosTicket t, KerberosPrincipal a) {
t.serverAlias = a;
}
+
+ public KerberosTicket kerberosTicketGetProxy(KerberosTicket t) {
+ return t.proxy;
+ }
+
+ public void kerberosTicketSetProxy(KerberosTicket t, KerberosTicket p) {
+ t.proxy = p;
+ }
}
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosTicket.java Fri Apr 19 10:22:20 2019 +0800
@@ -29,11 +29,13 @@
import java.util.Date;
import java.util.Arrays;
import java.net.InetAddress;
+import java.util.Objects;
import javax.crypto.SecretKey;
import javax.security.auth.Refreshable;
import javax.security.auth.Destroyable;
import javax.security.auth.RefreshFailedException;
import javax.security.auth.DestroyFailedException;
+
import sun.security.util.HexDumpEncoder;
/**
@@ -190,8 +192,13 @@
* @serial
*/
+ private InetAddress[] clientAddresses;
- private InetAddress[] clientAddresses;
+ /**
+ * Evidence ticket if proxy_impersonator. This field can be accessed
+ * by KerberosSecrets. It's serialized.
+ */
+ KerberosTicket proxy = null;
private transient boolean destroyed = false;
@@ -711,6 +718,7 @@
"Renew Till = " + String.valueOf(renewTill) + "\n" +
"Client Addresses " +
(clientAddresses == null ? " Null " : caddrString.toString() +
+ (proxy == null ? "" : "\nwith a proxy ticket") +
"\n"));
}
@@ -748,6 +756,10 @@
// clientAddress may be null, the array's hashCode is 0
result = result * 37 + Arrays.hashCode(clientAddresses);
+
+ if (proxy != null) {
+ result = result * 37 + proxy.hashCode();
+ }
return result * 37 + Arrays.hashCode(flags);
}
@@ -820,6 +832,10 @@
}
}
+ if (!Objects.equals(proxy, otherTicket.proxy)) {
+ return false;
+ }
+
return true;
}
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Fri Apr 19 10:22:20 2019 +0800
@@ -617,6 +617,8 @@
if (myCred == null) {
myCred = Krb5InitCredential.getInstance(caller, myName,
GSSCredential.DEFAULT_LIFETIME);
+ myCred = Krb5ProxyCredential.tryImpersonation(
+ caller, (Krb5InitCredential)myCred);
} else if (!myCred.isInitiatorCredential()) {
throw new GSSException(errorCode, -1,
"No TGT available");
@@ -653,8 +655,8 @@
// highly consider just calling:
// Subject.getSubject
// SubjectComber.find
- // instead of Krb5Util.getTicket
- return Krb5Util.getTicket(
+ // instead of Krb5Util.getServiceTicket
+ return Krb5Util.getServiceTicket(
GSSCaller.CALLER_UNKNOWN,
// since it's useSubjectCredsOnly here,
// don't worry about the null
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java Fri Apr 19 10:22:20 2019 +0800
@@ -55,6 +55,7 @@
private Krb5NameElement name;
private Credentials krb5Credentials;
+ public KerberosTicket proxyTicket;
private Krb5InitCredential(Krb5NameElement name,
byte[] asn1Encoding,
@@ -173,7 +174,7 @@
KerberosPrincipal serverAlias = KerberosSecrets
.getJavaxSecurityAuthKerberosAccess()
.kerberosTicketGetServerAlias(tgt);
- return new Krb5InitCredential(name,
+ Krb5InitCredential result = new Krb5InitCredential(name,
tgt.getEncoded(),
tgt.getClient(),
clientAlias,
@@ -187,6 +188,9 @@
tgt.getEndTime(),
tgt.getRenewTill(),
tgt.getClientAddresses());
+ result.proxyTicket = KerberosSecrets.getJavaxSecurityAuthKerberosAccess().
+ kerberosTicketGetProxy(tgt);
+ return result;
}
static Krb5InitCredential getInstance(Krb5NameElement name,
@@ -369,9 +373,9 @@
public KerberosTicket run() throws Exception {
// It's OK to use null as serverPrincipal. TGT is almost
// the first ticket for a principal and we use list.
- return Krb5Util.getTicket(
+ return Krb5Util.getInitialTicket(
realCaller,
- clientPrincipal, null, acc);
+ clientPrincipal, acc);
}});
} catch (PrivilegedActionException e) {
GSSException ge =
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5MechFactory.java Fri Apr 19 10:22:20 2019 +0800
@@ -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
@@ -124,6 +124,8 @@
usage == GSSCredential.INITIATE_AND_ACCEPT) {
credElement = Krb5InitCredential.getInstance
(caller, (Krb5NameElement) name, initLifetime);
+ credElement = Krb5ProxyCredential.tryImpersonation(
+ caller, (Krb5InitCredential)credElement);
checkInitCredPermission
((Krb5NameElement) credElement.getName());
} else if (usage == GSSCredential.ACCEPT_ONLY) {
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5NameElement.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5NameElement.java Fri Apr 19 10:22:20 2019 +0800
@@ -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
@@ -144,7 +144,7 @@
return new Krb5NameElement(principalName, gssNameStr, gssNameType);
}
- static Krb5NameElement getInstance(PrincipalName principalName) {
+ public static Krb5NameElement getInstance(PrincipalName principalName) {
return new Krb5NameElement(principalName,
principalName.getName(),
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5ProxyCredential.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5ProxyCredential.java Fri Apr 19 10:22:20 2019 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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,10 +26,17 @@
package sun.security.jgss.krb5;
import org.ietf.jgss.*;
+import sun.security.jgss.GSSCaller;
import sun.security.jgss.spi.*;
-import java.util.Date;
+
+import java.io.IOException;
+
+import sun.security.krb5.Credentials;
+import sun.security.krb5.KrbException;
import sun.security.krb5.internal.Ticket;
+import javax.security.auth.kerberos.KerberosTicket;
+
/**
* Implements the krb5 proxy credential element used in constrained
* delegation. It is used in both impersonation (where there is no Kerberos 5
@@ -112,4 +119,24 @@
throw new GSSException(GSSException.FAILURE, -1,
"Only an initiate credentials can impersonate");
}
+
+ // Try to see if a default credential should act as an impersonator.
+ static Krb5CredElement tryImpersonation(GSSCaller caller,
+ Krb5InitCredential initiator) throws GSSException {
+
+ try {
+ KerberosTicket proxy = initiator.proxyTicket;
+ if (proxy != null) {
+ Credentials proxyCreds = Krb5Util.ticketToCreds(proxy);
+ return new Krb5ProxyCredential(initiator,
+ Krb5NameElement.getInstance(proxyCreds.getClient()),
+ proxyCreds.getTicket());
+ } else {
+ return initiator;
+ }
+ } catch (KrbException | IOException e) {
+ throw new GSSException(GSSException.DEFECTIVE_CREDENTIAL, -1,
+ "Cannot create proxy credential");
+ }
+ }
}
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java Fri Apr 19 10:22:20 2019 +0800
@@ -60,11 +60,8 @@
/**
* Retrieves the ticket corresponding to the client/server principal
* pair from the Subject in the specified AccessControlContext.
- * If the ticket can not be found in the Subject, and if
- * useSubjectCredsOnly is false, then obtain ticket from
- * a LoginContext.
*/
- static KerberosTicket getTicket(GSSCaller caller,
+ static KerberosTicket getServiceTicket(GSSCaller caller,
String clientPrincipal, String serverPrincipal,
AccessControlContext acc) throws LoginException {
@@ -74,11 +71,31 @@
SubjectComber.find(accSubj, serverPrincipal, clientPrincipal,
KerberosTicket.class);
+ return ticket;
+ }
+
+ /**
+ * Retrieves the initial TGT corresponding to the client principal
+ * from the Subject in the specified AccessControlContext.
+ * If the ticket can not be found in the Subject, and if
+ * useSubjectCredsOnly is false, then obtain ticket from
+ * a LoginContext.
+ */
+ static KerberosTicket getInitialTicket(GSSCaller caller,
+ String clientPrincipal,
+ AccessControlContext acc) throws LoginException {
+
+ // Try to get ticket from acc's Subject
+ Subject accSubj = Subject.getSubject(acc);
+ KerberosTicket ticket =
+ SubjectComber.find(accSubj, null, clientPrincipal,
+ KerberosTicket.class);
+
// Try to get ticket from Subject obtained from GSSUtil
if (ticket == null && !GSSUtil.useSubjectCredsOnly(caller)) {
Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
ticket = SubjectComber.find(subject,
- serverPrincipal, clientPrincipal, KerberosTicket.class);
+ null, clientPrincipal, KerberosTicket.class);
}
return ticket;
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java Fri Apr 19 10:22:20 2019 +0800
@@ -59,13 +59,23 @@
KerberosTime endTime;
KerberosTime renewTill;
HostAddresses cAddr;
- EncryptionKey serviceKey;
AuthorizationData authzData;
private static boolean DEBUG = Krb5.DEBUG;
private static CredentialsCache cache;
static boolean alreadyLoaded = false;
private static boolean alreadyTried = false;
+ private Credentials proxy = null;
+
+ public Credentials getProxy() {
+ return proxy;
+ }
+
+ public Credentials setProxy(Credentials proxy) {
+ this.proxy = proxy;
+ return this;
+ }
+
// Read native ticket with session key type in the given list
private static native Credentials acquireDefaultNativeCreds(int[] eTypes);
@@ -361,20 +371,19 @@
return null;
}
- sun.security.krb5.internal.ccache.Credentials tgtCred =
- ccache.getDefaultCreds();
+ Credentials tgtCred = ccache.getInitialCreds();
if (tgtCred == null) {
return null;
}
- if (EType.isSupported(tgtCred.getEType())) {
- return tgtCred.setKrbCreds();
+ if (EType.isSupported(tgtCred.key.getEType())) {
+ return tgtCred;
} else {
if (DEBUG) {
System.out.println(
">>> unsupported key type found the default TGT: " +
- tgtCred.getEType());
+ tgtCred.key.getEType());
}
return null;
}
@@ -409,20 +418,19 @@
cache = CredentialsCache.getInstance();
}
if (cache != null) {
- sun.security.krb5.internal.ccache.Credentials temp =
- cache.getDefaultCreds();
+ Credentials temp = cache.getInitialCreds();
if (temp != null) {
if (DEBUG) {
System.out.println(">>> KrbCreds found the default ticket"
+ " granting ticket in credential cache.");
}
- if (EType.isSupported(temp.getEType())) {
- result = temp.setKrbCreds();
+ if (EType.isSupported(temp.key.getEType())) {
+ result = temp;
} else {
if (DEBUG) {
System.out.println(
">>> unsupported key type found the default TGT: " +
- temp.getEType());
+ temp.key.getEType());
}
}
}
@@ -499,10 +507,6 @@
return cache;
}
- public EncryptionKey getServiceKey() {
- return serviceKey;
- }
-
/*
* Prints out debug info.
*/
--- a/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java Fri Apr 19 10:22:20 2019 +0800
@@ -28,8 +28,6 @@
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;
/**
* An unsafe tunnel to get non-public access to classes in the
@@ -49,4 +47,13 @@
public KerberosPrincipal kerberosTicketGetServerAlias(KerberosTicket t);
public void kerberosTicketSetServerAlias(KerberosTicket t, KerberosPrincipal a);
+ /**
+ * Returns the proxy for a KerberosTicket.
+ */
+ public KerberosTicket kerberosTicketGetProxy(KerberosTicket t);
+
+ /**
+ * Sets the proxy for a KerberosTicket.
+ */
+ public void kerberosTicketSetProxy(KerberosTicket t, KerberosTicket p);
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/Realm.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/Realm.java Fri Apr 19 10:22:20 2019 +0800
@@ -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
@@ -186,7 +186,6 @@
return false;
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) == '/' ||
- name.charAt(i) == ':' ||
name.charAt(i) == '\0') {
return false;
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Fri Apr 19 10:22:20 2019 +0800
@@ -325,16 +325,13 @@
}
/**
- * Reads the next cred in stream.
- * @return the next cred, null if ticket or second_ticket unparseable.
+ * Reads the next cred or config entry in stream.
+ * @return the next cred or config entry, null if data unparseable.
*
- * Note: MIT krb5 1.8.1 might generate a config entry with server principal
- * X-CACHECONF:/krb5_ccache_conf_data/fast_avail/krbtgt/REALM@REALM. The
- * entry is used by KDC to inform the client that it support certain
- * features. Its ticket is not a valid krb5 ticket and thus this method
- * returns null.
+ * When data is unparseable, this method makes sure the correct number of
+ * bytes are consumed so it's safe to start reading the next element.
*/
- Credentials readCred(int version) throws IOException,RealmException, KrbApErrException, Asn1Exception {
+ Object readCred(int version) throws IOException,RealmException, KrbApErrException, Asn1Exception {
PrincipalName cpname = null;
try {
cpname = readPrincipal(version);
@@ -396,12 +393,23 @@
}
try {
+ if (spname.getRealmString().equals("X-CACHECONF:")) {
+ String[] nameParts = spname.getNameStrings();
+ if (nameParts[0].equals("krb5_ccache_conf_data")) {
+ return new CredentialsCache.ConfigEntry(nameParts[1],
+ nameParts.length > 2 ? new PrincipalName(nameParts[2]) : null,
+ ticketData);
+ }
+ }
return new Credentials(cpname, spname, key, authtime, starttime,
- endtime, renewTill, skey, tFlags,
- addrs, auData,
- ticketData != null ? new Ticket(ticketData) : null,
- ticketData2 != null ? new Ticket(ticketData2) : null);
+ endtime, renewTill, skey, tFlags,
+ addrs, auData,
+ ticketData != null ? new Ticket(ticketData) : null,
+ ticketData2 != null ? new Ticket(ticketData2) : null);
} catch (Exception e) { // If any of new Ticket(*) fails.
+ if (DEBUG) {
+ e.printStackTrace(System.out);
+ }
return null;
}
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheOutputStream.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheOutputStream.java Fri Apr 19 10:22:20 2019 +0800
@@ -31,7 +31,6 @@
package sun.security.krb5.internal.ccache;
import java.io.IOException;
-import java.io.FileOutputStream;
import java.io.OutputStream;
import sun.security.krb5.internal.util.KrbDataOutputStream;
import sun.security.krb5.*;
@@ -98,6 +97,21 @@
writeTicket(creds.secondTicket);
}
+ public void addConfigEntry(PrincipalName cname, CredentialsCache.ConfigEntry e)
+ throws IOException {
+ cname.writePrincipal(this);
+ e.getSName().writePrincipal(this);
+ write16(0); write16(0); write32(0);
+ write32(0); write32(0); write32(0); write32(0);
+ write8(0);
+ write32(0);
+ write32(0);
+ write32(0);
+ write32(e.getData().length);
+ write(e.getData());
+ write32(0);
+ }
+
void writeTicket(Ticket t) throws IOException, Asn1Exception {
if (t == null) {
write32(0);
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/Credentials.java Fri Apr 19 10:22:20 2019 +0800
@@ -169,6 +169,18 @@
return sname;
}
+ public Ticket getTicket() throws RealmException {
+ return ticket;
+ }
+
+ public PrincipalName getServicePrincipal2() throws RealmException {
+ return secondTicket == null ? null : secondTicket.sname;
+ }
+
+ public PrincipalName getClientPrincipal() throws RealmException {
+ return cname;
+ }
+
public sun.security.krb5.Credentials setKrbCreds() {
// Note: We will not pass authorizationData to s.s.k.Credentials. The
// field in that class will be passed to Krb5Context as the return
@@ -209,7 +221,15 @@
return key.getEType();
}
+ public EncryptionKey getKey() {
+ return key;
+ }
+
public int getTktEType() {
return ticket.encPart.getEType();
}
+
+ public int getTktEType2() {
+ return (secondTicket == null) ? 0 : secondTicket.encPart.getEType();
+ }
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java Fri Apr 19 10:22:20 2019 +0800
@@ -32,14 +32,9 @@
import sun.security.krb5.*;
import sun.security.krb5.internal.*;
-import java.util.StringTokenizer;
-import java.util.Vector;
+
+import java.util.List;
import java.io.IOException;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
/**
* CredentialsCache stores credentials(tickets, session keys, etc) in a semi-permanent store
@@ -120,6 +115,62 @@
public abstract void save() throws IOException, KrbException;
public abstract Credentials[] getCredsList();
public abstract Credentials getDefaultCreds();
+ public abstract sun.security.krb5.Credentials getInitialCreds();
public abstract Credentials getCreds(PrincipalName sname);
public abstract Credentials getCreds(LoginOptions options, PrincipalName sname);
+ public abstract void addConfigEntry(ConfigEntry e);
+ public abstract List<ConfigEntry> getConfigEntries();
+
+ public ConfigEntry getConfigEntry(String name) {
+ List<ConfigEntry> entries = getConfigEntries();
+ if (entries != null) {
+ for (ConfigEntry e : entries) {
+ if (e.getName().equals(name)) {
+ return e;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static class ConfigEntry {
+
+ public ConfigEntry(String name, PrincipalName princ, byte[] data) {
+ this.name = name;
+ this.princ = princ;
+ this.data = data;
+ }
+
+ private final String name;
+ private final PrincipalName princ;
+ private final byte[] data; // not worth cloning
+
+ public String getName() {
+ return name;
+ }
+
+ public PrincipalName getPrinc() {
+ return princ;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ @Override
+ public String toString() {
+ return name + (princ != null ? ("." + princ) : "")
+ + ": " + new String(data);
+ }
+
+ public PrincipalName getSName() {
+ try {
+ return new PrincipalName("krb5_ccache_conf_data/" + name
+ + (princ != null ? ("/" + princ) : "")
+ + "@X-CACHECONF:");
+ } catch (RealmException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
}
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java Fri Apr 19 10:22:20 2019 +0800
@@ -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
@@ -36,6 +36,12 @@
import sun.security.action.GetPropertyAction;
import sun.security.krb5.*;
import sun.security.krb5.internal.*;
+import sun.security.util.SecurityProperties;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.io.IOException;
@@ -182,9 +188,13 @@
primaryPrincipal = p;
credentialsList = new Vector<Credentials>();
while (cis.available() > 0) {
- Credentials cred = cis.readCred(version);
+ Object cred = cis.readCred(version);
if (cred != null) {
- credentialsList.addElement(cred);
+ if (cred instanceof Credentials) {
+ credentialsList.addElement((Credentials)cred);
+ } else {
+ addConfigEntry((CredentialsCache.ConfigEntry)cred);
+ }
}
}
}
@@ -255,6 +265,9 @@
cos.addCreds(tmp[i]);
}
}
+ for (ConfigEntry e : getConfigEntries()) {
+ cos.addConfigEntry(primaryPrincipal, e);
+ }
}
}
@@ -307,6 +320,17 @@
}
}
+ private List<ConfigEntry> configEntries = new ArrayList<>();
+
+ @Override
+ public void addConfigEntry(ConfigEntry e) {
+ configEntries.add(e);
+ }
+
+ @Override
+ public List<ConfigEntry> getConfigEntries() {
+ return Collections.unmodifiableList(configEntries);
+ }
/**
* Gets a credentials for a specified service.
@@ -326,6 +350,81 @@
return null;
}
+ public sun.security.krb5.Credentials getInitialCreds() {
+
+ Credentials defaultCreds = getDefaultCreds();
+ if (defaultCreds == null) {
+ return null;
+ }
+ sun.security.krb5.Credentials tgt = defaultCreds.setKrbCreds();
+
+ CredentialsCache.ConfigEntry entry = getConfigEntry("proxy_impersonator");
+ if (entry == null) {
+ if (DEBUG) {
+ System.out.println("get normal credential");
+ }
+ return tgt;
+ }
+
+ boolean force;
+ String prop = SecurityProperties.privilegedGetOverridable(
+ "jdk.security.krb5.default.initiate.credential");
+ if (prop == null) {
+ prop = "always-impersonate";
+ }
+ switch (prop) {
+ case "no-impersonate": // never try impersonation
+ if (DEBUG) {
+ System.out.println("get normal credential");
+ }
+ return tgt;
+ case "try-impersonate":
+ force = false;
+ break;
+ case "always-impersonate":
+ force = true;
+ break;
+ default:
+ throw new RuntimeException(
+ "Invalid jdk.security.krb5.default.initiate.credential");
+ }
+
+ try {
+ PrincipalName service = new PrincipalName(
+ new String(entry.getData(), StandardCharsets.UTF_8));
+ if (!tgt.getClient().equals(service)) {
+ if (DEBUG) {
+ System.out.println("proxy_impersonator does not match service name");
+ }
+ return force ? null : tgt;
+ }
+ PrincipalName client = getPrimaryPrincipal();
+ Credentials proxy = null;
+ for (Credentials c : getCredsList()) {
+ if (c.getClientPrincipal().equals(client)
+ && c.getServicePrincipal().equals(service)) {
+ proxy = c;
+ break;
+ }
+ }
+ if (proxy == null) {
+ if (DEBUG) {
+ System.out.println("Cannot find evidence ticket in ccache");
+ }
+ return force ? null : tgt;
+ }
+ if (DEBUG) {
+ System.out.println("Get proxied credential");
+ }
+ return tgt.setProxy(proxy.setKrbCreds());
+ } catch (KrbException e) {
+ if (DEBUG) {
+ System.out.println("Impersonation with ccache failed");
+ }
+ return force ? null : tgt;
+ }
+ }
+
public Credentials getDefaultCreds() {
Credentials[] list = getCredsList();
if (list == null) {
--- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java Fri Apr 19 10:22:20 2019 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -31,6 +31,8 @@
package sun.security.krb5.internal.tools;
import java.net.InetAddress;
+import java.util.List;
+
import sun.security.krb5.*;
import sun.security.krb5.internal.*;
import sun.security.krb5.internal.ccache.*;
@@ -249,6 +251,8 @@
String endtime;
String renewTill;
String servicePrincipal;
+ PrincipalName servicePrincipal2;
+ String clientPrincipal;
if (creds[i].getStartTime() != null) {
starttime = format(creds[i].getStartTime());
} else {
@@ -260,6 +264,18 @@
System.out.println("[" + (i + 1) + "] " +
" Service Principal: " +
servicePrincipal);
+ servicePrincipal2 =
+ creds[i].getServicePrincipal2();
+ if (servicePrincipal2 != null) {
+ System.out.println(" Second Service: "
+ + servicePrincipal2);
+ }
+ clientPrincipal =
+ creds[i].getClientPrincipal().toString();
+ if (!clientPrincipal.equals(defaultPrincipal)) {
+ System.out.println(" Client Principal: " +
+ clientPrincipal);
+ }
System.out.println(" Valid starting: " + starttime);
System.out.println(" Expires: " + endtime);
if (creds[i].getRenewTill() != null) {
@@ -270,8 +286,15 @@
if (options[0] == 'e') {
String eskey = EType.toString(creds[i].getEType());
String etkt = EType.toString(creds[i].getTktEType());
- System.out.println(" EType (skey, tkt): "
- + eskey + ", " + etkt);
+ if (creds[i].getTktEType2() == 0) {
+ System.out.println(" EType (skey, tkt): "
+ + eskey + ", " + etkt);
+ } else {
+ String etkt2 = EType.toString(creds[i].getTktEType2());
+ System.out.println(" EType (skey, tkts): "
+ + eskey + ", " + etkt
+ + ", " + etkt2);
+ }
}
if (options[1] == 'f') {
System.out.println(" Flags: " +
@@ -310,6 +333,15 @@
} else {
System.out.println("\nNo entries found.");
}
+
+ List<CredentialsCache.ConfigEntry> configEntries
+ = cache.getConfigEntries();
+ if (configEntries != null && !configEntries.isEmpty()) {
+ System.out.println("\nConfig entries:");
+ for (CredentialsCache.ConfigEntry e : configEntries) {
+ System.out.println(" " + e);
+ }
+ }
}
void displayMessage(String target) {
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Mon Mar 25 17:15:27 2019 +0000
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Fri Apr 19 10:22:20 2019 +0800
@@ -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
@@ -644,6 +644,7 @@
// renew if ticket is old.
Credentials newCred = renewCredentials(cred);
if (newCred != null) {
+ newCred.setProxy(cred.getProxy());
cred = newCred;
}
}
@@ -1070,6 +1071,10 @@
// create Kerberos Ticket
if (isInitiator) {
kerbTicket = Krb5Util.credsToTicket(cred);
+ if (cred.getProxy() != null) {
+ KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
+ .kerberosTicketSetProxy(kerbTicket,Krb5Util.credsToTicket(cred.getProxy()));
+ }
}
if (storeKey && encKeys != null) {