Delegation and Moonshot

Luke Howard lukeh at
Sat Apr 2 07:47:44 EDT 2011

I wanted to describe some interesting work in bringing delegation to Moonshot. (Well, at least I think it's interesting :-)) I've tried to keep this as high level as possible, but unfortunately it does require a bit of an understanding of GSS-API, Kerberos and SAML. I've used the terms "client" and "service", but you can read "initiator" and "acceptor" or "peer" and "AAA client". I'm cross-posting to krbdev, because the code involved here is all to do with MIT Kerberos; there are no changes to the Moonshot GSS mechanism.

So, delegation is useful when you have ono service that needs to contact another on behalf of a client, and you want to do end-to-end authentication. For example, consider a webmail service that gateways to an IMAP server. I'm sure there are more interesting examples.

With Kerberos, there are a couple of ways to do delegation. The modern approach is so-called "constrained delegation". This allows a service to delegate to a fixed set of other services (determined by KDC policy). At the GSS-API level, the service uses the delegated credential handle returned by gss_accept_sec_context() to create a security context for accessing the back-end service. At a protocol level, the service presents the KDC with the client's ticket, and asks for another one on its behalf to access the backend service. Unfortunately, this only works if the client originally authenticated with Kerberos.

What happens if the client authenticated with another protocol, such as GSS EAP? (For example, Moonshot in Firefox.) Well, it turns out there's a solution for this, too: protocol transition. This allows a service, trusted by the KDC to have authenticated a client by some other means, to acquire a ticket to itself; that ticket can then be used for constrained delegation to another service. The protocol is a variation on the normal ticket request protocol, including an additional field indicating the client on whose behalf the service is acting.

This is all very well, but protocol transition only provides a ticket with the client's name; the rich authorisation semantics provided by SAML in Moonshot are lost. Here's a proposal to allow protocol transition with "assertion transition". Apart from a couple of bugfixes, it doesn't require any source-level changes to MIT Kerberos (and the bugfixes are in the libraries only, not the KDC). The remainder is provided by two plugins: a library plugin that runs on the services, and a KDC plugin.

We define a new authorisation data type, KRB5_AUTHDATA_SAML, that contains a SAML assertion. Moonshot aside, KDCs are free to issue assertions based on their own information. An AAA server that supports services doing "assertion transition" signs assertions with a key shared between it and the KDC. (The AAA service is an ordinary service principal registered with the KDC. The signatures are XML DSIGs as specified by SAML.) In the Moonshot model, the AAA server vouches for assertions that it issues or forwards to the service; here, we extend this to other services in the KDC's realm.

A service doing "assertion transition" makes a normal protocol transition request to a KDC that has the SAML plugin installed. (A KDC without this plugin will copy the assertion into the response, but the service will not be able to validate it.) The KDC validates the AAA server's assertion signature, verifies that local policy permits it to vouch for the assertion, and returns the assertion in the issued ticket (this time signed with the ticket session key, and ultimately encrypted with the service's long term key).

The service receives the protocol transition ticket and validates the assertion (amongst other things, checking the signature). It can now surface the assertion, but this isn't particularly useful because the ticket is to itself. In order to delegate to another service, it makes a constrained delegation request to the KDC; this time, the SAML plugin validates the assertion implicitly because it was signed by the KDC (see for details).

The delegating service will receive a ticket from the client to the delegatee, which it submits in its application protocol (for example, IMAP). The backend-server can thus make authorisation decisions based on the attributes in the original assertion sent by the AAA server. In the IMAP example, this might determine which folders you're allowed to access.

Of course, this could be used with IdPs directly instead of a AAA server. I mentioned this topology here because it's relevant to Moonshot, and it has the nice property of not requiring a parallel PKI or Kerberos infrastructure to do delegation of federated identities within a Kerberos infrastructure. (For EAP identities outside the service realm, the anonymous Kerberos principal name can be used; this makes no difference to attribute-based authorisation.)

This all sounds complicated, but it's actually very easier from an application developer's perspective. The AAA server needs to be modified to sign the assertions, something which I haven't yet implemented (but it should be easy to piggyback on an AAA server that knows how to issue assertions). (In my testbed, the AAA server issued a fixed, signed assertion.)

The service itself just needs to do the following:

	// authenticate GSS EAP client
	do {
	    gss_accept_sec_context(&client_name); // establish GSS EAP security context
	} while (status == GSS_S_CONTINUE_NEEDED);

	// acquire credential for GSS EAP client
	gss_canonicalize_name(client_name, KRB5_MECH, &krb5_name);
	gss_acquire_cred_impersonate_name(client_name, &client_cred);

	// authenticate using Kerberos to backend service
	do {
	    gss_init_sec_context(client_cred, ...); // establish Kerberos security context
	} while (status == GSS_S_CONTINUE_NEEDED);

The backend-service then does:

	// authenticate Kerberos client
	do {
	    gss_accept_sec_context(&client_name); // establish GSS EAP security context
	} while (status == GSS_S_CONTINUE_NEEDED);

	gss_get_name_attribute(client_name, "some attribute");
	gss_get_name_attribute(client_name, "some other attribute");

If the delegating service wants to use anonymous names, then it's a few more lines of code (because you need to create a new name and copy the assertion explicitly), but if this was a common pattern we could probably do something (maybe overload the credential usage flags in gss_acquire_cred_impersonate_name(), or add a pseudo-mech to gss_canonicalize_name() that anonymised then canonicalised).

The observant reader will notice that there is some overlap with the fast reauthentication support provided by Moonshot, where the service mints a ticket to itself for use in subsequent authentication. This ticket cannot be used for constrained delegation, because it is not signed by the KDC. It is true that the service could use protocol transition to generate this ticket. I'm not sure at this stage whether this confers any advantages though (it requires changes to the Moonshot mechanism, and it requires a round trip to the KDC even if delegation is not desired). Sam will probably have more to say on this.

If you want to play with the code, it's in the users/lhoward/saml2 branch of MIT. gss-server has been enhanced to do protocol transition (I haven't committed the constrained delegation tests yet). You'll need to install the plugins in plugins/authdata/saml*.

-- Luke

More information about the krbdev mailing list