From: Greg Hudson Date: Sun, 16 Aug 2015 04:28:53 +0000 (-0400) Subject: Add cookie tests X-Git-Tag: krb5-1.14-alpha1~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=379239d98a05b271bbd6127f98bdb64646958b4c;p=thirdparty%2Fkrb5.git 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 --- diff --git a/src/plugins/preauth/test/cltest.c b/src/plugins/preauth/test/cltest.c index d101a210a1..5244a7d8d1 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 5ac1cd1f56..8c1d01dab8 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 feeeb43529..6bfdd8b9c7 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 e7872bf5d4..8ff6ad6664 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 0000000000..c42e0c435b --- /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')