Krb5Util.java 11.7 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2003, 2019, 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
 */

package sun.security.jgss.krb5;

import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
W
weijun 已提交
31
import javax.security.auth.kerberos.KeyTab;
D
duke 已提交
32 33 34 35
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import java.security.AccessControlContext;
import sun.security.jgss.GSSUtil;
36
import sun.security.jgss.GSSCaller;
D
duke 已提交
37 38 39 40 41

import sun.security.krb5.Credentials;
import sun.security.krb5.EncryptionKey;
import sun.security.krb5.KrbException;
import java.io.IOException;
W
weijun 已提交
42
import java.util.ArrayList;
D
duke 已提交
43
import java.util.List;
44
import sun.security.krb5.KerberosSecrets;
W
weijun 已提交
45
import sun.security.krb5.PrincipalName;
D
duke 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
/**
 * Utilities for obtaining and converting Kerberos tickets.
 *
 */
public class Krb5Util {

    static final boolean DEBUG =
        java.security.AccessController.doPrivileged(
            new sun.security.action.GetBooleanAction
            ("sun.security.krb5.debug")).booleanValue();

    /**
     * Default constructor
     */
    private Krb5Util() {  // Cannot create one of these
    }

    /**
     * Retrieve the service ticket for serverPrincipal from caller's Subject
     * or from Subject obtained by logging in, or if not found, via the
     * Ticket Granting Service using the TGT obtained from the Subject.
     *
     * Caller must have permission to:
     *    - access and update Subject's private credentials
     *    - create LoginContext
     *    - read the auth.login.defaultCallbackHandler security property
     *
     * NOTE: This method is used by JSSE Kerberos Cipher Suites
     */
75
    public static KerberosTicket getTicketFromSubjectAndTgs(GSSCaller caller,
D
duke 已提交
76 77 78 79 80 81
        String clientPrincipal, String serverPrincipal, String tgsPrincipal,
        AccessControlContext acc)
        throws LoginException, KrbException, IOException {

        // 1. Try to find service ticket in acc subject
        Subject accSubj = Subject.getSubject(acc);
W
weijun 已提交
82
        KerberosTicket ticket = SubjectComber.find(accSubj,
D
duke 已提交
83 84 85 86 87 88 89 90 91 92 93
            serverPrincipal, clientPrincipal, KerberosTicket.class);

        if (ticket != null) {
            return ticket;  // found it
        }

        Subject loginSubj = null;
        if (!GSSUtil.useSubjectCredsOnly(caller)) {
            // 2. Try to get ticket from login
            try {
                loginSubj = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
W
weijun 已提交
94
                ticket = SubjectComber.find(loginSubj,
D
duke 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108
                    serverPrincipal, clientPrincipal, KerberosTicket.class);
                if (ticket != null) {
                    return ticket; // found it
                }
            } catch (LoginException e) {
                // No login entry to use
                // ignore and continue
            }
        }

        // Service ticket not found in subject or login
        // Try to get TGT to acquire service ticket

        // 3. Try to get TGT from acc subject
W
weijun 已提交
109
        KerberosTicket tgt = SubjectComber.find(accSubj,
D
duke 已提交
110 111 112 113 114
            tgsPrincipal, clientPrincipal, KerberosTicket.class);

        boolean fromAcc;
        if (tgt == null && loginSubj != null) {
            // 4. Try to get TGT from login subject
W
weijun 已提交
115
            tgt = SubjectComber.find(loginSubj,
D
duke 已提交
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
                tgsPrincipal, clientPrincipal, KerberosTicket.class);
            fromAcc = false;
        } else {
            fromAcc = true;
        }

        // 5. Try to get service ticket using TGT
        if (tgt != null) {
            Credentials tgtCreds = ticketToCreds(tgt);
            Credentials serviceCreds = Credentials.acquireServiceCreds(
                        serverPrincipal, tgtCreds);
            if (serviceCreds != null) {
                ticket = credsToTicket(serviceCreds);

                // Store service ticket in acc's Subject
                if (fromAcc && accSubj != null && !accSubj.isReadOnly()) {
                    accSubj.getPrivateCredentials().add(ticket);
                }
            }
        }
        return ticket;
    }

    /**
     * Retrieves the ticket corresponding to the client/server principal
     * pair from the Subject in the specified AccessControlContext.
     */
143
    static KerberosTicket getServiceTicket(GSSCaller caller,
D
duke 已提交
144 145 146 147 148
        String clientPrincipal, String serverPrincipal,
        AccessControlContext acc) throws LoginException {

        // Try to get ticket from acc's Subject
        Subject accSubj = Subject.getSubject(acc);
W
weijun 已提交
149
        KerberosTicket ticket =
D
duke 已提交
150 151 152
            SubjectComber.find(accSubj, serverPrincipal, clientPrincipal,
                  KerberosTicket.class);

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
        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);

D
duke 已提交
173 174 175
        // 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);
W
weijun 已提交
176
            ticket = SubjectComber.find(subject,
177
                    null, clientPrincipal, KerberosTicket.class);
D
duke 已提交
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
        }
        return ticket;
    }

    /**
     * Retrieves the caller's Subject, or Subject obtained by logging in
     * via the specified caller.
     *
     * Caller must have permission to:
     *    - access the Subject
     *    - create LoginContext
     *    - read the auth.login.defaultCallbackHandler security property
     *
     * NOTE: This method is used by JSSE Kerberos Cipher Suites
     */
193
    public static Subject getSubject(GSSCaller caller,
D
duke 已提交
194 195 196 197 198 199 200 201 202 203 204 205
        AccessControlContext acc) throws LoginException {

        // Try to get the Subject from acc
        Subject subject = Subject.getSubject(acc);

        // Try to get Subject obtained from GSSUtil
        if (subject == null && !GSSUtil.useSubjectCredsOnly(caller)) {
            subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
        }
        return subject;
    }

W
weijun 已提交
206 207 208 209 210 211 212 213
    /**
     * Retrieves the ServiceCreds for the specified server principal from
     * the Subject in the specified AccessControlContext. If not found, and if
     * useSubjectCredsOnly is false, then obtain from a LoginContext.
     *
     * NOTE: This method is also used by JSSE Kerberos Cipher Suites
     */
    public static ServiceCreds getServiceCreds(GSSCaller caller,
D
duke 已提交
214 215 216 217
        String serverPrincipal, AccessControlContext acc)
                throws LoginException {

        Subject accSubj = Subject.getSubject(acc);
W
weijun 已提交
218 219 220
        ServiceCreds sc = null;
        if (accSubj != null) {
            sc = ServiceCreds.getInstance(accSubj, serverPrincipal);
D
duke 已提交
221
        }
W
weijun 已提交
222 223 224
        if (sc == null && !GSSUtil.useSubjectCredsOnly(caller)) {
            Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
            sc = ServiceCreds.getInstance(subject, serverPrincipal);
D
duke 已提交
225
        }
W
weijun 已提交
226
        return sc;
D
duke 已提交
227 228 229 230
    }

    public static KerberosTicket credsToTicket(Credentials serviceCreds) {
        EncryptionKey sessionKey =  serviceCreds.getSessionKey();
231
        KerberosTicket kt = new KerberosTicket(
D
duke 已提交
232 233 234 235 236 237 238 239 240 241 242 243
            serviceCreds.getEncoded(),
            new KerberosPrincipal(serviceCreds.getClient().getName()),
            new KerberosPrincipal(serviceCreds.getServer().getName(),
                                KerberosPrincipal.KRB_NT_SRV_INST),
            sessionKey.getBytes(),
            sessionKey.getEType(),
            serviceCreds.getFlags(),
            serviceCreds.getAuthTime(),
            serviceCreds.getStartTime(),
            serviceCreds.getEndTime(),
            serviceCreds.getRenewTill(),
            serviceCreds.getClientAddresses());
244 245 246 247 248 249 250 251 252 253 254 255 256
        PrincipalName clientAlias = serviceCreds.getClientAlias();
        PrincipalName serverAlias = serviceCreds.getServerAlias();
        if (clientAlias != null) {
            KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
                    .kerberosTicketSetClientAlias(kt, new KerberosPrincipal(
                            clientAlias.getName(), clientAlias.getNameType()));
        }
        if (serverAlias != null) {
            KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
                    .kerberosTicketSetServerAlias(kt, new KerberosPrincipal(
                            serverAlias.getName(), serverAlias.getNameType()));
        }
        return kt;
D
duke 已提交
257 258 259
    };

    public static Credentials ticketToCreds(KerberosTicket kerbTicket)
260
            throws KrbException, IOException {
261 262 263 264 265 266
        KerberosPrincipal clientAlias = KerberosSecrets
                .getJavaxSecurityAuthKerberosAccess()
                .kerberosTicketGetClientAlias(kerbTicket);
        KerberosPrincipal serverAlias = KerberosSecrets
                .getJavaxSecurityAuthKerberosAccess()
                .kerberosTicketGetServerAlias(kerbTicket);
D
duke 已提交
267 268 269
        return new Credentials(
            kerbTicket.getEncoded(),
            kerbTicket.getClient().getName(),
270
            (clientAlias != null ? clientAlias.getName() : null),
D
duke 已提交
271
            kerbTicket.getServer().getName(),
272
            (serverAlias != null ? serverAlias.getName() : null),
D
duke 已提交
273 274 275 276 277 278 279 280 281
            kerbTicket.getSessionKey().getEncoded(),
            kerbTicket.getSessionKeyType(),
            kerbTicket.getFlags(),
            kerbTicket.getAuthTime(),
            kerbTicket.getStartTime(),
            kerbTicket.getEndTime(),
            kerbTicket.getRenewTill(),
            kerbTicket.getClientAddresses());
    }
W
weijun 已提交
282

283 284 285 286 287 288 289 290 291 292 293
    /**
     * A helper method to get a sun..KeyTab from a javax..KeyTab
     * @param ktab the javax..KeyTab object
     * @return the sun..KeyTab object
     */
    public static sun.security.krb5.internal.ktab.KeyTab
            snapshotFromJavaxKeyTab(KeyTab ktab) {
        return KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
                .keyTabTakeSnapshot(ktab);
    }

W
weijun 已提交
294 295
    /**
     * A helper method to get EncryptionKeys from a javax..KeyTab
296
     * @param ktab the javax..KeyTab object
W
weijun 已提交
297 298 299 300 301
     * @param cname the PrincipalName
     * @return the EKeys, never null, might be empty
     */
    public static EncryptionKey[] keysFromJavaxKeyTab(
            KeyTab ktab, PrincipalName cname) {
302
        return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname);
W
weijun 已提交
303
    }
D
duke 已提交
304
}