[Twisted-Python] Passport, my ideas about an LDAP backend
Here's a sketch of how I imagine an LDAP backend to passport will work: LDAP is a logically simple (implementation horrible:) TCP protocol with messages passing in both directions. User authentication is one possible message type, and the server replies with either success or an error message. For just searching and browsing, you can bind anonymously. Most servers allow read-only access by default. But for any kind of modification, we need to bind. So far, this seems pretty much like with databases. However, here's the big catch: the normal way to use databases is to have one userid and password per application, and perhaps store actual userids and passwords within a table in the database. The normal way to use LDAP is to bind _as the user who is doing the operation_. Here is a list of requirements I can think, that need to be fulfilled in order for me to be able to use passport. Some of these may be very trivial, or taken for granted by now -- I'm just making sure they are seen. Requirement #1: Passport needs to be async. In order to be able to use LDAP as the backend for passport-like user verification, the backend needs to be able to talk to a possibly slow server. Requirement #2: Passport must be able to store data in the Perspective during authentication. However, if the application wants to use LDAP for more than just user authentication, things get a bit worse. We could just store the password we saw the user enter, and later bind to the LDAP server as this user. However, I dislike storing plain-text passwords in virtual memory. Requirement #3: Passport must be able to ask users to reauthenticate. A better way is to remember that we already did bind (authenticate) to the LDAP server as that user. Just reserve that connection for that user alone. As long as the connection is alive, we can keep on talking to the LDAP server. Now, programs can be restarted, TCP connections can die, and servers can utilize idle timeouts, maximum time limits, or limit maximum number of operations per connection. The TCP connection can die any moment. As we didn't store the user password, we need to ask it again when we see the connection has closed and the user tries an operation that requires talking to the LDAP server. This requires "invalidating" the users previous authentication. -- tv@{{hq.yok.utu,havoc,gaeshido}.fi,{debian,wanderer}.org,stonesoft.com} double a,b=4,c;main(){for(;++a<2e6;c-=(b=-b)/a++);printf("%f\n",c);}
On Sun, 2001-12-30 at 15:13, Tommi Virtanen wrote:
Here's a sketch of how I imagine an LDAP backend to passport will work:
LDAP is a logically simple (implementation horrible:) TCP protocol with messages passing in both directions. User authentication is one possible message type, and the server replies with either success or an error message.
For just searching and browsing, you can bind anonymously. Most servers allow read-only access by default.
But for any kind of modification, we need to bind.
So far, this seems pretty much like with databases. However, here's the big catch: the normal way to use databases is to have one userid and password per application, and perhaps store actual userids and passwords within a table in the database. The normal way to use LDAP is to bind _as the user who is doing the operation_.
Here is a list of requirements I can think, that need to be fulfilled in order for me to be able to use passport. Some of these may be very trivial, or taken for granted by now -- I'm just making sure they are seen.
Requirement #1: Passport needs to be async.
In order to be able to use LDAP as the backend for passport-like user verification, the backend needs to be able to talk to a possibly slow server.
There are other, perhaps obvious, reasons why this needs to be so. Identities are already async and I'm working on making Perspectives async right now. I'll check in something by tomorrow at the latest.
Requirement #2: Passport must be able to store data in the Perspective during authentication.
However, if the application wants to use LDAP for more than just user authentication, things get a bit worse. We could just store the password we saw the user enter, and later bind to the LDAP server as this user. However, I dislike storing plain-text passwords in virtual memory.
I'm not sure what you're talking about here -- it sounds like you're using "authentication" to mean two different things. First, what is *the* Perspective? An Identity (presumably Identities are stored in LDAP) has multiple Perspectives.
Requirement #3: Passport must be able to ask users to reauthenticate.
A better way is to remember that we already did bind (authenticate) to the LDAP server as that user. Just reserve that connection for that user alone. As long as the connection is alive, we can keep on talking to the LDAP server.
Now, programs can be restarted, TCP connections can die, and servers can utilize idle timeouts, maximum time limits, or limit maximum number of operations per connection. The TCP connection can die any moment. As we didn't store the user password, we need to ask it again when we see the connection has closed and the user tries an operation that requires talking to the LDAP server. This requires "invalidating" the users previous authentication.
OK. So it sounds like you want any interaction with a perspective or identity to be able to potentially raise an exception that says "you need to offer credentials for this Identity again". Frameworks (e.g. web.guard, pb.AuthRoot) will need to handle this sensibly. It's a reasonable requirement, but it may be domain-specific to your LDAP interaction stuff. I know that I have at least one system where authentication is persistent within a server once it's been accomplished (interaction with the authentication database stops after the user's been verified). -- ______ you are in a maze of twisted little applications, all | |_\ remarkably consistent. | | -- glyph lefkowitz, glyph @ twisted matrix . com |_____| http://www.twistedmatrix.com/
Glyph Lefkowitz <glyph@twistedmatrix.com> writes:
Requirement #2: Passport must be able to store data in the Perspective during authentication.
However, if the application wants to use LDAP for more than just user authentication, things get a bit worse. We could just store the password we saw the user enter, and later bind to the LDAP server as this user. However, I dislike storing plain-text passwords in virtual memory.
I'm not sure what you're talking about here -- it sounds like you're using "authentication" to mean two different things. First, what is *the* Perspective? An Identity (presumably Identities are stored in LDAP) has multiple Perspectives.
I'm probably all confused by Perspectives and Identities. s/Perspective/Identity/. And naturally the fd shouldn't be persistent -- just to make sure. Yes, I want LDAP to be more than authentication. Consider an application that has users stored in the LDAP tree, in one subtree. It also has some user-editable data stored in (same or different) subtree. LDAP server ACLs allow some of the users access to some of the fields, etc. If you want to make a web frontend, you need to use LDAP as an authentication backend, and you need to use that authentication (to the LDAP server) in order to perform actions on the LDAP server. Think of it this way: an authentication server gives you a key, and when you later perform actions toward external services as the authenticated user, you need to provide the key. In this case, the key is a TCP connection. I believe Kerberos follows this model, with a "real" key.
Requirement #3: Passport must be able to ask users to reauthenticate.
A better way is to remember that we already did bind (authenticate) to the LDAP server as that user. Just reserve that connection for that user alone. As long as the connection is alive, we can keep on talking to the LDAP server.
Now, programs can be restarted, TCP connections can die, and servers can utilize idle timeouts, maximum time limits, or limit maximum number of operations per connection. The TCP connection can die any moment. As we didn't store the user password, we need to ask it again when we see the connection has closed and the user tries an operation that requires talking to the LDAP server. This requires "invalidating" the users previous authentication.
OK. So it sounds like you want any interaction with a perspective or identity to be able to potentially raise an exception that says "you need to offer credentials for this Identity again". Frameworks (e.g. web.guard, pb.AuthRoot) will need to handle this sensibly.
Well, it is possible to handle with voiding the authentication data. For example, with web.guard, this could mean that 1. web.guard sees authentication is still valid, lets a request continue 2. actual request causes actions that discover the LDAP connection has closed, give back error 3. user sees error, clicks "submit" again, or refreshes. 4. web.guard sees an unauthenticated user, asks for authentication 5. user authenticates 6. web.guard lets the resource pass by (A separate ugliness is that web.guard complains if it has to authenticate anything with forms, and destroys submitted data)
It's a reasonable requirement, but it may be domain-specific to your LDAP interaction stuff. I know that I have at least one system where authentication is persistent within a server once it's been accomplished (interaction with the authentication database stops after the user's been verified).
Yes, and one time would be enough even for an LDAP server that is used as authentication only. The point where it isn't enough is achieved by creating a proxy in Twisted, where the proxy isn't the final service that authenticates users, but just acts as a smart protocol converter. Then the proxy is at the mercy of the final service. And that's what I've been doing. LDAP <-> web. -- tv@{{hq.yok.utu,havoc,gaeshido}.fi,{debian,wanderer}.org,stonesoft.com} double a,b=4,c;main(){for(;++a<2e6;c-=(b=-b)/a++);printf("%f\n",c);}
participants (2)
-
Glyph Lefkowitz
-
Tommi Virtanen