8220302: Better Kerberos ccache handling
Reviewed-by: valeriep
This commit is contained in:
parent
e4553cb2fa
commit
cb06712f5a
@ -1213,3 +1213,32 @@ jdk.sasl.disabledMechanisms=
|
||||
# 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
|
||||
|
@ -49,4 +49,12 @@ class JavaxSecurityAuthKerberosAccessImpl
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -29,11 +29,13 @@ import java.io.*;
|
||||
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,9 +192,14 @@ public class KerberosTicket implements Destroyable, Refreshable,
|
||||
* @serial
|
||||
*/
|
||||
|
||||
|
||||
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;
|
||||
|
||||
transient KerberosPrincipal clientAlias = null;
|
||||
@ -711,6 +718,7 @@ public class KerberosTicket implements Destroyable, Refreshable,
|
||||
"Renew Till = " + String.valueOf(renewTill) + "\n" +
|
||||
"Client Addresses " +
|
||||
(clientAddresses == null ? " Null " : caddrString.toString() +
|
||||
(proxy == null ? "" : "\nwith a proxy ticket") +
|
||||
"\n"));
|
||||
}
|
||||
|
||||
@ -748,6 +756,10 @@ public class KerberosTicket implements Destroyable, Refreshable,
|
||||
|
||||
// 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 @@ public class KerberosTicket implements Destroyable, Refreshable,
|
||||
}
|
||||
}
|
||||
|
||||
if (!Objects.equals(proxy, otherTicket.proxy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -617,6 +617,8 @@ class Krb5Context implements GSSContextSpi {
|
||||
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 @@ class Krb5Context implements GSSContextSpi {
|
||||
// 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
|
||||
|
@ -55,6 +55,7 @@ public class Krb5InitCredential
|
||||
|
||||
private Krb5NameElement name;
|
||||
private Credentials krb5Credentials;
|
||||
public KerberosTicket proxyTicket;
|
||||
|
||||
private Krb5InitCredential(Krb5NameElement name,
|
||||
byte[] asn1Encoding,
|
||||
@ -173,7 +174,7 @@ public class Krb5InitCredential
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(tgt);
|
||||
return new Krb5InitCredential(name,
|
||||
Krb5InitCredential result = new Krb5InitCredential(name,
|
||||
tgt.getEncoded(),
|
||||
tgt.getClient(),
|
||||
clientAlias,
|
||||
@ -187,6 +188,9 @@ public class Krb5InitCredential
|
||||
tgt.getEndTime(),
|
||||
tgt.getRenewTill(),
|
||||
tgt.getClientAddresses());
|
||||
result.proxyTicket = KerberosSecrets.getJavaxSecurityAuthKerberosAccess().
|
||||
kerberosTicketGetProxy(tgt);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Krb5InitCredential getInstance(Krb5NameElement name,
|
||||
@ -369,9 +373,9 @@ public class Krb5InitCredential
|
||||
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 =
|
||||
|
@ -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 @@ public final class Krb5MechFactory implements MechanismFactory {
|
||||
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) {
|
||||
|
@ -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 @@ public class Krb5NameElement
|
||||
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);
|
||||
|
@ -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 @@ public class Krb5ProxyCredential
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,11 +60,8 @@ public class Krb5Util {
|
||||
/**
|
||||
* 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 @@ public class Krb5Util {
|
||||
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;
|
||||
}
|
||||
|
@ -59,13 +59,23 @@ public class Credentials {
|
||||
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 @@ public class Credentials {
|
||||
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 @@ public class Credentials {
|
||||
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 @@ public class Credentials {
|
||||
return cache;
|
||||
}
|
||||
|
||||
public EncryptionKey getServiceKey() {
|
||||
return serviceKey;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prints out debug info.
|
||||
*/
|
||||
|
@ -28,8 +28,6 @@ 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;
|
||||
|
||||
/**
|
||||
* An unsafe tunnel to get non-public access to classes in the
|
||||
@ -49,4 +47,13 @@ public interface JavaxSecurityAuthKerberosAccess {
|
||||
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);
|
||||
}
|
||||
|
@ -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 @@ public class Realm implements Cloneable {
|
||||
return false;
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
if (name.charAt(i) == '/' ||
|
||||
name.charAt(i) == ':' ||
|
||||
name.charAt(i) == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
@ -325,16 +325,13 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public class CCacheOutputStream extends KrbDataOutputStream implements FileCCach
|
||||
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);
|
||||
|
@ -169,6 +169,18 @@ public class Credentials {
|
||||
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 @@ public class Credentials {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -32,14 +32,9 @@ package sun.security.krb5.internal.ccache;
|
||||
|
||||
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 class CredentialsCache {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ package sun.security.krb5.internal.ccache;
|
||||
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 @@ public class FileCredentialsCache extends CredentialsCache
|
||||
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 @@ public class FileCredentialsCache extends CredentialsCache
|
||||
cos.addCreds(tmp[i]);
|
||||
}
|
||||
}
|
||||
for (ConfigEntry e : getConfigEntries()) {
|
||||
cos.addConfigEntry(primaryPrincipal, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,6 +320,17 @@ public class FileCredentialsCache extends CredentialsCache
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class FileCredentialsCache extends CredentialsCache
|
||||
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) {
|
||||
|
@ -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 @@ public class Klist {
|
||||
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 @@ public class Klist {
|
||||
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 @@ public class Klist {
|
||||
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 @@ public class Klist {
|
||||
} 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) {
|
||||
|
@ -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 @@ public class Krb5LoginModule implements LoginModule {
|
||||
// renew if ticket is old.
|
||||
Credentials newCred = renewCredentials(cred);
|
||||
if (newCred != null) {
|
||||
newCred.setProxy(cred.getProxy());
|
||||
cred = newCred;
|
||||
}
|
||||
}
|
||||
@ -1070,6 +1071,10 @@ public class Krb5LoginModule implements LoginModule {
|
||||
// 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) {
|
||||
|
Loading…
Reference in New Issue
Block a user