To perform a constrained delegation operation, the intermediate
service must submit to the KDC an "evidence ticket" from the client to
-the intermediate service with the forwardable bit set. An evidence
-ticket can be acquired when the client authenticates to the
-intermediate service with Kerberos, or with an S4U2Self request if the
-KDC allows it. The MIT krb5 GSSAPI library represents an evidence
-ticket using a "proxy credential", which is a special kind of
-gss_cred_id_t object whose underlying credential cache contains the
-evidence ticket and a krbtgt ticket for the intermediate service.
+the intermediate service. An evidence ticket can be acquired when the
+client authenticates to the intermediate service with Kerberos, or
+with an S4U2Self request if the KDC allows it. The MIT krb5 GSSAPI
+library represents an evidence ticket using a "proxy credential",
+which is a special kind of gss_cred_id_t object whose underlying
+credential cache contains the evidence ticket and a krbtgt ticket for
+the intermediate service.
To acquire a proxy credential during client authentication, the
service should first create an acceptor credential using the
and also pass a *delegated_cred_handle* output parameter to receive a
proxy credential containing the evidence ticket. The output value of
*delegated_cred_handle* may be a delegated ticket-granting ticket if
-the client sent one, or a proxy credential if the client authenticated
-with a forwardable service ticket, or **GSS_C_NO_CREDENTIAL** if
-neither is the case.
+the client sent one, or a proxy credential if not. If the library can
+determine that the client's ticket is not a valid evidence ticket, it
+will place **GSS_C_NO_CREDENTIAL** in *delegated_cred_handle*.
To acquire a proxy credential using an S4U2Self request, the service
can use the following GSSAPI extension::
intermediate service. Both *icred* and *desired_name* are required
for this function; passing **GSS_C_NO_CREDENTIAL** or
**GSS_C_NO_NAME** will cause the call to fail. *icred* must contain a
-krbtgt ticket for the intermediate service. If the KDC returns a
-forwardable ticket, the result of this operation is a proxy
-credential; if it is not forwardable, the result is a regular
-credential for *desired_name*.
-
-A recent KDC will usually allow any service to acquire a ticket from a
-client to itself with an S4U2Self request, but the ticket will only be
-forwardable if the service has a specific privilege. In the MIT krb5
-KDC, this privilege is determined by the **ok_to_auth_as_delegate**
-bit on the intermediate service's principal entry, which can be
-configured with :ref:`kadmin(1)`.
+krbtgt ticket for the intermediate service. The result of this
+operation is a proxy credential. (Prior to release 1.18, the result
+of this operation may be a regular credential for *desired_name*, if
+the KDC issues a non-forwardable ticket.)
Once the intermediate service has a proxy credential, it can simply
pass it to gss_init_sec_context_ as the *initiator_cred_handle*
}
if (proxy) {
- if (keytab_name == NULL) {
- fprintf(stderr, _("Option -P (constrained delegation) "
- "requires keytab to be specified\n"));
- xusage();
- } else if (!impersonate) {
+ if (!impersonate) {
fprintf(stderr, _("Option -P (constrained delegation) requires "
"option -I|-U|-F (protocol transition)\n"));
xusage();
printf(_("%s: kvno = %d, keytab entry valid\n"), princ,
ticket->enc_part.kvno);
}
- if (proxy) {
- krb5_free_creds(context, out_creds);
- out_creds = NULL;
-
- in_creds.client = ticket->enc_part2->client;
- in_creds.server = server;
-
- ret = krb5_get_credentials_for_proxy(context, KRB5_GC_CANONICALIZE,
- ccache, &in_creds, ticket,
- &out_creds);
- if (ret) {
- com_err(prog, ret, _("%s: constrained delegation failed"),
- princ);
- goto cleanup;
- }
- }
} else {
if (!quiet)
printf(_("%s: kvno = %d\n"), princ, ticket->enc_part.kvno);
}
+ if (proxy) {
+ in_creds.client = out_creds->client;
+ out_creds->client = NULL;
+ krb5_free_creds(context, out_creds);
+ out_creds = NULL;
+ in_creds.server = server;
+
+ ret = krb5_get_credentials_for_proxy(context, KRB5_GC_CANONICALIZE,
+ ccache, &in_creds, ticket,
+ &out_creds);
+ krb5_free_principal(context, in_creds.client);
+ if (ret) {
+ com_err(prog, ret, _("%s: constrained delegation failed"),
+ princ);
+ goto cleanup;
+ }
+ }
+
cleanup:
krb5_free_principal(context, server);
krb5_free_ticket(context, ticket);
if (delegated_cred_handle != NULL &&
deleg_cred == NULL && /* no unconstrained delegation */
- cred->usage == GSS_C_BOTH &&
- (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
+ cred->usage == GSS_C_BOTH) {
/*
* Now, we always fabricate a delegated credentials handle
* containing the service ticket to ourselves, which can be
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;
if (code != 0)
goto cleanup;
- /*
- * Only return a "proxy" credential for use with constrained
- * delegation if the subject credentials are forwardable.
- * Submitting non-forwardable credentials to the KDC for use
- * with constrained delegation will only return an error.
- */
- if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) {
- code = make_proxy_cred(context, cred, impersonator_cred);
- if (code != 0)
- goto cleanup;
- }
+ code = make_proxy_cred(context, cred, impersonator_cred);
+ if (code != 0)
+ goto cleanup;
code = krb5_cc_store_cred(context, cred->ccache, subject_creds);
if (code != 0)
*out_creds = NULL;
- if (in_creds == NULL || in_creds->client == NULL ||
- evidence_tkt == NULL || evidence_tkt->enc_part2 == NULL) {
+ if (in_creds == NULL || in_creds->client == NULL || evidence_tkt == NULL) {
code = EINVAL;
goto cleanup;
}
/*
* Caller should have set in_creds->client to match evidence
- * ticket client
+ * ticket client. If we can, verify it before issuing the request.
*/
- if (!krb5_principal_compare(context, evidence_tkt->enc_part2->client,
+ if (evidence_tkt->enc_part2 != NULL &&
+ !krb5_principal_compare(context, evidence_tkt->enc_part2->client,
in_creds->client)) {
code = EINVAL;
goto cleanup;
}
- if ((evidence_tkt->enc_part2->flags & TKT_FLG_FORWARDABLE) == 0) {
- code = KRB5_TKT_NOT_FORWARDABLE;
- goto cleanup;
- }
-
code = krb5int_construct_matching_creds(context, options, in_creds,
&mcreds, &fields);
if (code != 0)
* Check client name because we couldn't compare that inside
* krb5_get_credentials() (enc_part2 is unavailable in clear)
*/
- if (!krb5_principal_compare(context,
- evidence_tkt->enc_part2->client,
+ if (!krb5_principal_compare(context, in_creds->client,
(*out_creds)->client)) {
code = KRB5_KDCREP_MODIFIED;
goto cleanup;
'NOT_ALLOWED_TO_DELEGATE' not in output):
fail('krb5 -> s4u2proxy (SPNEGO)')
-# Try krb5 -> S4U2Proxy without forwardable user creds. This should
-# result in no delegated credential being created by
-# accept_sec_context.
+# Try krb5 -> S4U2Proxy without forwardable user creds.
realm.kinit(realm.user_princ, password('user'), ['-c', usercache])
-realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, pservice1,
- pservice1, pservice2], expected_msg='no credential delegated')
+output = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, pservice1,
+ pservice1, pservice2], expected_code=1)
+if ('auth1: ' + realm.user_princ not in output or
+ 'EVIDENCE_TKT_NOT_FORWARDABLE' not in output):
+ fail('krb5 -> s4u2proxy not-forwardable')
-# Try S4U2Self. Ask for an S4U2Proxy step; this won't happen because
+# Try S4U2Self. Ask for an S4U2Proxy step; this won't succeed because
# service/1 isn't allowed to get a forwardable S4U2Self ticket.
-output = realm.run(['./t_s4u', puser, pservice2])
-if ('Warning: no delegated cred handle' not in output or
- 'Source name:\t' + realm.user_princ not in output):
- fail('s4u2self')
-output = realm.run(['./t_s4u', '--spnego', puser, pservice2])
-if ('Warning: no delegated cred handle' not in output or
- 'Source name:\t' + realm.user_princ not in output):
- fail('s4u2self (SPNEGO)')
+realm.run(['./t_s4u', puser, pservice2], expected_code=1,
+ expected_msg='EVIDENCE_TKT_NOT_FORWARDABLE')
+realm.run(['./t_s4u', '--spnego', puser, pservice2], expected_code=1,
+ expected_msg='EVIDENCE_TKT_NOT_FORWARDABLE')
# Correct that problem and try again. As above, the S4U2Proxy step
# won't actually succeed since we don't support that in DB2.