changeset 5807:79b63e8eceda

6966259: Make PrincipalName and Realm immutable Reviewed-by: xuelei
author weijun
date Wed, 11 Jul 2012 17:10:34 +0800
parents 516e0c884af2
children e9461aeff91f
files src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java src/share/classes/sun/security/jgss/krb5/Krb5NameElement.java src/share/classes/sun/security/krb5/Credentials.java src/share/classes/sun/security/krb5/KrbApReq.java src/share/classes/sun/security/krb5/KrbAppMessage.java src/share/classes/sun/security/krb5/KrbAsRep.java src/share/classes/sun/security/krb5/KrbAsReq.java src/share/classes/sun/security/krb5/KrbAsReqBuilder.java src/share/classes/sun/security/krb5/KrbCred.java src/share/classes/sun/security/krb5/KrbException.java src/share/classes/sun/security/krb5/KrbKdcRep.java src/share/classes/sun/security/krb5/KrbPriv.java src/share/classes/sun/security/krb5/KrbSafe.java src/share/classes/sun/security/krb5/KrbTgsRep.java src/share/classes/sun/security/krb5/KrbTgsReq.java src/share/classes/sun/security/krb5/PrincipalName.java src/share/classes/sun/security/krb5/Realm.java src/share/classes/sun/security/krb5/RealmException.java src/share/classes/sun/security/krb5/ServiceName.java src/share/classes/sun/security/krb5/internal/ASRep.java src/share/classes/sun/security/krb5/internal/Authenticator.java src/share/classes/sun/security/krb5/internal/CredentialsUtil.java src/share/classes/sun/security/krb5/internal/EncASRepPart.java src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java src/share/classes/sun/security/krb5/internal/EncTGSRepPart.java src/share/classes/sun/security/krb5/internal/EncTicketPart.java src/share/classes/sun/security/krb5/internal/KDCRep.java src/share/classes/sun/security/krb5/internal/KDCReqBody.java src/share/classes/sun/security/krb5/internal/KRBError.java src/share/classes/sun/security/krb5/internal/KrbCredInfo.java src/share/classes/sun/security/krb5/internal/TGSRep.java src/share/classes/sun/security/krb5/internal/Ticket.java src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java src/share/classes/sun/security/krb5/internal/ccache/Credentials.java src/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java src/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java src/share/classes/sun/security/krb5/internal/ccache/MemoryCredentialsCache.java src/share/classes/sun/security/krb5/internal/ktab/KeyTabInputStream.java src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java src/windows/classes/sun/security/krb5/internal/tools/Kinit.java src/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java src/windows/classes/sun/security/krb5/internal/tools/Ktab.java src/windows/native/sun/security/krb5/NativeCreds.c test/sun/security/krb5/ServiceNameClone.java test/sun/security/krb5/auto/KDC.java test/sun/security/krb5/name/Constructors.java test/sun/security/krb5/name/empty.conf test/sun/security/krb5/name/krb5.conf
diffstat 48 files changed, 480 insertions(+), 645 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java	Wed Jul 11 17:10:34 2012 +0800
@@ -26,7 +26,6 @@
 package javax.security.auth.kerberos;
 
 import java.io.*;
-import sun.security.krb5.Asn1Exception;
 import sun.security.krb5.KrbException;
 import sun.security.krb5.PrincipalName;
 import sun.security.krb5.Realm;
@@ -81,14 +80,12 @@
 
     public static final int KRB_NT_UID = 5;
 
-
     private transient String fullName;
 
     private transient String realm;
 
     private transient int nameType;
 
-    private static final char NAME_REALM_SEPARATOR = '@';
 
     /**
      * Constructs a KerberosPrincipal from the provided string input. The
@@ -233,41 +230,35 @@
      *          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 {
+            throws IOException {
 
-        PrincipalName krb5Principal = null;
+        PrincipalName krb5Principal;
         try {
-            krb5Principal  = new PrincipalName(fullName,nameType);
+            krb5Principal  = new PrincipalName(fullName, nameType);
             oos.writeObject(krb5Principal.asn1Encode());
             oos.writeObject(krb5Principal.getRealm().asn1Encode());
         } catch (Exception e) {
-            IOException ioe = new IOException(e.getMessage());
-            ioe.initCause(e);
-            throw ioe;
+            throw new IOException(e);
         }
     }
 
     /**
      * Reads this object from a stream (i.e., deserializes it)
      */
-
     private void readObject(ObjectInputStream ois)
-         throws IOException, ClassNotFoundException {
+            throws IOException, ClassNotFoundException {
         byte[] asn1EncPrincipal = (byte [])ois.readObject();
         byte[] encRealm = (byte [])ois.readObject();
         try {
-           PrincipalName krb5Principal = new PrincipalName(new
-                                                DerValue(asn1EncPrincipal));
-           realm = (new Realm(new DerValue(encRealm))).toString();
-           fullName = krb5Principal.toString() + NAME_REALM_SEPARATOR +
-                         realm.toString();
+           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) {
-            IOException ioe = new IOException(e.getMessage());
-            ioe.initCause(e);
-            throw ioe;
+            throw new IOException(e);
         }
     }
 
@@ -288,9 +279,7 @@
      * <a href=http://www.ietf.org/rfc/rfc4120.txt> RFC4120</a>.
      *
      * @return the name type.
-     *
      */
-
     public int getNameType() {
         return nameType;
     }
--- a/src/share/classes/sun/security/jgss/krb5/Krb5NameElement.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/jgss/krb5/Krb5NameElement.java	Wed Jul 11 17:10:34 2012 +0800
@@ -27,10 +27,8 @@
 
 import org.ietf.jgss.*;
 import sun.security.jgss.spi.*;
-import javax.security.auth.kerberos.*;
 import sun.security.krb5.PrincipalName;
 import sun.security.krb5.KrbException;
-import sun.security.krb5.ServiceName;
 import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -119,8 +117,8 @@
                         hostName = components[1];
 
                     String principal = getHostBasedInstance(service, hostName);
-                    principalName = new ServiceName(principal,
-                                            PrincipalName.KRB_NT_SRV_HST);
+                    principalName = new PrincipalName(principal,
+                            PrincipalName.KRB_NT_SRV_HST);
                 }
             }
 
--- a/src/share/classes/sun/security/krb5/Credentials.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/Credentials.java	Wed Jul 11 17:10:34 2012 +0800
@@ -464,8 +464,7 @@
         System.out.println(">>> DEBUG: ----Credentials----");
         System.out.println("\tclient: " + c.client.toString());
         System.out.println("\tserver: " + c.server.toString());
-        System.out.println("\tticket: realm: " + c.ticket.realm.toString());
-        System.out.println("\t        sname: " + c.ticket.sname.toString());
+        System.out.println("\tticket: sname: " + c.ticket.sname.toString());
         if (c.startTime != null) {
             System.out.println("\tstartTime: " + c.startTime.getTime());
         }
--- a/src/share/classes/sun/security/krb5/KrbApReq.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbApReq.java	Wed Jul 11 17:10:34 2012 +0800
@@ -179,7 +179,6 @@
     KrbApReq(APOptions apOptions,
              Ticket ticket,
              EncryptionKey key,
-             Realm crealm,
              PrincipalName cname,
              Checksum cksum,
              KerberosTime ctime,
@@ -189,7 +188,7 @@
         throws Asn1Exception, IOException,
                KdcErrException, KrbCryptoException {
 
-        init(apOptions, ticket, key, crealm, cname,
+        init(apOptions, ticket, key, cname,
              cksum, ctime, subKey, seqNumber, authorizationData,
             KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR);
 
@@ -208,7 +207,6 @@
         init(options,
              tgs_creds.ticket,
              tgs_creds.key,
-             tgs_creds.client.getRealm(),
              tgs_creds.client,
              cksum,
              ctime,
@@ -221,7 +219,6 @@
     private void init(APOptions apOptions,
                       Ticket ticket,
                       EncryptionKey key,
-                      Realm crealm,
                       PrincipalName cname,
                       Checksum cksum,
                       KerberosTime ctime,
@@ -232,7 +229,7 @@
         throws Asn1Exception, IOException,
                KdcErrException, KrbCryptoException {
 
-        createMessage(apOptions, ticket, key, crealm, cname,
+        createMessage(apOptions, ticket, key, cname,
                       cksum, ctime, subKey, seqNumber, authorizationData,
             usage);
         obuf = apReqMessg.asn1Encode();
@@ -289,9 +286,6 @@
         ctime = authenticator.ctime;
         cusec = authenticator.cusec;
         authenticator.ctime.setMicroSeconds(authenticator.cusec);
-        authenticator.cname.setRealm(authenticator.crealm);
-        apReqMessg.ticket.sname.setRealm(apReqMessg.ticket.realm);
-        enc_ticketPart.cname.setRealm(enc_ticketPart.crealm);
 
         if (!authenticator.cname.equals(enc_ticketPart.cname))
             throw new KrbApErrException(Krb5.KRB_AP_ERR_BADMATCH);
@@ -457,7 +451,6 @@
     private void createMessage(APOptions apOptions,
                                Ticket ticket,
                                EncryptionKey key,
-                               Realm crealm,
                                PrincipalName cname,
                                Checksum cksum,
                                KerberosTime ctime,
@@ -474,8 +467,7 @@
             seqno = new Integer(seqNumber.current());
 
         authenticator =
-            new Authenticator(crealm,
-                              cname,
+            new Authenticator(cname,
                               cksum,
                               ctime.getMicroSeconds(),
                               ctime,
--- a/src/share/classes/sun/security/krb5/KrbAppMessage.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbAppMessage.java	Wed Jul 11 17:10:34 2012 +0800
@@ -48,8 +48,7 @@
                HostAddress rAddress,
                boolean timestampRequired,
                boolean seqNumberRequired,
-               PrincipalName packetPrincipal,
-               Realm packetRealm)
+               PrincipalName packetPrincipal)
         throws KrbApErrException {
 
         if (!Krb5.AP_EMPTY_ADDRESSES_ALLOWED || sAddress != null) {
--- a/src/share/classes/sun/security/krb5/KrbAsRep.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbAsRep.java	Wed Jul 11 17:10:34 2012 +0800
@@ -152,11 +152,10 @@
 
         DerValue encoding = new DerValue(enc_as_rep_part);
         EncASRepPart enc_part = new EncASRepPart(encoding);
-        rep.ticket.sname.setRealm(rep.ticket.realm);
         rep.encKDCRepPart = enc_part;
 
         ASReq req = asReq.getMessage();
-        check(req, rep);
+        check(true, req, rep);
 
         creds = new Credentials(
                                 rep.ticket,
--- a/src/share/classes/sun/security/krb5/KrbAsReq.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbAsReq.java	Wed Jul 11 17:10:34 2012 +0800
@@ -115,10 +115,8 @@
         }
 
         if (sname == null) {
-            sname = new PrincipalName("krbtgt" +
-                                      PrincipalName.NAME_COMPONENT_SEPARATOR +
-                                      cname.getRealmAsString(),
-                            PrincipalName.KRB_NT_SRV_INST);
+            String realm = cname.getRealmAsString();
+            sname = PrincipalName.tgsService(realm, realm);
         }
 
         if (till == null) {
@@ -128,7 +126,6 @@
         // enc-authorization-data and additional-tickets never in AS-REQ
         KDCReqBody kdc_req_body = new KDCReqBody(options,
                                                  cname,
-                                                 cname.getRealm(),
                                                  sname,
                                                  from,
                                                  till,
--- a/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java	Wed Jul 11 17:10:34 2012 +0800
@@ -99,9 +99,6 @@
     // Called by other constructors
     private void init(PrincipalName cname)
             throws KrbException {
-        if (cname.getRealm() == null) {
-            cname.setRealm(Config.getInstance().getDefaultRealm());
-        }
         this.cname = cname;
         state = State.INIT;
     }
--- a/src/share/classes/sun/security/krb5/KrbCred.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbCred.java	Wed Jul 11 17:10:34 2012 +0800
@@ -96,12 +96,11 @@
         PrincipalName princ = delegatedCreds.getClient();
         Realm realm = princ.getRealm();
         PrincipalName tgService = delegatedCreds.getServer();
-        Realm tgsRealm = tgService.getRealm();
 
-        KrbCredInfo credInfo = new KrbCredInfo(sessionKey, realm,
+        KrbCredInfo credInfo = new KrbCredInfo(sessionKey,
                                                princ, delegatedCreds.flags, delegatedCreds.authTime,
                                                delegatedCreds.startTime, delegatedCreds.endTime,
-                                               delegatedCreds.renewTill, tgsRealm, tgService,
+                                               delegatedCreds.renewTill, tgService,
                                                delegatedCreds.cAddr);
 
         timeStamp = new KerberosTime(KerberosTime.NOW);
@@ -138,19 +137,13 @@
 
         KrbCredInfo credInfo = encPart.ticketInfo[0];
         EncryptionKey credInfoKey = credInfo.key;
-        Realm prealm = credInfo.prealm;
-        // XXX PrincipalName can store realm + principalname or
-        // just principal name.
         PrincipalName pname = credInfo.pname;
-        pname.setRealm(prealm);
         TicketFlags flags = credInfo.flags;
         KerberosTime authtime = credInfo.authtime;
         KerberosTime starttime = credInfo.starttime;
         KerberosTime endtime = credInfo.endtime;
         KerberosTime renewTill = credInfo.renewTill;
-        Realm srealm = credInfo.srealm;
         PrincipalName sname = credInfo.sname;
-        sname.setRealm(srealm);
         HostAddresses caddr = credInfo.caddr;
 
         if (DEBUG) {
--- a/src/share/classes/sun/security/krb5/KrbException.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbException.java	Wed Jul 11 17:10:34 2012 +0800
@@ -45,6 +45,10 @@
         super(s);
     }
 
+    public KrbException(Throwable cause) {
+        super(cause);
+    }
+
     public KrbException(int i) {
         returnCode = i;
     }
--- a/src/share/classes/sun/security/krb5/KrbKdcRep.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbKdcRep.java	Wed Jul 11 17:10:34 2012 +0800
@@ -35,28 +35,17 @@
 abstract class KrbKdcRep {
 
     static void check(
+                      boolean isAsReq,
                       KDCReq req,
                       KDCRep rep
                       ) throws KrbApErrException {
 
-        if (!req.reqBody.cname.equalsWithoutRealm(rep.cname)) {
+        if (isAsReq && !req.reqBody.cname.equals(rep.cname)) {
             rep.encKDCRepPart.key.destroy();
             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
         }
 
-        /**** XXX
-              if (!req.reqBody.crealm.equals(rep.crealm)) {
-              rep.encKDCRepPart.key.destroy();
-              throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
-              }
-        *****/
-
-        if (!req.reqBody.sname.equalsWithoutRealm(rep.encKDCRepPart.sname)) {
-            rep.encKDCRepPart.key.destroy();
-            throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
-        }
-
-        if (!req.reqBody.crealm.equals(rep.encKDCRepPart.srealm)) {
+        if (!req.reqBody.sname.equals(rep.encKDCRepPart.sname)) {
             rep.encKDCRepPart.key.destroy();
             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
         }
@@ -73,7 +62,6 @@
             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
         }
 
-
         for (int i = 1; i < 6; i++) {
             if (req.reqBody.kdcOptions.get(i) !=
                 rep.encKDCRepPart.flags.get(i)) {
--- a/src/share/classes/sun/security/krb5/KrbPriv.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbPriv.java	Wed Jul 11 17:10:34 2012 +0800
@@ -89,8 +89,7 @@
                            raddr,
                            timestampRequired,
                            seqNumberRequired,
-                           creds.client,
-                           creds.client.getRealm()
+                           creds.client
                            );
     }
 
@@ -151,8 +150,7 @@
                            HostAddress rAddress,
                            boolean timestampRequired,
                            boolean seqNumberRequired,
-                           PrincipalName cname,
-                           Realm crealm
+                           PrincipalName cname
                            ) throws Asn1Exception, KdcErrException,
                            KrbApErrException, IOException, KrbCryptoException {
 
@@ -172,8 +170,7 @@
                                      rAddress,
                                      timestampRequired,
                                      seqNumberRequired,
-                                     cname,
-                                     crealm
+                                     cname
                                      );
 
                                return enc_part.userData;
--- a/src/share/classes/sun/security/krb5/KrbSafe.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbSafe.java	Wed Jul 11 17:10:34 2012 +0800
@@ -90,8 +90,7 @@
                            raddr,
                            timestampRequired,
                            seqNumberRequired,
-                           creds.client,
-                           creds.client.getRealm()
+                           creds.client
                            );
     }
 
@@ -154,8 +153,7 @@
                            HostAddress rAddress,
                            boolean timestampRequired,
                            boolean seqNumberRequired,
-                           PrincipalName cname,
-                           Realm crealm
+                           PrincipalName cname
                            ) throws Asn1Exception, KdcErrException,
                            KrbApErrException, IOException, KrbCryptoException {
 
@@ -177,8 +175,7 @@
                                      rAddress,
                                      timestampRequired,
                                      seqNumberRequired,
-                                     cname,
-                                     crealm
+                                     cname
                                      );
 
                                return krb_safe.safeBody.userData;
--- a/src/share/classes/sun/security/krb5/KrbTgsRep.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbTgsRep.java	Wed Jul 11 17:10:34 2012 +0800
@@ -82,12 +82,11 @@
         byte[] enc_tgs_rep_part = rep.encPart.reset(enc_tgs_rep_bytes);
         ref = new DerValue(enc_tgs_rep_part);
         EncTGSRepPart enc_part = new EncTGSRepPart(ref);
-        rep.ticket.sname.setRealm(rep.ticket.realm);
         rep.encKDCRepPart = enc_part;
 
-        check(req, rep);
+        check(false, req, rep);
 
-        creds = new Credentials(rep.ticket,
+        this.creds = new Credentials(rep.ticket,
                                 req.reqBody.cname,
                                 rep.ticket.sname,
                                 enc_part.key,
@@ -99,7 +98,6 @@
                                 enc_part.caddr
                                 );
         this.rep = rep;
-        this.creds = creds;
         this.secondTicket = tgsReq.getSecondTicket();
     }
 
--- a/src/share/classes/sun/security/krb5/KrbTgsReq.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/KrbTgsReq.java	Wed Jul 11 17:10:34 2012 +0800
@@ -148,7 +148,6 @@
                 asCreds.key,
                 ctime,
                 princName,
-                princName.getRealm(),
                 servName,
                 from,
                 till,
@@ -214,7 +213,6 @@
                          EncryptionKey key,
                          KerberosTime ctime,
                          PrincipalName cname,
-                         Realm crealm,
                          PrincipalName sname,
                          KerberosTime from,
                          KerberosTime till,
@@ -273,8 +271,6 @@
         KDCReqBody reqBody = new KDCReqBody(
                                             kdc_options,
                                             cname,
-                                            // crealm,
-                                            sname.getRealm(), // TO
                                             sname,
                                             from,
                                             req_till,
@@ -315,7 +311,6 @@
                                          new APOptions(),
                                          ticket,
                                          key,
-                                         crealm,
                                          cname,
                                          cksum,
                                          ctime,
--- a/src/share/classes/sun/security/krb5/PrincipalName.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/PrincipalName.java	Wed Jul 11 17:10:34 2012 +0800
@@ -38,15 +38,25 @@
 import java.util.Locale;
 import java.io.IOException;
 import java.math.BigInteger;
+import java.util.Arrays;
 import sun.security.krb5.internal.ccache.CCacheOutputStream;
 import sun.security.krb5.internal.util.KerberosString;
 
 
 /**
- * This class encapsulates a Kerberos principal.
+ * Implements the ASN.1 PrincipalName type and its realm in a single class.
+ * <xmp>
+ *    Realm           ::= KerberosString
+ *
+ *    PrincipalName   ::= SEQUENCE {
+ *            name-type       [0] Int32,
+ *            name-string     [1] SEQUENCE OF KerberosString
+ *    }
+ * </xmp>
+ * This class is immutable.
+ * @see Realm
  */
-public class PrincipalName
-    implements Cloneable {
+public class PrincipalName implements Cloneable {
 
     //name types
 
@@ -80,8 +90,6 @@
      */
     public static final int KRB_NT_UID = 5;
 
-
-
     /**
      * TGS Name
      */
@@ -96,98 +104,109 @@
     public static final String NAME_REALM_SEPARATOR_STR = "@";
     public static final String REALM_COMPONENT_SEPARATOR_STR = ".";
 
-    private int nameType;
-    private String[] nameStrings;  // Principal names don't mutate often
+    // Instance fields.
+
+    /**
+     * The name type, from PrincipalName's name-type field.
+     */
+    private final int nameType;
+
+    /**
+     * The name strings, from PrincipalName's name-strings field. This field
+     * must be neither null nor empty. Each entry of it must also be neither
+     * null nor empty. Make sure to clone the field when it's passed in or out.
+     */
+    private final String[] nameStrings;
+
+    /**
+     * The realm this principal belongs to.
+     */
+    private final Realm nameRealm;      // not null
+
+    // cached default salt, not used in clone
+    private transient String salt = null;
 
-    private Realm nameRealm;  // optional; a null realm means use default
-    // Note: the nameRealm is not included in the default ASN.1 encoding
+    // There are 3 basic constructors. All other constructors must call them.
+    // All basic constructors must call validateNameStrings.
+    // 1. From name components
+    // 2. From name
+    // 3. From DER encoding
 
-    // cached salt, might be changed by KDC info, not used in clone
-    private String salt = null;
+    /**
+     * Creates a PrincipalName.
+     */
+    public PrincipalName(int nameType, String[] nameStrings, Realm nameRealm) {
+        if (nameRealm == null) {
+            throw new IllegalArgumentException("Null realm not allowed");
+        }
+        validateNameStrings(nameStrings);
+        this.nameType = nameType;
+        this.nameStrings = nameStrings.clone();
+        this.nameRealm = nameRealm;
+    }
 
-    protected PrincipalName() {
+    // This method is called by Windows NativeCred.c
+    public PrincipalName(String[] nameParts, String realm) throws RealmException {
+        this(KRB_NT_UNKNOWN, nameParts, new Realm(realm));
     }
 
     public PrincipalName(String[] nameParts, int type)
-        throws IllegalArgumentException, IOException {
-        if (nameParts == null) {
-            throw new IllegalArgumentException("Null input not allowed");
-        }
-        nameStrings = new String[nameParts.length];
-        System.arraycopy(nameParts, 0, nameStrings, 0, nameParts.length);
-        nameType = type;
-        nameRealm = null;
+            throws IllegalArgumentException, RealmException {
+        this(type, nameParts, Realm.getDefault());
     }
 
-    public PrincipalName(String[] nameParts) throws IOException {
-        this(nameParts, KRB_NT_UNKNOWN);
+    // Validate a nameStrings argument
+    private static void validateNameStrings(String[] ns) {
+        if (ns == null) {
+            throw new IllegalArgumentException("Null nameStrings not allowed");
+        }
+        if (ns.length == 0) {
+            throw new IllegalArgumentException("Empty nameStrings not allowed");
+        }
+        for (String s: ns) {
+            if (s == null) {
+                throw new IllegalArgumentException("Null nameString not allowed");
+            }
+            if (s.isEmpty()) {
+                throw new IllegalArgumentException("Empty nameString not allowed");
+            }
+        }
     }
 
     public Object clone() {
         try {
             PrincipalName pName = (PrincipalName) super.clone();
-            // Re-assign mutable fields
-            if (nameStrings != null) {
-                pName.nameStrings = nameStrings.clone();
-            }
-            if (nameRealm != null) {
-                pName.nameRealm = (Realm)nameRealm.clone();
-            }
+            UNSAFE.putObject(this, NAME_STRINGS_OFFSET, nameStrings.clone());
             return pName;
         } catch (CloneNotSupportedException ex) {
             throw new AssertionError("Should never happen");
         }
     }
 
-    /*
-     * Added to workaround a bug where the equals method that takes a
-     * PrincipalName is not being called but Object.equals(Object) is
-     * being called.
-     */
-    public boolean equals(Object o) {
-        if (o instanceof PrincipalName)
-            return equals((PrincipalName)o);
-        else
-            return false;
+    private static final long NAME_STRINGS_OFFSET;
+    private static final sun.misc.Unsafe UNSAFE;
+    static {
+        try {
+            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            NAME_STRINGS_OFFSET = unsafe.objectFieldOffset(
+                    PrincipalName.class.getDeclaredField("nameStrings"));
+            UNSAFE = unsafe;
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
     }
 
-    public boolean equals(PrincipalName other) {
-
-
-        if (!equalsWithoutRealm(other)) {
-            return false;
-        }
-
-        if ((nameRealm != null && other.nameRealm == null) ||
-            (nameRealm == null && other.nameRealm != null)) {
-            return false;
-        }
-
-        if (nameRealm != null && other.nameRealm != null) {
-            if (!nameRealm.equals(other.nameRealm)) {
-                return false;
-            }
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
         }
-
-        return true;
-    }
-
-    boolean equalsWithoutRealm(PrincipalName other) {
-
-        if ((nameStrings != null && other.nameStrings == null) ||
-            (nameStrings == null && other.nameStrings != null))
-            return false;
-
-        if (nameStrings != null && other.nameStrings != null) {
-            if (nameStrings.length != other.nameStrings.length)
-                return false;
-            for (int i = 0; i < nameStrings.length; i++)
-                if (!nameStrings[i].equals(other.nameStrings[i]))
-                    return false;
+        if (o instanceof PrincipalName) {
+            PrincipalName other = (PrincipalName)o;
+            return nameRealm.equals(other.nameRealm) &&
+                    Arrays.equals(nameStrings, other.nameStrings);
         }
-
-        return true;
-
+        return false;
     }
 
     /**
@@ -208,20 +227,23 @@
      * http://www.ietf.org/rfc/rfc4120.txt</a>.
      *
      * @param encoding a Der-encoded data.
+     * @param realm the realm for this name
      * @exception Asn1Exception if an error occurs while decoding
      * an ASN1 encoded data.
      * @exception Asn1Exception if there is an ASN1 encoding error
      * @exception IOException if an I/O error occurs
      * @exception IllegalArgumentException if encoding is null
      * reading encoded data.
-     *
      */
-    public PrincipalName(DerValue encoding)
-        throws Asn1Exception, IOException {
-        nameRealm = null;
+    public PrincipalName(DerValue encoding, Realm realm)
+            throws Asn1Exception, IOException {
+        if (realm == null) {
+            throw new IllegalArgumentException("Null realm not allowed");
+        }
+        nameRealm = realm;
         DerValue der;
         if (encoding == null) {
-            throw new IllegalArgumentException("Null input not allowed");
+            throw new IllegalArgumentException("Null encoding not allowed");
         }
         if (encoding.getTag() != DerValue.tag_Sequence) {
             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
@@ -243,14 +265,12 @@
             DerValue subSubDer;
             while(subDer.getData().available() > 0) {
                 subSubDer = subDer.getData().getDerValue();
-                v.addElement(new KerberosString(subSubDer).toString());
+                String namePart = new KerberosString(subSubDer).toString();
+                v.addElement(namePart);
             }
-            if (v.size() > 0) {
-                nameStrings = new String[v.size()];
-                v.copyInto(nameStrings);
-            } else {
-                nameStrings = new String[] {""};
-            }
+            nameStrings = new String[v.size()];
+            v.copyInto(nameStrings);
+            validateNameStrings(nameStrings);
         } else  {
             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
         }
@@ -267,32 +287,35 @@
      * more marshaled value.
      * @param explicitTag tag number.
      * @param optional indicate if this data field is optional
-     * @return an instance of <code>PrincipalName</code>.
-     *
+     * @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)
-        throws Asn1Exception, IOException {
+                                      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))
+        if (explicitTag != (der.getTag() & (byte)0x1F)) {
             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
-        else {
+        } else {
             DerValue subDer = der.getData().getDerValue();
-            return new PrincipalName(subDer);
+            if (realm == null) {
+                realm = Realm.getDefault();
+            }
+            return new PrincipalName(subDer, realm);
         }
     }
 
 
-    // This is protected because the definition of a principal
-    // string is fixed
     // XXX Error checkin consistent with MIT krb5_parse_name
     // Code repetition, realm parsed again by class Realm
-    protected static String[] parseName(String name) {
+    private static String[] parseName(String name) {
 
         Vector<String> tempStrings = new Vector<>();
         String temp = name;
@@ -312,13 +335,13 @@
                     continue;
                 }
                 else {
-                    if (componentStart < i) {
+                    if (componentStart <= i) {
                         component = temp.substring(componentStart, i);
                         tempStrings.addElement(component);
                     }
                     componentStart = i + 1;
                 }
-            } else
+            } else {
                 if (temp.charAt(i) == NAME_REALM_SEPARATOR) {
                     /*
                      * If this separator is escaped then don't treat it
@@ -337,11 +360,11 @@
                         break;
                     }
                 }
+            }
             i++;
         }
 
-        if (i == temp.length())
-        if (componentStart < i) {
+        if (i == temp.length()) {
             component = temp.substring(componentStart, i);
             tempStrings.addElement(component);
         }
@@ -351,30 +374,26 @@
         return result;
     }
 
-    public PrincipalName(String name, int type)
-        throws RealmException {
+    /**
+     * 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);
-        Realm tempRealm = null;
-        String realmString = Realm.parseRealmAtSeparator(name);
-
-        if (realmString == null) {
-            try {
-                Config config = Config.getInstance();
-                realmString = config.getDefaultRealm();
-            } catch (KrbException e) {
-                RealmException re =
-                    new RealmException(e.getMessage());
-                re.initCause(e);
-                throw re;
-            }
+        validateNameStrings(nameParts);
+        if (realm == null) {
+            realm = Realm.parseRealmAtSeparator(name);
         }
-
-        if (realmString != null)
-            tempRealm = new Realm(realmString);
-
         switch (type) {
         case KRB_NT_SRV_HST:
             if (nameParts.length >= 2) {
@@ -401,18 +420,22 @@
             }
             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 = tempRealm;
+                String mapRealm =  mapHostToRealm(nameParts[1]);
+                if (mapRealm != null) {
+                    nameRealm = new Realm(mapRealm);
+                } else {
+                    nameRealm = Realm.getDefault();
+                }
             }
             break;
         case KRB_NT_UNKNOWN:
@@ -422,20 +445,34 @@
         case KRB_NT_UID:
             nameStrings = nameParts;
             nameType = type;
-            nameRealm = tempRealm;
+            if (realm != null) {
+                nameRealm = new Realm(realm);
+            } else {
+                nameRealm = Realm.getDefault();
+            }
             break;
         default:
             throw new IllegalArgumentException("Illegal name type");
         }
     }
 
+    public PrincipalName(String name, int type) throws RealmException {
+        this(name, type, (String)null);
+    }
+
     public PrincipalName(String name) throws RealmException {
         this(name, KRB_NT_UNKNOWN);
     }
 
     public PrincipalName(String name, String realm) throws RealmException {
-        this(name, KRB_NT_UNKNOWN);
-        nameRealm = new Realm(realm);
+        this(name, KRB_NT_UNKNOWN, realm);
+    }
+
+    public static PrincipalName tgsService(String r1, String r2)
+            throws KrbException {
+        return new PrincipalName(PrincipalName.KRB_NT_SRV_INST,
+                new String[] {PrincipalName.TGS_DEFAULT_SRV_NAME, r1},
+                new Realm(r2));
     }
 
     public String getRealmAsString() {
@@ -475,29 +512,17 @@
     }
 
     public String getRealmString() {
-        if (nameRealm != null)
-            return nameRealm.toString();
-        return null;
+        return nameRealm.toString();
     }
 
     public Realm getRealm() {
         return nameRealm;
     }
 
-    public void setRealm(Realm new_nameRealm) throws RealmException {
-        nameRealm = new_nameRealm;
-    }
-
-    public void setRealm(String realmsString) throws RealmException {
-        nameRealm = new Realm(realmsString);
-    }
-
     public String getSalt() {
         if (salt == null) {
             StringBuffer salt = new StringBuffer();
-            if (nameRealm != null) {
-                salt.append(nameRealm.toString());
-            }
+            salt.append(nameRealm.toString());
             for (int i = 0; i < nameStrings.length; i++) {
                 salt.append(nameStrings[i]);
             }
@@ -513,11 +538,8 @@
                 str.append("/");
             str.append(nameStrings[i]);
         }
-        if (nameRealm != null) {
-            str.append("@");
-            str.append(nameRealm.toString());
-        }
-
+        str.append("@");
+        str.append(nameRealm.toString());
         return str.toString();
     }
 
@@ -532,7 +554,8 @@
     }
 
     /**
-     * Encodes a <code>PrincipalName</code> object.
+     * Encodes a <code>PrincipalName</code> object. Note that only the type and
+     * names are encoded. To encode the realm, call getRealm().asn1Encode().
      * @return the byte array of the encoded PrncipalName object.
      * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
      * @exception IOException if an I/O error occurs while reading encoded data.
@@ -597,12 +620,10 @@
     public void writePrincipal(CCacheOutputStream cos) throws IOException {
         cos.write32(nameType);
         cos.write32(nameStrings.length);
-        if (nameRealm != null) {
-            byte[] realmBytes = null;
-            realmBytes = nameRealm.toString().getBytes();
-            cos.write32(realmBytes.length);
-            cos.write(realmBytes, 0, realmBytes.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();
@@ -612,31 +633,6 @@
     }
 
     /**
-     * Creates a KRB_NT_SRV_INST name from the supplied
-     * name components and realm.
-     * @param primary the primary component of the name
-     * @param instance the instance component of the name
-     * @param realm the realm
-     * @throws KrbException
-     */
-    protected PrincipalName(String primary, String instance, String realm,
-                            int type)
-        throws KrbException {
-
-        if (type != KRB_NT_SRV_INST) {
-            throw new KrbException(Krb5.KRB_ERR_GENERIC, "Bad name type");
-        }
-
-        String[] nParts = new String[2];
-        nParts[0] = primary;
-        nParts[1] = instance;
-
-        this.nameStrings = nParts;
-        this.nameRealm = new Realm(realm);
-        this.nameType = type;
-    }
-
-    /**
      * Returns the instance component of a name.
      * In a multi-component name such as a KRB_NT_SRV_INST
      * name, the second component is returned.
--- a/src/share/classes/sun/security/krb5/Realm.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/Realm.java	Wed Jul 11 17:10:34 2012 +0800
@@ -46,24 +46,29 @@
  * <xmp>
  * Realm ::= GeneralString
  * </xmp>
+ * This class is immutable.
  */
 public class Realm implements Cloneable {
-    private String realm;
+    private final String realm; // not null nor empty
     private static boolean DEBUG = Krb5.DEBUG;
 
-    private Realm() {
-    }
-
     public Realm(String name) throws RealmException {
         realm = parseRealm(name);
     }
 
+    public static Realm getDefault() throws RealmException {
+        try {
+            return new Realm(Config.getInstance().getDefaultRealm());
+        } catch (RealmException re) {
+            throw re;
+        } catch (KrbException ke) {
+            throw new RealmException(ke);
+        }
+    }
+
+    // Immutable class, no need to clone
     public Object clone() {
-        Realm new_realm = new Realm();
-        if (realm != null) {
-            new_realm.realm = new String(realm);
-        }
-        return new_realm;
+        return this;
     }
 
     public boolean equals(Object obj) {
@@ -76,21 +81,11 @@
         }
 
         Realm that = (Realm)obj;
-        if (this.realm != null && that.realm != null ) {
-            return this.realm.equals(that.realm);
-        } else {
-            return (this.realm == null && that.realm == null);
-        }
+        return this.realm.equals(that.realm);
     }
 
     public int hashCode() {
-        int result = 17 ;
-
-        if( realm != null ) {
-            result = 37 * result + realm.hashCode();
-        }
-
-        return result;
+        return realm.hashCode();
     }
 
     /**
@@ -116,6 +111,7 @@
         return realm;
     }
 
+    // Extract realm from a string like dummy@REALM
     public static String parseRealmAtSeparator(String name)
         throws RealmException {
         if (name == null) {
@@ -128,8 +124,12 @@
         while (i < temp.length()) {
             if (temp.charAt(i) == PrincipalName.NAME_REALM_SEPARATOR) {
                 if (i == 0 || temp.charAt(i - 1) != '\\') {
-                    if (i + 1 < temp.length())
+                    if (i + 1 < temp.length()) {
                         result = temp.substring(i + 1, temp.length());
+                    } else {
+                        throw new IllegalArgumentException
+                                ("empty realm part not allowed");
+                    }
                     break;
                 }
             }
@@ -219,7 +219,8 @@
      * @return an instance of Realm.
      *
      */
-    public static Realm parse(DerInputStream data, byte explicitTag, boolean optional) throws Asn1Exception, IOException, RealmException {
+    public static Realm parse(DerInputStream data, byte explicitTag, boolean optional)
+            throws Asn1Exception, IOException, RealmException {
         if ((optional) && (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) {
             return null;
         }
--- a/src/share/classes/sun/security/krb5/RealmException.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/RealmException.java	Wed Jul 11 17:10:34 2012 +0800
@@ -47,4 +47,7 @@
         super(i,s);
     }
 
+    public RealmException(Throwable cause) {
+        super(cause);
+    }
 }
--- a/src/share/classes/sun/security/krb5/ServiceName.java	Mon Jul 09 22:26:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-/*
- *
- *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
- *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
- */
-
-package sun.security.krb5;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-public class ServiceName extends PrincipalName {
-
-    public ServiceName(String name, int type) throws RealmException {
-        super(name, type);
-
-    }
-    public ServiceName(String name) throws RealmException {
-        this(name, PrincipalName.KRB_NT_UNKNOWN);
-    }
-
-    public ServiceName(String name, String realm) throws RealmException {
-        this(name, PrincipalName.KRB_NT_UNKNOWN);
-        setRealm(realm);
-    }
-
-    public ServiceName (String service, String instance, String realm)
-        throws KrbException
-    {
-        super(service, instance, realm, PrincipalName.KRB_NT_SRV_INST);
-    }
-
-}
--- a/src/share/classes/sun/security/krb5/internal/ASRep.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ASRep.java	Wed Jul 11 17:10:34 2012 +0800
@@ -42,11 +42,10 @@
 
     public ASRep(
             PAData[] new_pAData,
-            Realm new_crealm,
             PrincipalName new_cname,
             Ticket new_ticket,
             EncryptedData new_encPart) throws IOException {
-        super(new_pAData, new_crealm, new_cname, new_ticket,
+        super(new_pAData, new_cname, new_ticket,
                 new_encPart, Krb5.KRB_AS_REP);
     }
 
--- a/src/share/classes/sun/security/krb5/internal/Authenticator.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/Authenticator.java	Wed Jul 11 17:10:34 2012 +0800
@@ -61,7 +61,6 @@
 public class Authenticator {
 
     public int authenticator_vno;
-    public Realm crealm;
     public PrincipalName cname;
     Checksum cksum; //optional
     public int cusec;
@@ -71,7 +70,6 @@
     public AuthorizationData authorizationData; //optional
 
     public Authenticator(
-            Realm new_crealm,
             PrincipalName new_cname,
             Checksum new_cksum,
             int new_cusec,
@@ -80,7 +78,6 @@
             Integer new_seqNumber,
             AuthorizationData new_authorizationData) {
         authenticator_vno = Krb5.AUTHNETICATOR_VNO;
-        crealm = new_crealm;
         cname = new_cname;
         cksum = new_cksum;
         cusec = new_cusec;
@@ -131,8 +128,8 @@
         if (authenticator_vno != 5) {
             throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION);
         }
-        crealm = Realm.parse(der.getData(), (byte) 0x01, false);
-        cname = PrincipalName.parse(der.getData(), (byte) 0x02, false);
+        Realm crealm = Realm.parse(der.getData(), (byte) 0x01, false);
+        cname = PrincipalName.parse(der.getData(), (byte) 0x02, false, crealm);
         cksum = Checksum.parse(der.getData(), (byte) 0x03, true);
         subDer = der.getData().getDerValue();
         if ((subDer.getTag() & (byte) 0x1F) == 0x04) {
@@ -180,7 +177,7 @@
         DerOutputStream temp = new DerOutputStream();
         temp.putInteger(BigInteger.valueOf(authenticator_vno));
         v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x00), temp.toByteArray()));
-        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), crealm.asn1Encode()));
+        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), cname.getRealm().asn1Encode()));
         v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x02), cname.asn1Encode()));
         if (cksum != null) {
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x03), cksum.asn1Encode()));
--- a/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/CredentialsUtil.java	Wed Jul 11 17:10:34 2012 +0800
@@ -72,23 +72,9 @@
     public static Credentials acquireServiceCreds(
                 String service, Credentials ccreds)
     throws KrbException, IOException {
-        ServiceName sname = new ServiceName(service);
+        PrincipalName sname = new PrincipalName(service);
         String serviceRealm = sname.getRealmString();
         String localRealm = ccreds.getClient().getRealmString();
-        String defaultRealm = Config.getInstance().getDefaultRealm();
-
-        if (localRealm == null) {
-            PrincipalName temp = null;
-            if ((temp = ccreds.getServer()) != null)
-                localRealm = temp.getRealmString();
-        }
-        if (localRealm == null) {
-            localRealm = defaultRealm;
-        }
-        if (serviceRealm == null) {
-            serviceRealm = localRealm;
-            sname.setRealm(serviceRealm);
-        }
 
         /*
           if (!localRealm.equalsIgnoreCase(serviceRealm)) { //do cross-realm auth entication
@@ -128,13 +114,12 @@
 
         int i = 0, k = 0;
         Credentials cTgt = null, newTgt = null, theTgt = null;
-        ServiceName tempService = null;
+        PrincipalName tempService = null;
         String realm = null, newTgtRealm = null, theTgtRealm = null;
 
         for (cTgt = ccreds, i = 0; i < realms.length;)
         {
-            tempService = new ServiceName(PrincipalName.TGS_DEFAULT_SRV_NAME,
-                                          serviceRealm, realms[i]);
+            tempService = PrincipalName.tgsService(serviceRealm, realms[i]);
 
             if (DEBUG)
             {
@@ -164,9 +149,7 @@
                      newTgt == null && k > i; k--)
                 {
 
-                    tempService = new ServiceName(
-                                       PrincipalName.TGS_DEFAULT_SRV_NAME,
-                                       realms[k], realms[i]);
+                    tempService = PrincipalName.tgsService(realms[k], realms[i]);
                     if (DEBUG)
                     {
                         System.out.println(">>> Credentials acquireServiceCreds: inner loop: [" + k +"] tempService=" + tempService);
@@ -306,7 +289,7 @@
     * This method does the real job to request the service credential.
     */
     private static Credentials serviceCreds(
-            ServiceName service, Credentials ccreds)
+            PrincipalName service, Credentials ccreds)
             throws KrbException, IOException {
         return new KrbTgsReq(ccreds, service).sendAndGetCreds();
     }
--- a/src/share/classes/sun/security/krb5/internal/EncASRepPart.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/EncASRepPart.java	Wed Jul 11 17:10:34 2012 +0800
@@ -46,7 +46,6 @@
             KerberosTime new_starttime,
             KerberosTime new_endtime,
             KerberosTime new_renewTill,
-            Realm new_srealm,
             PrincipalName new_sname,
             HostAddresses new_caddr) {
         super(
@@ -59,7 +58,6 @@
                 new_starttime,
                 new_endtime,
                 new_renewTill,
-                new_srealm,
                 new_sname,
                 new_caddr,
                 Krb5.KRB_ENC_AS_REP_PART
--- a/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/EncKDCRepPart.java	Wed Jul 11 17:10:34 2012 +0800
@@ -74,7 +74,6 @@
     public KerberosTime starttime; //optional
     public KerberosTime endtime;
     public KerberosTime renewTill; //optional
-    public Realm srealm;
     public PrincipalName sname;
     public HostAddresses caddr; //optional
     public int msgType; //not included in sequence
@@ -89,7 +88,6 @@
             KerberosTime new_starttime,
             KerberosTime new_endtime,
             KerberosTime new_renewTill,
-            Realm new_srealm,
             PrincipalName new_sname,
             HostAddresses new_caddr,
             int new_msgType) {
@@ -102,7 +100,6 @@
         starttime = new_starttime;
         endtime = new_endtime;
         renewTill = new_renewTill;
-        srealm = new_srealm;
         sname = new_sname;
         caddr = new_caddr;
         msgType = new_msgType;
@@ -158,8 +155,8 @@
         starttime = KerberosTime.parse(der.getData(), (byte) 0x06, true);
         endtime = KerberosTime.parse(der.getData(), (byte) 0x07, false);
         renewTill = KerberosTime.parse(der.getData(), (byte) 0x08, true);
-        srealm = Realm.parse(der.getData(), (byte) 0x09, false);
-        sname = PrincipalName.parse(der.getData(), (byte) 0x0A, false);
+        Realm srealm = Realm.parse(der.getData(), (byte) 0x09, false);
+        sname = PrincipalName.parse(der.getData(), (byte) 0x0A, false, srealm);
         if (der.getData().available() > 0) {
             caddr = HostAddresses.parse(der.getData(), (byte) 0x0B, true);
         }
@@ -206,7 +203,7 @@
                     true, (byte) 0x08), renewTill.asn1Encode());
         }
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
-                true, (byte) 0x09), srealm.asn1Encode());
+                true, (byte) 0x09), sname.getRealm().asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
                 true, (byte) 0x0A), sname.asn1Encode());
         if (caddr != null) {
--- a/src/share/classes/sun/security/krb5/internal/EncTGSRepPart.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/EncTGSRepPart.java	Wed Jul 11 17:10:34 2012 +0800
@@ -45,7 +45,6 @@
             KerberosTime new_starttime,
             KerberosTime new_endtime,
             KerberosTime new_renewTill,
-            Realm new_srealm,
             PrincipalName new_sname,
             HostAddresses new_caddr) {
         super(
@@ -58,7 +57,6 @@
                 new_starttime,
                 new_endtime,
                 new_renewTill,
-                new_srealm,
                 new_sname,
                 new_caddr,
                 Krb5.KRB_ENC_TGS_REP_PART);
--- a/src/share/classes/sun/security/krb5/internal/EncTicketPart.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/EncTicketPart.java	Wed Jul 11 17:10:34 2012 +0800
@@ -65,7 +65,6 @@
 
     public TicketFlags flags;
     public EncryptionKey key;
-    public Realm crealm;
     public PrincipalName cname;
     public TransitedEncoding transited;
     public KerberosTime authtime;
@@ -78,7 +77,6 @@
     public EncTicketPart(
             TicketFlags new_flags,
             EncryptionKey new_key,
-            Realm new_crealm,
             PrincipalName new_cname,
             TransitedEncoding new_transited,
             KerberosTime new_authtime,
@@ -89,7 +87,6 @@
             AuthorizationData new_authorizationData) {
         flags = new_flags;
         key = new_key;
-        crealm = new_crealm;
         cname = new_cname;
         transited = new_transited;
         authtime = new_authtime;
@@ -151,8 +148,8 @@
         }
         flags = TicketFlags.parse(der.getData(), (byte) 0x00, false);
         key = EncryptionKey.parse(der.getData(), (byte) 0x01, false);
-        crealm = Realm.parse(der.getData(), (byte) 0x02, false);
-        cname = PrincipalName.parse(der.getData(), (byte) 0x03, false);
+        Realm crealm = Realm.parse(der.getData(), (byte) 0x02, false);
+        cname = PrincipalName.parse(der.getData(), (byte) 0x03, false, crealm);
         transited = TransitedEncoding.parse(der.getData(), (byte) 0x04, false);
         authtime = KerberosTime.parse(der.getData(), (byte) 0x05, false);
         starttime = KerberosTime.parse(der.getData(), (byte) 0x06, true);
@@ -186,7 +183,7 @@
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
                 true, (byte) 0x01), key.asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
-                true, (byte) 0x02), crealm.asn1Encode());
+                true, (byte) 0x02), cname.getRealm().asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
                 true, (byte) 0x03), cname.asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
--- a/src/share/classes/sun/security/krb5/internal/KDCRep.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/KDCRep.java	Wed Jul 11 17:10:34 2012 +0800
@@ -61,7 +61,6 @@
  */
 public class KDCRep {
 
-    public Realm crealm;
     public PrincipalName cname;
     public Ticket ticket;
     public EncryptedData encPart;
@@ -73,7 +72,6 @@
 
     public KDCRep(
             PAData[] new_pAData,
-            Realm new_crealm,
             PrincipalName new_cname,
             Ticket new_ticket,
             EncryptedData new_encPart,
@@ -90,7 +88,6 @@
                 }
             }
         }
-        crealm = new_crealm;
         cname = new_cname;
         ticket = new_ticket;
         encPart = new_encPart;
@@ -174,8 +171,8 @@
         } else {
             pAData = null;
         }
-        crealm = Realm.parse(der.getData(), (byte) 0x03, false);
-        cname = PrincipalName.parse(der.getData(), (byte) 0x04, false);
+        Realm crealm = Realm.parse(der.getData(), (byte) 0x03, false);
+        cname = PrincipalName.parse(der.getData(), (byte) 0x04, false, crealm);
         ticket = Ticket.parse(der.getData(), (byte) 0x05, false);
         encPart = EncryptedData.parse(der.getData(), (byte) 0x06, false);
         if (der.getData().available() > 0) {
@@ -212,7 +209,7 @@
                     true, (byte) 0x02), temp);
         }
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
-                true, (byte) 0x03), crealm.asn1Encode());
+                true, (byte) 0x03), cname.getRealm().asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
                 true, (byte) 0x04), cname.asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT,
--- a/src/share/classes/sun/security/krb5/internal/KDCReqBody.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/KDCReqBody.java	Wed Jul 11 17:10:34 2012 +0800
@@ -72,7 +72,6 @@
 public class KDCReqBody {
     public KDCOptions kdcOptions;
     public PrincipalName cname; //optional in ASReq only
-    public Realm crealm;
     public PrincipalName sname; //optional
     public KerberosTime from; //optional
     public KerberosTime till;
@@ -87,7 +86,6 @@
     public KDCReqBody(
             KDCOptions new_kdcOptions,
             PrincipalName new_cname, //optional in ASReq only
-            Realm new_crealm,
             PrincipalName new_sname, //optional
             KerberosTime new_from, //optional
             KerberosTime new_till,
@@ -100,7 +98,6 @@
             ) throws IOException {
         kdcOptions = new_kdcOptions;
         cname = new_cname;
-        crealm = new_crealm;
         sname = new_sname;
         from = new_from;
         till = new_till;
@@ -142,12 +139,22 @@
             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
         }
         kdcOptions = KDCOptions.parse(encoding.getData(), (byte)0x00, false);
-        cname = PrincipalName.parse(encoding.getData(), (byte)0x01, true);
+
+        // cname only appears in AS-REQ and it shares the realm field with
+        // sname. This is the only place where realm comes after the name.
+        // We first give cname a fake realm and reassign it the correct
+        // realm after the realm field is read.
+        cname = PrincipalName.parse(encoding.getData(), (byte)0x01, true,
+                new Realm("PLACEHOLDER"));
         if ((msgType != Krb5.KRB_AS_REQ) && (cname != null)) {
             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
         }
-        crealm = Realm.parse(encoding.getData(), (byte)0x02, false);
-        sname = PrincipalName.parse(encoding.getData(), (byte)0x03, true);
+        Realm realm = Realm.parse(encoding.getData(), (byte)0x02, false);
+        if (cname != null) {
+            cname = new PrincipalName(
+                    cname.getNameType(), cname.getNameStrings(), realm);
+        }
+        sname = PrincipalName.parse(encoding.getData(), (byte)0x03, true, realm);
         from = KerberosTime.parse(encoding.getData(), (byte)0x04, true);
         till = KerberosTime.parse(encoding.getData(), (byte)0x05, false);
         rtime = KerberosTime.parse(encoding.getData(), (byte)0x06, true);
@@ -223,9 +230,11 @@
                 v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), cname.asn1Encode()));
             }
         }
-        v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), crealm.asn1Encode()));
         if (sname != null) {
+            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), sname.getRealm().asn1Encode()));
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), sname.asn1Encode()));
+        } else if (cname != null) {
+            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), cname.getRealm().asn1Encode()));
         }
         if (from != null) {
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x04), from.asn1Encode()));
--- a/src/share/classes/sun/security/krb5/internal/KRBError.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/KRBError.java	Wed Jul 11 17:10:34 2012 +0800
@@ -90,9 +90,7 @@
     private KerberosTime sTime;
     private Integer suSec;
     private int errorCode;
-    private Realm crealm; //optional
     private PrincipalName cname; //optional
-    private Realm realm;
     private PrincipalName sname;
     private String eText; //optional
     private byte[] eData; //optional
@@ -128,9 +126,7 @@
                     KerberosTime new_sTime,
                     Integer new_suSec,
                     int new_errorCode,
-                    Realm new_crealm,
                     PrincipalName new_cname,
-                    Realm new_realm,
                     PrincipalName new_sname,
                     String new_eText,
                     byte[] new_eData
@@ -142,9 +138,7 @@
         sTime = new_sTime;
         suSec = new_suSec;
         errorCode = new_errorCode;
-        crealm =  new_crealm;
         cname = new_cname;
-        realm = new_realm;
         sname = new_sname;
         eText = new_eText;
         eData = new_eData;
@@ -159,9 +153,7 @@
                     KerberosTime new_sTime,
                     Integer new_suSec,
                     int new_errorCode,
-                    Realm new_crealm,
                     PrincipalName new_cname,
-                    Realm new_realm,
                     PrincipalName new_sname,
                     String new_eText,
                     byte[] new_eData,
@@ -174,9 +166,7 @@
         sTime = new_sTime;
         suSec = new_suSec;
         errorCode = new_errorCode;
-        crealm =  new_crealm;
         cname = new_cname;
-        realm = new_realm;
         sname = new_sname;
         eText = new_eText;
         eData = new_eData;
@@ -359,10 +349,10 @@
             errorCode = subDer.getData().getBigInteger().intValue();
         }
         else  throw new Asn1Exception(Krb5.ASN1_BAD_ID);
-        crealm = Realm.parse(der.getData(), (byte)0x07, true);
-        cname = PrincipalName.parse(der.getData(), (byte)0x08, true);
-        realm = Realm.parse(der.getData(), (byte)0x09, false);
-        sname = PrincipalName.parse(der.getData(), (byte)0x0A, false);
+        Realm crealm = Realm.parse(der.getData(), (byte)0x07, true);
+        cname = PrincipalName.parse(der.getData(), (byte)0x08, true, crealm);
+        Realm realm = Realm.parse(der.getData(), (byte)0x09, false);
+        sname = PrincipalName.parse(der.getData(), (byte)0x0A, false, realm);
         eText = null;
         eData = null;
         eCksum = null;
@@ -403,15 +393,9 @@
             System.out.println("\t suSec is " + suSec);
             System.out.println("\t error code is " + errorCode);
             System.out.println("\t error Message is " + Krb5.getErrorMessage(errorCode));
-            if (crealm != null) {
-                System.out.println("\t crealm is " + crealm.toString());
-            }
             if (cname != null) {
                 System.out.println("\t cname is " + cname.toString());
             }
-            if (realm != null) {
-                System.out.println("\t realm is " + realm.toString());
-            }
             if (sname != null) {
                 System.out.println("\t sname is " + sname.toString());
             }
@@ -458,14 +442,12 @@
         temp.putInteger(BigInteger.valueOf(errorCode));
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x06), temp);
 
-        if (crealm != null) {
-            bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x07), crealm.asn1Encode());
-        }
         if (cname != null) {
+            bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x07), cname.getRealm().asn1Encode());
             bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x08), cname.asn1Encode());
         }
 
-        bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x09), realm.asn1Encode());
+        bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x09), sname.getRealm().asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x0A), sname.asn1Encode());
 
         if (eText != null) {
@@ -506,9 +488,7 @@
                 isEqual(sTime, other.sTime) &&
                 isEqual(suSec, other.suSec) &&
                 errorCode == other.errorCode &&
-                isEqual(crealm, other.crealm) &&
                 isEqual(cname, other.cname) &&
-                isEqual(realm, other.realm) &&
                 isEqual(sname, other.sname) &&
                 isEqual(eText, other.eText) &&
                 java.util.Arrays.equals(eData, other.eData) &&
@@ -528,9 +508,7 @@
         if (sTime != null) result = 37 * result + sTime.hashCode();
         if (suSec != null) result = 37 * result + suSec.hashCode();
         result = 37 * result + errorCode;
-        if (crealm != null) result = 37 * result + crealm.hashCode();
         if (cname != null) result = 37 * result + cname.hashCode();
-        if (realm != null) result = 37 * result + realm.hashCode();
         if (sname != null) result = 37 * result + sname.hashCode();
         if (eText != null) result = 37 * result + eText.hashCode();
         result = 37 * result + Arrays.hashCode(eData);
--- a/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java	Wed Jul 11 17:10:34 2012 +0800
@@ -63,14 +63,12 @@
 
 public class KrbCredInfo {
     public EncryptionKey key;
-    public Realm prealm; //optional
     public PrincipalName pname; //optional
     public TicketFlags flags; //optional
     public KerberosTime authtime; //optional
     public KerberosTime starttime; //optional
     public KerberosTime endtime; //optional
     public KerberosTime renewTill; //optional
-    public Realm srealm; //optional
     public PrincipalName sname; //optional
     public HostAddresses caddr; //optional
 
@@ -79,26 +77,22 @@
 
     public KrbCredInfo(
                        EncryptionKey new_key,
-                       Realm new_prealm,
                        PrincipalName new_pname,
                        TicketFlags new_flags,
                        KerberosTime new_authtime,
                        KerberosTime new_starttime,
                        KerberosTime new_endtime,
                        KerberosTime new_renewTill,
-                       Realm new_srealm,
                        PrincipalName new_sname,
                        HostAddresses new_caddr
                            ) {
         key = new_key;
-        prealm = new_prealm;
         pname = new_pname;
         flags = new_flags;
         authtime = new_authtime;
         starttime = new_starttime;
         endtime = new_endtime;
         renewTill = new_renewTill;
-        srealm = new_srealm;
         sname = new_sname;
         caddr = new_caddr;
     }
@@ -115,21 +109,20 @@
         if (encoding.getTag() != DerValue.tag_Sequence) {
             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
         }
-        prealm = null;
         pname = null;
         flags = null;
         authtime = null;
         starttime = null;
         endtime = null;
         renewTill = null;
-        srealm = null;
         sname = null;
         caddr = null;
         key = EncryptionKey.parse(encoding.getData(), (byte)0x00, false);
+        Realm prealm = null, srealm = null;
         if (encoding.getData().available() > 0)
             prealm = Realm.parse(encoding.getData(), (byte)0x01, true);
         if (encoding.getData().available() > 0)
-            pname = PrincipalName.parse(encoding.getData(), (byte)0x02, true);
+            pname = PrincipalName.parse(encoding.getData(), (byte)0x02, true, prealm);
         if (encoding.getData().available() > 0)
             flags = TicketFlags.parse(encoding.getData(), (byte)0x03, true);
         if (encoding.getData().available() > 0)
@@ -143,7 +136,7 @@
         if (encoding.getData().available() > 0)
             srealm = Realm.parse(encoding.getData(), (byte)0x08, true);
         if (encoding.getData().available() > 0)
-            sname = PrincipalName.parse(encoding.getData(), (byte)0x09, true);
+            sname = PrincipalName.parse(encoding.getData(), (byte)0x09, true, srealm);
         if (encoding.getData().available() > 0)
             caddr = HostAddresses.parse(encoding.getData(), (byte)0x0A, true);
         if (encoding.getData().available() > 0)
@@ -159,10 +152,10 @@
     public byte[] asn1Encode() throws Asn1Exception, IOException {
         Vector<DerValue> v = new Vector<>();
         v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), key.asn1Encode()));
-        if (prealm != null)
-            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), prealm.asn1Encode()));
-        if (pname != null)
+        if (pname != null) {
+            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), pname.getRealm().asn1Encode()));
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), pname.asn1Encode()));
+        }
         if (flags != null)
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), flags.asn1Encode()));
         if (authtime != null)
@@ -173,10 +166,10 @@
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x06), endtime.asn1Encode()));
         if (renewTill != null)
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x07), renewTill.asn1Encode()));
-        if (srealm != null)
-            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x08), srealm.asn1Encode()));
-        if (sname != null)
+        if (sname != null) {
+            v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x08), sname.getRealm().asn1Encode()));
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x09), sname.asn1Encode()));
+        }
         if (caddr != null)
             v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x0A), caddr.asn1Encode()));
         DerValue der[] = new DerValue[v.size()];
@@ -190,8 +183,6 @@
         KrbCredInfo kcred = new KrbCredInfo();
         kcred.key = (EncryptionKey)key.clone();
         // optional fields
-        if (prealm != null)
-            kcred.prealm = (Realm)prealm.clone();
         if (pname != null)
             kcred.pname = (PrincipalName)pname.clone();
         if (flags != null)
@@ -204,8 +195,6 @@
             kcred.endtime = (KerberosTime)endtime.clone();
         if (renewTill != null)
             kcred.renewTill = (KerberosTime)renewTill.clone();
-        if (srealm != null)
-            kcred.srealm = (Realm)srealm.clone();
         if (sname != null)
             kcred.sname = (PrincipalName)sname.clone();
         if (caddr != null)
--- a/src/share/classes/sun/security/krb5/internal/TGSRep.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/TGSRep.java	Wed Jul 11 17:10:34 2012 +0800
@@ -42,12 +42,11 @@
 
     public TGSRep(
                   PAData[] new_pAData,
-                  Realm new_crealm,
                   PrincipalName new_cname,
                   Ticket new_ticket,
                   EncryptedData new_encPart
                       ) throws IOException {
-        super(new_pAData, new_crealm, new_cname, new_ticket,
+        super(new_pAData, new_cname, new_ticket,
               new_encPart, Krb5.KRB_TGS_REP);
     }
 
--- a/src/share/classes/sun/security/krb5/internal/Ticket.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/Ticket.java	Wed Jul 11 17:10:34 2012 +0800
@@ -60,7 +60,6 @@
 
 public class Ticket implements Cloneable {
     public int tkt_vno;
-    public Realm realm;
     public PrincipalName sname;
     public EncryptedData encPart;
 
@@ -69,7 +68,6 @@
 
     public Object clone() {
         Ticket new_ticket = new Ticket();
-        new_ticket.realm = (Realm)realm.clone();
         new_ticket.sname = (PrincipalName)sname.clone();
         new_ticket.encPart = (EncryptedData)encPart.clone();
         new_ticket.tkt_vno = tkt_vno;
@@ -77,12 +75,10 @@
     }
 
     public Ticket(
-                  Realm new_realm,
                   PrincipalName new_sname,
                   EncryptedData new_encPart
                       ) {
         tkt_vno = Krb5.TICKET_VNO;
-        realm = new_realm;
         sname = new_sname;
         encPart = new_encPart;
     }
@@ -123,8 +119,8 @@
         tkt_vno = subDer.getData().getBigInteger().intValue();
         if (tkt_vno != Krb5.TICKET_VNO)
             throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION);
-        realm = Realm.parse(der.getData(), (byte)0x01, false);
-        sname = PrincipalName.parse(der.getData(), (byte)0x02, false);
+        Realm srealm = Realm.parse(der.getData(), (byte)0x01, false);
+        sname = PrincipalName.parse(der.getData(), (byte)0x02, false, srealm);
         encPart = EncryptedData.parse(der.getData(), (byte)0x03, false);
         if (der.getData().available() > 0)
             throw new Asn1Exception(Krb5.ASN1_BAD_ID);
@@ -142,7 +138,7 @@
         DerValue der[] = new DerValue[4];
         temp.putInteger(BigInteger.valueOf(tkt_vno));
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp);
-        bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), realm.asn1Encode());
+        bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), sname.getRealm().asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), sname.asn1Encode());
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), encPart.asn1Encode());
         temp = new DerOutputStream();
--- a/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java	Wed Jul 11 17:10:34 2012 +0800
@@ -114,7 +114,6 @@
     // made public for KinitOptions to call directly
     public PrincipalName readPrincipal(int version) throws IOException, RealmException {
         int type, length, namelength, kret;
-        PrincipalName p;
         String[] pname = null;
         String realm;
         /* Read principal type */
@@ -144,11 +143,13 @@
             realm = result[0];
             pname = new String[length];
             System.arraycopy(result, 1, pname, 0, length);
-            p = new PrincipalName(pname, type);
-            p.setRealm(realm);
+            return new PrincipalName(type, pname, new Realm(realm));
         }
-        else p = new PrincipalName(result, type);
-        return p;
+        try {
+            return new PrincipalName(result, type);
+        } catch (RealmException re) {
+            return null;
+        }
     }
 
     /*
@@ -342,10 +343,10 @@
     Credentials readCred(int version) throws IOException,RealmException, KrbApErrException, Asn1Exception {
         PrincipalName cpname = readPrincipal(version);
         if (DEBUG)
-            System.out.println(">>>DEBUG <CCacheInputStream>  client principal is " + cpname.toString());
+            System.out.println(">>>DEBUG <CCacheInputStream>  client principal is " + cpname);
         PrincipalName spname = readPrincipal(version);
         if (DEBUG)
-            System.out.println(">>>DEBUG <CCacheInputStream> server principal is " + spname.toString());
+            System.out.println(">>>DEBUG <CCacheInputStream> server principal is " + spname);
         EncryptionKey key = readKey(version);
         if (DEBUG)
             System.out.println(">>>DEBUG <CCacheInputStream> key type: " + key.getEType());
--- a/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java	Wed Jul 11 17:10:34 2012 +0800
@@ -36,9 +36,7 @@
 public class Credentials {
 
     PrincipalName cname;
-    Realm crealm;
     PrincipalName sname;
-    Realm srealm;
     EncryptionKey key;
     KerberosTime authtime;
     KerberosTime starttime;//optional
@@ -67,15 +65,7 @@
             Ticket new_ticket,
             Ticket new_secondTicket) {
         cname = (PrincipalName) new_cname.clone();
-        if (new_cname.getRealm() != null) {
-            crealm = (Realm) new_cname.getRealm().clone();
-        }
-
         sname = (PrincipalName) new_sname.clone();
-        if (new_sname.getRealm() != null) {
-            srealm = (Realm) new_sname.getRealm().clone();
-        }
-
         key = (EncryptionKey) new_key.clone();
 
         authtime = (KerberosTime) new_authtime.clone();
@@ -110,7 +100,6 @@
         {
             return;
         }
-        crealm = (Realm) kdcRep.crealm.clone();
         cname = (PrincipalName) kdcRep.cname.clone();
         ticket = (Ticket) kdcRep.ticket.clone();
         key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone();
@@ -123,7 +112,6 @@
         if (kdcRep.encKDCRepPart.renewTill != null) {
             renewTill = (KerberosTime) kdcRep.encKDCRepPart.renewTill.clone();
         }
-        srealm = (Realm) kdcRep.encKDCRepPart.srealm.clone();
         sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone();
         caddr = (HostAddresses) kdcRep.encKDCRepPart.caddr.clone();
         secondTicket = (Ticket) new_secondTicket.clone();
@@ -138,17 +126,7 @@
 
     public Credentials(KDCRep kdcRep, Ticket new_ticket) {
         sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone();
-        srealm = (Realm) kdcRep.encKDCRepPart.srealm.clone();
-        try {
-            sname.setRealm(srealm);
-        } catch (RealmException e) {
-        }
         cname = (PrincipalName) kdcRep.cname.clone();
-        crealm = (Realm) kdcRep.crealm.clone();
-        try {
-            cname.setRealm(crealm);
-        } catch (RealmException e) {
-        }
         key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone();
         authtime = (KerberosTime) kdcRep.encKDCRepPart.authtime.clone();
         if (kdcRep.encKDCRepPart.starttime != null) {
@@ -202,9 +180,6 @@
     }
 
     public PrincipalName getServicePrincipal() throws RealmException {
-        if (sname.getRealm() == null) {
-            sname.setRealm(srealm);
-        }
         return sname;
     }
 
--- a/src/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ccache/CredentialsCache.java	Wed Jul 11 17:10:34 2012 +0800
@@ -120,6 +120,6 @@
     public abstract void save() throws IOException, KrbException;
     public abstract Credentials[] getCredsList();
     public abstract Credentials getDefaultCreds();
-    public abstract Credentials getCreds(PrincipalName sname, Realm srealm) ;
-    public abstract Credentials getCreds(LoginOptions options, PrincipalName sname, Realm srealm) ;
+    public abstract Credentials getCreds(PrincipalName sname);
+    public abstract Credentials getCreds(LoginOptions options, PrincipalName sname);
 }
--- a/src/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java	Wed Jul 11 17:10:34 2012 +0800
@@ -59,7 +59,6 @@
     public int version;
     public Tag tag; // optional
     public PrincipalName primaryPrincipal;
-    public Realm primaryRealm;
     private Vector<Credentials> credentialsList;
     private static String dir;
     private static boolean DEBUG = Krb5.DEBUG;
@@ -79,7 +78,6 @@
             }
             if (principal != null) {
                 fcc.primaryPrincipal = principal;
-                fcc.primaryRealm = principal.getRealm();
             }
             fcc.load(cacheName);
             return fcc;
@@ -153,7 +151,6 @@
     synchronized void init(PrincipalName principal, String name)
         throws IOException, KrbException {
         primaryPrincipal = principal;
-        primaryRealm = principal.getRealm();
         CCacheOutputStream cos =
             new CCacheOutputStream(new FileOutputStream(name));
         version = KRB5_FCC_FVNO_3;
@@ -183,7 +180,6 @@
             }
         } else
             primaryPrincipal = p;
-        primaryRealm = primaryPrincipal.getRealm();
         credentialsList = new Vector<Credentials> ();
         while (cis.available() > 0) {
             Credentials cred = cis.readCred(version);
@@ -291,18 +287,16 @@
 
     }
 
-    public Credentials getCreds(LoginOptions options,
-                                PrincipalName sname, Realm srealm) {
+    public Credentials getCreds(LoginOptions options, PrincipalName sname) {
         if (options == null) {
-            return getCreds(sname, srealm);
+            return getCreds(sname);
         } else {
             Credentials[] list = getCredsList();
             if (list == null) {
                 return null;
             } else {
                 for (int i = 0; i < list.length; i++) {
-                    if (sname.match(list[i].sname) &&
-                        (srealm.toString().equals(list[i].srealm.toString()))) {
+                    if (sname.match(list[i].sname)) {
                         if (list[i].flags.match(options)) {
                             return list[i];
                         }
@@ -317,16 +311,14 @@
     /**
      * Gets a credentials for a specified service.
      * @param sname service principal name.
-     * @param srealm the realm that the service belongs to.
      */
-    public Credentials getCreds(PrincipalName sname, Realm srealm) {
+    public Credentials getCreds(PrincipalName sname) {
         Credentials[] list = getCredsList();
         if (list == null) {
             return null;
         } else {
             for (int i = 0; i < list.length; i++) {
-                if (sname.match(list[i].sname) &&
-                    (srealm.toString().equals(list[i].srealm.toString()))) {
+                if (sname.match(list[i].sname)) {
                     return list[i];
                 }
             }
@@ -343,7 +335,7 @@
                 if (list[i].sname.toString().startsWith("krbtgt")) {
                     String[] nameStrings = list[i].sname.getNameStrings();
                     // find the TGT for the current realm krbtgt/realm@realm
-                    if (nameStrings[1].equals(list[i].srealm.toString())) {
+                    if (nameStrings[1].equals(list[i].sname.getRealm().toString())) {
                        return list[i];
                     }
                 }
--- a/src/share/classes/sun/security/krb5/internal/ccache/MemoryCredentialsCache.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ccache/MemoryCredentialsCache.java	Wed Jul 11 17:10:34 2012 +0800
@@ -64,7 +64,7 @@
 
     public abstract Credentials[] getCredsList();
 
-    public abstract Credentials getCreds(PrincipalName sname, Realm srealm) ;
+    public abstract Credentials getCreds(PrincipalName sname) ;
 
     public abstract PrincipalName getPrimaryPrincipal();
 
--- a/src/share/classes/sun/security/krb5/internal/ktab/KeyTabInputStream.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ktab/KeyTabInputStream.java	Wed Jul 11 17:10:34 2012 +0800
@@ -83,8 +83,7 @@
         }
         int nameType = read(4);
         index -= 4;
-        PrincipalName service = new PrincipalName(nameParts, nameType);
-        service.setRealm(realm);
+        PrincipalName service = new PrincipalName(nameType, nameParts, realm);
         KerberosTime timeStamp = readTimeStamp();
 
         int keyVersion = read() & 0xff;
--- a/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java	Wed Jul 11 17:10:34 2012 +0800
@@ -163,7 +163,7 @@
 
             EncryptedData encPart = t.encPart;
             PrincipalName ticketSname = t.sname;
-            Realm ticketRealm = t.realm;
+            Realm ticketRealm = t.sname.getRealm();
 
             String serverPrincipal = serverKeys[0].getPrincipal().getName();
 
@@ -175,8 +175,7 @@
              */
 
             // Check that ticket Sname matches serverPrincipal
-            String ticketPrinc = ticketSname.toString().concat("@" +
-                                        ticketRealm.toString());
+            String ticketPrinc = ticketSname.toString();
             if (!ticketPrinc.equals(serverPrincipal)) {
                 if (debug != null && Debug.isOn("handshake"))
                    System.out.println("Service principal in Ticket does not"
@@ -224,7 +223,6 @@
 
             if (debug != null && Debug.isOn("handshake")) {
                 System.out.println("server principal: " + serverPrincipal);
-                System.out.println("realm: " + encTicketPart.crealm.toString());
                 System.out.println("cname: " + encTicketPart.cname.toString());
             }
         } catch (IOException e) {
--- a/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java	Wed Jul 11 17:10:34 2012 +0800
@@ -206,9 +206,7 @@
             System.out.println(">>> Kinit realm name is " + realm);
         }
 
-        PrincipalName sname = new PrincipalName("krbtgt" + "/" + realm,
-                                        PrincipalName.KRB_NT_SRV_INST);
-        sname.setRealm(realm);
+        PrincipalName sname = PrincipalName.tgsService(realm, realm);
         builder.setTarget(sname);
 
         if (DEBUG) {
--- a/src/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java	Wed Jul 11 17:10:34 2012 +0800
@@ -146,15 +146,6 @@
                                                        "Principal name: " + p +
                                                        e.getMessage());
                 }
-                if (principal.getRealm() == null) {
-                    String realm =
-                        Config.getInstance().getDefault("default_realm",
-                                                        "libdefaults");
-                    if (realm != null) {
-                        principal.setRealm(realm);
-                    } else throw new IllegalArgumentException("invalid " +
-                                                              "Realm name");
-                }
             } else if (this.password == null) {
                 // Have already processed a Principal, this must be a password
                 password = args[i].toCharArray();
@@ -175,16 +166,6 @@
     }
 
     PrincipalName getDefaultPrincipal() {
-        String cname;
-        String realm = null;
-        try {
-            realm = Config.getInstance().getDefaultRealm();
-        } catch (KrbException e) {
-            System.out.println ("Can not get default realm " +
-                                e.getMessage());
-            e.printStackTrace();
-            return null;
-        }
 
         // get default principal name from the cachename if it is
         // available.
@@ -204,10 +185,6 @@
             }
             PrincipalName p = cis.readPrincipal(version);
             cis.close();
-            String temp = p.getRealmString();
-            if (temp == null) {
-                p.setRealm(realm);
-            }
             if (DEBUG) {
                 System.out.println(">>>KinitOptions principal name from "+
                                    "the cache is :" + p);
@@ -230,19 +207,15 @@
             System.out.println(">>>KinitOptions default username is :"
                                + username);
         }
-        if (realm != null) {
-            try {
-                PrincipalName p = new PrincipalName(username);
-                if (p.getRealm() == null)
-                    p.setRealm(realm);
-                return p;
-            } catch (RealmException e) {
-                // ignore exception , return null
-                if (DEBUG) {
-                    System.out.println ("Exception in getting principal " +
-                                        "name " + e.getMessage());
-                    e.printStackTrace();
-                }
+        try {
+            PrincipalName p = new PrincipalName(username);
+            return p;
+        } catch (RealmException e) {
+            // ignore exception , return null
+            if (DEBUG) {
+                System.out.println ("Exception in getting principal " +
+                                    "name " + e.getMessage());
+                e.printStackTrace();
             }
         }
         return null;
--- a/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java	Wed Jul 11 17:10:34 2012 +0800
@@ -273,9 +273,6 @@
         PrincipalName pname = null;
         try {
             pname = new PrincipalName(principal);
-            if (pname.getRealm() == null) {
-                pname.setRealm(Config.getInstance().getDefaultRealm());
-            }
         } catch (KrbException e) {
             System.err.println("Failed to add " + principal +
                                " to keytab.");
@@ -382,9 +379,6 @@
         PrincipalName pname = null;
         try {
             pname = new PrincipalName(principal);
-            if (pname.getRealm() == null) {
-                pname.setRealm(Config.getInstance().getDefaultRealm());
-            }
             if (!forced) {
                 String answer;
                 BufferedReader cis =
--- a/src/windows/native/sun/security/krb5/NativeCreds.c	Mon Jul 09 22:26:08 2012 +0100
+++ b/src/windows/native/sun/security/krb5/NativeCreds.c	Wed Jul 11 17:10:34 2012 +0800
@@ -67,7 +67,6 @@
 jmethodID ticketFlagsConstructor = 0;
 jmethodID kerberosTimeConstructor = 0;
 jmethodID krbcredsConstructor = 0;
-jmethodID setRealmMethod = 0;
 
 /*
  * Function prototypes for internal routines
@@ -279,7 +278,7 @@
     }
 
     principalNameConstructor = (*env)->GetMethodID(env, principalNameClass,
-                                    "<init>", "([Ljava/lang/String;)V");
+                        "<init>", "([Ljava/lang/String;Ljava/lang/String;)V");
     if (principalNameConstructor == 0) {
         printf("LSA: Couldn't find PrincipalName constructor\n");
         return JNI_ERR;
@@ -318,14 +317,6 @@
         printf("LSA: Found KerberosTime constructor\n");
     }
 
-    // load the setRealm method in PrincipalName
-    setRealmMethod = (*env)->GetMethodID(env, principalNameClass,
-                                    "setRealm", "(Ljava/lang/String;)V");
-    if (setRealmMethod == 0) {
-        printf("LSA: Couldn't find setRealm in PrincipalName\n");
-        return JNI_ERR;
-    }
-
     if (native_debug) {
         printf("LSA: Finished OnLoad processing\n");
     }
@@ -952,13 +943,12 @@
 
         // Do I have to worry about storage reclamation here?
     }
-    principal = (*env)->NewObject(env, principalNameClass,
-                    principalNameConstructor, stringArray);
-
     // now set the realm in the principal
     realmLen = (ULONG)wcslen((PWCHAR)realm);
     realmStr = (*env)->NewString(env, (PWCHAR)realm, (USHORT)realmLen);
-    (*env)->CallVoidMethod(env, principal, setRealmMethod, realmStr);
+
+    principal = (*env)->NewObject(env, principalNameClass,
+                    principalNameConstructor, stringArray, realmStr);
 
     // free local resources
     LocalFree(realm);
--- a/test/sun/security/krb5/ServiceNameClone.java	Mon Jul 09 22:26:08 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2010, 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.
- *
- * 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.
- */
-/*
- * @test
- * @bug 6856069
- * @summary PrincipalName.clone() does not invoke super.clone()
- */
-
-import sun.security.krb5.ServiceName;
-
-public class ServiceNameClone {
-    public static void main(String[] args) throws Exception {
-        ServiceName sn = new ServiceName("me@HERE");
-        if (sn.clone().getClass() != ServiceName.class) {
-            throw new Exception("ServiceName's clone is not a ServiceName");
-        }
-        if (!sn.clone().equals(sn)) {
-            throw new Exception("ServiceName's clone changed");
-        }
-    }
-}
--- a/test/sun/security/krb5/auto/KDC.java	Mon Jul 09 22:26:08 2012 +0100
+++ b/test/sun/security/krb5/auto/KDC.java	Wed Jul 11 17:10:34 2012 +0800
@@ -606,9 +606,8 @@
         TGSReq tgsReq = new TGSReq(in);
         PrincipalName service = tgsReq.reqBody.sname;
         if (options.containsKey(KDC.Option.RESP_NT)) {
-            service = new PrincipalName(service.getNameStrings(),
-                    (int)options.get(KDC.Option.RESP_NT));
-            service.setRealm(service.getRealm());
+            service = new PrincipalName((int)options.get(KDC.Option.RESP_NT),
+                    service.getNameStrings(), service.getRealm());
         }
         try {
             System.out.println(realm + "> " + tgsReq.reqBody.cname +
@@ -632,7 +631,6 @@
                         EncryptedData ed = apReq.authenticator;
                         tkt = apReq.ticket;
                         int te = tkt.encPart.getEType();
-                        tkt.sname.setRealm(tkt.realm);
                         EncryptionKey kkey = keyForUser(tkt.sname, te, true);
                         byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET);
                         DerInputStream derIn = new DerInputStream(bb);
@@ -693,7 +691,6 @@
             EncTicketPart enc = new EncTicketPart(
                     tFlags,
                     key,
-                    etp.crealm,
                     etp.cname,
                     new TransitedEncoding(1, new byte[0]),  // TODO
                     new KerberosTime(new Date()),
@@ -709,7 +706,6 @@
                 throw new KrbException(Krb5.KDC_ERR_SUMTYPE_NOSUPP); // TODO
             }
             Ticket t = new Ticket(
-                    body.crealm,
                     service,
                     new EncryptedData(skey, enc.asn1Encode(), KeyUsage.KU_TICKET)
             );
@@ -725,7 +721,6 @@
                     new KerberosTime(new Date()),
                     body.from,
                     till, body.rtime,
-                    body.crealm,
                     service,
                     body.addresses != null  // always set caddr
                             ? body.addresses
@@ -734,7 +729,6 @@
                     );
             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
             TGSRep tgsRep = new TGSRep(null,
-                    etp.crealm,
                     etp.cname,
                     t,
                     edata);
@@ -756,8 +750,8 @@
                         new KerberosTime(new Date()),
                         0,
                         ke.returnCode(),
-                        body.crealm, body.cname,
-                        new Realm(getRealm()), service,
+                        body.cname,
+                        service,
                         KrbException.errorMessage(ke.returnCode()),
                         null);
             }
@@ -780,7 +774,6 @@
         if (options.containsKey(KDC.Option.RESP_NT)) {
             service = new PrincipalName(service.getNameStrings(),
                     (int)options.get(KDC.Option.RESP_NT));
-            service.setRealm(service.getRealm());
         }
         try {
             System.out.println(realm + "> " + asReq.reqBody.cname +
@@ -788,7 +781,6 @@
                     service);
 
             KDCReqBody body = asReq.reqBody;
-            body.cname.setRealm(getRealm());
 
             eTypes = KDCReqBodyDotEType(body);
             int eType = eTypes[0];
@@ -971,7 +963,6 @@
             EncTicketPart enc = new EncTicketPart(
                     tFlags,
                     key,
-                    body.crealm,
                     body.cname,
                     new TransitedEncoding(1, new byte[0]),
                     new KerberosTime(new Date()),
@@ -980,7 +971,6 @@
                     body.addresses,
                     null);
             Ticket t = new Ticket(
-                    body.crealm,
                     service,
                     new EncryptedData(skey, enc.asn1Encode(), KeyUsage.KU_TICKET)
             );
@@ -996,14 +986,12 @@
                     new KerberosTime(new Date()),
                     body.from,
                     till, body.rtime,
-                    body.crealm,
                     service,
                     body.addresses
                     );
             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_AS_REP_PART);
             ASRep asRep = new ASRep(
                     outPAs.toArray(new PAData[outPAs.size()]),
-                    body.crealm,
                     body.cname,
                     t,
                     edata);
@@ -1024,7 +1012,6 @@
                 asRep.encKDCRepPart = enc_part;
                 sun.security.krb5.internal.ccache.Credentials credentials =
                     new sun.security.krb5.internal.ccache.Credentials(asRep);
-                asReq.reqBody.cname.setRealm(getRealm());
                 CredentialsCache cache =
                     CredentialsCache.create(asReq.reqBody.cname, ccache);
                 if (cache == null) {
@@ -1059,8 +1046,8 @@
                         new KerberosTime(new Date()),
                         0,
                         ke.returnCode(),
-                        body.crealm, body.cname,
-                        new Realm(getRealm()), service,
+                        body.cname,
+                        service,
                         KrbException.errorMessage(ke.returnCode()),
                         eData);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/krb5/name/Constructors.java	Wed Jul 11 17:10:34 2012 +0800
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+/*
+ * @test
+ * @bug 6966259
+ * @summary Make PrincipalName and Realm immutable
+ * @run main/othervm Constructors
+ */
+
+import java.util.Arrays;
+import sun.security.krb5.*;
+
+public class Constructors {
+    public static void main(String[] args) throws Exception {
+
+        int type;
+        boolean testNoDefaultDomain;
+
+        // Part 1: on format
+
+        // Good ones
+        type = PrincipalName.KRB_NT_UNKNOWN;
+        checkName("a", type, "R", "R", "a");
+        checkName("a@R2", type, "R", "R", "a");
+        checkName("a/b", type, "R", "R", "a", "b");
+        checkName("a/b@R2", type, "R", "R", "a", "b");
+        checkName("a/b/c", type, "R", "R", "a", "b", "c");
+        checkName("a/b/c@R2", type, "R", "R", "a", "b", "c");
+        // Weird ones
+        checkName("a\\/b", type, "R", "R", "a/b");
+        checkName("a\\/b\\/c", type, "R", "R", "a/b/c");
+        checkName("a\\/b\\@R2", type, "R", "R", "a/b@R2");
+        // Bad ones
+        checkName("a", type, "", null);
+        checkName("a/", type, "R", null);
+        checkName("/a", type, "R", null);
+        checkName("a//b", type, "R", null);
+        checkName("a@", type, null, null);
+        type = PrincipalName.KRB_NT_SRV_HST;
+
+        // Part 2: on realm choices
+
+        // When there is no default realm
+        System.setProperty("java.security.krb5.conf",
+                System.getProperty("test.src", ".") + "/empty.conf");
+        Config.refresh();
+
+        // A Windows client login to AD always has a default realm
+        try {
+            Realm r = Realm.getDefault();
+            System.out.println("testNoDefaultDomain = false. Realm is " + r);
+            testNoDefaultDomain = false;
+        } catch (RealmException re) {
+            // Great. This is what we expected
+            testNoDefaultDomain = true;
+        }
+
+        if (testNoDefaultDomain) {
+            type = PrincipalName.KRB_NT_UNKNOWN;
+            checkName("a", type, "R1", "R1", "a");      // arg
+            checkName("a@R1", type, null, "R1", "a");   // or r in name
+            checkName("a@R2", type, "R1", "R1", "a");   // arg over r
+            checkName("a", type, null, null);      // fail if none
+            checkName("a/b@R1", type, null, "R1", "a", "b");
+            type = PrincipalName.KRB_NT_SRV_HST;
+            // Let's pray "b.h" won't be canonicalized
+            checkName("a/b.h", type, "R1", "R1", "a", "b.h");    // arg
+            checkName("a/b.h@R1", type, null, "R1", "a", "b.h"); // or r in name
+            checkName("a/b.h@R1", type, "R2", "R2", "a", "b.h"); // arg over r
+            checkName("a/b.h", type, null, null);    // fail if none
+        }
+
+        // When there is default realm
+        System.setProperty("java.security.krb5.conf",
+                System.getProperty("test.src", ".") + "/krb5.conf");
+        Config.refresh();
+
+        type = PrincipalName.KRB_NT_UNKNOWN;
+        checkName("a", type, "R1", "R1", "a");      // arg
+        checkName("a@R1", type, null, "R1", "a");   // or r in name
+        checkName("a@R2", type, "R1", "R1", "a");   // arg over r
+        checkName("a", type, null, "R", "a");       // default
+        checkName("a/b", type, null, "R", "a", "b");
+        type = PrincipalName.KRB_NT_SRV_HST;
+        checkName("a/b.h3", type, "R1", "R1", "a", "b.h3");     // arg
+        checkName("a/b.h@R1", type, null, "R1", "a", "b.h");    // or r in name
+        checkName("a/b.h3@R2", type, "R1", "R1", "a", "b.h3");  // arg over r
+        checkName("a/b.h2", type, "R1", "R1", "a", "b.h2");     // arg over map
+        checkName("a/b.h2@R1", type, null, "R1", "a", "b.h2");  // r over map
+        checkName("a/b.h2", type, null, "R2", "a", "b.h2");     // map
+        checkName("a/b.h", type, null, "R", "a", "b.h");        // default
+    }
+
+    // Check if the creation matches the expected output.
+    // Note: realm == null means creation failure
+    static void checkName(String n, int t, String s,
+            String realm, String... parts)
+            throws Exception {
+        PrincipalName pn = null;
+        try {
+            pn = new PrincipalName(n, t, s);
+        } catch (Exception e) {
+            if (realm == null) {
+                return; // This is expected
+            } else {
+                throw e;
+            }
+        }
+        if (!pn.getRealmAsString().equals(realm)
+                || !Arrays.equals(pn.getNameStrings(), parts)) {
+            throw new Exception(pn.toString() + " vs "
+                    + Arrays.toString(parts) + "@" + realm);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/krb5/name/empty.conf	Wed Jul 11 17:10:34 2012 +0800
@@ -0,0 +1,2 @@
+[libdefaults]
+dns_fallback = false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/krb5/name/krb5.conf	Wed Jul 11 17:10:34 2012 +0800
@@ -0,0 +1,10 @@
+[libdefaults]
+default_realm = R
+
+[realms]
+R = {
+    kdc = kdc
+}
+
+[domain_realm]
+.h2 = R2