[Twisted-Python] Must avatarId always be a string?

Peter Westlake peter.westlake at pobox.com
Mon Jan 14 06:18:55 EST 2013


On Sun, Jan 13, 2013, at 6:39, Glyph wrote:
> 
> On Jan 10, 2013, at 6:41 AM, Peter Westlake <peter.westlake at pobox.com>
> wrote:
> 
> > On Wed, Jan 9, 2013, at 18:02, Glyph wrote
> >> On Jan 9, 2013, at 9:26 AM, Peter Westlake <peter.westlake at pobox.com>
> >> wrote:
> >>> On Jan 9, Adi wrote:
> >>>> I am not an expert in Twisted, but from my understanding, the "string"
> >>>> requirement is there to provide a plugable interface. So that you can
> >>>> have generic credentials checkers, working with generic realms.
> >>>> Having simple "strings" could also help with AvatarId serialization,
> >>>> in case you have the CredentialsChecker on one computer and the you
> >>>> will pass them over network/socket to a remote Realm.
> >>> 
> >>> Those are both good points! I'll leave it this way until there's
> >>> a more official way of doing it.
> >> 
> >> I hope it's clear that just hard-coding your avatars and realms to work
> >> only with each other is a sub-optimal solution :).
> > 
> > Indeed :-)
> > 
> >> The architecture of cred is supposed to be that you can plug realms and
> >> checkers together so that a change to your authentication backend doesn't
> >> completely change your application.  Of course, that architecture is
> >> flawed in the sense that a string is a bit too narrow of a communication
> >> channel to get information about the authenticated user from one to the
> >> other, especially in cases where the application needs information from a
> >> directory service to function.
> >> 
> >> If you're interested in an improved, official way to deal with this
> >> use-case, the best way to do that would be to get involved and actively
> >> try to specify what you need.
> > 
> > Here's my use case. The CredentialsChecker takes a login name,
> > e.g. "pwest", and looks it up in LDAP. It gets back an LDAP record
> > something like this:
> > 
> > {
> >   'distinguishedName': 'CN=Peter Westlake,OU=User
> >   Accounts,OU=EMEA,DC=example,DC=com',
> >   'cn': 'Peter Westlake',
> >   'name': 'Peter Westlake',
> >   'sn': 'Westlake',
> >   'mail': 'Peter.Westlake at example.com',
> >   'givenName': 'Peter',
> >   'sAMAccountName': 'pwest'
> > }
> > 
> > It passes the distinguishedName and the supplied password
> > to the LDAP password checker function for authorization.
> > 
> > At this point the correct thing to do would be to return "pwest"
> > as the avatarId. But I've got all that other useful information
> > available, and it seems a shame to have to get it again in
> > the Realm, so I return the whole dictionary.
> 
> One potentially interesting question here, as well, is "why
> sAMAccountName" as the avatarID?  Isn't there a UID or UUID in there
> somewhere?  In my application, all the user identifiers are opaque, and
> that makes a bit more sense, since those values don't change, although
> any other part of the user's record could change as information evolves
> over time.  For example, if someone gets married and changes their name,
> they might find it annoying to have to log in with a username that
> references their maiden name all the time.

That would be a good design, yes, and I'll bear it in mind for future
use.
But for now I'm stuck with a system that has no way to change usernames,
as I discovered the hard way when my original employer was acquired. To
this day I have different logins for Unix and the rest of the corporate
infrastructure. (In case someone asks: the Unix name would be easy
enough to change, but it's used in a lot of places. One day, maybe.)
The account name is the closest thing to a unique id that's available.

> > Some points to note:
> > 
> > 1. Converting the dict to a string would make
> >   the avatarId conform to the interface, but
> >   it still wouldn't be pluggable, because other
> >   checkers wouldn't return the extra information.
> > 
> >   This strikes me as a general problem. If the
> >   checker returns more than an avatarId, whether
> >   directly or through some official-sanctioned channel,
> >   it will only be interchangeable with other
> >   checkers that also return the extra information.
> > 
> > 2. The application knows about LDAP, and uses it
> >   to find things like your manager and your email
> >   address. Some of this information is in the
> >   avatarId, but some of it isn't, so some LDAP
> >   calls will have to be made. This weakens the
> >   argument against duplicating the lookup.
> > 
> > The correct thing to do in this case would undoubtedly
> > be to accept that an LDAP call isn't very expensive,
> > and repeat it in the Realm. In other words, my use
> > case isn't very compelling. You have shamed me into
> > changing it :-)   In one way this is a good result,
> > though it doesn't help with the design.
> > 
> > Having made that change, I can use a password file
> > or an in-memory database for testing, and write
> > test scripts that don't need a real password. That's
> > well worth the /completely unnoticeable/ expense
> > of an extra LDAP call!
> 
> As other posters have already said, you can also have your realm and your
> checker share a reference to an object that caches credentials.  This
> would also let you cache other calls that are made later, too.
> 
> > BUT:
> > This only works because it doesn't use the user's
> > password for binding to LDAP. If it did, then either
> > the password or the LDAP session would have
> > to be made available to the Realm, and we're
> > back at square 1.
> 
> It seems like the "shared caching reference" would solve this problem
> as well?

Yes, I think that's the right answer. It's certainly the right design
in my case, and perhaps in the general case too.

Thanks for looking into this,

Peter.



More information about the Twisted-Python mailing list