--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2001, 2013, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *
+ * (C) Copyright IBM Corp. 1999 All Rights Reserved.
+ * Copyright 1997 The Open Group Research Institute. All rights reserved.
+ */
+
+package sun.security.krb5.internal;
+
+import sun.security.krb5.*;
+import java.io.IOException;
+
+/**
+ * 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.
+ */
+public class CredentialsUtil {
+
+ private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
+
+ /**
+ * Used by a middle server to acquire credentials on behalf of a
+ * client to itself using the S4U2self extension.
+ * @param client the client to impersonate
+ * @param ccreds the TGT of the middle service
+ * @return the new creds (cname=client, sname=middle)
+ */
+ public static Credentials acquireS4U2selfCreds(PrincipalName client,
+ Credentials ccreds) throws KrbException, IOException {
+ String uRealm = client.getRealmString();
+ String localRealm = ccreds.getClient().getRealmString();
+ if (!uRealm.equals(localRealm)) {
+ // TODO: we do not support kerberos referral now
+ 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,
+ new PAForUserEnc(client,
+ ccreds.getSessionKey()).asn1Encode()));
+ Credentials creds = req.sendAndGetCreds();
+ 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");
+ }
+ return creds;
+ }
+
+ /**
+ * Used by a middle server to acquire a service ticket to a backend
+ * server using the S4U2proxy extension.
+ * @param backend the name of the backend service
+ * @param second the client's service ticket to the middle server
+ * @param ccreds the TGT of the middle server
+ * @return the creds (cname=client, sname=backend)
+ */
+ 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();
+ if (!creds.getClient().equals(client)) {
+ throw new KrbException("S4U2proxy request not honored by KDC");
+ }
+ return creds;
+ }
+
+ /**
+ * Acquires credentials for a specified service using initial
+ * credential. When the service has a different realm from the initial
+ * credential, we do cross-realm authentication - first, we use the
+ * current credential to get a cross-realm credential from the local KDC,
+ * then use that cross-realm credential to request service credential
+ * from the foreign KDC.
+ *
+ * @param service the name of service principal
+ * @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");
+ }
+ 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
+ * @param ccreds TGT in this realm
+ * @param okAsDelegate an [out] argument to receive the okAsDelegate
+ * property. True only if all realms allow delegation.
+ * @return the TGT for the other realm, null if cannot find a path
+ * @throws KrbException if something goes wrong
+ */
+ private static Credentials getTGTforRealm(String localRealm,
+ String serviceRealm, Credentials ccreds, boolean[] okAsDelegate)
+ throws KrbException {
+
+ // Get a list of realms to traverse
+ String[] realms = Realm.getRealmsList(localRealm, serviceRealm);
+
+ int i = 0, k = 0;
+ Credentials cTgt = null, newTgt = null, theTgt = null;
+ PrincipalName tempService = null;
+ String newTgtRealm = null;
+
+ okAsDelegate[0] = true;
+ for (cTgt = ccreds, i = 0; i < realms.length;) {
+ tempService = PrincipalName.tgsService(serviceRealm, realms[i]);
+
+ if (DEBUG) {
+ System.out.println(
+ ">>> Credentials acquireServiceCreds: main loop: ["
+ + i +"] tempService=" + tempService);
+ }
+
+ try {
+ newTgt = serviceCreds(tempService, cTgt);
+ } catch (Exception exc) {
+ newTgt = null;
+ }
+
+ if (newTgt == null) {
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "no tgt; searching thru capath");
+ }
+
+ /*
+ * No tgt found. Let's go thru the realms list one by one.
+ */
+ for (newTgt = null, k = i+1;
+ newTgt == null && k < realms.length; k++) {
+ tempService = PrincipalName.tgsService(realms[k], realms[i]);
+ if (DEBUG) {
+ System.out.println(
+ ">>> Credentials acquireServiceCreds: "
+ + "inner loop: [" + k
+ + "] tempService=" + tempService);
+ }
+ try {
+ newTgt = serviceCreds(tempService, cTgt);
+ } catch (Exception exc) {
+ newTgt = null;
+ }
+ }
+ } // Ends 'if (newTgt == null)'
+
+ if (newTgt == null) {
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "no tgt; cannot get creds");
+ }
+ break;
+ }
+
+ /*
+ * We have a tgt. It may or may not be for the target.
+ * If it's for the target realm, we're done looking for a tgt.
+ */
+ newTgtRealm = newTgt.getServer().getInstanceComponent();
+ if (okAsDelegate[0] && !newTgt.checkDelegate()) {
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: " +
+ "global OK-AS-DELEGATE turned off at " +
+ newTgt.getServer());
+ }
+ okAsDelegate[0] = false;
+ }
+
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "got tgt");
+ }
+
+ if (newTgtRealm.equals(serviceRealm)) {
+ /* We got the right tgt */
+ theTgt = newTgt;
+ break;
+ }
+
+ /*
+ * The new tgt is not for the target realm.
+ * See if the realm of the new tgt is in the list of realms
+ * and continue looking from there.
+ */
+ for (k = i+1; k < realms.length; k++) {
+ if (newTgtRealm.equals(realms[k])) {
+ break;
+ }
+ }
+
+ if (k < realms.length) {
+ /*
+ * (re)set the counter so we start looking
+ * from the realm we just obtained a tgt for.
+ */
+ i = k;
+ cTgt = newTgt;
+
+ if (DEBUG) {
+ System.out.println(">>> Credentials acquireServiceCreds: "
+ + "continuing with main loop counter reset to " + i);
+ }
+ continue;
+ }
+ else {
+ /*
+ * The new tgt's realm is not in the hierarchy of realms.
+ * It's probably not safe to get a tgt from
+ * a tgs that is outside the known list of realms.
+ * Give up now.
+ */
+ break;
+ }
+ } // Ends outermost/main 'for' loop
+
+ return theTgt;
+ }
+
+ /*
+ * 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();
+ }
+}