
glyph@divmod.com wrote:
On Mon, 28 Nov 2005 18:18:28 -0800, Kevin Turner <kevin@janrain.com> wrote:
On Sun, 2005-11-27 at 21:31 +0000, Phil Mayers wrote:
it seems the "credentials" *are* the HTTP request object (which in fact is true, given how the HTTP spec is worded I think?).
This is what I tried up doing; including the request in the Credentials. This works a bit, but it really isn't compatible with t.web.guard. Mostly because my Checker ends up doing things to the request, but Guard really had plans to do *other* things with that request once Portal.login returned, so it ends up in a bit of a wreck. Maybe it would work better if I used a livepage channel instead of a dumb request.
It would be better if some specific interface were published via wrapping the request, so that the authentication code could be clearly recognizable. I don't think it makes sense to think of the request
But the data you need to wrap is different for each mechanism, so all that does is move the knowledge of 1 protocol (HTTP) out of the checker (which I agree is hacky), and put the knowledge of N mechanisms into the protocol. It's possible this is unavoidable with HTTP :o(
itself as the authentication interface or the credentials, especially as any interesting HTTP-based authentication scheme (even simple challenge/response digest auth) spans multiple requests.
You're probably right. But there are non-obvious (to me at least) difficulties, in particular with keeping the HTTP protocol clear of knowledge about the specifics of the auth mechanisms, permitting >1 WWW-Authenticate challenge header, and keeping the HTTP server free of state to route challenge responses back to the appropriate deferreds (memory exhaustion attack waiting to happen). And also permitting the obligatory HTML-form-based fallback. I'm having difficulty seeing what it would look like, especially the bit of allowing a single portal and list of checkers to support the multi-mechanism bit. You need something pam-like or similar to traverse the checker list with "empty" creds, allow all checkers to challenge for their mechanism, then pass the challenge-response back to just the single mechanism that's chosen. At the moment, the best I can come up with is: class Request(http.Request): def process(self): variousCreds = [] if self.isSecure(): # Can't "challenge" at this stage, he doesn't need to know # about us variousCreds.append(SSLClientCert(self.sslFoo)) authz = self.getHeader('Authorization') if authz: mech, rest = authz.split(' ', 1) mech = mech.lower() mechCreds = httpMechWrapperFactory(mech, rest, self) variousCreds.append(mechCreds) # other stuff goes here e.g. URL arguments, pubcookie cookies, etc. self.portal.login(variousCreds) class MultiPortal(Portal): def login(self, credlist): for c in self.checkers: # All or a subset... if c.canHandle(credlist): return c.login(credlist) for c in self.checkers: c.maybeChallenge(credlist) ...which starts to look very different from cred as-is Perhaps this comes from a misunderstanding in the goals? Am I right to assume we want to support both the HTTP-standard mechs and also HTML-form-based ones? Am I right in assuming >1 mechanism challenge is a wanted? The counter question is, if not, can I assume whatever replaces guard will be swappable-out without breaking sessions and/or livepage?