krb5 commit: Conditionally test KEYRING ccache type

Greg Hudson ghudson at MIT.EDU
Wed Oct 2 10:45:03 EDT 2013


https://github.com/krb5/krb5/commit/5d03cb6b235f0ee0e30b34630f95f208d6acd3d0
commit 5d03cb6b235f0ee0e30b34630f95f208d6acd3d0
Author: Greg Hudson <ghudson at mit.edu>
Date:   Sat Sep 28 16:29:36 2013 -0400

    Conditionally test KEYRING ccache type
    
    If the keyctl command is found and klist recognizes the KEYRING
    credential cache type, then run several tests against keyring ccaches:
    the collection test program in lib/krb5/ccache, the command-line
    collection tests in tests/t_ccache.py, and some new tests to verify
    legacy session cache behavior.  Much of the Python code in t_ccache.py
    is moved into a new function named "collection_test" so we can run it
    once against a DIR collection and once against a KEYRING collection.
    
    Also: fix a memory leak in the collection test program; add a test for
    iteration when the default cache name is a subsidiary name; use a
    process keyring ccache in t_cc.c to avoid leaving behind empty
    collections in the session keyring after each test run.
    
    Adapted from a patch by simo at redhat.com.
    
    ticket: 7711

 src/lib/krb5/ccache/t_cc.c     |    4 +-
 src/lib/krb5/ccache/t_cccol.c  |   10 +++
 src/lib/krb5/ccache/t_cccol.py |   58 ++++++++++++++++++-
 src/tests/t_ccache.py          |  128 +++++++++++++++++++++++++++-------------
 4 files changed, 156 insertions(+), 44 deletions(-)

diff --git a/src/lib/krb5/ccache/t_cc.c b/src/lib/krb5/ccache/t_cc.c
index 991cef0..6069cab 100644
--- a/src/lib/krb5/ccache/t_cc.c
+++ b/src/lib/krb5/ccache/t_cc.c
@@ -426,8 +426,8 @@ main(void)
     test_misc(context);
     do_test(context, "");
 
-    if(check_registered(context, "KEYRING:"))
-        do_test(context, "KEYRING:");
+    if (check_registered(context, "KEYRING:process:"))
+        do_test(context, "KEYRING:process:");
     else
         printf("Skiping KEYRING: test - unregistered type\n");
 
diff --git a/src/lib/krb5/ccache/t_cccol.c b/src/lib/krb5/ccache/t_cccol.c
index 3b4d3b3..444806e 100644
--- a/src/lib/krb5/ccache/t_cccol.c
+++ b/src/lib/krb5/ccache/t_cccol.c
@@ -294,6 +294,15 @@ main(int argc, char **argv)
     check_collection(initial_primary_name, 2, unique1_name, unique2_name);
 
     /*
+     * Temporarily set the context default ccache to a subsidiary name, and
+     * check that iterating over the collection yields that subsidiary cache
+     * and no others.
+     */
+    check(krb5_cc_set_default_name(ctx, unique1_name));
+    check_collection(unique1_name, 0);
+    check(krb5_cc_set_default_name(ctx, collection_name));
+
+    /*
      * Destroy the primary cache.  Make sure this causes both the initial
      * primary name and the collection name to resolve to an uninitialized
      * cache.  Make sure the primary name doesn't change and doesn't appear in
@@ -349,5 +358,6 @@ main(int argc, char **argv)
     krb5_free_principal(ctx, princ1);
     krb5_free_principal(ctx, princ2);
     krb5_free_principal(ctx, princ3);
+    krb5_free_context(ctx);
     return 0;
 }
diff --git a/src/lib/krb5/ccache/t_cccol.py b/src/lib/krb5/ccache/t_cccol.py
index 8b70470..e762625 100644
--- a/src/lib/krb5/ccache/t_cccol.py
+++ b/src/lib/krb5/ccache/t_cccol.py
@@ -1,9 +1,43 @@
 #!/usr/bin/python
 from k5test import *
 
-# Run the collection test program against each collection-enabled type.
 realm = K5Realm(create_kdb=False)
+
+keyctl = which('keyctl')
+out = realm.run([klist, '-c', 'KEYRING:process:abcd'], expected_code=1)
+test_keyring = (keyctl is not None and
+                'Unknown credential cache type' not in out)
+
+# Run the collection test program against each collection-enabled type.
 realm.run(['./t_cccol', 'DIR:' + os.path.join(realm.testdir, 'cc')])
+if test_keyring:
+    # Use the test directory as the collection name to avoid colliding
+    # with other build trees.
+    cname = realm.testdir
+
+    # Remove any keys left behind by previous failed test runs.
+    realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname])
+    realm.run(['keyctl', 'purge', 'keyring', cname])
+    out = realm.run(['keyctl', 'list', '@u'])
+    if ('keyring: _krb_' + cname + '\n') in out:
+        id = realm.run(['keyctl', 'search', '@u', 'keyring', '_krb_' + cname])
+        realm.run(['keyctl', 'unlink', id.strip(), '@u'])
+
+    # Run test program over each subtype, cleaning up as we go.  Don't
+    # test the persistent subtype, since it supports only one
+    # collection and might be in actual use.
+    realm.run(['./t_cccol', 'KEYRING:' + cname])
+    realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname])
+    realm.run(['./t_cccol', 'KEYRING:legacy:' + cname])
+    realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname])
+    realm.run(['./t_cccol', 'KEYRING:session:' + cname])
+    realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname])
+    realm.run(['./t_cccol', 'KEYRING:user:' + cname])
+    id = realm.run(['keyctl', 'search', '@u', 'keyring', '_krb_' + cname])
+    realm.run(['keyctl', 'unlink', id.strip(), '@u'])
+    realm.run(['./t_cccol', 'KEYRING:process:abcd'])
+    realm.run(['./t_cccol', 'KEYRING:thread:abcd'])
+
 realm.stop()
 
 # Test cursor semantics using real ccaches.
@@ -22,6 +56,18 @@ realm.kinit('user', password('user'), flags=['-c', duser])
 realm.kinit('alice', password('alice'), flags=['-c', dalice])
 realm.kinit('bob', password('bob'), flags=['-c', dbob])
 
+if test_keyring:
+    cname = realm.testdir
+    realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname])
+    krccname = 'KEYRING:session:' + cname
+    kruser = '%s:tkt1' % krccname
+    kralice = '%s:tkt2' % krccname
+    krbob = '%s:tkt3' % krccname
+    krnoent = '%s:noent' % krccname
+    realm.kinit('user', password('user'), flags=['-c', kruser])
+    realm.kinit('alice', password('alice'), flags=['-c', kralice])
+    realm.kinit('bob', password('bob'), flags=['-c', krbob])
+
 def cursor_test(testname, args, expected):
     outlines = realm.run(['./t_cccursor'] + args).splitlines()
     outlines.sort()
@@ -40,16 +86,26 @@ cursor_test('dir', [dccname], [duser, dalice, dbob])
 cursor_test('dir-subsidiary', [duser], [duser])
 cursor_test('dir-nofile', [dnoent], [])
 
+if test_keyring:
+    cursor_test('keyring', [krccname], [kruser, kralice, krbob])
+    cursor_test('keyring-subsidiary', [kruser], [kruser])
+    cursor_test('keyring-noent', [krnoent], [])
+
 mfoo = 'MEMORY:foo'
 mbar = 'MEMORY:bar'
 cursor_test('filemem', [fccname, mfoo, mbar], [fccname, mfoo, mbar])
 cursor_test('dirmem', [dccname, mfoo], [duser, dalice, dbob, mfoo])
+if test_keyring:
+    cursor_test('keyringmem', [krccname, mfoo], [kruser, kralice, krbob, mfoo])
 
 # Test krb5_cccol_have_content.
 realm.run(['./t_cccursor', dccname, 'CONTENT'])
 realm.run(['./t_cccursor', fccname, 'CONTENT'])
 realm.run(['./t_cccursor', realm.ccache, 'CONTENT'])
 realm.run(['./t_cccursor', mfoo, 'CONTENT'], expected_code=1)
+if test_keyring:
+    realm.run(['./t_cccursor', krccname, 'CONTENT'])
+    realm.run(['keyctl', 'purge', 'keyring', '_krb_' + cname])
 
 # Make sure FILE doesn't yield a nonexistent default cache.
 realm.run([kdestroy])
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
index a761d48..15d8141 100644
--- a/src/tests/t_ccache.py
+++ b/src/tests/t_ccache.py
@@ -25,58 +25,104 @@ from k5test import *
 
 realm = K5Realm(create_host=False)
 
+keyctl = which('keyctl')
+out = realm.run([klist, '-c', 'KEYRING:process:abcd'], expected_code=1)
+test_keyring = (keyctl is not None and
+                'Unknown credential cache type' not in out)
+
 # Test kdestroy and klist of a non-existent ccache.
 realm.run([kdestroy])
 output = realm.run([klist], expected_code=1)
 if 'No credentials cache found' not in output:
     fail('Expected error message not seen in klist output')
 
-# Make a directory collection and use it for client commands.
-ccname = 'DIR:' + os.path.join(realm.testdir, 'cc')
-realm.env['KRB5CCNAME'] = ccname
-
 realm.addprinc('alice', password('alice'))
 realm.addprinc('bob', password('bob'))
 realm.addprinc('carol', password('carol'))
 
-realm.kinit('alice', password('alice'))
-output = realm.run([klist])
-if 'Default principal: alice@' not in output:
-    fail('Initial kinit failed to get credentials for alice.')
-realm.run([kdestroy])
-output = realm.run([klist], expected_code=1)
-if 'No credentials cache found' not in output:
-    fail('Initial kdestroy failed to destroy primary cache.')
-output = realm.run([klist, '-l'], expected_code=1)
-if not output.endswith('---\n') or output.count('\n') != 2:
-    fail('Initial kdestroy failed to empty cache collection.')
+def collection_test(realm, ccname):
+    realm.env['KRB5CCNAME'] = ccname
 
-realm.kinit('alice', password('alice'))
-realm.kinit('carol', password('carol'))
-output = realm.run([klist, '-l'])
-if '---\ncarol@' not in output or '\nalice@' not in output:
-    fail('klist -l did not show expected output after two kinits.')
-realm.kinit('alice', password('alice'))
-output = realm.run([klist, '-l'])
-if '---\nalice@' not in output or output.count('\n') != 4:
-    fail('klist -l did not show expected output after re-kinit for alice.')
-realm.kinit('bob', password('bob'))
-output = realm.run([klist, '-A'])
-if 'bob@' not in output.splitlines()[1] or 'alice@' not in output or \
-        'carol' not in output or output.count('Default principal:') != 3:
-    fail('klist -A did not show expected output after kinit for bob.')
-realm.run([kswitch, '-p', 'carol'])
-output = realm.run([klist, '-l'])
-if '---\ncarol@' not in output or output.count('\n') != 5:
-    fail('klist -l did not show expected output after kswitch to carol.')
-realm.run([kdestroy])
-output = realm.run([klist, '-l'])
-if 'carol@' in output or 'bob@' not in output or output.count('\n') != 4:
-    fail('kdestroy failed to remove only primary ccache.')
-realm.run([kdestroy, '-A'])
-output = realm.run([klist, '-l'], expected_code=1)
-if not output.endswith('---\n') or output.count('\n') != 2:
-    fail('kdestroy -a failed to empty cache collection.')
+    realm.kinit('alice', password('alice'))
+    output = realm.run([klist])
+    if 'Default principal: alice@' not in output:
+        fail('Initial kinit failed to get credentials for alice.')
+    realm.run([kdestroy])
+    output = realm.run([klist], expected_code=1)
+    if 'No credentials cache found' not in output:
+        fail('Initial kdestroy failed to destroy primary cache.')
+    output = realm.run([klist, '-l'], expected_code=1)
+    if not output.endswith('---\n') or output.count('\n') != 2:
+        fail('Initial kdestroy failed to empty cache collection.')
+
+    realm.kinit('alice', password('alice'))
+    realm.kinit('carol', password('carol'))
+    output = realm.run([klist, '-l'])
+    if '---\ncarol@' not in output or '\nalice@' not in output:
+        fail('klist -l did not show expected output after two kinits.')
+    realm.kinit('alice', password('alice'))
+    output = realm.run([klist, '-l'])
+    if '---\nalice@' not in output or output.count('\n') != 4:
+        fail('klist -l did not show expected output after re-kinit for alice.')
+    realm.kinit('bob', password('bob'))
+    output = realm.run([klist, '-A'])
+    if 'bob@' not in output.splitlines()[1] or 'alice@' not in output or \
+            'carol' not in output or output.count('Default principal:') != 3:
+        fail('klist -A did not show expected output after kinit for bob.')
+    realm.run([kswitch, '-p', 'carol'])
+    output = realm.run([klist, '-l'])
+    if '---\ncarol@' not in output or output.count('\n') != 5:
+        fail('klist -l did not show expected output after kswitch to carol.')
+    realm.run([kdestroy])
+    output = realm.run([klist, '-l'])
+    if 'carol@' in output or 'bob@' not in output or output.count('\n') != 4:
+        fail('kdestroy failed to remove only primary ccache.')
+    realm.run([kdestroy, '-A'])
+    output = realm.run([klist, '-l'], expected_code=1)
+    if not output.endswith('---\n') or output.count('\n') != 2:
+        fail('kdestroy -a failed to empty cache collection.')
+
+
+collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
+if test_keyring:
+    # Use realm.testdir as the collection name to avoid conflicts with
+    # other build trees.
+    cname = realm.testdir
+
+    realm.run([keyctl, 'purge', 'keyring', '_krb_' + cname])
+    collection_test(realm, 'KEYRING:session:' + cname)
+    realm.run([keyctl, 'purge', 'keyring', '_krb_' + cname])
+
+    # Test legacy keyring cache linkage.
+    realm.env['KRB5CCNAME'] = 'KEYRING:' + cname
+    realm.run([kdestroy, '-A'])
+    realm.kinit(realm.user_princ, password('user'))
+    out = realm.run([klist, '-l'])
+    if 'KEYRING:legacy:' + cname + ':' + cname not in out:
+        fail('Wrong initial primary name in keyring legacy collection')
+    # Make sure this cache is linked to the session keyring.
+    id = realm.run([keyctl, 'search', '@s', 'keyring', cname])
+    out = realm.run([keyctl, 'list', id.strip()])
+    if 'user: __krb5_princ__' not in out:
+        fail('Legacy cache not linked into session keyring')
+    # Remove the collection keyring.  When the collection is
+    # reinitialized, the legacy cache should reappear inside it
+    # automatically as the primary cache.
+    out = realm.run([keyctl, 'purge', 'keyring', '_krb_' + cname])
+    if 'purged 1 keys' not in out:
+        fail('Could not purge collection keyring')
+    out = realm.run([klist])
+    if realm.user_princ not in out:
+        fail('Cannot see legacy cache after purging collection')
+    coll_id = realm.run([keyctl, 'search', '@s', 'keyring', '_krb_' + cname])
+    out = realm.run([keyctl, 'list', coll_id.strip()])
+    if (id.strip() + ':') not in out:
+        fail('Legacy cache did not reappear in collection after klist')
+    # Destroy the cache and check that it is unlinked from the session keyring.
+    realm.run([kdestroy])
+    realm.run([keyctl, 'search', '@s', 'keyring', cname], expected_code=1)
+    # Clean up the collection key.
+    realm.run([keyctl, 'purge', 'keyring', '_krb_' + cname])
 
 # Test parameter expansion in default_ccache_name
 realm.stop()


More information about the cvs-krb5 mailing list