Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/jgss/krb5/Krb5NameElement.java
38922 views
/*1* Copyright (c) 2000, 2019, 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 sun.security.jgss.krb5;2627import org.ietf.jgss.*;28import sun.security.jgss.spi.*;29import sun.security.krb5.PrincipalName;30import sun.security.krb5.Realm;31import sun.security.krb5.KrbException;3233import javax.security.auth.kerberos.ServicePermission;34import java.io.UnsupportedEncodingException;35import java.net.InetAddress;36import java.net.UnknownHostException;37import java.security.Provider;38import java.util.Locale;3940/**41* Implements the GSSNameSpi for the krb5 mechanism.42*43* @author Mayank Upadhyay44*/45public class Krb5NameElement46implements GSSNameSpi {4748private PrincipalName krb5PrincipalName;4950private String gssNameStr = null;51private Oid gssNameType = null;5253// XXX Move this concept into PrincipalName's asn1Encode() sometime54private static String CHAR_ENCODING = "UTF-8";5556private Krb5NameElement(PrincipalName principalName,57String gssNameStr,58Oid gssNameType) {59this.krb5PrincipalName = principalName;60this.gssNameStr = gssNameStr;61this.gssNameType = gssNameType;62}6364/**65* Instantiates a new Krb5NameElement object. Internally it stores the66* information provided by the input parameters so that they may later67* be used for output when a printable representaion of this name is68* needed in GSS-API format rather than in Kerberos format.69*70*/71static Krb5NameElement getInstance(String gssNameStr, Oid gssNameType)72throws GSSException {7374/*75* A null gssNameType implies that the mechanism default76* Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL be used.77*/78if (gssNameType == null)79gssNameType = Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL;80else81if (!gssNameType.equals(GSSName.NT_USER_NAME) &&82!gssNameType.equals(GSSName.NT_HOSTBASED_SERVICE) &&83!gssNameType.equals(Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL) &&84!gssNameType.equals(GSSName.NT_EXPORT_NAME))85throw new GSSException(GSSException.BAD_NAMETYPE, -1,86gssNameType.toString()87+" is an unsupported nametype");8889PrincipalName principalName;90try {9192if (gssNameType.equals(GSSName.NT_EXPORT_NAME) ||93gssNameType.equals(Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL)) {94principalName = new PrincipalName(gssNameStr,95PrincipalName.KRB_NT_PRINCIPAL);96} else {9798String[] components = getComponents(gssNameStr);99100/*101* We have forms of GSS name strings that can come in:102*103* 1. names of the form "foo" with just one104* component. (This might include a "@" but only in escaped105* form like "\@")106* 2. names of the form "foo@bar" with two components107*108* The nametypes that are accepted are NT_USER_NAME, and109* NT_HOSTBASED_SERVICE.110*/111112if (gssNameType.equals(GSSName.NT_USER_NAME))113principalName = new PrincipalName(gssNameStr,114PrincipalName.KRB_NT_PRINCIPAL);115else {116String hostName = null;117String service = components[0];118if (components.length >= 2)119hostName = components[1];120121String principal = getHostBasedInstance(service, hostName);122principalName = new PrincipalName(principal,123PrincipalName.KRB_NT_SRV_HST);124}125}126127} catch (KrbException e) {128throw new GSSException(GSSException.BAD_NAME, -1, e.getMessage());129}130131if (principalName.isRealmDeduced() && !Realm.AUTODEDUCEREALM) {132SecurityManager sm = System.getSecurityManager();133if (sm != null) {134try {135sm.checkPermission(new ServicePermission(136"@" + principalName.getRealmAsString(), "-"));137} catch (SecurityException se) {138// Do not chain the actual exception to hide info139throw new GSSException(GSSException.FAILURE);140}141}142}143return new Krb5NameElement(principalName, gssNameStr, gssNameType);144}145146public static Krb5NameElement getInstance(PrincipalName principalName) {147return new Krb5NameElement(principalName,148principalName.getName(),149Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);150}151152private static String[] getComponents(String gssNameStr)153throws GSSException {154155String[] retVal;156157// XXX Perhaps provide this parsing code in PrincipalName158159// Look for @ as in service@host160// Assumes host name will not have an escaped '@'161int separatorPos = gssNameStr.lastIndexOf('@', gssNameStr.length());162163// Not really a separator if it is escaped. Then this is just part164// of the principal name or service name165if ((separatorPos > 0) &&166(gssNameStr.charAt(separatorPos-1) == '\\')) {167// Is the `\` character escaped itself?168if ((separatorPos - 2 < 0) ||169(gssNameStr.charAt(separatorPos-2) != '\\'))170separatorPos = -1;171}172173if (separatorPos > 0) {174String serviceName = gssNameStr.substring(0, separatorPos);175String hostName = gssNameStr.substring(separatorPos+1);176retVal = new String[] { serviceName, hostName};177} else {178retVal = new String[] {gssNameStr};179}180181return retVal;182183}184185private static String getHostBasedInstance(String serviceName,186String hostName)187throws GSSException {188StringBuffer temp = new StringBuffer(serviceName);189190try {191// A lack of "@" defaults to the service being on the local192// host as per RFC 2743193// XXX Move this part into JGSS framework194if (hostName == null)195hostName = InetAddress.getLocalHost().getHostName();196197} catch (UnknownHostException e) {198// use hostname as it is199}200hostName = hostName.toLowerCase(Locale.ENGLISH);201202temp = temp.append('/').append(hostName);203return temp.toString();204}205206public final PrincipalName getKrb5PrincipalName() {207return krb5PrincipalName;208}209210/**211* Equal method for the GSSNameSpi objects.212* If either name denotes an anonymous principal, the call should213* return false.214*215* @param other to be compared with216* @return true if they both refer to the same entity, else false217* @exception GSSException with major codes of BAD_NAMETYPE,218* BAD_NAME, FAILURE219*/220public boolean equals(GSSNameSpi other) throws GSSException {221222if (other == this)223return true;224225if (other instanceof Krb5NameElement) {226Krb5NameElement that = (Krb5NameElement) other;227return (this.krb5PrincipalName.getName().equals(228that.krb5PrincipalName.getName()));229}230return false;231}232233/**234* Compares this <code>GSSNameSpi</code> object to another Object235* that might be a <code>GSSNameSpi</code>. The behaviour is exactly236* the same as in {@link #equals(GSSNameSpi) equals} except that237* no GSSException is thrown; instead, false will be returned in the238* situation where an error occurs.239*240* @param another the object to be compared to241* @return true if they both refer to the same entity, else false242* @see #equals(GSSNameSpi)243*/244public boolean equals(Object another) {245if (this == another) {246return true;247}248249try {250if (another instanceof Krb5NameElement)251return equals((Krb5NameElement) another);252} catch (GSSException e) {253// ignore exception254}255return false;256}257258/**259* Returns a hashcode value for this GSSNameSpi.260*261* @return a hashCode value262*/263public int hashCode() {264return 37 * 17 + krb5PrincipalName.getName().hashCode();265}266267268/**269* Returns the principal name in the form user@REALM or270* host/service@REALM but with the following constraints that are271* imposed by RFC 1964:272* <pre>273* (1) all occurrences of the characters `@`, `/`, and `\` within274* principal components or realm names shall be quoted with an275* immediately-preceding `\`.276*277* (2) all occurrences of the null, backspace, tab, or newline278* characters within principal components or realm names will be279* represented, respectively, with `\0`, `\b`, `\t`, or `\n`.280*281* (3) the `\` quoting character shall not be emitted within an282* exported name except to accommodate cases (1) and (2).283* </pre>284*/285public byte[] export() throws GSSException {286// XXX Apply the above constraints.287byte[] retVal = null;288try {289retVal = krb5PrincipalName.getName().getBytes(CHAR_ENCODING);290} catch (UnsupportedEncodingException e) {291// Can't happen292}293return retVal;294}295296/**297* Get the mechanism type that this NameElement corresponds to.298*299* @return the Oid of the mechanism type300*/301public Oid getMechanism() {302return (Krb5MechFactory.GSS_KRB5_MECH_OID);303}304305/**306* Returns a string representation for this name. The printed307* name type can be obtained by calling getStringNameType().308*309* @return string form of this name310* @see #getStringNameType()311* @overrides Object#toString312*/313public String toString() {314return (gssNameStr);315// For testing: return (super.toString());316}317318/**319* Returns the name type oid.320*/321public Oid getGSSNameType() {322return (gssNameType);323}324325/**326* Returns the oid describing the format of the printable name.327*328* @return the Oid for the format of the printed name329*/330public Oid getStringNameType() {331// XXX For NT_EXPORT_NAME return a different name type. Infact,332// don't even store NT_EXPORT_NAME in the cons.333return (gssNameType);334}335336/**337* Indicates if this name object represents an Anonymous name.338*/339public boolean isAnonymousName() {340return (gssNameType.equals(GSSName.NT_ANONYMOUS));341}342343public Provider getProvider() {344return Krb5MechFactory.PROVIDER;345}346347}348349350