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?

_______________________________________________
Twisted-web mailing list
[email protected]
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web

Reply via email to