CredentialsUtil.java 11.5 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * 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
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * 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.
 *
21 22 23
 * 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.
D
duke 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 */

/*
 *
 *  (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;

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    /**
     * 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");
        }
61 62 63
        if (!ccreds.isForwardable()) {
            throw new KrbException("S4U2self needs a FORWARDABLE ticket");
        }
64 65 66 67 68 69 70 71 72 73
        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");
        }
74 75 76
        if (!creds.isForwardable()) {
            throw new KrbException("S4U2self ticket must be FORWARDABLE");
        }
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
        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
     */
D
duke 已提交
114 115
    public static Credentials acquireServiceCreds(
                String service, Credentials ccreds)
116
            throws KrbException, IOException {
117
        PrincipalName sname = new PrincipalName(service);
D
duke 已提交
118 119 120
        String serviceRealm = sname.getRealmString();
        String localRealm = ccreds.getClient().getRealmString();

121 122 123 124 125
        if (localRealm.equals(serviceRealm)) {
            if (DEBUG) {
                System.out.println(
                        ">>> Credentials acquireServiceCreds: same realm");
            }
D
duke 已提交
126 127
            return serviceCreds(sname, ccreds);
        }
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
        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
169
     * @param serviceRealm the other realm, cannot equals to localRealm
170 171 172 173 174 175 176 177 178
     * @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 {
D
duke 已提交
179 180 181 182 183 184

        // 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;
185
        PrincipalName tempService = null;
186
        String newTgtRealm = null;
D
duke 已提交
187

188 189
        okAsDelegate[0] = true;
        for (cTgt = ccreds, i = 0; i < realms.length;) {
190
            tempService = PrincipalName.tgsService(serviceRealm, realms[i]);
D
duke 已提交
191

192 193 194 195
            if (DEBUG) {
                System.out.println(
                        ">>> Credentials acquireServiceCreds: main loop: ["
                        + i +"] tempService=" + tempService);
D
duke 已提交
196 197 198 199 200 201 202 203
            }

            try {
                newTgt = serviceCreds(tempService, cTgt);
            } catch (Exception exc) {
                newTgt = null;
            }

204 205 206
            if (newTgt == null) {
                if (DEBUG) {
                    System.out.println(">>> Credentials acquireServiceCreds: "
207
                            + "no tgt; searching thru capath");
D
duke 已提交
208 209 210
                }

                /*
211
                 * No tgt found. Let's go thru the realms list one by one.
D
duke 已提交
212
                 */
213 214
                for (newTgt = null, k = i+1;
                        newTgt == null && k < realms.length; k++) {
215
                    tempService = PrincipalName.tgsService(realms[k], realms[i]);
216 217 218 219 220
                    if (DEBUG) {
                        System.out.println(
                                ">>> Credentials acquireServiceCreds: "
                                + "inner loop: [" + k
                                + "] tempService=" + tempService);
D
duke 已提交
221 222 223 224 225 226 227 228 229
                    }
                    try {
                        newTgt = serviceCreds(tempService, cTgt);
                    } catch (Exception exc) {
                        newTgt = null;
                    }
                }
            } // Ends 'if (newTgt == null)'

230 231 232 233
            if (newTgt == null) {
                if (DEBUG) {
                    System.out.println(">>> Credentials acquireServiceCreds: "
                            + "no tgt; cannot get creds");
D
duke 已提交
234 235 236 237 238 239 240 241 242
                }
                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();
243 244
            if (okAsDelegate[0] && !newTgt.checkDelegate()) {
                if (DEBUG) {
W
weijun 已提交
245 246 247 248
                    System.out.println(">>> Credentials acquireServiceCreds: " +
                            "global OK-AS-DELEGATE turned off at " +
                            newTgt.getServer());
                }
249
                okAsDelegate[0] = false;
W
weijun 已提交
250
            }
D
duke 已提交
251

252 253 254
            if (DEBUG) {
                System.out.println(">>> Credentials acquireServiceCreds: "
                        + "got tgt");
D
duke 已提交
255 256
            }

257
            if (newTgtRealm.equals(serviceRealm)) {
D
duke 已提交
258 259 260 261 262 263 264 265 266 267
                /* 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.
             */
268 269
            for (k = i+1; k < realms.length; k++) {
                if (newTgtRealm.equals(realms[k])) {
D
duke 已提交
270 271 272 273
                    break;
                }
            }

274
            if (k < realms.length) {
D
duke 已提交
275 276 277 278 279 280 281
                /*
                 * (re)set the counter so we start looking
                 * from the realm we just obtained a tgt for.
                 */
                i = k;
                cTgt = newTgt;

282 283 284
                if (DEBUG) {
                    System.out.println(">>> Credentials acquireServiceCreds: "
                            + "continuing with main loop counter reset to " + i);
D
duke 已提交
285 286 287
                }
                continue;
            }
288
            else {
D
duke 已提交
289
                /*
290
                 * The new tgt's realm is not in the hierarchy of realms.
D
duke 已提交
291 292 293 294 295 296 297 298
                 * 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

299
        return theTgt;
D
duke 已提交
300 301 302 303 304 305
    }

   /*
    * This method does the real job to request the service credential.
    */
    private static Credentials serviceCreds(
306
            PrincipalName service, Credentials ccreds)
D
duke 已提交
307 308 309 310
            throws KrbException, IOException {
        return new KrbTgsReq(ccreds, service).sendAndGetCreds();
    }
}