alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ServiceCreds.java)

This example Java source code file (ServiceCreds.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

arraylist, encryptionkey, illegalstateexception, ioexception, kerberoskey, kerberosprincipal, keytab, list, principalname, servicecreds, set, string, this, util

The ServiceCreds.java Java example source code

/*
 * Copyright (c) 2012, 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.
 */

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;

/**
 * Credentials of a kerberos acceptor. A KerberosPrincipal object (kp) is
 * the principal. It can be specified as the serverPrincipal argument
 * in the getInstance() method, or uses only KerberosPrincipal in the subject.
 * Otherwise, the creds object is unbound and kp is null.
 *
 * The class also encapsulates various secrets, which can be:
 *
 *   1. Some KerberosKeys (generated from password)
 *   2. Some KeyTabs (for a typical service based on keytabs)
 *   3. A TGT (for S4U2proxy extension or user2user)
 *
 * Note that some secrets can coexist. For example, a user2user service
 * can use its keytab (or keys) if the client can successfully obtain a
 * normal service ticket, or it can use the TGT (actually, the session key
 * of the TGT) if the client can only acquire a service ticket
 * of ENC-TKT-IN-SKEY style.
 *
 * @since 1.8
 */
public final class ServiceCreds {
    // The principal, or null if unbound
    private KerberosPrincipal kp;

    // All principals in the subject's princ set
    private Set<KerberosPrincipal> allPrincs;

    // All private credentials that can be used
    private List<KeyTab> ktabs;
    private List<KerberosKey> kk;
    private KerberosTicket tgt;

    private boolean destroyed;

    private ServiceCreds() {
        // Make sure this class cannot be instantiated externally.
    }

    /**
     * Creates a ServiceCreds object based on info in a Subject for
     * a given principal name (if specified).
     * @return the object, or null if there is no private creds for it
     */
    public static ServiceCreds getInstance(
            Subject subj, String serverPrincipal) {

        ServiceCreds sc = new ServiceCreds();

        sc.allPrincs =
                subj.getPrincipals(KerberosPrincipal.class);

        // Compatibility. A key implies its own principal
        for (KerberosKey key: SubjectComber.findMany(
                subj, serverPrincipal, null, KerberosKey.class)) {
            sc.allPrincs.add(key.getPrincipal());
        }

        if (serverPrincipal != null) {      // A named principal
            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
            // only one KerberosPrincipal and there is no unbound keytabs
            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;
    }

    // can be null
    public String getName() {
        if (destroyed) {
            throw new IllegalStateException("This object is destroyed");
        }
        return kp == null ? null : kp.getName();
    }

    /**
     * Gets keys for "someone". Used in 2 cases:
     * 1. By TLS because it needs to get keys before client comes in.
     * 2. As a fallback in getEKeys() below.
     * This method can still return an empty array.
     */
    public KerberosKey[] getKKeys() {
        if (destroyed) {
            throw new IllegalStateException("This object is destroyed");
        }
        KerberosPrincipal one = kp;                 // named principal
        if (one == null && !allPrincs.isEmpty()) {  // or, a known principal
            one = allPrincs.iterator().next();
        }
        if (one == null) {                          // Or, some random one
            for (KeyTab ktab: ktabs) {
                // Must be unbound keytab, otherwise, allPrincs is not empty
                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];
        }
    }

    /**
     * Get kkeys for a principal,
     * @param princ the target name initiator requests. Not null.
     * @return keys for the princ, never null, might be empty
     */
    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)) {      // named principal
            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
                // the bound principal is, it must be in allPrincs
                if (!allPrincs.contains(princ)) {
                    continue;   // skip this legacy bound keytab
                }
            }
            for (KerberosKey k: ktab.getKeys(princ)) {
                keys.add(k);
            }
        }
        return keys.toArray(new KerberosKey[keys.size()]);
    }

    /**
     * Gets EKeys for a principal.
     * @param princ the target name initiator requests. Not null.
     * @return keys for the princ, never null, might be empty
     */
    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
            // names for a single service.
            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
        // priv creds in subject. Just make it useless.
        destroyed = true;
        kp = null;
        ktabs.clear();
        kk.clear();
        tgt = null;
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java ServiceCreds.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.