public String toString() {
   StringBuffer str = new StringBuffer();
   for (int i = 0; i < nameStrings.length; i++) {
     if (i > 0) str.append("/");
     str.append(nameStrings[i]);
   }
   str.append("@");
   str.append(nameRealm.toString());
   return str.toString();
 }
 public String getSalt() {
   if (salt == null) {
     StringBuffer salt = new StringBuffer();
     salt.append(nameRealm.toString());
     for (int i = 0; i < nameStrings.length; i++) {
       salt.append(nameStrings[i]);
     }
     return salt.toString();
   }
   return salt;
 }
 @Override
 public boolean equals(Object o) {
   if (this == o) {
     return true;
   }
   if (o instanceof PrincipalName) {
     PrincipalName other = (PrincipalName) o;
     return nameRealm.equals(other.nameRealm) && Arrays.equals(nameStrings, other.nameStrings);
   }
   return false;
 }
 /**
  * Writes data field values of <code>PrincipalName</code> in FCC format to an output stream.
  *
  * @param cos a <code>CCacheOutputStream</code> for writing data.
  * @exception IOException if an I/O exception occurs.
  * @see sun.security.krb5.internal.ccache.CCacheOutputStream
  */
 public void writePrincipal(CCacheOutputStream cos) throws IOException {
   cos.write32(nameType);
   cos.write32(nameStrings.length);
   byte[] realmBytes = null;
   realmBytes = nameRealm.toString().getBytes();
   cos.write32(realmBytes.length);
   cos.write(realmBytes, 0, realmBytes.length);
   byte[] bytes = null;
   for (int i = 0; i < nameStrings.length; i++) {
     bytes = nameStrings[i].getBytes();
     cos.write32(bytes.length);
     cos.write(bytes, 0, bytes.length);
   }
 }
  /**
   * Parse (unmarshal) a <code>PrincipalName</code> from a DER input stream. This form parsing might
   * be used when expanding a value which is part of a constructed sequence and uses explicitly
   * tagged type.
   *
   * @exception Asn1Exception on error.
   * @param data the Der input stream value, which contains one or more marshaled value.
   * @param explicitTag tag number.
   * @param optional indicate if this data field is optional
   * @param realm the realm for the name
   * @return an instance of <code>PrincipalName</code>, or null if the field is optional and
   *     missing.
   */
  public static PrincipalName parse(
      DerInputStream data, byte explicitTag, boolean optional, Realm realm)
      throws Asn1Exception, IOException, RealmException {

    if ((optional) && (((byte) data.peekByte() & (byte) 0x1F) != explicitTag)) return null;
    DerValue der = data.getDerValue();
    if (explicitTag != (der.getTag() & (byte) 0x1F)) {
      throw new Asn1Exception(Krb5.ASN1_BAD_ID);
    } else {
      DerValue subDer = der.getData().getDerValue();
      if (realm == null) {
        realm = Realm.getDefault();
      }
      return new PrincipalName(subDer, realm);
    }
  }
 public String getRealmString() {
   return nameRealm.toString();
 }
  /**
   * Constructs a PrincipalName from a string.
   *
   * @param name the name
   * @param type the type
   * @param realm the realm, null if not known. Note that when realm is not null, it will be always
   *     used even if there is a realm part in name. When realm is null, will read realm part from
   *     name, or try to map a realm (for KRB_NT_SRV_HST), or use the default realm, or fail
   * @throws RealmException
   */
  public PrincipalName(String name, int type, String realm) throws RealmException {
    if (name == null) {
      throw new IllegalArgumentException("Null name not allowed");
    }
    String[] nameParts = parseName(name);
    validateNameStrings(nameParts);
    if (realm == null) {
      realm = Realm.parseRealmAtSeparator(name);
    }
    switch (type) {
      case KRB_NT_SRV_HST:
        if (nameParts.length >= 2) {
          String hostName = nameParts[1];
          try {
            // RFC4120 does not recommend canonicalizing a hostname.
            // However, for compatibility reason, we will try
            // canonicalize it and see if the output looks better.

            String canonicalized = (InetAddress.getByName(hostName)).getCanonicalHostName();

            // Looks if canonicalized is a longer format of hostName,
            // we accept cases like
            //     bunny -> bunny.rabbit.hole
            if (canonicalized
                .toLowerCase(Locale.ENGLISH)
                .startsWith(hostName.toLowerCase(Locale.ENGLISH) + ".")) {
              hostName = canonicalized;
            }
          } catch (UnknownHostException e) {
            // no canonicalization, use old
          }
          nameParts[1] = hostName.toLowerCase(Locale.ENGLISH);
        }
        nameStrings = nameParts;
        nameType = type;

        if (realm != null) {
          nameRealm = new Realm(realm);
        } else {
          // We will try to get realm name from the mapping in
          // the configuration. If it is not specified
          // we will use the default realm. This nametype does
          // not allow a realm to be specified. The name string must of
          // the form service@host and this is internally changed into
          // service/host by Kerberos
          String mapRealm = mapHostToRealm(nameParts[1]);
          if (mapRealm != null) {
            nameRealm = new Realm(mapRealm);
          } else {
            nameRealm = Realm.getDefault();
          }
        }
        break;
      case KRB_NT_UNKNOWN:
      case KRB_NT_PRINCIPAL:
      case KRB_NT_SRV_INST:
      case KRB_NT_SRV_XHST:
      case KRB_NT_UID:
        nameStrings = nameParts;
        nameType = type;
        if (realm != null) {
          nameRealm = new Realm(realm);
        } else {
          nameRealm = Realm.getDefault();
        }
        break;
      default:
        throw new IllegalArgumentException("Illegal name type");
    }
  }
 public PrincipalName(String[] nameParts, int type)
     throws IllegalArgumentException, RealmException {
   this(type, nameParts, Realm.getDefault());
 }