krb5 commit: Add tests for localauth interface

Greg Hudson ghudson at MIT.EDU
Sat Mar 9 02:13:24 EST 2013


https://github.com/krb5/krb5/commit/b8696b1ed70ffebbeee7142f1e5e086d75ce4e30
commit b8696b1ed70ffebbeee7142f1e5e086d75ce4e30
Author: Greg Hudson <ghudson at mit.edu>
Date:   Wed Feb 27 15:00:37 2013 -0500

    Add tests for localauth interface
    
    Create a test module, program, and script to exercise the
    krb5_aname_to_localname and krb5_k5userok functions as well as the
    localauth pluggable interface.
    
    ticket: 7583

 .gitignore                                        |    1 +
 src/Makefile.in                                   |    1 +
 src/configure.in                                  |    1 +
 src/plugins/localauth/test/Makefile.in            |   29 ++++
 src/plugins/localauth/test/deps                   |   23 +++
 src/plugins/localauth/test/localauth_test.exports |    2 +
 src/plugins/localauth/test/main.c                 |  169 +++++++++++++++++++++
 src/tests/Makefile.in                             |   12 +-
 src/tests/t_localauth.c                           |   72 +++++++++
 src/tests/t_localauth.py                          |  144 ++++++++++++++++++
 10 files changed, 450 insertions(+), 4 deletions(-)

diff --git a/.gitignore b/.gitignore
index 697807f..7a5671f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -247,6 +247,7 @@ testlog
 /src/tests/kdbtest
 /src/tests/kdc.conf
 /src/tests/krb5.conf
+/src/tests/t_localauth
 
 /src/tests/asn.1/expected_encode.out
 /src/tests/asn.1/expected_trval.out
diff --git a/src/Makefile.in b/src/Makefile.in
index 0d07b71..d62033a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -10,6 +10,7 @@ mydir=.
 SUBDIRS=util include lib \
 	@sam2_plugin@ \
 	plugins/kadm5_hook/test \
+	plugins/localauth/test \
 	plugins/kdb/db2 \
 	@ldap_plugin_dir@ \
 	plugins/preauth/pkinit \
diff --git a/src/configure.in b/src/configure.in
index 600cc8d..5650148 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1333,6 +1333,7 @@ dnl	ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test
 	kdc slave config-files build-tools man doc include
 
 	plugins/locate/python
+	plugins/localauth/test
 	plugins/kadm5_hook/test
 	plugins/kdb/db2
 	plugins/kdb/db2/libdb2
diff --git a/src/plugins/localauth/test/Makefile.in b/src/plugins/localauth/test/Makefile.in
new file mode 100644
index 0000000..fd1d656
--- /dev/null
+++ b/src/plugins/localauth/test/Makefile.in
@@ -0,0 +1,29 @@
+mydir=plugins$(S)localauth$(S)test
+BUILDTOP=$(REL)..$(S)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+LIBBASE=localauth_test
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+RELDIR=../plugins/localauth/test
+SHLIB_EXPDEPS=$(SUPPORT_DEPLIB)
+SHLIB_EXPLIBS=$(SUPPORT_LIB) $(LIBS)
+
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+STOBJLISTS=OBJS.ST
+STLIBOBJS=main.o
+
+SRCS=$(srcdir)/main.c
+
+all-unix:: all-libs
+install-unix::
+clean-unix:: clean-libs clean-libobjs
+
+clean::
+	$(RM) lib$(LIBBASE)$(SO_EXT)
+
+ at libnover_frag@
+ at libobj_frag@
diff --git a/src/plugins/localauth/test/deps b/src/plugins/localauth/test/deps
new file mode 100644
index 0000000..872c3bc
--- /dev/null
+++ b/src/plugins/localauth/test/deps
@@ -0,0 +1,23 @@
+#
+# Generated makefile dependencies follow.
+#
+main.so main.po $(OUTPRE)main.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \
+  $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+  $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(top_srcdir)/include/gssrpc/auth.h \
+  $(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_unix.h \
+  $(top_srcdir)/include/gssrpc/clnt.h $(top_srcdir)/include/gssrpc/rename.h \
+  $(top_srcdir)/include/gssrpc/rpc.h $(top_srcdir)/include/gssrpc/rpc_msg.h \
+  $(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \
+  $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/k5-buf.h \
+  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+  $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/clpreauth_plugin.h \
+  $(top_srcdir)/include/krb5/localauth_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+  main.c
diff --git a/src/plugins/localauth/test/localauth_test.exports b/src/plugins/localauth/test/localauth_test.exports
new file mode 100644
index 0000000..63c1396
--- /dev/null
+++ b/src/plugins/localauth/test/localauth_test.exports
@@ -0,0 +1,2 @@
+localauth_test1_initvt
+localauth_test2_initvt
diff --git a/src/plugins/localauth/test/main.c b/src/plugins/localauth/test/main.c
new file mode 100644
index 0000000..9e96900
--- /dev/null
+++ b/src/plugins/localauth/test/main.c
@@ -0,0 +1,169 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* plugins/localauth/test/main.c - test modules for localauth interface */
+/*
+ * Copyright (C) 2013 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This file implements two testing localauth modules, each implementing
+ * clearly recognizable behavior for the localauth test script. */
+
+#include "k5-int.h"
+#include <krb5/localauth_plugin.h>
+
+struct krb5_localauth_moddata_st {
+    int a;
+    int b;
+};
+
+static krb5_error_code
+init_test(krb5_context context, krb5_localauth_moddata *data_out)
+{
+    krb5_localauth_moddata d;
+
+    *data_out = NULL;
+    d = malloc(sizeof(*d));
+    if (d == NULL)
+        return ENOMEM;
+    d->a = 3;
+    d->b = 4;
+    *data_out = d;
+    return 0;
+}
+
+static void
+fini_test(krb5_context context, krb5_localauth_moddata data)
+{
+    assert(data->a == 3);
+    assert(data->b == 4);
+    free(data);
+}
+
+static krb5_error_code
+an2ln_test(krb5_context context, krb5_localauth_moddata data, const char *type,
+           const char *residual, krb5_const_principal aname, char **lname_out)
+{
+    krb5_error_code ret;
+    char *lname = NULL;
+
+    *lname_out = NULL;
+    if (data != NULL) {
+        assert(data->a == 3);
+        assert(data->b == 4);
+    }
+    if (type == NULL) {
+        /* Map any three-component test/___/___ principal to its realm name. */
+        if (aname->length == 3 && data_eq_string(aname->data[0], "test")) {
+            lname = k5memdup0(aname->realm.data, aname->realm.length, &ret);
+            if (lname == NULL)
+                return ret;
+        }
+    } else if (strcmp(type, "TYPEA") == 0) {
+        /* Map any two-component principal to its second component. */
+        if (aname->length == 2) {
+            lname = k5memdup0(aname->data[1].data, aname->data[1].length,
+                              &ret);
+            if (lname == NULL)
+                return ret;
+        }
+    } else {
+        assert(strcmp(type, "TYPEB") == 0);
+        /* Map to the residual string. */
+        lname = strdup(residual == NULL ? "(null)" : residual);
+        if (lname == NULL)
+            return ENOMEM;
+    }
+    if (lname == NULL)
+        return KRB5_LNAME_NOTRANS;
+    *lname_out = lname;
+    return 0;
+}
+
+static krb5_error_code
+userok_test(krb5_context context, krb5_localauth_moddata data,
+            krb5_const_principal aname, const char *lname)
+{
+    if (data != NULL) {
+        assert(data->a == 3);
+        assert(data->b == 4);
+    }
+
+    /* Return success if the number of components in the principal is equal to
+     * the length of the local name. */
+    if ((size_t)aname->length == strlen(lname))
+        return 0;
+
+    /* Pass control down if the first component is "pass". */
+    if (aname->length >= 1 && data_eq_string(aname->data[0], "pass"))
+        return KRB5_PLUGIN_NO_HANDLE;
+
+    /* Otherwise reject. */
+    return EPERM;
+}
+
+static void
+freestr(krb5_context context, krb5_localauth_moddata data, char *str)
+{
+    free(str);
+}
+
+krb5_error_code
+localauth_test1_initvt(krb5_context context, int maj_ver, int min_ver,
+                       krb5_plugin_vtable vtable);
+krb5_error_code
+localauth_test2_initvt(krb5_context context, int maj_ver, int min_ver,
+                       krb5_plugin_vtable vtable);
+
+krb5_error_code
+localauth_test1_initvt(krb5_context context, int maj_ver, int min_ver,
+                       krb5_plugin_vtable vtable)
+{
+    krb5_localauth_vtable vt = (krb5_localauth_vtable)vtable;
+
+    vt->init = init_test;
+    vt->fini = fini_test;
+    vt->name = "test1";
+    vt->an2ln = an2ln_test;
+    vt->userok = userok_test;
+    vt->free_string = freestr;
+    return 0;
+}
+
+krb5_error_code
+localauth_test2_initvt(krb5_context context, int maj_ver, int min_ver,
+                       krb5_plugin_vtable vtable)
+{
+    krb5_localauth_vtable vt = (krb5_localauth_vtable)vtable;
+    static const char *types[] = { "TYPEA", "TYPEB", NULL };
+
+    vt->name = "test2";
+    vt->an2ln_types = types;
+    vt->an2ln = an2ln_test;
+    vt->free_string = freestr;
+    return 0;
+}
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 32bc0b7..45f3e8f 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -8,8 +8,8 @@ KRB5_RUN_ENV= @KRB5_RUN_ENV@
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
-OBJS= gcred.o hist.o kdbtest.o
-EXTRADEPSRCS= gcred.c hist.c kdbtest.c
+OBJS= gcred.o hist.o kdbtest.o t_localauth.o
+EXTRADEPSRCS= gcred.c hist.c kdbtest.c t_localauth.c
 
 TEST_DB = ./testdb
 TEST_REALM = FOO.TEST.REALM
@@ -31,6 +31,9 @@ kdbtest: kdbtest.o $(KDB5_DEPLIBS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o $@ kdbtest.o $(KDB5_LIBS) $(KADMSRV_LIBS) \
 		$(KRB5_BASE_LIBS)
 
+t_localauth: t_localauth.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $@ t_localauth.o $(KRB5_BASE_LIBS)
+
 check-unix:: kdb_check
 
 kdc.conf: Makefile
@@ -73,13 +76,14 @@ kdb_check: kdc.conf krb5.conf
 	$(RUN_SETUP) $(VALGRIND) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f
 	$(RM) $(TEST_DB)* stash_file
 
-check-pytests:: gcred hist kdbtest
+check-pytests:: gcred hist kdbtest t_localauth
 	$(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_dump.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_iprop.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_kprop.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_anonpkinit.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_policy.py $(PYTESTFLAGS)
+	$(RUNPYTEST) $(srcdir)/t_localauth.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_kadm5_hook.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_kdb_locking.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_keyrollover.py $(PYTESTFLAGS)
@@ -98,5 +102,5 @@ check-pytests:: gcred hist kdbtest
 	$(RUNPYTEST) $(srcdir)/t_cve-2012-1015.py $(PYTESTFLAGS)
 
 clean::
-	$(RM) gcred hist kdbtest krb5.conf kdc.conf
+	$(RM) gcred hist kdbtest krb5.conf kdc.conf t_localauth
 	$(RM) -rf kdc_realm/sandbox ldap
diff --git a/src/tests/t_localauth.c b/src/tests/t_localauth.c
new file mode 100644
index 0000000..3a65b5b
--- /dev/null
+++ b/src/tests/t_localauth.c
@@ -0,0 +1,72 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* tests/t_localauth.c - test harness for kuserok and aname_to_lname */
+/*
+ * Copyright (C) 2013 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <krb5.h>
+#include <stdio.h>
+
+static krb5_context ctx;
+
+static void
+check(krb5_error_code code)
+{
+    const char *errmsg;
+
+    if (code) {
+        errmsg = krb5_get_error_message(ctx, code);
+        fprintf(stderr, "%s\n", errmsg);
+        krb5_free_error_message(ctx, errmsg);
+        exit(1);
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+    krb5_principal princ;
+    char buf[1024];
+
+    if (argc < 2 || argc > 3) {
+        fprintf(stderr, "Usage: t_localauth principal [localuser]\n");
+        return 1;
+    }
+    check(krb5_init_context(&ctx));
+    check(krb5_parse_name(ctx, argv[1], &princ));
+    if (argc == 3) {
+        printf("%s\n", krb5_kuserok(ctx, princ, argv[2]) ? "yes" : "no");
+    } else {
+        check(krb5_aname_to_localname(ctx, princ, sizeof(buf), buf));
+        printf("%s\n", buf);
+    }
+    krb5_free_principal(ctx, princ);
+    krb5_free_context(ctx);
+    return 0;
+}
diff --git a/src/tests/t_localauth.py b/src/tests/t_localauth.py
new file mode 100644
index 0000000..1d498ed
--- /dev/null
+++ b/src/tests/t_localauth.py
@@ -0,0 +1,144 @@
+#!/usr/bin/python
+from k5test import *
+
+# Unfortunately, we can't reliably test the k5login module.  We can control
+# the directory where k5login files are read, but we can't suppress the UID
+# validity check, which might fail in some filesystems for a .k5login file
+# we create.
+conf = {'plugins': {'localauth': { 'disable': 'k5login'}}}
+realm = K5Realm(create_kdb=False, krb5_conf=conf)
+
+def test_an2ln(env, aname, result, msg):
+    out = realm.run(['./t_localauth', aname], env=env)
+    if out != result + '\n':
+        fail(msg)
+
+def test_an2ln_err(env, aname, err, msg):
+    out = realm.run(['./t_localauth', aname], env=env, expected_code=1)
+    if err not in out:
+        fail(msg)
+
+def test_userok(env, aname, lname, ok, msg):
+    out = realm.run(['./t_localauth', aname, lname], env=env)
+    if ((ok and out != 'yes\n') or
+        (not ok and out != 'no\n')):
+        fail(msg)
+
+# The default an2ln method works only in the default realm, and works
+# for a single-component principal or a two-component principal where
+# the second component is the default realm.
+test_an2ln(None, 'user at KRBTEST.COM', 'user', 'default rule 1')
+test_an2ln(None, 'user/KRBTEST.COM at KRBTEST.COM', 'user', 'default rule 2')
+test_an2ln_err(None, 'user/KRBTEST.COM/x at KRBTEST.COM', 'No translation',
+               'default rule (3)')
+test_an2ln_err(None, 'user/X at KRBTEST.COM', 'No translation',
+               'default rule comp mismatch')
+test_an2ln_err(None, 'user at X', 'No translation', 'default rule realm mismatch')
+
+# auth_to_local_names matches ignore the realm but are case-sensitive.
+conf_names1 = {'realms': {'$realm': {'auth_to_local_names': {'user': 'abcd'}}}}
+names1 = realm.special_env('names1', False, conf_names1)
+test_an2ln(names1, 'user at KRBTEST.COM', 'abcd', 'auth_to_local_names match')
+test_an2ln(names1, 'user at X', 'abcd', 'auth_to_local_names out-of-realm match')
+test_an2ln(names1, 'x at KRBTEST.COM', 'x', 'auth_to_local_names mismatch')
+test_an2ln(names1, 'User at KRBTEST.COM', 'User', 'auth_to_local_names case')
+
+# auth_to_local_names values must be in the default realm's section.
+conf_names2 = {'realms': {'X': {'auth_to_local_names': {'user': 'abcd'}}}}
+names2 = realm.special_env('names2', False, conf_names2)
+test_an2ln_err(names2, 'user at X', 'No translation',
+               'auth_to_local_names section mismatch')
+
+# Return a realm environment containing an auth_to_local value (or list).
+def a2l_realm(name, values):
+    conf = {'realms': {'$realm': {'auth_to_local': values}}}
+    return realm.special_env(name, False, conf)
+
+# Test explicit use of default method.
+auth1 = a2l_realm('auth1', 'DEFAULT')
+test_an2ln(auth1, 'user at KRBTEST.COM', 'user', 'default rule')
+
+# Test some invalid auth_to_local values.
+auth2 = a2l_realm('auth2', 'RULE')
+test_an2ln_err(auth2, 'user at X', 'Improper format', 'null rule')
+auth3 = a2l_realm('auth3', 'UNRECOGNIZED:stuff')
+test_an2ln_err(auth3, 'user at X', 'Improper format', 'null rule')
+
+# An empty rule has the default selection string (unparsed principal
+# without realm) and no match or substitutions.
+rule1 = a2l_realm('rule1', 'RULE:')
+test_an2ln(rule1, 'user at KRBTEST.COM', 'user', 'empty rule')
+test_an2ln(rule1, 'user at X', 'user', 'empty rule (foreign realm)')
+test_an2ln(rule1, 'a/b/c at X', 'a/b/c', 'empty rule (multi-component)')
+
+# Test explicit selection string.  Also test that the default method
+# is suppressed when auth_to_local values are present.
+rule2 = a2l_realm('rule2', 'RULE:[2:$$0.$$2.$$1]')
+test_an2ln(rule2, 'aaron/burr at REALM', 'REALM.burr.aaron', 'selection string')
+test_an2ln_err(rule2, 'user at KRBTEST.COM', 'No translation', 'suppress default')
+
+# Test match string.
+rule3 = a2l_realm('rule3', 'RULE:(.*tail)')
+test_an2ln(rule3, 'withtail at X', 'withtail', 'rule match 1')
+test_an2ln(rule3, 'x/withtail at X', 'x/withtail', 'rule match 2')
+test_an2ln_err(rule3, 'tails at X', 'No translation', 'rule anchor mismatch')
+
+# Test substitutions.
+rule4 = a2l_realm('rule4', 'RULE:s/birds/bees/')
+test_an2ln(rule4, 'thebirdsbirdsbirds at X', 'thebeesbirdsbirds', 'subst 1')
+rule5 = a2l_realm('rule4', 'RULE:s/birds/bees/g  s/bees/birds/')
+test_an2ln(rule4, 'the/birdsbirdsbirds at x', 'the/birdsbeesbees', 'subst 2')
+
+# Test a bunch of auth_to_local values and rule features in combination.
+combo = a2l_realm('combo', ['RULE:[1:$$1-$$0](fred.*)s/-/ /g',
+                            'DEFAULT',
+                            'RULE:[3:$$1](z.*z)'])
+test_an2ln(combo, 'fred at X', 'fred X', 'combo 1')
+test_an2ln(combo, 'fred-too at X', 'fred too X', 'combo 2')
+test_an2ln(combo, 'fred at KRBTEST.COM', 'fred KRBTEST.COM', 'combo 3')
+test_an2ln(combo, 'user at KRBTEST.COM', 'user', 'combo 4')
+test_an2ln(combo, 'zazz/b/c at X', 'zazz', 'combo 5')
+test_an2ln_err(combo, 'a/b at KRBTEST.COM', 'No translation', 'combo 6')
+
+# Test the an2ln userok method with the combo environment.
+test_userok(combo, 'fred at X', 'fred X', True, 'combo userok 1')
+test_userok(combo, 'user at KRBTEST.COM', 'user', True, 'combo userok 2')
+test_userok(combo, 'user at KRBTEST.COM', 'X', False, 'combo userok 3')
+test_userok(combo, 'a/b at KRBTEST.COM', 'a/b', False, 'combo userok 4')
+
+# Register the two test modules and set up some auth_to_local and
+# auth_to_local_names entries.
+modpath = os.path.join(buildtop, 'plugins', 'localauth', 'test',
+                       'localauth_test.so')
+conf = {'plugins': {'localauth': { 'module': [
+                'test1:' + modpath,
+                'test2:' + modpath]}},
+        'realms': {'$realm': {'auth_to_local': [
+                'RULE:(test/rulefirst)s/.*/rule/',
+                'TYPEA',
+                'DEFAULT',
+                'TYPEB:resid']},
+                   'auth_to_local_names': {'test/a/b': 'name'}}}
+mod = realm.special_env('mod', False, conf)
+
+# test1's untyped an2ln method should come before the names method, mapping
+# test/a/b at X to its realm name (superceding auth_to_local_names).
+test_an2ln(mod, 'test/a/b at X', 'X', 'mod untyped an2ln')
+
+# Match the auth_to_local values in order.  test2's TYPEA should map
+# test/notrule to its second component, and its TYPEB should map
+# anything which gets there to the residual string.
+test_an2ln(mod, 'test/rulefirst at X', 'rule', 'mod auth_to_local 1')
+test_an2ln(mod, 'test/notrule', 'notrule', 'mod auth_to_local 2')
+test_an2ln(mod, 'user at KRBTEST.COM', 'user', 'mod auth_to_local 3')
+test_an2ln(mod, 'xyz at X', 'resid', 'mod auth_to_local 4')
+
+# test2's userok module should succeed when the number of components
+# is equal to the length of the local name, should pass if the first
+# component is 'pass', and should reject otherwise.
+test_userok(mod, 'a/b/c/d at X', 'four', True, 'mod userok 1')
+test_userok(mod, 'x/y/z at X', 'four', False, 'mod userok 2')
+test_userok(mod, 'pass at KRBTEST.COM', 'pass', True, 'mod userok 3')
+test_userok(mod, 'user at KRBTEST.COM', 'user', False, 'mod userok 4')
+
+success('krb5_kuserok and krb5_aname_to_localname tests')


More information about the cvs-krb5 mailing list