< prev index next >

test/jdk/sun/security/krb5/auto/KDC.java

Print this page
rev 54745 : 8215032: Support Kerberos cross-realm referrals (RFC 6806)
Reviewed-by: weijun

@@ -163,10 +163,18 @@
     // different s2kparams for different etypes, pretend they are the same
     // at the moment.
     private TreeMap<String,byte[]> s2kparamses = new TreeMap<>
             (String.CASE_INSENSITIVE_ORDER);
 
+    // Alias for referrals.
+    private TreeMap<String,KDC> aliasReferrals = new TreeMap<>
+            (String.CASE_INSENSITIVE_ORDER);
+
+    // Alias for local resolution.
+    private TreeMap<String,PrincipalName> alias2Principals = new TreeMap<>
+            (String.CASE_INSENSITIVE_ORDER);
+
     // Realm name
     private String realm;
     // KDC
     private String kdc;
     // Service port number

@@ -551,10 +559,33 @@
      */
     public int getPort() {
         return port;
     }
 
+    /**
+     * Register an alias name to be referred to a different KDC for
+     * resolution, according to RFC 6806.
+     * @param alias Alias name (i.e. user@REALM.COM).
+     * @param referredKDC KDC to which the alias is referred for resolution.
+     */
+    public void registerAlias(String alias, KDC referredKDC) {
+        aliasReferrals.remove(alias);
+        aliasReferrals.put(alias, referredKDC);
+    }
+
+    /**
+     * Register an alias to be resolved to a Principal Name locally,
+     * according to RFC 6806.
+     * @param alias Alias name (i.e. user@REALM.COM).
+     * @param user Principal Name to which the alias is resolved.
+     */
+    public void registerAlias(String alias, String user)
+            throws RealmException {
+        alias2Principals.remove(alias);
+        alias2Principals.put(alias, new PrincipalName(user));
+    }
+
     // Private helper methods
 
     /**
      * Private constructor, cannot be called outside.
      * @param realm

@@ -776,10 +807,21 @@
             EncTicketPart etp = null;
 
             PrincipalName cname = null;
             boolean allowForwardable = true;
 
+            if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) {
+                KDC referral = aliasReferrals.get(body.sname.getNameString());
+                if (referral != null) {
+                    service = new PrincipalName(
+                            PrincipalName.TGS_DEFAULT_SRV_NAME +
+                            PrincipalName.NAME_COMPONENT_SEPARATOR_STR +
+                            referral.getRealm(), PrincipalName.KRB_NT_SRV_INST,
+                            this.getRealm());
+                }
+            }
+
             if (pas == null || pas.length == 0) {
                 throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
             } else {
                 PrincipalName forUserCName = null;
                 for (PAData pa: pas) {

@@ -962,11 +1004,12 @@
                     tFlags,
                     timeAfter(0),
                     from,
                     till, renewTill,
                     service,
-                    body.addresses
+                    body.addresses,
+                    null
                     );
             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(),
                     KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
             TGSRep tgsRep = new TGSRep(null,
                     cname,

@@ -1006,10 +1049,11 @@
      * @return the response
      * @throws java.lang.Exception for various errors
      */
     protected byte[] processAsReq(byte[] in) throws Exception {
         ASReq asReq = new ASReq(in);
+        byte[] asReqbytes = asReq.asn1Encode();
         int[] eTypes = null;
         List<PAData> outPAs = new ArrayList<>();
 
         PrincipalName service = asReq.reqBody.sname;
         if (options.containsKey(KDC.Option.RESP_NT)) {

@@ -1028,10 +1072,28 @@
             if (eTypes.length == 0) {
                 throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
             }
             int eType = eTypes[0];
 
+            if (body.kdcOptions.get(KDCOptions.CANONICALIZE) &&
+                    body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) {
+                PrincipalName principal = alias2Principals.get(
+                        body.cname.getNameString());
+                if (principal != null) {
+                    body.cname = principal;
+                } else {
+                    KDC referral = aliasReferrals.get(body.cname.getNameString());
+                    if (referral != null) {
+                        body.cname = new PrincipalName(
+                                PrincipalName.TGS_DEFAULT_SRV_NAME,
+                                PrincipalName.KRB_NT_SRV_INST,
+                                referral.getRealm());
+                        throw new KrbException(Krb5.KRB_ERR_WRONG_REALM);
+                    }
+                }
+            }
+
             EncryptionKey ckey = keyForUser(body.cname, eType, false);
             EncryptionKey skey = keyForUser(service, eType, true);
 
             if (options.containsKey(KDC.Option.ONLY_RC4_TGT)) {
                 int tgtEType = EncryptedData.ETYPE_ARCFOUR_HMAC;

@@ -1209,28 +1271,40 @@
                 eid.putSequence(pas);
                 outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray()));
             }
 
             PAData[] inPAs = KDCReqDotPAData(asReq);
+            List<PAData> enc_outPAs = new ArrayList<>();
             if (inPAs == null || inPAs.length == 0) {
                 Object preauth = options.get(Option.PREAUTH_REQUIRED);
                 if (preauth == null || preauth.equals(Boolean.TRUE)) {
                     throw new KrbException(Krb5.KDC_ERR_PREAUTH_REQUIRED);
                 }
             } else {
+                EncryptionKey pakey = null;
                 try {
                     EncryptedData data = newEncryptedData(
                             new DerValue(inPAs[0].getValue()));
-                    EncryptionKey pakey
-                            = keyForUser(body.cname, data.getEType(), false);
+                    pakey = keyForUser(body.cname, data.getEType(), false);
                     data.decrypt(pakey, KeyUsage.KU_PA_ENC_TS);
                 } catch (Exception e) {
                     KrbException ke = new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED);
                     ke.initCause(e);
                     throw ke;
                 }
                 bFlags[Krb5.TKT_OPTS_PRE_AUTHENT] = true;
+                for (PAData pa : inPAs) {
+                    if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) {
+                        Checksum ckSum = new Checksum(
+                                Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128,
+                                asReqbytes, ckey, KeyUsage.KU_AS_REQ);
+                        enc_outPAs.add(new PAData(Krb5.PA_REQ_ENC_PA_REP,
+                                ckSum.asn1Encode()));
+                        bFlags[Krb5.TKT_OPTS_ENC_PA_REP] = true;
+                        break;
+                    }
+                }
             }
 
             TicketFlags tFlags = new TicketFlags(bFlags);
             EncTicketPart enc = new EncTicketPart(
                     tFlags,

@@ -1257,11 +1331,12 @@
                     tFlags,
                     timeAfter(0),
                     from,
                     till, rtime,
                     service,
-                    body.addresses
+                    body.addresses,
+                    enc_outPAs.toArray(new PAData[enc_outPAs.size()])
                     );
             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(),
                     KeyUsage.KU_ENC_AS_REP_PART);
             ASRep asRep = new ASRep(
                     outPAs.toArray(new PAData[outPAs.size()]),

@@ -1305,12 +1380,14 @@
                     + " " +ke.returnCodeMessage());
             byte[] eData = null;
             if (kerr == null) {
                 if (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED ||
                         ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) {
+                    outPAs.add(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0]));
+                }
+                if (outPAs.size() > 0) {
                     DerOutputStream bytes = new DerOutputStream();
-                    bytes.write(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0]).asn1Encode());
                     for (PAData p: outPAs) {
                         bytes.write(p.asn1Encode());
                     }
                     DerOutputStream temp = new DerOutputStream();
                     temp.write(DerValue.tag_Sequence, bytes);
< prev index next >