230 lines · 8.9 KB · Java
RawDownload
/* * Copyright (c) 2011, 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 javax.security.auth.kerberos; import java.io.File;import java.util.Objects;import sun.misc.SharedSecrets;import sun.security.krb5.EncryptionKey;import sun.security.krb5.PrincipalName;import sun.security.krb5.RealmException; /** * This class encapsulates a keytab file. * <p> * A Kerberos JAAS login module that obtains long term secret keys from a * keytab file should use this class. The login module will store * an instance of this class in the private credential set of a * {@link javax.security.auth.Subject Subject} during the commit phase of the * authentication process. * <p> * It might be necessary for the application to be granted a * {@link javax.security.auth.PrivateCredentialPermission * PrivateCredentialPermission} if it needs to access the KeyTab * instance from a Subject. This permission is not needed when the * application depends on the default JGSS Kerberos mechanism to access the * KeyTab. In that case, however, the application will need an appropriate * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}. * <p> * The keytab file format is described at * <a href="http://www.ioplex.com/utilities/keytab.txt"> * http://www.ioplex.com/utilities/keytab.txt</a>. * * @since 1.7 */public final class KeyTab {     /*     * Impl notes:     *     * This class is only a name, a permanent link to the keytab source     * (can be missing). Itself has no content. In order to read content,     * take a snapshot and read from it.     *     * The snapshot is of type sun.security.krb5.internal.ktab.KeyTab, which     * contains the content of the keytab file when the snapshot is taken.     * Itself has no refresh function and mostly an immutable class (except     * for the create/add/save methods only used by the ktab command).     */     // Source, null if using the default one. Note that the default name    // is maintained in snapshot, this field is never "resolved".    private final File file;     // Set up JavaxSecurityAuthKerberosAccess in SharedSecrets    static {        SharedSecrets.setJavaxSecurityAuthKerberosAccess(                new JavaxSecurityAuthKerberosAccessImpl());    }     private KeyTab(File file) {        this.file = file;    }     /**     * Returns a {@code KeyTab} instance from a {@code File} object.     * <p>     * The result of this method is never null. This method only associates     * the returned {@code KeyTab} object with the file and does not read it.     * @param file the keytab {@code File} object, must not be null     * @return the keytab instance     * @throws NullPointerException if the {@code file} argument is null     */    public static KeyTab getInstance(File file) {        if (file == null) {            throw new NullPointerException("file must be non null");        }        return new KeyTab(file);    }     /**     * Returns the default {@code KeyTab} instance.     * <p>     * The result of this method is never null. This method only associates     * the returned {@code KeyTab} object with the default keytab file and     * does not read it.     * @return the default keytab instance.     */    public static KeyTab getInstance() {        return new KeyTab(null);    }     //Takes a snapshot of the keytab content    private sun.security.krb5.internal.ktab.KeyTab takeSnapshot() {        return sun.security.krb5.internal.ktab.KeyTab.getInstance(file);    }     /**     * Returns fresh keys for the given Kerberos principal.     * <p>     * Implementation of this method should make sure the returned keys match     * the latest content of the keytab file. The result is a newly created     * copy that can be modified by the caller without modifying the keytab     * object. The caller should {@link KerberosKey#destroy() destroy} the     * result keys after they are used.     * <p>     * Please note that the keytab file can be created after the     * {@code KeyTab} object is instantiated and its content may change over     * time. Therefore, an application should call this method only when it     * needs to use the keys. Any previous result from an earlier invocation     * could potentially be expired.     * <p>     * If there is any error (say, I/O error or format error)     * during the reading process of the KeyTab file, a saved result should be     * returned. If there is no saved result (say, this is the first time this     * method is called, or, all previous read attempts failed), an empty array     * should be returned. This can make sure the result is not drastically     * changed during the (probably slow) update of the keytab file.     * <p>     * Each time this method is called and the reading of the file succeeds     * with no exception (say, I/O error or file format error),     * the result should be saved for {@code principal}. The implementation can     * also save keys for other principals having keys in the same keytab object     * if convenient.     * <p>     * Any unsupported key read from the keytab is ignored and not included     * in the result.     *     * @param principal the Kerberos principal, must not be null.     * @return the keys (never null, may be empty)     * @throws NullPointerException if the {@code principal}     * argument is null     * @throws SecurityException if a security manager exists and the read     * access to the keytab file is not permitted     */    public KerberosKey[] getKeys(KerberosPrincipal principal) {        try {            EncryptionKey[] keys = takeSnapshot().readServiceKeys(                    new PrincipalName(principal.getName()));            KerberosKey[] kks = new KerberosKey[keys.length];            for (int i=0; i<kks.length; i++) {                Integer tmp = keys[i].getKeyVersionNumber();                kks[i] = new KerberosKey(                        principal,                        keys[i].getBytes(),                        keys[i].getEType(),                        tmp == null ? 0 : tmp.intValue());                keys[i].destroy();            }            return kks;        } catch (RealmException re) {            return new KerberosKey[0];        }    }     EncryptionKey[] getEncryptionKeys(PrincipalName principal) {        return takeSnapshot().readServiceKeys(principal);    }     /**     * Checks if the keytab file exists. Implementation of this method     * should make sure that the result matches the latest status of the     * keytab file.     * <p>     * The caller can use the result to determine if it should fallback to     * another mechanism to read the keys.     * @return true if the keytab file exists; false otherwise.     * @throws SecurityException if a security manager exists and the read     * access to the keytab file is not permitted     */    public boolean exists() {        return !takeSnapshot().isMissing();    }     public String toString() {        return file == null ? "Default keytab" : file.toString();    }     /**     * Returns a hashcode for this KeyTab.     *     * @return a hashCode() for the <code>KeyTab</code>     */    public int hashCode() {        return Objects.hash(file);    }     /**     * Compares the specified Object with this KeyTab for equality.     * Returns true if the given object is also a     * <code>KeyTab</code> and the two     * <code>KeyTab</code> instances are equivalent.     *     * @param other the Object to compare to     * @return true if the specified object is equal to this KeyTab     */    public boolean equals(Object other) {        if (other == this)            return true;         if (! (other instanceof KeyTab)) {            return false;        }         KeyTab otherKtab = (KeyTab) other;        return Objects.equals(otherKtab.file, file);    }}