krb5 commit: Add test for cross realm S4U2Self using referrals

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/aec6e0f51bfc20be67b70a7d81808b4add22838a
commit aec6e0f51bfc20be67b70a7d81808b4add22838a
Author: Isaac Boukris <[email protected]>
Date:   Sat Oct 13 16:27:02 2018 +0300

    Add test for cross realm S4U2Self using referrals
    
    [[email protected]: factored out tgtname() in kdb_test.c; added trace
    messages to tests and removed old redundant test]
    
    ticket: 8747

 src/plugins/kdb/test/kdb_test.c |   37 +++++++++++++++++++++++++++++---
 src/tests/gssapi/t_s4u.py       |   44 +++++++++++++++++++++++++++++---------
 2 files changed, 66 insertions(+), 15 deletions(-)

diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
index 776dda3..bc65bfb 100644
--- a/src/plugins/kdb/test/kdb_test.c
+++ b/src/plugins/kdb/test/kdb_test.c
@@ -64,6 +64,9 @@
  * Key values are generated using a hash of the kvno, enctype, salt type, and
  * principal name.  This module does not use master key encryption, so it
  * serves as a partial test of the DAL's ability to avoid that.
+ *
+ * For cross realm, just add outbound 'krbtgt/OTHER_REALM' principal to each
+ * kdc configuration, while for inbound trust the local krbtgt will be used.
  */
 
 #include "k5-int.h"
@@ -297,12 +300,27 @@ test_close(krb5_context context)
     return 0;
 }
 
+/* Return the principal name krbtgt/tgs_realm@our_realm. */
+static krb5_principal
+tgtname(krb5_context context, const krb5_data *tgs_realm,
+        const krb5_data *our_realm)
+{
+    krb5_principal princ;
+
+    check(krb5_build_principal_ext(context, &princ,
+                                   our_realm->length, our_realm->data,
+                                   KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
+                                   tgs_realm->length, tgs_realm->data, 0));
+    princ->type = KRB5_NT_SRV_INST;
+    return princ;
+}
+
 static krb5_error_code
 test_get_principal(krb5_context context, krb5_const_principal search_for,
                    unsigned int flags, krb5_db_entry **entry)
 {
     krb5_error_code ret;
-    krb5_principal princ = NULL;
+    krb5_principal princ = NULL, tgtprinc;
     krb5_principal_data empty_princ = { KV5M_PRINCIPAL };
     testhandle h = context->dal_handle->db_context;
     char *search_name = NULL, *canon = NULL, *flagstr, **names, **key_strings;
@@ -330,14 +348,25 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
                 princ = NULL;
                 ret = 0;
                 goto cleanup;
+            } else if (flags & KRB5_KDB_FLAG_CANONICALIZE) {
+                /* Generate a server referral by looking up the TGT for the
+                 * canonical name's realm. */
+                tgtprinc = tgtname(context, &princ->realm, &search_for->realm);
+                krb5_free_principal(context, princ);
+                princ = tgtprinc;
+
+                krb5_free_unparsed_name(context, search_name);
+                check(krb5_unparse_name_flags(context, princ,
+                                              KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+                                              &search_name));
+                ename = search_name;
             } else {
-                /* We could look up a cross-realm TGS entry, but we don't need
-                 * that behavior yet. */
                 ret = KRB5_KDB_NOENTRY;
                 goto cleanup;
             }
+        } else {
+            ename = canon;
         }
-        ename = canon;
     } else {
         check(krb5_copy_principal(context, search_for, &princ));
         ename = search_name;
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index 35bc9e4..eb9545d 100755
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -139,21 +139,43 @@ if 'auth1: user@' not in out or 'auth2: user@' not in out:
 
 realm.stop()
 
-# Exercise cross-realm S4U2Self.  The query in the foreign realm will
-# fail, but we can check that the right server principal was used.
+# Test cross realm S4U2Self using server referrals.
+mark('cross-realm S4U2Self')
+testprincs = {'krbtgt/SREALM': {'keys': 'aes128-cts'},
+              'krbtgt/UREALM': {'keys': 'aes128-cts'},
+              'user': {'keys': 'aes128-cts'}}
+kdcconf1 = {'realms': {'$realm': {'database_module': 'test'}},
+            'dbmodules': {'test': {'db_library': 'test',
+                                   'princs': testprincs }}}
+kdcconf2 = {'realms': {'$realm': {'database_module': 'test'}},
+            'dbmodules': {'test': {'db_library': 'test',
+                                   'princs': testprincs,
+                                   'alias': {'user@SREALM': '@SREALM'}}}}
+r1, r2 = cross_realms(2, xtgts=(),
+                      args=({'realm': 'SREALM', 'kdc_conf': kdcconf1},
+                            {'realm': 'UREALM', 'kdc_conf': kdcconf2}),
+                      create_kdb=False)
+
+r1.start_kdc()
+r2.start_kdc()
+r1.extract_keytab(r1.user_princ, r1.keytab)
+r1.kinit(r1.user_princ, None, ['-k', '-t', r1.keytab])
+
 # Include a regression test for #8741 by unsetting the default realm.
-r1, r2 = cross_realms(2, create_user=False)
-r1.run([kinit, '-k', r1.host_princ])
 remove_default = {'libdefaults': {'default_realm': None}}
 no_default = r1.special_env('no_default', False, krb5_conf=remove_default)
-r1.run(['./t_s4u', 'p:' + r2.host_princ], env=no_default, expected_code=1,
-       expected_msg='Server not found in Kerberos database')
+msgs = ('Getting credentials user@UREALM -> user@SREALM',
+        '/Matching credential not found',
+        'Getting credentials user@SREALM -> krbtgt/UREALM@SREALM',
+        'Received creds for desired service krbtgt/UREALM@SREALM',
+        'via TGT krbtgt/UREALM@SREALM after requesting user\\@SREALM@UREALM',
+        'krbtgt/SREALM@UREALM differs from requested user\\@SREALM@UREALM',
+        'via TGT krbtgt/SREALM@UREALM after requesting user@SREALM',
+        'TGS reply is for user@UREALM -> user@SREALM')
+r1.run(['./t_s4u', 'p:' + r2.user_princ, '-', r1.keytab], env=no_default,
+       expected_trace=msgs)
+
 r1.stop()
 r2.stop()
-with open(os.path.join(r2.testdir, 'kdc.log')) as f:
-    kdclog = f.read()
-exp_princ = r1.host_princ.replace('/', '\\/').replace('@', '\\@')
-if ('for %s@%s, Server not found' % (exp_princ, r2.realm)) not in kdclog:
-    fail('cross-realm s4u2self (kdc log)')
 
 success('S4U test cases')
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.