krb5 commit: Use cached S4U2Proxy tickets in GSSAPI
Greg Hudson
ghudson at mit.edu
Mon Feb 29 16:13:23 EST 2016
https://github.com/krb5/krb5/commit/f149b9cc1e0f8c6e7cca2ee0a5fd8feff7deaf58
commit f149b9cc1e0f8c6e7cca2ee0a5fd8feff7deaf58
Author: Isaac Boukris <iboukris at gmail.com>
Date: Mon Feb 1 18:08:24 2016 +0200
Use cached S4U2Proxy tickets in GSSAPI
Ticket #7047 allowed credentials obtain using S4U2Proxy through GSSAPI
to be cached, but doesn't actually use the cached credentials. Modify
get_credentials() to check the cache for the desired client name
first, then to make an S4U2Proxy request if we don't find it.
Test this change by adding code to t_s4u.c to repeat the constrained
delegation request and verify that only three tickets are present in
the cache.
[ghudson at mit.edu: squash commits; commit message rewrite; minor style
edits; changed test code to use gss_store_cred_into() to avoid the
need to pick a principal to initialize the ccache with]
ticket: 8372 (new)
src/lib/gssapi/krb5/init_sec_context.c | 71 ++++++++++++++++---------------
src/tests/gssapi/t_s4u.c | 66 +++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 34 deletions(-)
diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index 4d05d78..70f7955 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -127,7 +127,7 @@ static krb5_error_code get_credentials(context, cred, server, now,
krb5_creds **out_creds;
{
krb5_error_code code;
- krb5_creds in_creds, evidence_creds, *result_creds = NULL;
+ krb5_creds in_creds, evidence_creds, mcreds, *result_creds = NULL;
krb5_flags flags = 0;
*out_creds = NULL;
@@ -139,37 +139,7 @@ static krb5_error_code get_credentials(context, cred, server, now,
assert(cred->name != NULL);
- /*
- * Do constrained delegation if we have proxy credentials and
- * we're not trying to get a ticket to ourselves (in which case
- * we can just use the S4U2Self or evidence ticket directly).
- */
- if (cred->impersonator &&
- !krb5_principal_compare(context, cred->impersonator, server->princ)) {
- krb5_creds mcreds;
-
- flags |= KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
-
- memset(&mcreds, 0, sizeof(mcreds));
-
- mcreds.magic = KV5M_CREDS;
- mcreds.server = cred->impersonator;
- mcreds.client = cred->name->princ;
-
- code = krb5_cc_retrieve_cred(context, cred->ccache,
- KRB5_TC_MATCH_AUTHDATA, &mcreds,
- &evidence_creds);
- if (code)
- goto cleanup;
-
- assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
-
- in_creds.client = cred->impersonator;
- in_creds.second_ticket = evidence_creds.ticket;
- } else {
- in_creds.client = cred->name->princ;
- }
-
+ in_creds.client = cred->name->princ;
in_creds.server = server->princ;
in_creds.times.endtime = endtime;
in_creds.authdata = NULL;
@@ -188,12 +158,45 @@ static krb5_error_code get_credentials(context, cred, server, now,
goto cleanup;
}
- /* Don't go out over the network if we used IAKERB */
- if (cred->iakerb_mech)
+ /*
+ * For IAKERB or constrained delegation, only check the cache in this step.
+ * For IAKERB we will ask the server to make any necessary TGS requests;
+ * for constrained delegation we will adjust in_creds and make an S4U2Proxy
+ * request below if the cache lookup fails.
+ */
+ if (cred->impersonator != NULL || cred->iakerb_mech)
flags |= KRB5_GC_CACHED;
code = krb5_get_credentials(context, flags, cred->ccache,
&in_creds, &result_creds);
+
+ /*
+ * Try constrained delegation if we have proxy credentials, unless
+ * we are trying to get a ticket to ourselves (in which case we could
+ * just use the evidence ticket directly from cache).
+ */
+ if (code == KRB5_CC_NOTFOUND && cred->impersonator != NULL &&
+ !cred->iakerb_mech &&
+ !krb5_principal_compare(context, cred->impersonator, server->princ)) {
+
+ memset(&mcreds, 0, sizeof(mcreds));
+ mcreds.magic = KV5M_CREDS;
+ mcreds.server = cred->impersonator;
+ mcreds.client = cred->name->princ;
+ code = krb5_cc_retrieve_cred(context, cred->ccache,
+ KRB5_TC_MATCH_AUTHDATA, &mcreds,
+ &evidence_creds);
+ if (code)
+ goto cleanup;
+
+ assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
+ in_creds.client = cred->impersonator;
+ in_creds.second_ticket = evidence_creds.ticket;
+ flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
+ code = krb5_get_credentials(context, flags, cred->ccache,
+ &in_creds, &result_creds);
+ }
+
if (code)
goto cleanup;
diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c
index c33560f..5bc1e44 100644
--- a/src/tests/gssapi/t_s4u.c
+++ b/src/tests/gssapi/t_s4u.c
@@ -123,6 +123,55 @@ init_accept_sec_context(gss_cred_id_t claimant_cred_handle,
}
static void
+check_ticket_count(gss_cred_id_t cred, int expected)
+{
+ krb5_error_code ret;
+ krb5_context context = NULL;
+ krb5_creds kcred;
+ krb5_cc_cursor cur;
+ krb5_ccache ccache;
+ int count = 0;
+ gss_key_value_set_desc store;
+ gss_key_value_element_desc elem;
+ OM_uint32 major, minor;
+ const char *ccname = "MEMORY:count";
+
+ store.count = 1;
+ store.elements = &elem;
+ elem.key = "ccache";
+ elem.value = ccname;
+ major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE, &mech_krb5, 1, 0,
+ &store, NULL, NULL);
+ check_gsserr("gss_store_cred_into", major, minor);
+
+ ret = krb5_init_context(&context);
+ check_k5err(context, "krb5_init_context", ret);
+
+ ret = krb5_cc_resolve(context, ccname, &ccache);
+ check_k5err(context, "krb5_cc_resolve", ret);
+
+ ret = krb5_cc_start_seq_get(context, ccache, &cur);
+ check_k5err(context, "krb5_cc_start_seq_get", ret);
+
+ while (!krb5_cc_next_cred(context, ccache, &cur, &kcred)) {
+ if (!krb5_is_config_principal(context, kcred.server))
+ count++;
+ krb5_free_cred_contents(context, &kcred);
+ }
+
+ ret = krb5_cc_end_seq_get(context, ccache, &cur);
+ check_k5err(context, "krb5_cc_end_seq_get", ret);
+
+ if (expected != count) {
+ printf("Expected %d tickets but got %d\n", expected, count);
+ exit(1);
+ }
+
+ krb5_cc_destroy(context, ccache);
+ krb5_free_context(context);
+}
+
+static void
constrained_delegate(gss_OID_set desired_mechs, gss_name_t target,
gss_cred_id_t delegated_cred_handle,
gss_cred_id_t verifier_cred_handle)
@@ -164,7 +213,24 @@ constrained_delegate(gss_OID_set desired_mechs, gss_name_t target,
(void)gss_release_buffer(&minor, &token);
(void)gss_delete_sec_context(&minor, &initiator_context, NULL);
+
+ /* Ensure a second call does not acquire new ticket. */
+ major = gss_init_sec_context(&minor, delegated_cred_handle,
+ &initiator_context, target,
+ mechs ? &mechs->elements[0] : &mech_krb5,
+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+ GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
+ GSS_C_NO_BUFFER, NULL, &token, NULL,
+ &time_rec);
+ check_gsserr("gss_init_sec_context", major, minor);
+
+ (void)gss_release_buffer(&minor, &token);
+ (void)gss_delete_sec_context(&minor, &initiator_context, NULL);
(void)gss_release_oid_set(&minor, &mechs);
+
+ /* We expect three tickets: our TGT, the evidence ticket, and the ticket to
+ * the target service. */
+ check_ticket_count(delegated_cred_handle, 3);
}
int
More information about the cvs-krb5
mailing list