[Twisted-Python] newpb authorization

Brian Warner warner at lothar.com
Tue Nov 29 02:37:40 EST 2005


> There's an entry in the newpb-docs, newpb-jobs.txt or so,
> where an example is given how this authorization might/will look like.
> it seems that it is to be implemented in the negotiation-phase, before
> the switch-to-banana. Is that interpretation right, or am i wrong about
> this, and the authorization is meant to take place via a mediating
> pb.referenceable, similar to oldpb?

My current thought is the latter, keeping all notion of authorization at the
Referenceable layer, out of the connection itself. I'm thinking that the
Realm (in cred terms) is a Referenceable, and you send your credentials to it
via a login() method. The Realm then returns another Referenceable (the
Avatar), which you interact with to your hearts content. On the client side,
you'd have some sort of higher-level object to which you would pass the
PB-URL of the target Realm and your Credentials. When all was said and done,
you'd wind up with a RemoteReference to the remote Avatar. You could have
multiple Realms on the same host, distinguished by their URLs.

I'm definitely leaning in a capabilities-based direction these days, so both
the Realm (which anybody can access) and the Avatar (which can only be
accessed by the person with the right credentials) are reachable with URLs,
the only difference being that the Realm's URL is public knowledge, while the
Avatar URLs are randomly-generated and unguessable. If you want to bypass the
whole username/password thing, you just give the hopeful client the URL of
their Avatar, and let them connect directly to that.

[note that some of the things I wrote about cred-vs-newpb were before I was
fully aware of the capabilities model. back in those days, I was vaguely
thinking of having a "default object" for each connection, which could accept
credentials and return Avatars, such that it might make sense to put things
like username and passwords in the URLs. Also, back then it seemed reasonable
to use Interfaces or RemoteInterfaces as ways to specify "who" or "what" you
wanted to talk to. I've since come to my senses. newpb provides a layer of
secure remote references, on top of which you can build whatever sort of
authorization scheme you like]

[also, back then I was expecting Glyph to swoop down and implement the whole
thing in one afternoon's frantic coding binge, absolving me from needing to
understand how it would actually work or get used. fortunately this has not
come to pass, so I get to write something that can be comprehended by my own
humble brain. muahahaha.]

> What i'm thinking of is two distinct uses of cred in pb. one at an early
> stage, affecting the whole connection to be or not to be, and one in
> later phases, to have a basis for managing roles and permissions while
> the app is running.

It sounds like the capabilities-based scheme I have in mind fits the second
of your use cases. As for the first one.. what sort of things connection-time
things would you like to be controlled by authorization information? One
thing that comes to mind is whether the connection will be accepted or not,
presumeably to reduce resource utilization, but consider this:

 the TCP connection will be accepted regardless. until the first byte of data
 arrives, the only thing we can deduce about the client is their IP address,
 and we all know how unhelpful it is to make decisions upon purely that
 basis.

 given that tub.registerReference() returns an unguessable URL by default,
 the only objects that can be reached will be ones to which you have
 explicitly granted access, either by registering a well-known URL (like
 "/login") or by giving the URL to the client by some other channel. So
 allowing the "bad guy" to establish a connection doesn't actually let them
 access anything you don't want them to have.

 newpb's Schemas can be used to minimize resource utilization (specifically
 memory consumption) required by messages sent to those public objects. If
 the only object exposed to the world at large is the "/login" Realm, and if
 it only has a single remote_login(username, password) method, then a simple
 (username=str, password=str) schema will prevent that one permissible
 message from consuming too much space, limiting its utility in a DoS attack.


Given those, what other connection-time authorization checks do you think
might be useful?

Having authorization take place entirely at the object layer also has the
nice property that you can run arbitrary numbers of mutually-unaware services
off the same connection. My reluctance to add authorization below that layer
comes partially from the benefits of this property. As an example, in the
Buildbot[1], there are several PB services provided to entities in the
outside world (buildslaves, a status client, a debug client, and a Change
inlet), each distinguished by the cred username/password provided by the
various clients. The nominal API for these services (i.e., what you put in
the config file to create each service) would allow you to choose an
arbitrary TCP port for each, which may or may not overlap with each other. In
practice, the hassle of creating a Realm for each PBServerFactory (some of
which know about some usernames, others which don't, all of which could
change each time the config file is changed, etc) was so great that I punted
and just forced the user to make all those services share a single TCP port,
hence using a single Realm which knows about everything.

I haven't quite figured out how this would work if Buildbot used newpb, but I
know that I'd expose, say, the status service with a URL that ended in
"/status", and the debug service (which is supposed to be protected, and thus
gets a user-specified password in oldpb) would just get an unguessable URL.
The same TCP port could be used for different services that had different
authorization requirements.

If authorization took place before the object-level connection could be
established, I'd have to coordinate another layer of usernames and passwords
(or challenge-response pairs, or SRP exchanges, or whatever) without the
benefit of using PB serialization or object references. Having already built
one remote-method-invocation protocol this decade, I'm not keen on creating
another one quite yet :).


cheers,
 -Brian

PS: Yay! Somebody is looking at newpb! :)


[1] Buildbot: http://buildbot.sf.net/




More information about the Twisted-Python mailing list