svn rev #25429: trunk/src/ tests/ util/

ghudson@MIT.EDU ghudson at MIT.EDU
Thu Nov 3 13:27:59 EDT 2011


http://src.mit.edu/fisheye/changelog/krb5/?cs=25429
Commit By: ghudson
Log Message:
Add cross-realm tests to python test framework

Add a cross_realms function to k5test.py to generate several linked
realms.  Add a test script t_crossrealm.py to exercise six different
cross-realm scenarios.


Changed Files:
U   trunk/src/tests/Makefile.in
A   trunk/src/tests/t_crossrealm.py
U   trunk/src/util/k5test.py
Modified: trunk/src/tests/Makefile.in
===================================================================
--- trunk/src/tests/Makefile.in	2011-11-02 20:49:57 UTC (rev 25428)
+++ trunk/src/tests/Makefile.in	2011-11-03 17:27:59 UTC (rev 25429)
@@ -70,6 +70,7 @@
 	$(RUNPYTEST) $(srcdir)/t_renprinc.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_cccol.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_stringattr.py $(PYTESTFLAGS)
+	$(RUNPYTEST) $(srcdir)/t_crossrealm.py $(PYTESTFLAGS)
 #	$(RUNPYTEST) $(srcdir)/kdc_realm/kdcref.py $(PYTESTFLAGS)
 
 clean::

Added: trunk/src/tests/t_crossrealm.py
===================================================================
--- trunk/src/tests/t_crossrealm.py	                        (rev 0)
+++ trunk/src/tests/t_crossrealm.py	2011-11-03 17:27:59 UTC (rev 25429)
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+
+# Copyright (C) 2011 by the Massachusetts Institute of Technology.
+# All rights reserved.
+#
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+#
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+
+from k5test import *
+
+def test_kvno(r, princ, test):
+    output = r.run_as_client([kvno, princ])
+    if princ not in output:
+        fail('%s: principal %s not in kvno output' % (test, princ))
+
+
+def stop(*realms):
+    for r in realms:
+        r.stop()
+
+
+# Basic two-realm test with cross TGTs in both directions.
+r1, r2 = cross_realms(2, start_kadmind=False)
+test_kvno(r1, r2.host_princ, 'basic r1->r2')
+test_kvno(r2, r1.host_princ, 'basic r2->r1')
+stop(r1, r2)
+
+# Test the KDC domain walk for hierarchically arranged realms.  The
+# client in A.X will ask for a cross TGT to B.X, but A.X's KDC only
+# has a TGT for the intermediate realm X, so it will return that
+# instead.  The client will use that to get a TGT for B.X.
+r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)), 
+                          args=({'realm': 'A.X'}, {'realm': 'X'},
+                                {'realm': 'B.X'}),
+                          start_kadmind=False)
+test_kvno(r1, r3.host_princ, 'KDC domain walk')
+stop(r1, r2, r3)
+
+# Test client capaths.  The client in A will ask for a cross TGT to D,
+# but A's KDC won't have it and won't know an intermediate to return.
+# The client will walk its A->D capaths to get TGTs for B, then C,
+# then D.  The KDCs for C and D need capaths settings to avoid failing
+# transited checks, including a capaths for A->C.
+capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}}}
+r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),
+                              args=({'realm': 'A',
+                                     'krb5_conf': {'client': capaths}},
+                                    {'realm': 'B'},
+                                    {'realm': 'C',
+                                     'krb5_conf': {'master': capaths}},
+                                    {'realm': 'D',
+                                     'krb5_conf': {'master': capaths}}),
+                              start_kadmind=False)
+test_kvno(r1, r4.host_princ, 'client capaths')
+
+# Test KDC capaths.  The KDCs for A and B have appropriate capaths
+# settings to determine intermediate TGTs to return, but the client
+# has no idea.
+capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}, 'B': {'D': 'C'}}}
+conf = {'master': capaths}
+r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),
+                              args=({'realm': 'A', 'krb5_conf': conf},
+                                    {'realm': 'B', 'krb5_conf': conf},
+                                    {'realm': 'C', 'krb5_conf': conf},
+                                    {'realm': 'D', 'krb5_conf': conf}),
+                              start_kadmind=False)
+test_kvno(r1, r4.host_princ, 'KDC capaths')
+
+# Test transited error.  The KDC for C does not recognize B as an
+# intermediate realm for A->C, so it refuses to issue a service
+# ticket.
+capaths = {'capaths': {'A': {'C': 'B'}}}
+r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
+                          args=({'realm': 'A',
+                                 'krb5_conf': {'client': capaths}},
+                                {'realm': 'B'}, {'realm': 'C'}),
+                          start_kadmind=False)
+output = r1.run_as_client([kvno, r3.host_princ], expected_code=1)
+if 'KDC policy rejects request' not in output:
+    fail('transited 1: Expected error message not in output')
+
+# Test a different kind of transited error.  The KDC for D does not
+# recognize B as an intermediate realm for A->C, so it refuses to
+# verify the krbtgt/C at B ticket in the TGS AP-REQ.
+capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}, 'B': {'D': 'C'}}}
+conf = {'master': capaths}
+r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),
+                              args=({'realm': 'A', 'krb5_conf': conf},
+                                    {'realm': 'B', 'krb5_conf': conf},
+                                    {'realm': 'C', 'krb5_conf': conf},
+                                    {'realm': 'D'}),
+                              start_kadmind=False)
+output = r1.run_as_client([kvno, r4.host_princ], expected_code=1)
+if 'Illegal cross-realm ticket' not in output:
+    fail('transited 2: Expected error message not in output')
+
+success('Cross-realm tests.')

Modified: trunk/src/util/k5test.py
===================================================================
--- trunk/src/util/k5test.py	2011-11-02 20:49:57 UTC (rev 25428)
+++ trunk/src/util/k5test.py	2011-11-03 17:27:59 UTC (rev 25429)
@@ -154,6 +154,19 @@
   honored.  If keywords contains krb5_conf and/or kdc_conf fragments,
   they will be merged with the default and per-pass specifications.
 
+* cross_realms(num, xtgts=None, args=None, **keywords): This function
+  returns a list of num realms, where each realm's configuration knows
+  how to contact all of the realms.  By default, each realm will
+  contain cross TGTs in both directions for all other realms; this
+  default may be overridden by specifying a collection of tuples in
+  the xtgts parameter, where each tuple is a pair of zero-based realm
+  indexes, indicating that the first realm can authenticate to the
+  second (i.e. krbtgt/secondrealm at firstrealm exists in both realm's
+  databases).  If args is given, it should be a list of keyword
+  arguments specific to each realm; these will be merged with the
+  global keyword arguments passed to cross_realms, with specific
+  arguments taking priority.
+
 * buildtop: The top of the build directory (absolute path).
 
 * srctop: The top of the source directory (absolute path).
@@ -301,6 +314,7 @@
 """
 
 import atexit
+import itertools
 import optparse
 import os
 import shlex
@@ -934,6 +948,70 @@
         _current_pass = None
 
 
+def cross_realms(num, xtgts=None, args=None, **keywords):
+    # Build keyword args for each realm.
+    realm_args = []
+    for i in range(num):
+        realmnumber = i + 1
+        # Start with any global keyword arguments to this function.
+        a = keywords.copy()
+        if args and args[i]:
+            # Merge in specific arguments for this realm.  Use
+            # _cfg_merge for config fragments.
+            a.update(args[i])
+            for cf in ('krb5_conf', 'kdc_conf'):
+                if cf in keywords and cf in args[i]:
+                    a[cf] = _cfg_merge(keywords[cf], args[i][cf])
+        # Set defaults for the realm name, testdir, and portbase.
+        if not 'realm' in a:
+            a['realm'] = 'KRBTEST%d.COM' % realmnumber
+        if not 'testdir' in a:
+            a['testdir'] = os.path.join('testdir', str(realmnumber))
+        if not 'portbase' in a:
+            a['portbase'] = 61000 + 10 * realmnumber
+        realm_args.append(a)
+        
+    # Build a [realms] config fragment containing all of the realms.
+    realmsection = { '$realm' : None }
+    for a in realm_args:
+        name = a['realm']
+        portbase = a['portbase']
+        realmsection[name] = {
+            'kdc' : '$hostname:%d' % portbase,
+            'admin_server' : '$hostname:%d' % (portbase + 1),
+            'kpasswd_server' : '$hostname:%d' % (portbase + 2)
+            }
+    realmscfg = { 'all' : { 'realms' : realmsection } }
+
+    # Set realmsection in each realm's krb5_conf keyword argument.
+    for a in realm_args:
+        a['krb5_conf'] = _cfg_merge(realmscfg, a.get('krb5_conf'))
+
+    if xtgts is None:
+        # Default to cross tgts for every pair of realms.
+        xtgts = frozenset(itertools.permutations(range(num), 2))
+
+    # Create the realms.
+    realms = []
+    for i in range(num):
+        r = K5Realm(**realm_args[i])
+        # Create specified cross TGTs in this realm's db.
+        for j in range(num):
+            if j == i:
+                continue
+            iname = r.realm
+            jname = realm_args[j]['realm']
+            if (i, j) in xtgts:
+                # This realm can authenticate to realm j.
+                r.addprinc('krbtgt/%s' % jname, password('cr-%d-%d-' % (i, j)))
+            if (j, i) in xtgts:
+                # Realm j can authenticate to this realm.
+                r.addprinc('krbtgt/%s@%s' % (iname, jname),
+                           password('cr-%d-%d-' % (j, i)))
+        realms.append(r)
+    return realms
+
+
 _default_krb5_conf = {
     'all' : {
         'libdefaults' : {




More information about the cvs-krb5 mailing list