[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: (ITS#6757) SASL canonicalize doesn't work as documented



I've been doing some analysis of the Cyrus SASL code.

When you say "we're using the parameters as documented by Cyrus", I presume
the documentation you refer to is the comments within the source, in which
case this all hinges on one line in include/sasl.h:

 *  user_realm    -- the user realm (may be NULL in case of client)

(in the parameter list for the SASL_CB_CANON_USER callback). So what's meant
by "the user realm"?

When the callback is actually made (in lib/canonusr.c), the value passed is
sconn->user_realm.  This appears to be the value you get from sasl_getprop()
with SASL_DEFUSERREALM.

The user_realm value can be set in sasl_server_new (lib/server.c) and
sasl_setprop (lib/common.c).

There is a further description of realms in sasl/include.h:

 * IMPORTANT NOTE: server realms / username syntax
 * ... A single server may support multiple realms.  If the
 * server knows the realm at connection creation time (e.g., a server
 * with multiple IP addresses tightly binds one address to a specific
 * realm) then that realm must be passed in the user_realm field of
 * the sasl_server_new call.  If user_realm is non-empty and an
 * unqualified user name is supplied, then the canon_user facility is
 * expected to append "@" and user_realm to the user name.

That is: it seems to me fairly clear that the purpose of user_realm is to
provide a *default* realm which can be appended to the username when
canonicalizing it.

As a specific example, the code in _canonuser_internal() appends
@<user_realm> if the username doesn't contain '@'.

Furthermore, it's also clear from this that the username (SASL_USERNAME) is
intended to include '@' and a realm; Cyrus is not designed to split it into
a username part and a realm part.  This matches what I see when using Cyrus
SASL's standalone "sample-server" and "sample-client" programs, with GSSAPI
and a client with a kerberos ticket from a different realm to the server:

...
Negotiation complete
Username: student@REALM3.WS.NSRC.ORG    << sasl_getprop SASL_USERNAME
Realm: (NULL)                           << sasl_getprop SASL_DEFUSERREALM
SSF: 56
...

There's a full transcript of this example at
http://lists.andrew.cmu.edu/pipermail/cyrus-sasl/2010-December/002177.html

Next, looking at plugins/gssapi.c: AFAICS it doesn't make use of user_realm,
but does ask GSSAPI if the name without realm is the same as the name with
realm, and if so returns the name with the realm stripped off.

        /* If the id contains a realm get the identifier for the user
           without the realm and see if it's the same id (i.e. 
           tmartin == tmartin@ANDREW.CMU.EDU. If this is the case we just want
           to return the id (i.e. just "tmartin" */

So, there is code in the GSSAPI plugin to *strip* the realm if it's the same
as the default, but I don't think there's code to *separate* the username
from the realm if the realm is foreign.

Putting all this together: it seems to me that the "user_realm" you see is
really just the configured default realm for the session; and that when you
query SASL_USERNAME for a Kerberos client, you will see "username" if it's
in the default realm, and "username@foreign.realm" for other realms.  And
this matches what I observe when testing this in OpenLDAP.

As you suggested, I did bring this up on the cyrus-sasl mailing list
(archive URL above), but no replies have been forthcoming so far.

Now, if my understanding of the user_realm parameter is correct, I think
there are two ways to make OpenLDAP's behaviour consistent with its
documentation.

(1) Stick more or less with the current behaviour, and change the
documentation to say that you'll get
    uid=ursula/admin@foreign.realm,cn=gssapi,cn=auth
for foreign realms.

However, the odd thing about the current behaviour is that setting
olcSaslRealm always sticks a static value (...,cn=<olcSaslRealm>,...) into
the auth DN, regardless of whether it's local or foreign.  That's not very
useful.

I think it would make more sense, if olcSaslRealm is present, to use it to
*qualify* usernames which don't have a realm.

     uid=kurt,cn=gssapi,cn=auth
---> uid=kurt@<olcsaslrealm>,cn=gssapi,cn=auth

i.e. change the canonicalize function to append @user_realm if the username
doesn't contain '@'.

This would be useful if you want to undo the Cyrus SASL GSSAPI behaviour of
stripping off the default realm.

(2) Change the OpenLDAP behaviour so that it matches the documentation at
http://www.openldap.org/doc/admin24/sasl.html#GSSAPI

To do this, the canonicalize function would have to parse the username,
splitting it on '@' to separate username from realm, so that you would get

    uid=ursula/admin,cn=foreign.realm,cn=gssapi,cn=auth

If the username doesn't contain '@', but olcSaslRealm is set, then I suggest
you insert that instead:

    uid=kurt,cn=<olcsaslrealm>,cn=gssapi,cn=auth

And if there's no '@' and no olcSaslRealm, then just leave it alone:

    uid=kurt,cn=gssapi,cn=auth

Regards, Brian.