[Date Prev][Date Next]
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()
The user_realm value can be set in sasl_server_new (lib/server.c) and
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
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:
Username: student@REALM3.WS.NSRC.ORG << sasl_getprop SASL_USERNAME
Realm: (NULL) << sasl_getprop SASL_DEFUSERREALM
There's a full transcript of this example at
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 "email@example.com" 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
(1) Stick more or less with the current behaviour, and change the
documentation to say that you'll get
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
I think it would make more sense, if olcSaslRealm is present, to use it to
*qualify* usernames which don't have a realm.
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
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
If the username doesn't contain '@', but olcSaslRealm is set, then I suggest
you insert that instead:
And if there's no '@' and no olcSaslRealm, then just leave it alone: