blob: edfce9f13dc1fae003f77ccad177a574111d6848 [file] [log] [blame]
/*
* 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();
}
}