[Twisted-web] Sessions and Authentication for Web2
Phil Mayers
p.mayers at imperial.ac.uk
Sat Nov 19 16:00:31 MST 2005
David Reid wrote:
>
> But in Basic and Digest auth you don't have the username until you get
> the response to your challenge. So this is where IAuthorizer comes in
> it handles all the steps prior to having something that you can use to
> build a credentials.
I'm no cred expert, and I dislike it conceptually, but as far as I can
tell it's got all the facilities it needs. HTTP is slightly more complex
so I'll start with a SASL-ised imap-like example, to see if I've got the
right idea:
class simpleproto(basic.LineReceiver):
def lineReceived(self, line):
if self.creds:
# forward to CR module that's in progress
self.creds.lineReceived(line)
else:
cmd, rest = line.split(' ', 1)
fn = getattr(self, 'do_'+cmd, None)
if not fn:
self.transport.write('NO unknown command %s\n' % (cmd,))
self.transport.loseConnection()
def do_AUTHENTICATE(self, mechanism):
if mechanism=='GSSAPI':
self.creds = ChallengeResponse(self)
return self.portal.login(self.creds).addCallbacks(self.authok,
self.authfail)
def authok(self, avatar):
self.avatar = avatar
self.lineReceived = avatar.lineReceived
def authfail(self, why):
self.transport.write(why.getErrorMessage()+'\n')
self.transport.loseConnection()
class ChallengeResponse:
def __init__(self, conn):
self.conn = conn
self.started = False
self.context = hypotheticalGssapiModule.init()
def lineReceived(self, line):
done, response = self.context.input(line.decode('base64'))
self.conn.transport.write(response.encode('base64')+'\n')
if done:
if self.context.success():
self.finish.callback(self.context.getPrincipal())
else:
self.finish.errback(self.context.errMsg())
class GssapiChecker:
implements(checkers.ICredentialsChecker)
def requestAvatarId(self, creds):
creds.finish = defer.Deferred()
return creds.finish
The neat thing about cred is that the code above (if it worked at all,
which it would with only slight fiddling) doesn't require the portal or
realm to change. Similarly, only a bit of fiddling permits multi-method
auth e.g. for IMAP brokenness:
def do_LOGIN(self, data):
user, pass = data.split(' ', 1)
creds = credentials.UsernamePassword(user, pass)
return self.portal.login(creds).addCallbacks(...)
...and add an appropriate checker to the portal.
HTTP is a bit of a pain because of the "connectionless" basis. The RFCs
for the hacky mechanisms like "Negotiate" (the MS-ism for kerberos over
HTTP) and such show that. Digest would want some kind of stateless
version - you're effectively authenticating requests as opposed to the
connection, but the basic principle is the same. I'm sure you know all this.
So am I missing something? It looks like cred needs no extending?
More information about the Twisted-web
mailing list