Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java
38918 views
/*1* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth.kerberos;2627import java.io.File;28import java.security.AccessControlException;29import java.util.Objects;30import sun.security.krb5.EncryptionKey;31import sun.security.krb5.KerberosSecrets;32import sun.security.krb5.PrincipalName;33import sun.security.krb5.RealmException;3435/**36* This class encapsulates a keytab file.37* <p>38* A Kerberos JAAS login module that obtains long term secret keys from a39* keytab file should use this class. The login module will store40* an instance of this class in the private credential set of a41* {@link javax.security.auth.Subject Subject} during the commit phase of the42* authentication process.43* <p>44* If a {@code KeyTab} object is obtained from {@link #getUnboundInstance()}45* or {@link #getUnboundInstance(java.io.File)}, it is unbound and thus can be46* used by any service principal. Otherwise, if it's obtained from47* {@link #getInstance(KerberosPrincipal)} or48* {@link #getInstance(KerberosPrincipal, java.io.File)}, it is bound to the49* specific service principal and can only be used by it.50* <p>51* Please note the constructors {@link #getInstance()} and52* {@link #getInstance(java.io.File)} were created when there was no support53* for unbound keytabs. These methods should not be used anymore. An object54* created with either of these methods are considered to be bound to an55* unknown principal, which means, its {@link #isBound()} returns true and56* {@link #getPrincipal()} returns null.57* <p>58* It might be necessary for the application to be granted a59* {@link javax.security.auth.PrivateCredentialPermission60* PrivateCredentialPermission} if it needs to access the KeyTab61* instance from a Subject. This permission is not needed when the62* application depends on the default JGSS Kerberos mechanism to access the63* KeyTab. In that case, however, the application will need an appropriate64* {@link javax.security.auth.kerberos.ServicePermission ServicePermission}.65* <p>66* The keytab file format is described at67* <a href="http://www.ioplex.com/utilities/keytab.txt">68* http://www.ioplex.com/utilities/keytab.txt</a>.69* <p>70* @since 1.771*/72public final class KeyTab {7374/*75* Impl notes:76*77* This class is only a name, a permanent link to the keytab source78* (can be missing). Itself has no content. In order to read content,79* take a snapshot and read from it.80*81* The snapshot is of type sun.security.krb5.internal.ktab.KeyTab, which82* contains the content of the keytab file when the snapshot is taken.83* Itself has no refresh function and mostly an immutable class (except84* for the create/add/save methods only used by the ktab command).85*/8687// Source, null if using the default one. Note that the default name88// is maintained in snapshot, this field is never "resolved".89private final File file;9091// Bound user: normally from the "principal" value in a JAAS krb592// login conf. Will be null if it's "*".93private final KerberosPrincipal princ;9495private final boolean bound;9697// Set up JavaxSecurityAuthKerberosAccess in KerberosSecrets98static {99KerberosSecrets.setJavaxSecurityAuthKerberosAccess(100new JavaxSecurityAuthKerberosAccessImpl());101}102103private KeyTab(KerberosPrincipal princ, File file, boolean bound) {104this.princ = princ;105this.file = file;106this.bound = bound;107}108109/**110* Returns a {@code KeyTab} instance from a {@code File} object111* that is bound to an unknown service principal.112* <p>113* The result of this method is never null. This method only associates114* the returned {@code KeyTab} object with the file and does not read it.115* <p>116* Developers should call {@link #getInstance(KerberosPrincipal,File)}117* when the bound service principal is known.118* @param file the keytab {@code File} object, must not be null119* @return the keytab instance120* @throws NullPointerException if the {@code file} argument is null121*/122public static KeyTab getInstance(File file) {123if (file == null) {124throw new NullPointerException("file must be non null");125}126return new KeyTab(null, file, true);127}128129/**130* Returns an unbound {@code KeyTab} instance from a {@code File}131* object.132* <p>133* The result of this method is never null. This method only associates134* the returned {@code KeyTab} object with the file and does not read it.135* @param file the keytab {@code File} object, must not be null136* @return the keytab instance137* @throws NullPointerException if the file argument is null138* @since 1.8139*/140public static KeyTab getUnboundInstance(File file) {141if (file == null) {142throw new NullPointerException("file must be non null");143}144return new KeyTab(null, file, false);145}146147/**148* Returns a {@code KeyTab} instance from a {@code File} object149* that is bound to the specified service principal.150* <p>151* The result of this method is never null. This method only associates152* the returned {@code KeyTab} object with the file and does not read it.153* @param princ the bound service principal, must not be null154* @param file the keytab {@code File} object, must not be null155* @return the keytab instance156* @throws NullPointerException if either of the arguments is null157* @since 1.8158*/159public static KeyTab getInstance(KerberosPrincipal princ, File file) {160if (princ == null) {161throw new NullPointerException("princ must be non null");162}163if (file == null) {164throw new NullPointerException("file must be non null");165}166return new KeyTab(princ, file, true);167}168169/**170* Returns the default {@code KeyTab} instance that is bound171* to an unknown service principal.172* <p>173* The result of this method is never null. This method only associates174* the returned {@code KeyTab} object with the default keytab file and175* does not read it.176* <p>177* Developers should call {@link #getInstance(KerberosPrincipal)}178* when the bound service principal is known.179* @return the default keytab instance.180*/181public static KeyTab getInstance() {182return new KeyTab(null, null, true);183}184185/**186* Returns the default unbound {@code KeyTab} instance.187* <p>188* The result of this method is never null. This method only associates189* the returned {@code KeyTab} object with the default keytab file and190* does not read it.191* @return the default keytab instance192* @since 1.8193*/194public static KeyTab getUnboundInstance() {195return new KeyTab(null, null, false);196}197198/**199* Returns the default {@code KeyTab} instance that is bound200* to the specified service principal.201* <p>202* The result of this method is never null. This method only associates203* the returned {@code KeyTab} object with the default keytab file and204* does not read it.205* @param princ the bound service principal, must not be null206* @return the default keytab instance207* @throws NullPointerException if {@code princ} is null208* @since 1.8209*/210public static KeyTab getInstance(KerberosPrincipal princ) {211if (princ == null) {212throw new NullPointerException("princ must be non null");213}214return new KeyTab(princ, null, true);215}216217// Takes a snapshot of the keytab content. This method is called by218// JavaxSecurityAuthKerberosAccessImpl so no more private219sun.security.krb5.internal.ktab.KeyTab takeSnapshot() {220try {221return sun.security.krb5.internal.ktab.KeyTab.getInstance(file);222} catch (AccessControlException ace) {223if (file != null) {224// It's OK to show the name if caller specified it225throw ace;226} else {227AccessControlException ace2 = new AccessControlException(228"Access to default keytab denied (modified exception)");229ace2.setStackTrace(ace.getStackTrace());230throw ace2;231}232}233}234235/**236* Returns fresh keys for the given Kerberos principal.237* <p>238* Implementation of this method should make sure the returned keys match239* the latest content of the keytab file. The result is a newly created240* copy that can be modified by the caller without modifying the keytab241* object. The caller should {@link KerberosKey#destroy() destroy} the242* result keys after they are used.243* <p>244* Please note that the keytab file can be created after the245* {@code KeyTab} object is instantiated and its content may change over246* time. Therefore, an application should call this method only when it247* needs to use the keys. Any previous result from an earlier invocation248* could potentially be expired.249* <p>250* If there is any error (say, I/O error or format error)251* during the reading process of the KeyTab file, a saved result should be252* returned. If there is no saved result (say, this is the first time this253* method is called, or, all previous read attempts failed), an empty array254* should be returned. This can make sure the result is not drastically255* changed during the (probably slow) update of the keytab file.256* <p>257* Each time this method is called and the reading of the file succeeds258* with no exception (say, I/O error or file format error),259* the result should be saved for {@code principal}. The implementation can260* also save keys for other principals having keys in the same keytab object261* if convenient.262* <p>263* Any unsupported key read from the keytab is ignored and not included264* in the result.265* <p>266* If this keytab is bound to a specific principal, calling this method on267* another principal will return an empty array.268*269* @param principal the Kerberos principal, must not be null.270* @return the keys (never null, may be empty)271* @throws NullPointerException if the {@code principal}272* argument is null273* @throws SecurityException if a security manager exists and the read274* access to the keytab file is not permitted275*/276public KerberosKey[] getKeys(KerberosPrincipal principal) {277try {278if (princ != null && !principal.equals(princ)) {279return new KerberosKey[0];280}281PrincipalName pn = new PrincipalName(principal.getName());282EncryptionKey[] keys = takeSnapshot().readServiceKeys(pn);283KerberosKey[] kks = new KerberosKey[keys.length];284for (int i=0; i<kks.length; i++) {285Integer tmp = keys[i].getKeyVersionNumber();286kks[i] = new KerberosKey(287principal,288keys[i].getBytes(),289keys[i].getEType(),290tmp == null ? 0 : tmp.intValue());291keys[i].destroy();292}293return kks;294} catch (RealmException re) {295return new KerberosKey[0];296}297}298299EncryptionKey[] getEncryptionKeys(PrincipalName principal) {300return takeSnapshot().readServiceKeys(principal);301}302303/**304* Checks if the keytab file exists. Implementation of this method305* should make sure that the result matches the latest status of the306* keytab file.307* <p>308* The caller can use the result to determine if it should fallback to309* another mechanism to read the keys.310* @return true if the keytab file exists; false otherwise.311* @throws SecurityException if a security manager exists and the read312* access to the keytab file is not permitted313*/314public boolean exists() {315return !takeSnapshot().isMissing();316}317318public String toString() {319String s = (file == null) ? "Default keytab" : file.toString();320if (!bound) return s;321else if (princ == null) return s + " for someone";322else return s + " for " + princ;323}324325/**326* Returns a hashcode for this KeyTab.327*328* @return a hashCode() for the {@code KeyTab}329*/330public int hashCode() {331return Objects.hash(file, princ, bound);332}333334/**335* Compares the specified Object with this KeyTab for equality.336* Returns true if the given object is also a337* {@code KeyTab} and the two338* {@code KeyTab} instances are equivalent.339*340* @param other the Object to compare to341* @return true if the specified object is equal to this KeyTab342*/343public boolean equals(Object other) {344if (other == this)345return true;346347if (! (other instanceof KeyTab)) {348return false;349}350351KeyTab otherKtab = (KeyTab) other;352return Objects.equals(otherKtab.princ, princ) &&353Objects.equals(otherKtab.file, file) &&354bound == otherKtab.bound;355}356357/**358* Returns the service principal this {@code KeyTab} object359* is bound to. Returns {@code null} if it's not bound.360* <p>361* Please note the deprecated constructors create a KeyTab object bound for362* some unknown principal. In this case, this method also returns null.363* User can call {@link #isBound()} to verify this case.364* @return the service principal365* @since 1.8366*/367public KerberosPrincipal getPrincipal() {368return princ;369}370371/**372* Returns if the keytab is bound to a principal373* @return if the keytab is bound to a principal374* @since 1.8375*/376public boolean isBound() {377return bound;378}379}380381382