src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java
changeset 47216 71c04702a3d5
parent 45665 6f21cd7ec80e
child 55258 d65d3c37232c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2000, 2017, 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.*;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.PrincipalName;
+import sun.security.krb5.Realm;
+import sun.security.util.*;
+
+/**
+ * This class encapsulates a Kerberos principal.
+ *
+ * @author Mayank Upadhyay
+ * @since 1.4
+ */
+
+public final class KerberosPrincipal
+    implements java.security.Principal, java.io.Serializable {
+
+    private static final long serialVersionUID = -7374788026156829911L;
+
+    //name types
+
+    /**
+     * unknown name type.
+     */
+
+    public static final int KRB_NT_UNKNOWN =   0;
+
+    /**
+     * user principal name type.
+     */
+
+    public static final int KRB_NT_PRINCIPAL = 1;
+
+    /**
+     * service and other unique instance (krbtgt) name type.
+     */
+    public static final int KRB_NT_SRV_INST =  2;
+
+    /**
+     * service with host name as instance (telnet, rcommands) name type.
+     */
+
+    public static final int KRB_NT_SRV_HST =   3;
+
+    /**
+     * service with host as remaining components name type.
+     */
+
+    public static final int KRB_NT_SRV_XHST =  4;
+
+    /**
+     * unique ID name type.
+     */
+
+    public static final int KRB_NT_UID = 5;
+
+    private transient String fullName;
+
+    private transient String realm;
+
+    private transient int nameType;
+
+
+    /**
+     * Constructs a {@code KerberosPrincipal} from the provided string input.
+     * The name type for this principal defaults to
+     * {@link #KRB_NT_PRINCIPAL KRB_NT_PRINCIPAL}
+     * This string is assumed to contain a name in the format
+     * that is specified in Section 2.1.1. (Kerberos Principal Name Form) of
+     * <a href=http://www.ietf.org/rfc/rfc1964.txt> RFC 1964 </a>
+     * (for example, <i>duke@FOO.COM</i>, where <i>duke</i>
+     * represents a principal, and <i>FOO.COM</i> represents a realm).
+     *
+     * <p>If the input name does not contain a realm, the default realm
+     * is used. The default realm can be specified either in a Kerberos
+     * configuration file or via the java.security.krb5.realm
+     * system property. For more information, see the
+     * {@extLink security_guide_jgss_tutorial Kerberos Requirements}.
+     * Additionally, if a security manager is
+     * installed, a {@link ServicePermission} must be granted and the service
+     * principal of the permission must minimally be inside the
+     * {@code KerberosPrincipal}'s realm. For example, if the result of
+     * {@code new KerberosPrincipal("user")} is {@code user@EXAMPLE.COM},
+     * then a {@code ServicePermission} with service principal
+     * {@code host/www.example.com@EXAMPLE.COM} (and any action)
+     * must be granted.
+     *
+     * @param name the principal name
+     * @throws IllegalArgumentException if name is improperly
+     * formatted, if name is null, or if name does not contain
+     * the realm to use and the default realm is not specified
+     * in either a Kerberos configuration file or via the
+     * java.security.krb5.realm system property.
+     * @throws SecurityException if a security manager is installed and
+     * {@code name} does not contain the realm to use, and a proper
+     * {@link ServicePermission} as described above is not granted.
+     */
+    public KerberosPrincipal(String name) {
+        this(name, KRB_NT_PRINCIPAL);
+    }
+
+    /**
+     * Constructs a {@code KerberosPrincipal} from the provided string and
+     * name type input.  The string is assumed to contain a name in the
+     * format that is specified in Section 2.1 (Mandatory Name Forms) of
+     * <a href=http://www.ietf.org/rfc/rfc1964.txt>RFC 1964</a>.
+     * Valid name types are specified in Section 6.2 (Principal Names) of
+     * <a href=http://www.ietf.org/rfc/rfc4120.txt>RFC 4120</a>.
+     * The input name must be consistent with the provided name type.
+     * (for example, <i>duke@FOO.COM</i>, is a valid input string for the
+     * name type, KRB_NT_PRINCIPAL where <i>duke</i>
+     * represents a principal, and <i>FOO.COM</i> represents a realm).
+     *
+     * <p>If the input name does not contain a realm, the default realm
+     * is used. The default realm can be specified either in a Kerberos
+     * configuration file or via the java.security.krb5.realm
+     * system property. For more information, see the
+     * {@extLink security_guide_jgss_tutorial Kerberos Requirements}.
+     * Additionally, if a security manager is
+     * installed, a {@link ServicePermission} must be granted and the service
+     * principal of the permission must minimally be inside the
+     * {@code KerberosPrincipal}'s realm. For example, if the result of
+     * {@code new KerberosPrincipal("user")} is {@code user@EXAMPLE.COM},
+     * then a {@code ServicePermission} with service principal
+     * {@code host/www.example.com@EXAMPLE.COM} (and any action)
+     * must be granted.
+     *
+     * @param name the principal name
+     * @param nameType the name type of the principal
+     * @throws IllegalArgumentException if name is improperly
+     * formatted, if name is null, if the nameType is not supported,
+     * or if name does not contain the realm to use and the default
+     * realm is not specified in either a Kerberos configuration
+     * file or via the java.security.krb5.realm system property.
+     * @throws SecurityException if a security manager is installed and
+     * {@code name} does not contain the realm to use, and a proper
+     * {@link ServicePermission} as described above is not granted.
+     */
+
+    public KerberosPrincipal(String name, int nameType) {
+
+        PrincipalName krb5Principal = null;
+
+        try {
+            // Appends the default realm if it is missing
+            krb5Principal  = new PrincipalName(name,nameType);
+        } catch (KrbException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+
+        if (krb5Principal.isRealmDeduced() && !Realm.AUTODEDUCEREALM) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                try {
+                    sm.checkPermission(new ServicePermission(
+                            "@" + krb5Principal.getRealmAsString(), "-"));
+                } catch (SecurityException se) {
+                    // Swallow the actual exception to hide info
+                    throw new SecurityException("Cannot read realm info");
+                }
+            }
+        }
+        this.nameType = nameType;
+        fullName = krb5Principal.toString();
+        realm = krb5Principal.getRealmString();
+    }
+    /**
+     * Returns the realm component of this Kerberos principal.
+     *
+     * @return the realm component of this Kerberos principal.
+     */
+    public String getRealm() {
+        return realm;
+    }
+
+    /**
+     * Returns a hash code for this {@code KerberosPrincipal}. The hash code
+     * is defined to be the result of the following calculation:
+     * <pre>{@code
+     *  hashCode = getName().hashCode();
+     * }</pre>
+     *
+     * @return a hash code for this {@code KerberosPrincipal}.
+     */
+    public int hashCode() {
+        return getName().hashCode();
+    }
+
+    /**
+     * Compares the specified object with this principal for equality.
+     * Returns true if the given object is also a
+     * {@code KerberosPrincipal} and the two
+     * {@code KerberosPrincipal} instances are equivalent.
+     * More formally two {@code KerberosPrincipal} instances are equal
+     * if the values returned by {@code getName()} are equal.
+     *
+     * @param other the object to compare to
+     * @return true if the object passed in represents the same principal
+     * as this one, false otherwise.
+     */
+    public boolean equals(Object other) {
+
+        if (other == this)
+            return true;
+
+        if (! (other instanceof KerberosPrincipal)) {
+            return false;
+        }
+        String myFullName = getName();
+        String otherFullName = ((KerberosPrincipal) other).getName();
+        return myFullName.equals(otherFullName);
+    }
+
+    /**
+     * Save the {@code KerberosPrincipal} object to a stream
+     *
+     * @serialData this {@code KerberosPrincipal} is serialized
+     *          by writing out the PrincipalName and the
+     *          Realm in their DER-encoded form as specified in Section 5.2.2 of
+     *          <a href=http://www.ietf.org/rfc/rfc4120.txt> RFC4120</a>.
+     */
+    private void writeObject(ObjectOutputStream oos)
+            throws IOException {
+
+        PrincipalName krb5Principal;
+        try {
+            krb5Principal  = new PrincipalName(fullName, nameType);
+            oos.writeObject(krb5Principal.asn1Encode());
+            oos.writeObject(krb5Principal.getRealm().asn1Encode());
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+    }
+
+    /**
+     * Reads this object from a stream (i.e., deserializes it)
+     */
+    private void readObject(ObjectInputStream ois)
+            throws IOException, ClassNotFoundException {
+        byte[] asn1EncPrincipal = (byte [])ois.readObject();
+        byte[] encRealm = (byte [])ois.readObject();
+        try {
+           Realm realmObject = new Realm(new DerValue(encRealm));
+           PrincipalName krb5Principal = new PrincipalName(
+                   new DerValue(asn1EncPrincipal), realmObject);
+           realm = realmObject.toString();
+           fullName = krb5Principal.toString();
+           nameType = krb5Principal.getNameType();
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+    }
+
+    /**
+     * The returned string corresponds to the single-string
+     * representation of a Kerberos Principal name as specified in
+     * Section 2.1 of <a href=http://www.ietf.org/rfc/rfc1964.txt>RFC 1964</a>.
+     *
+     * @return the principal name.
+     */
+    public String getName() {
+        return fullName;
+    }
+
+    /**
+     * Returns the name type of the {@code KerberosPrincipal}. Valid name types
+     * are specified in Section 6.2 of
+     * <a href=http://www.ietf.org/rfc/rfc4120.txt> RFC4120</a>.
+     *
+     * @return the name type.
+     */
+    public int getNameType() {
+        return nameType;
+    }
+
+    /**
+     * Returns an informative textual representation of this {@code KerberosPrincipal}.
+     *
+     * @return an informative textual representation of this {@code KerberosPrincipal}.
+     */
+    public String toString() {
+        return getName();
+    }
+}