Fwd: Delegation and Moonshot

Luke Howard lukeh at padl.com
Sun Apr 3 01:27:52 EDT 2011


If you're interested in protocol transition with preservation of authorisation attributes, see below. It allows you to delegate a user authenticated via GSS EAP to Kerberos, whilst preserving the SAML attributes present in an assertion received from a AAA (RADIUS) server.

Begin forwarded message:

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 http://k5wiki.kerberos.org/wiki/Projects/ConstrainedDelegation 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_acquire_cred(&impersonator_cred);
	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, you will need:

* a working Moonshot configuration (http://www.project-moonshot.org/developers/repository)
* MIT source checked out from the users/lhoward/saml2 SVN branch
* create a key for saml-idp/REALM at REALM and extract it to your keytab
* sign the assertion you want to return with the saml_sign -radius tool (obviously, returning the same assertion for every user isn't useful for much beyond testing, but that's the same stage we're at with Moonshot)
* add the assertion to sites-enabled/default and restart radiusd
* make install in  src/plugins/authdata/{saml_client,saml_server}
* if you want to support KDC-generated assertions as well, install the modified LDAP plugin in src/plugins/kdb/ldap

For example:

gss-server -port 5555 -s4u -anon -deleg ldap at constellation.project-moonshot.org -export host at constellation.project-moonshot.org"

gss-client -port 5555 -spnego -mech "{1 3 6 1 4 1 5322 22 1 18}" -user lukeh at PROJECT-MOONSHOT.ORG -pass foo rand host at constellation.project-moonshot.org "test"

The -s4u flag enables the protocol transition test. The -anon flag uses the anonymous principal name as the protocol transition target; you can omit this if the RADIUS user exists in your Kerberos database. The -deleg flag service flag enables the constrained delegation test. The client arguments are the same as for testing Moonshot normally.

You'll also want to configure Shibboleth, because the Kerberos SAML plugin only exposes mapped attributes. For example, I have the following in attribute-map.xml:

    <Attribute name="urn:oid:0.9.2342.19200300.100.1.1" id="local-login-user"/>
    <Attribute name="urn:oid:1.3.6.1.1.1.1.4" id="local-login-shell"/>
    <Attribute name="urn:oid:2.5.4.3" id="cn"/>
    <Attribute name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" id="eduPersonPrincipalName"/>

On the gss-server side, you'll first see the attributes from the GSS EAP authentication; then you'll see "Protocol transition tests follow" and, all going well, you'll also see something like:

Target name:	host/constellation.project-moonshot.org at PROJECT-MOONSHOT.ORG
Target mech:	{ 1 2 840 113554 1 2 2 }
Source name:	WELLKNOWN/ANONYMOUS at WELLKNOWN:ANONYMOUS
Source mech:	{ 1 2 840 113554 1 2 2 }

Attribute urn:ietf:params:gss-eap:saml-aaa-assertion Authenticated 
...

Constrained delegation tests follow
-----------------------------------

Proxy name:	host/constellation.project-moonshot.org at PROJECT-MOONSHOT.ORG
Target name:	ldap/constellation.project-moonshot.org at PROJECT-MOONSHOT.ORG
Delegated name:	WELLKNOWN/ANONYMOUS at WELLKNOWN:ANONYMOUS
Delegated mech:	{ 1 2 840 113554 1 2 2 }

This should contain the same assertion as returned by the RADIUS server and it should be marked Authenticated.

If you need to debug, you might want to set the SAML_DEBUG_SERIALIZE environment variable on the KDC, and you'll see any assertions printed to stderr. The entry point on the KDC is saml_authdata; on the service, saml_import_authdata and saml_verify_authdata. Debugging skills will probably be handy at this stage.

-- Luke


More information about the krbdev mailing list