|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.jgss.krb5; |
|
|
|
import javax.security.auth.kerberos.KerberosTicket; |
|
import javax.security.auth.kerberos.KerberosKey; |
|
import javax.security.auth.kerberos.KerberosPrincipal; |
|
import javax.security.auth.kerberos.KeyTab; |
|
import javax.security.auth.Subject; |
|
|
|
import sun.security.krb5.Credentials; |
|
import sun.security.krb5.EncryptionKey; |
|
import sun.security.krb5.KrbException; |
|
import java.io.IOException; |
|
import java.util.ArrayList; |
|
import java.util.List; |
|
import java.util.Set; |
|
import sun.security.krb5.*; |
|
import sun.security.krb5.internal.Krb5; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final class ServiceCreds { |
|
|
|
private KerberosPrincipal kp; |
|
|
|
|
|
private Set<KerberosPrincipal> allPrincs; |
|
|
|
|
|
private List<KeyTab> ktabs; |
|
private List<KerberosKey> kk; |
|
private KerberosTicket tgt; |
|
|
|
private boolean destroyed; |
|
|
|
private ServiceCreds() { |
|
// Make sure this class cannot be instantiated externally. |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static ServiceCreds getInstance( |
|
Subject subj, String serverPrincipal) { |
|
|
|
ServiceCreds sc = new ServiceCreds(); |
|
|
|
sc.allPrincs = |
|
subj.getPrincipals(KerberosPrincipal.class); |
|
|
|
|
|
for (KerberosKey key: SubjectComber.findMany( |
|
subj, serverPrincipal, null, KerberosKey.class)) { |
|
sc.allPrincs.add(key.getPrincipal()); |
|
} |
|
|
|
if (serverPrincipal != null) { |
|
sc.kp = new KerberosPrincipal(serverPrincipal); |
|
} else { |
|
// For compatibility reason, we set the name of default principal |
|
// to the "only possible" name it can take, which means there is |
|
|
|
if (sc.allPrincs.size() == 1) { |
|
boolean hasUnbound = false; |
|
for (KeyTab ktab: SubjectComber.findMany( |
|
subj, null, null, KeyTab.class)) { |
|
if (!ktab.isBound()) { |
|
hasUnbound = true; |
|
break; |
|
} |
|
} |
|
if (!hasUnbound) { |
|
sc.kp = sc.allPrincs.iterator().next(); |
|
serverPrincipal = sc.kp.getName(); |
|
} |
|
} |
|
} |
|
|
|
sc.ktabs = SubjectComber.findMany( |
|
subj, serverPrincipal, null, KeyTab.class); |
|
sc.kk = SubjectComber.findMany( |
|
subj, serverPrincipal, null, KerberosKey.class); |
|
sc.tgt = SubjectComber.find( |
|
subj, null, serverPrincipal, KerberosTicket.class); |
|
if (sc.ktabs.isEmpty() && sc.kk.isEmpty() && sc.tgt == null) { |
|
return null; |
|
} |
|
|
|
sc.destroyed = false; |
|
|
|
return sc; |
|
} |
|
|
|
|
|
public String getName() { |
|
if (destroyed) { |
|
throw new IllegalStateException("This object is destroyed"); |
|
} |
|
return kp == null ? null : kp.getName(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public KerberosKey[] getKKeys() { |
|
if (destroyed) { |
|
throw new IllegalStateException("This object is destroyed"); |
|
} |
|
KerberosPrincipal one = kp; |
|
if (one == null && !allPrincs.isEmpty()) { |
|
one = allPrincs.iterator().next(); |
|
} |
|
if (one == null) { |
|
for (KeyTab ktab: ktabs) { |
|
|
|
PrincipalName pn = |
|
Krb5Util.snapshotFromJavaxKeyTab(ktab).getOneName(); |
|
if (pn != null) { |
|
one = new KerberosPrincipal(pn.getName()); |
|
break; |
|
} |
|
} |
|
} |
|
if (one != null) { |
|
return getKKeys(one); |
|
} else { |
|
return new KerberosKey[0]; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public KerberosKey[] getKKeys(KerberosPrincipal princ) { |
|
if (destroyed) { |
|
throw new IllegalStateException("This object is destroyed"); |
|
} |
|
ArrayList<KerberosKey> keys = new ArrayList<>(); |
|
if (kp != null && !princ.equals(kp)) { |
|
return new KerberosKey[0]; |
|
} |
|
for (KerberosKey k: kk) { |
|
if (k.getPrincipal().equals(princ)) { |
|
keys.add(k); |
|
} |
|
} |
|
for (KeyTab ktab: ktabs) { |
|
if (ktab.getPrincipal() == null && ktab.isBound()) { |
|
// legacy bound keytab. although we don't know who |
|
|
|
if (!allPrincs.contains(princ)) { |
|
continue; |
|
} |
|
} |
|
for (KerberosKey k: ktab.getKeys(princ)) { |
|
keys.add(k); |
|
} |
|
} |
|
return keys.toArray(new KerberosKey[keys.size()]); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public EncryptionKey[] getEKeys(PrincipalName princ) { |
|
if (destroyed) { |
|
throw new IllegalStateException("This object is destroyed"); |
|
} |
|
KerberosKey[] kkeys = getKKeys(new KerberosPrincipal(princ.getName())); |
|
if (kkeys.length == 0) { |
|
// Fallback: old JDK does not perform real name checking. If the |
|
// acceptor has host.sun.com but initiator requests for host, |
|
// as long as their keys match (i.e. keys for one can decrypt |
|
// the other's service ticket), the authentication is OK. |
|
// There are real customers depending on this to use different |
|
|
|
kkeys = getKKeys(); |
|
} |
|
EncryptionKey[] ekeys = new EncryptionKey[kkeys.length]; |
|
for (int i=0; i<ekeys.length; i++) { |
|
ekeys[i] = new EncryptionKey( |
|
kkeys[i].getEncoded(), kkeys[i].getKeyType(), |
|
new Integer(kkeys[i].getVersionNumber())); |
|
} |
|
return ekeys; |
|
} |
|
|
|
public Credentials getInitCred() { |
|
if (destroyed) { |
|
throw new IllegalStateException("This object is destroyed"); |
|
} |
|
if (tgt == null) { |
|
return null; |
|
} |
|
try { |
|
return Krb5Util.ticketToCreds(tgt); |
|
} catch (KrbException | IOException e) { |
|
return null; |
|
} |
|
} |
|
|
|
public void destroy() { |
|
// Do not wipe out real keys because they are references to the |
|
|
|
destroyed = true; |
|
kp = null; |
|
ktabs.clear(); |
|
kk.clear(); |
|
tgt = null; |
|
} |
|
} |