< prev index next >
src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java
Print this page
rev 54745 : 8215032: Support Kerberos cross-realm referrals (RFC 6806)
Reviewed-by: weijun
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
@@ -31,10 +31,13 @@
package sun.security.krb5.internal;
import sun.security.krb5.*;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
/**
* This class is a utility that contains much of the TGS-Exchange
* protocol. It is used by ../Credentials.java for service ticket
* acquisition in both the normal and the x-realm case.
@@ -59,17 +62,15 @@
throw new KrbException("Cross realm impersonation not supported");
}
if (!ccreds.isForwardable()) {
throw new KrbException("S4U2self needs a FORWARDABLE ticket");
}
- KrbTgsReq req = new KrbTgsReq(
- ccreds,
- ccreds.getClient(),
- new PAData(Krb5.PA_FOR_USER,
+ Credentials creds = serviceCreds(KDCOptions.with(KDCOptions.FORWARDABLE),
+ ccreds, ccreds.getClient(), ccreds.getClient(), null,
+ new PAData[] {new PAData(Krb5.PA_FOR_USER,
new PAForUserEnc(client,
- ccreds.getSessionKey()).asn1Encode()));
- Credentials creds = req.sendAndGetCreds();
+ ccreds.getSessionKey()).asn1Encode())});
if (!creds.getClient().equals(client)) {
throw new KrbException("S4U2self request not honored by KDC");
}
if (!creds.isForwardable()) {
throw new KrbException("S4U2self ticket must be FORWARDABLE");
@@ -87,15 +88,14 @@
*/
public static Credentials acquireS4U2proxyCreds(
String backend, Ticket second,
PrincipalName client, Credentials ccreds)
throws KrbException, IOException {
- KrbTgsReq req = new KrbTgsReq(
- ccreds,
- second,
- new PrincipalName(backend));
- Credentials creds = req.sendAndGetCreds();
+ Credentials creds = serviceCreds(KDCOptions.with(
+ KDCOptions.CNAME_IN_ADDL_TKT, KDCOptions.FORWARDABLE),
+ ccreds, ccreds.getClient(), new PrincipalName(backend),
+ new Ticket[] {second}, null);
if (!creds.getClient().equals(client)) {
throw new KrbException("S4U2proxy request not honored by KDC");
}
return creds;
}
@@ -112,58 +112,14 @@
* @param ccreds client's initial credential
*/
public static Credentials acquireServiceCreds(
String service, Credentials ccreds)
throws KrbException, IOException {
- PrincipalName sname = new PrincipalName(service);
- String serviceRealm = sname.getRealmString();
- String localRealm = ccreds.getClient().getRealmString();
-
- if (localRealm.equals(serviceRealm)) {
- if (DEBUG) {
- System.out.println(
- ">>> Credentials acquireServiceCreds: same realm");
- }
+ PrincipalName sname = new PrincipalName(service,
+ PrincipalName.KRB_NT_SRV_HST);
return serviceCreds(sname, ccreds);
}
- Credentials theCreds = null;
-
- boolean[] okAsDelegate = new boolean[1];
- Credentials theTgt = getTGTforRealm(localRealm, serviceRealm,
- ccreds, okAsDelegate);
- if (theTgt != null) {
- if (DEBUG) {
- System.out.println(">>> Credentials acquireServiceCreds: "
- + "got right tgt");
- System.out.println(">>> Credentials acquireServiceCreds: "
- + "obtaining service creds for " + sname);
- }
-
- try {
- theCreds = serviceCreds(sname, theTgt);
- } catch (Exception exc) {
- if (DEBUG) {
- System.out.println(exc);
- }
- theCreds = null;
- }
- }
-
- if (theCreds != null) {
- if (DEBUG) {
- System.out.println(">>> Credentials acquireServiceCreds: "
- + "returning creds:");
- Credentials.printDebug(theCreds);
- }
- if (!okAsDelegate[0]) {
- theCreds.resetDelegate();
- }
- return theCreds;
- }
- throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
- "No service creds");
- }
/**
* Gets a TGT to another realm
* @param localRealm this realm
* @param serviceRealm the other realm, cannot equals to localRealm
@@ -303,8 +259,137 @@
* This method does the real job to request the service credential.
*/
private static Credentials serviceCreds(
PrincipalName service, Credentials ccreds)
throws KrbException, IOException {
- return new KrbTgsReq(ccreds, service).sendAndGetCreds();
+ return serviceCreds(new KDCOptions(), ccreds,
+ ccreds.getClient(), service, null, null);
+ }
+
+ private static Credentials serviceCreds(
+ KDCOptions options, Credentials asCreds,
+ PrincipalName cname, PrincipalName sname,
+ Ticket[] additionalTickets, PAData[] extraPAs)
+ throws KrbException, IOException {
+ if (!Config.DISABLE_REFERRALS) {
+ try {
+ return serviceCredsReferrals(options, asCreds,
+ cname, sname, additionalTickets, extraPAs);
+ } catch (KrbException e) {
+ // Server may raise an error if CANONICALIZE is true.
+ // Try CANONICALIZE false.
+ }
+ }
+ return serviceCredsSingle(options, asCreds,
+ cname, sname, additionalTickets, extraPAs);
+ }
+
+ private static Credentials serviceCredsReferrals(
+ KDCOptions options, Credentials asCreds,
+ PrincipalName cname, PrincipalName sname,
+ Ticket[] additionalTickets, PAData[] extraPAs)
+ throws KrbException, IOException {
+ options = new KDCOptions(options.toBooleanArray());
+ options.set(KDCOptions.CANONICALIZE, true);
+ PrincipalName cSname = (PrincipalName) sname.clone();
+ Credentials creds = null;
+ boolean isReferral = false;
+ List<String> referrals = new LinkedList<>();
+ while (referrals.size() <= Config.MAX_REFERRALS) {
+ ReferralsCache.ReferralCacheEntry ref =
+ ReferralsCache.get(sname, cSname.getRealmString());
+ String toRealm = null;
+ if (ref == null) {
+ creds = serviceCredsSingle(options, asCreds,
+ cname, cSname, additionalTickets, extraPAs);
+ PrincipalName server = creds.getServer();
+ if (!cSname.equals(server)) {
+ String[] serverNameStrings = server.getNameStrings();
+ if (serverNameStrings.length == 2 &&
+ serverNameStrings[0].equals(
+ PrincipalName.TGS_DEFAULT_SRV_NAME) &&
+ !cSname.getRealmAsString().equals(serverNameStrings[1])) {
+ // Server Name (sname) has the following format:
+ // krbtgt/TO-REALM.COM@FROM-REALM.COM
+ ReferralsCache.put(sname, server.getRealmString(),
+ serverNameStrings[1], creds);
+ toRealm = serverNameStrings[1];
+ isReferral = true;
+ asCreds = creds;
+ }
+ }
+ } else {
+ toRealm = ref.getToRealm();
+ asCreds = ref.getCreds();
+ isReferral = true;
+ }
+ if (isReferral) {
+ if (referrals.contains(toRealm)) {
+ // Referrals loop detected
+ return null;
+ }
+ cSname = new PrincipalName(cSname.getNameString(),
+ cSname.getNameType(), toRealm);
+ referrals.add(toRealm);
+ isReferral = false;
+ continue;
+ }
+ break;
+ }
+ return creds;
+ }
+
+ private static Credentials serviceCredsSingle(
+ KDCOptions options, Credentials asCreds,
+ PrincipalName cname, PrincipalName sname,
+ Ticket[] additionalTickets, PAData[] extraPAs)
+ throws KrbException, IOException {
+ Credentials theCreds = null;
+ boolean[] okAsDelegate = new boolean[]{true};
+ String[] serverAsCredsNames = asCreds.getServer().getNameStrings();
+ if (serverAsCredsNames.length == 2 &&
+ serverAsCredsNames[0].equals(
+ PrincipalName.TGS_DEFAULT_SRV_NAME)) {
+ String tgtRealm = serverAsCredsNames[1];
+ String serviceRealm = sname.getRealmString();
+ if (!serviceRealm.equals(tgtRealm)) {
+ // This is a cross-realm service request
+ if (DEBUG) {
+ System.out.println(">>> serviceCredsSingle:" +
+ " cross-realm authentication");
+ System.out.println(">>> serviceCredsSingle:" +
+ " obtaining credentials from " + tgtRealm +
+ " to " + serviceRealm);
+ }
+ Credentials newTgt = getTGTforRealm(tgtRealm, serviceRealm,
+ asCreds, okAsDelegate);
+ if (newTgt == null) {
+ throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
+ "No service creds");
+ }
+ if (DEBUG) {
+ System.out.println(">>> Cross-realm TGT Credentials" +
+ " serviceCredsSingle: ");
+ Credentials.printDebug(newTgt);
+ }
+ asCreds = newTgt;
+ cname = asCreds.getClient();
+ } else if (DEBUG) {
+ System.out.println(">>> Credentials serviceCredsSingle:" +
+ " same realm");
+ }
+ }
+ KrbTgsReq req = new KrbTgsReq(options, asCreds,
+ cname, sname, additionalTickets, extraPAs);
+ theCreds = req.sendAndGetCreds();
+ if (theCreds != null) {
+ if (DEBUG) {
+ System.out.println(">>> TGS credentials serviceCredsSingle:");
+ Credentials.printDebug(theCreds);
+ }
+ if (!okAsDelegate[0]) {
+ theCreds.resetDelegate();
+ }
+ }
+ return theCreds;
}
}
< prev index next >