I've been working on the fabled twisted.web2.client, and now that the low level API has made it to trunk I'm ready to start thinking about the authentication api. So I've started out by googling "http client authentication apis". This led me to the Jakarta HttpClient, which seems reasonably sane until you get to the part about Alternate Authentication which just has too many hoops to go through.
So after a few days of thinking about this I've hit on an API I like. You should be warned that some of the parts in the belowe example are nebulus and don't work yet (and may not work ever.)
from twisted.web2.client import HTTPClient
from twisted.web2.auth.credpool import ANY_SCOPE, AuthenticationScope
client = HTTPClient('mysite', 80)
There that creates a client, that is connected/will connect to mysite on port 80 (and expect it to be talking http.) I'd like for the CredentialPool (the map of credentials to use and when and where to use them (notice I didn't say "how" to use them) to be created automagically, since it's basically a fancy dictionary.
client.credentials.addCredentials(ANY_SCOPE, ('foo', 'bar'))
Hooray our first set of credentials, the ANY_SCOPE is kind of special, it's really the default credentials. Which could be dangerous, and you probably should never use them, it's just an example.
client.credentials.addCredentials(AuthenticationScope(realm="my realm"), ('baz', 'bax'))
There now we have some more useful credentials. These credentials will only get used on "my realm" within "my site"
client.credentials.addCredentials(AuthenticationScope(realm="my other realm",
schemes=('digest','ntlm')),
('important username', 'important password'))
client.credentials.addCredentials(AuthenticationScope(realm="my other realm",
schemes=('basic',)),
('loseruser', 'loserpass'))
As these two lines demonstrate you can have multiple authentication schemes, and make sure really important credentials only ever go out via more secure schemes.
AuthenticationScope is also capable of knowing about the host and port that the credentials should be sent on, so in a more complicated HTTPClient (perhaps WebBrowser) that is expected to access more than one site, and create new connections, and do piplining magically, the credential pool can be shared (read from a file, read from a database whatever) and still be able to support the case of "if all else fails, send these credentials."
Now, tear it apart you dogs!
Update: A crappy implementation and some unittests (not all of which pass) are available at
svn://svn.twistedmatrix.com/svn/Twisted/sandbox/dreid/client_auth.py and svn://svn.twistedmatrix.com/svn/Twisted/sandbox/dreid/test_client_auth.py |