1/*
2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.security.auth.kerberos;
27
28import java.io.*;
29import sun.security.krb5.KrbException;
30import sun.security.krb5.PrincipalName;
31import sun.security.krb5.Realm;
32import sun.security.util.*;
33
34/**
35 * This class encapsulates a Kerberos principal.
36 *
37 * @author Mayank Upadhyay
38 * @since 1.4
39 */
40
41public final class KerberosPrincipal
42    implements java.security.Principal, java.io.Serializable {
43
44    private static final long serialVersionUID = -7374788026156829911L;
45
46    //name types
47
48    /**
49     * unknown name type.
50     */
51
52    public static final int KRB_NT_UNKNOWN =   0;
53
54    /**
55     * user principal name type.
56     */
57
58    public static final int KRB_NT_PRINCIPAL = 1;
59
60    /**
61     * service and other unique instance (krbtgt) name type.
62     */
63    public static final int KRB_NT_SRV_INST =  2;
64
65    /**
66     * service with host name as instance (telnet, rcommands) name type.
67     */
68
69    public static final int KRB_NT_SRV_HST =   3;
70
71    /**
72     * service with host as remaining components name type.
73     */
74
75    public static final int KRB_NT_SRV_XHST =  4;
76
77    /**
78     * unique ID name type.
79     */
80
81    public static final int KRB_NT_UID = 5;
82
83    private transient String fullName;
84
85    private transient String realm;
86
87    private transient int nameType;
88
89
90    /**
91     * Constructs a {@code KerberosPrincipal} from the provided string input.
92     * The name type for this principal defaults to
93     * {@link #KRB_NT_PRINCIPAL KRB_NT_PRINCIPAL}
94     * This string is assumed to contain a name in the format
95     * that is specified in Section 2.1.1. (Kerberos Principal Name Form) of
96     * <a href=http://www.ietf.org/rfc/rfc1964.txt> RFC 1964 </a>
97     * (for example, <i>duke@FOO.COM</i>, where <i>duke</i>
98     * represents a principal, and <i>FOO.COM</i> represents a realm).
99     *
100     * <p>If the input name does not contain a realm, the default realm
101     * is used. The default realm can be specified either in a Kerberos
102     * configuration file or via the java.security.krb5.realm
103     * system property. For more information, see the
104     * {@extLink security_guide_jgss_tutorial Kerberos Requirements}.
105     * Additionally, if a security manager is
106     * installed, a {@link ServicePermission} must be granted and the service
107     * principal of the permission must minimally be inside the
108     * {@code KerberosPrincipal}'s realm. For example, if the result of
109     * {@code new KerberosPrincipal("user")} is {@code user@EXAMPLE.COM},
110     * then a {@code ServicePermission} with service principal
111     * {@code host/www.example.com@EXAMPLE.COM} (and any action)
112     * must be granted.
113     *
114     * @param name the principal name
115     * @throws IllegalArgumentException if name is improperly
116     * formatted, if name is null, or if name does not contain
117     * the realm to use and the default realm is not specified
118     * in either a Kerberos configuration file or via the
119     * java.security.krb5.realm system property.
120     * @throws SecurityException if a security manager is installed and
121     * {@code name} does not contain the realm to use, and a proper
122     * {@link ServicePermission} as described above is not granted.
123     */
124    public KerberosPrincipal(String name) {
125        this(name, KRB_NT_PRINCIPAL);
126    }
127
128    /**
129     * Constructs a {@code KerberosPrincipal} from the provided string and
130     * name type input.  The string is assumed to contain a name in the
131     * format that is specified in Section 2.1 (Mandatory Name Forms) of
132     * <a href=http://www.ietf.org/rfc/rfc1964.txt>RFC 1964</a>.
133     * Valid name types are specified in Section 6.2 (Principal Names) of
134     * <a href=http://www.ietf.org/rfc/rfc4120.txt>RFC 4120</a>.
135     * The input name must be consistent with the provided name type.
136     * (for example, <i>duke@FOO.COM</i>, is a valid input string for the
137     * name type, KRB_NT_PRINCIPAL where <i>duke</i>
138     * represents a principal, and <i>FOO.COM</i> represents a realm).
139     *
140     * <p>If the input name does not contain a realm, the default realm
141     * is used. The default realm can be specified either in a Kerberos
142     * configuration file or via the java.security.krb5.realm
143     * system property. For more information, see the
144     * {@extLink security_guide_jgss_tutorial Kerberos Requirements}.
145     * Additionally, if a security manager is
146     * installed, a {@link ServicePermission} must be granted and the service
147     * principal of the permission must minimally be inside the
148     * {@code KerberosPrincipal}'s realm. For example, if the result of
149     * {@code new KerberosPrincipal("user")} is {@code user@EXAMPLE.COM},
150     * then a {@code ServicePermission} with service principal
151     * {@code host/www.example.com@EXAMPLE.COM} (and any action)
152     * must be granted.
153     *
154     * @param name the principal name
155     * @param nameType the name type of the principal
156     * @throws IllegalArgumentException if name is improperly
157     * formatted, if name is null, if the nameType is not supported,
158     * or if name does not contain the realm to use and the default
159     * realm is not specified in either a Kerberos configuration
160     * file or via the java.security.krb5.realm system property.
161     * @throws SecurityException if a security manager is installed and
162     * {@code name} does not contain the realm to use, and a proper
163     * {@link ServicePermission} as described above is not granted.
164     */
165
166    public KerberosPrincipal(String name, int nameType) {
167
168        PrincipalName krb5Principal = null;
169
170        try {
171            // Appends the default realm if it is missing
172            krb5Principal  = new PrincipalName(name,nameType);
173        } catch (KrbException e) {
174            throw new IllegalArgumentException(e.getMessage());
175        }
176
177        if (krb5Principal.isRealmDeduced() && !Realm.AUTODEDUCEREALM) {
178            SecurityManager sm = System.getSecurityManager();
179            if (sm != null) {
180                try {
181                    sm.checkPermission(new ServicePermission(
182                            "@" + krb5Principal.getRealmAsString(), "-"));
183                } catch (SecurityException se) {
184                    // Swallow the actual exception to hide info
185                    throw new SecurityException("Cannot read realm info");
186                }
187            }
188        }
189        this.nameType = nameType;
190        fullName = krb5Principal.toString();
191        realm = krb5Principal.getRealmString();
192    }
193    /**
194     * Returns the realm component of this Kerberos principal.
195     *
196     * @return the realm component of this Kerberos principal.
197     */
198    public String getRealm() {
199        return realm;
200    }
201
202    /**
203     * Returns a hash code for this {@code KerberosPrincipal}. The hash code
204     * is defined to be the result of the following calculation:
205     * <pre>{@code
206     *  hashCode = getName().hashCode();
207     * }</pre>
208     *
209     * @return a hash code for this {@code KerberosPrincipal}.
210     */
211    public int hashCode() {
212        return getName().hashCode();
213    }
214
215    /**
216     * Compares the specified object with this principal for equality.
217     * Returns true if the given object is also a
218     * {@code KerberosPrincipal} and the two
219     * {@code KerberosPrincipal} instances are equivalent.
220     * More formally two {@code KerberosPrincipal} instances are equal
221     * if the values returned by {@code getName()} are equal.
222     *
223     * @param other the object to compare to
224     * @return true if the object passed in represents the same principal
225     * as this one, false otherwise.
226     */
227    public boolean equals(Object other) {
228
229        if (other == this)
230            return true;
231
232        if (! (other instanceof KerberosPrincipal)) {
233            return false;
234        }
235        String myFullName = getName();
236        String otherFullName = ((KerberosPrincipal) other).getName();
237        return myFullName.equals(otherFullName);
238    }
239
240    /**
241     * Save the {@code KerberosPrincipal} object to a stream
242     *
243     * @serialData this {@code KerberosPrincipal} is serialized
244     *          by writing out the PrincipalName and the
245     *          Realm in their DER-encoded form as specified in Section 5.2.2 of
246     *          <a href=http://www.ietf.org/rfc/rfc4120.txt> RFC4120</a>.
247     */
248    private void writeObject(ObjectOutputStream oos)
249            throws IOException {
250
251        PrincipalName krb5Principal;
252        try {
253            krb5Principal  = new PrincipalName(fullName, nameType);
254            oos.writeObject(krb5Principal.asn1Encode());
255            oos.writeObject(krb5Principal.getRealm().asn1Encode());
256        } catch (Exception e) {
257            throw new IOException(e);
258        }
259    }
260
261    /**
262     * Reads this object from a stream (i.e., deserializes it)
263     */
264    private void readObject(ObjectInputStream ois)
265            throws IOException, ClassNotFoundException {
266        byte[] asn1EncPrincipal = (byte [])ois.readObject();
267        byte[] encRealm = (byte [])ois.readObject();
268        try {
269           Realm realmObject = new Realm(new DerValue(encRealm));
270           PrincipalName krb5Principal = new PrincipalName(
271                   new DerValue(asn1EncPrincipal), realmObject);
272           realm = realmObject.toString();
273           fullName = krb5Principal.toString();
274           nameType = krb5Principal.getNameType();
275        } catch (Exception e) {
276            throw new IOException(e);
277        }
278    }
279
280    /**
281     * The returned string corresponds to the single-string
282     * representation of a Kerberos Principal name as specified in
283     * Section 2.1 of <a href=http://www.ietf.org/rfc/rfc1964.txt>RFC 1964</a>.
284     *
285     * @return the principal name.
286     */
287    public String getName() {
288        return fullName;
289    }
290
291    /**
292     * Returns the name type of the {@code KerberosPrincipal}. Valid name types
293     * are specified in Section 6.2 of
294     * <a href=http://www.ietf.org/rfc/rfc4120.txt> RFC4120</a>.
295     *
296     * @return the name type.
297     */
298    public int getNameType() {
299        return nameType;
300    }
301
302    /**
303     * Returns an informative textual representation of this {@code KerberosPrincipal}.
304     *
305     * @return an informative textual representation of this {@code KerberosPrincipal}.
306     */
307    public String toString() {
308        return getName();
309    }
310}
311