krb5 commit: Add cookie tests
Greg Hudson
ghudson at mit.edu
Wed Aug 26 13:29:49 EDT 2015
https://github.com/krb5/krb5/commit/379239d98a05b271bbd6127f98bdb64646958b4c
commit 379239d98a05b271bbd6127f98bdb64646958b4c
Author: Greg Hudson <ghudson at mit.edu>
Date: Sun Aug 16 00:28:53 2015 -0400
Add cookie tests
Add cookie and KDC_ERR_MORE_PREAUTH_DATA_REQUIRED functionality to the
test preauth plugins modules. Create a new test script t_preauth.py
and move a test there from t_etype_info.py which is only marginally
related to etype-info. Add a new test which exercises a multi-hop
preauth scenario and generates different cookies for each KDC error.
ticket: 8233
src/plugins/preauth/test/cltest.c | 40 +++++++++++++++++++--
src/plugins/preauth/test/kdctest.c | 71 ++++++++++++++++++++++++++++--------
src/tests/Makefile.in | 1 +
src/tests/t_etype_info.py | 20 ----------
src/tests/t_preauth.py | 25 +++++++++++++
5 files changed, 119 insertions(+), 38 deletions(-)
diff --git a/src/plugins/preauth/test/cltest.c b/src/plugins/preauth/test/cltest.c
index d101a21..5244a7d 100644
--- a/src/plugins/preauth/test/cltest.c
+++ b/src/plugins/preauth/test/cltest.c
@@ -34,13 +34,17 @@
* This module is used to test preauth interface features. At this time, the
* clpreauth module does two things:
*
- * - It decrypts a message from the initial KDC padata using the reply key and
+ * - It decrypts a message from the initial KDC pa-data using the reply key and
* prints it to stdout. (The unencrypted message "no key" can also be
* displayed.)
*
+ * - If a second round trip is requested, it prints the pa-data contents
+ * accompanying the second round trip request.
+ *
* - It pulls an "indicators" attribute from the gic preauth options and sends
* it to the server, instructing the kdcpreauth module to assert one or more
- * space-separated authentication indicators.
+ * space-separated authentication indicators. (This string is sent on both
+ * round trips if a second round trip is requested.)
*/
#include "k5-int.h"
@@ -54,6 +58,10 @@ struct client_state {
char *indicators;
};
+struct client_request_state {
+ krb5_boolean second_round_trip;
+};
+
static krb5_error_code
test_init(krb5_context context, krb5_clpreauth_moddata *moddata_out)
{
@@ -75,6 +83,25 @@ test_fini(krb5_context context, krb5_clpreauth_moddata moddata)
free(st);
}
+static void
+test_request_init(krb5_context context, krb5_clpreauth_moddata moddata,
+ krb5_clpreauth_modreq *modreq_out)
+{
+ struct client_request_state *reqst;
+
+ reqst = malloc(sizeof(*reqst));
+ assert(reqst != NULL);
+ reqst->second_round_trip = FALSE;
+ *modreq_out = (krb5_clpreauth_modreq)reqst;
+}
+
+static void
+test_request_fini(krb5_context context, krb5_clpreauth_moddata moddata,
+ krb5_clpreauth_modreq modreq)
+{
+ free(modreq);
+}
+
static krb5_error_code
test_process(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
@@ -85,6 +112,7 @@ test_process(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_pa_data ***out_pa_data)
{
struct client_state *st = (struct client_state *)moddata;
+ struct client_request_state *reqst = (struct client_request_state *)modreq;
krb5_error_code ret;
krb5_pa_data **list, *pa;
krb5_keyblock *k;
@@ -92,7 +120,10 @@ test_process(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_data plain;
const char *indstr;
- if (pa_data->length == 6 && memcmp(pa_data->contents, "no key", 6) == 0) {
+ if (reqst->second_round_trip) {
+ printf("2rt: %.*s\n", pa_data->length, pa_data->contents);
+ } else if (pa_data->length == 6 &&
+ memcmp(pa_data->contents, "no key", 6) == 0) {
printf("no key\n");
} else {
/* This fails during s4u_identify_user(), so don't assert. */
@@ -108,6 +139,7 @@ test_process(krb5_context context, krb5_clpreauth_moddata moddata,
printf("%.*s\n", plain.length, plain.data);
free(plain.data);
}
+ reqst->second_round_trip = TRUE;
indstr = (st->indicators != NULL) ? st->indicators : "";
list = k5calloc(2, sizeof(*list), &ret);
@@ -155,6 +187,8 @@ clpreauth_test_initvt(krb5_context context, int maj_ver,
vt->pa_type_list = pa_types;
vt->init = test_init;
vt->fini = test_fini;
+ vt->request_init = test_request_init;
+ vt->request_fini = test_request_fini;
vt->process = test_process;
vt->gic_opts = test_gic_opt;
return 0;
diff --git a/src/plugins/preauth/test/kdctest.c b/src/plugins/preauth/test/kdctest.c
index 5ac1cd1..8c1d01d 100644
--- a/src/plugins/preauth/test/kdctest.c
+++ b/src/plugins/preauth/test/kdctest.c
@@ -32,12 +32,18 @@
/*
* This module is used to test preauth interface features. Currently, the
- * kdcpreauth module does two things:
+ * kdcpreauth module does the following:
*
- * - It retrieves the "teststring" attribute from the client principal and
- * sends it to the client, encrypted in the reply key. (The plain text "no
- * key" is sent if there is no reply key; the encrypted message "no attr" is
- * sent if there is no string attribute.)
+ * - When generating initial method-data, it retrieves the "teststring"
+ * attribute from the client principal and sends it to the client, encrypted
+ * in the reply key. (The plain text "no key" is sent if there is no reply
+ * key; the encrypted message "no attr" is sent if there is no string
+ * attribute.) It also sets a cookie containing "method-data".
+ *
+ * - It retrieves the "2rt" attribute from the client principal. If set, the
+ * verify method sends the client a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error
+ * with the contents of the 2rt attribute as pa-data, and sets a cookie
+ * containing "more".
*
* - It receives a space-separated list from the clpreauth module and asserts
* each string as an authentication indicator. It always succeeds in
@@ -87,6 +93,12 @@ test_edata(krb5_context context, krb5_kdc_req *req,
assert(pa->contents != NULL);
pa->length = 6;
}
+
+ /* Exercise setting a cookie information from the edata method. */
+ d = string2data("method-data");
+ ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);
+ assert(!ret);
+
cb->free_string(context, rock, attr);
(*respond)(arg, 0, pa);
}
@@ -99,19 +111,48 @@ test_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
krb5_kdcpreauth_verify_respond_fn respond, void *arg)
{
krb5_error_code ret;
- char *str, *ind, *toksave = NULL;
+ krb5_boolean second_round_trip = FALSE;
+ krb5_pa_data **list;
+ krb5_data cookie_data, d;
+ char *str, *ind, *attr, *toksave = NULL;
+
+ ret = cb->get_string(context, rock, "2rt", &attr);
+ assert(!ret);
- str = k5memdup0(data->contents, data->length, &ret);
- if (ret)
+ /* Check the incoming cookie value. */
+ if (!cb->get_cookie(context, rock, TEST_PA_TYPE, &cookie_data))
abort();
- ind = strtok_r(str, " ", &toksave);
- while (ind != NULL) {
- cb->add_auth_indicator(context, rock, ind);
- ind = strtok_r(NULL, " ", &toksave);
+ if (data_eq_string(cookie_data, "more"))
+ second_round_trip = TRUE;
+ else
+ assert(data_eq_string(cookie_data, "method-data"));
+
+ if (attr == NULL || second_round_trip) {
+ /* Parse and assert the indicators. */
+ str = k5memdup0(data->contents, data->length, &ret);
+ if (ret)
+ abort();
+ ind = strtok_r(str, " ", &toksave);
+ while (ind != NULL) {
+ cb->add_auth_indicator(context, rock, ind);
+ ind = strtok_r(NULL, " ", &toksave);
+ }
+ free(str);
+ enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
+ (*respond)(arg, 0, NULL, NULL, NULL);
+ } else {
+ d = string2data("more");
+ ret = cb->set_cookie(context, rock, TEST_PA_TYPE, &d);
+ list = k5calloc(2, sizeof(*list), &ret);
+ assert(!ret);
+ list[0] = k5alloc(sizeof(*list[0]), &ret);
+ assert(!ret);
+ list[0]->pa_type = TEST_PA_TYPE;
+ list[0]->contents = (uint8_t *)attr;
+ list[0]->length = strlen(attr);
+ (*respond)(arg, KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED, NULL, list,
+ NULL);
}
- free(str);
- enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
- (*respond)(arg, 0, NULL, NULL, NULL);
}
static krb5_error_code
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index feeeb43..6bfdd8b 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -153,6 +153,7 @@ check-pytests:: responder s2p s4u2proxy t_init_creds t_localauth unlockiter
$(RUNPYTEST) $(srcdir)/t_unlockiter.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_errmsg.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_authdata.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_preauth.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_princflags.py $(PYTESTFLAGS)
clean::
diff --git a/src/tests/t_etype_info.py b/src/tests/t_etype_info.py
index e7872bf..8ff6ad6 100644
--- a/src/tests/t_etype_info.py
+++ b/src/tests/t_etype_info.py
@@ -73,24 +73,4 @@ test_etinfo('user', 'des-cbc-md5 rc4',
test_etinfo('rc4user', 'des3', [])
test_etinfo('nokeyuser', 'des3', [])
-realm.stop()
-
-# Test that the kdcpreauth client_keyblock() callback matches the key
-# indicated by the etype info, and returns NULL if key was selected.
-testpreauth = os.path.join(buildtop, 'plugins', 'preauth', 'test', 'test.so')
-plugconf = {'plugins': {'kdcpreauth': {'module': 'test:' + testpreauth},
- 'clpreauth': {'module': 'test:' + testpreauth}}}
-conf.update(plugconf)
-realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf)
-realm.run([kadminl, 'modprinc', '+requires_preauth', realm.user_princ])
-realm.run([kadminl, 'setstr', realm.user_princ, 'teststring', 'testval'])
-realm.run([kadminl, 'addprinc', '-nokey', '+requires_preauth', 'nokeyuser'])
-out = realm.run([kinit, realm.user_princ], input=password('user')+'\n')
-if 'testval' not in out:
- fail('Decrypted string attribute not in kinit output')
-out = realm.run([kinit, 'nokeyuser'], input=password('user')+'\n',
- expected_code=1)
-if 'no key' not in out:
- fail('Expected "no key" message not in kinit output')
-
success('KDC etype-info tests')
diff --git a/src/tests/t_preauth.py b/src/tests/t_preauth.py
new file mode 100644
index 0000000..c42e0c4
--- /dev/null
+++ b/src/tests/t_preauth.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+from k5test import *
+
+# Test that the kdcpreauth client_keyblock() callback matches the key
+# indicated by the etype info, and returns NULL if no key was selected.
+testpreauth = os.path.join(buildtop, 'plugins', 'preauth', 'test', 'test.so')
+conf = {'plugins': {'kdcpreauth': {'module': 'test:' + testpreauth},
+ 'clpreauth': {'module': 'test:' + testpreauth}}}
+realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf)
+realm.run([kadminl, 'modprinc', '+requires_preauth', realm.user_princ])
+realm.run([kadminl, 'setstr', realm.user_princ, 'teststring', 'testval'])
+realm.run([kadminl, 'addprinc', '-nokey', '+requires_preauth', 'nokeyuser'])
+out = realm.run([kinit, realm.user_princ], input=password('user')+'\n')
+if 'testval' not in out:
+ fail('Decrypted string attribute not in kinit output')
+out = realm.run([kinit, 'nokeyuser'], input=password('user')+'\n',
+ expected_code=1)
+if 'no key' not in out:
+ fail('Expected "no key" message not in kinit output')
+
+# Exercise KDC_ERR_MORE_PREAUTH_DATA_REQUIRED and secure cookies.
+realm.run([kadminl, 'setstr', realm.user_princ, '2rt', 'secondtrip'])
+out = realm.run([kinit, realm.user_princ], input=password('user')+'\n')
+if '2rt: secondtrip' not in out:
+ fail('multi round-trip cookie test')
More information about the cvs-krb5
mailing list