[Zope-PAS] Challengers (and Zope 3)

Lennart Regebro regebro at nuxeo.com
Fri Oct 1 08:13:40 EDT 2004

Jim Fulton wrote:
 > The purpose is to support protocols, like HTTP, that allow
 > multiple challenges, while not mixing challenges across protocols.

Well, that is possible anyway, but I guess you want to allow different 
plugins to interact and provide the different challenges, which is what 
we discussed a week ago, and which everybody thought was to complicated 
and privided lot's of headaches and back-aches. ;)

Jim Fulton wrote:
> Lennart Regebro wrote:
>> Jim Fulton wrote:
>>> Lennart Regebro wrote:
>>>> Having several WWW-Authenticate headers usually seem to work, just 
>>>> try putting in several WWW-Authenticate: Basic headers. Yup, you'll 
>>>> get several login dialogs. ;)
>>> Do you mean that the browser actually presents multiple dialogs
>>> for the same request?
>> Yup.
> That's very weird.

Well, maybe. Or Firefox simply goes through the WWW-Authenticate in 
order and tries them out, and doesn't care that they are duplicates. 
Which makes perfect sense. Also, if it gets a challenge it doesn't 
understand: like NTLM, significantly enough, it will throw up a dialog box.

>>> Actually, I'm looking for a definition of protocols that says they
>>> can't be mixed.  Essentially, I want to use protocols as a way of
>>> modeling what sorts of challenges can abd cannot be mixed.
>>> Challenges can be mixed if they come from the same protocol.
>>> They cannot be mixed otherwise.
>> I can't think of any definiton that succeds with that.
> I can't figure out what you just said.

Well, good, because I now think I was wrong. I have made some testing 
(with Firefox) and scratched my head a bit, and this is what I came up with:

Check these challenge methods out:

0. WWW-Authenticate: Negotiate
1. WWW-Authenticate: Basic
2. WWW-Authenticate: NTLM
3. Redirecting to a login-page
4. Having an inline login-page

It's hard to see any actual protocol definition that says "different 
protocols can not be mixed", since 0-2 can be mixed with 4, but they are 
not exactly the same protocol... unless you look at the response status.

Reasonably, the response status on all cases except 3 will be 404, and 
in 3 it will be 302. So then we have two protocols: 401 and 302... ;)
So I was wrong. As protocol definition where this is true is possible:

"Challenges can be mixed if they come from the same protocol.
They cannot be mixed otherwise."


Your implementation will in that case mean that the LAST plugin to set 
the body will override earlier plugins bodies. Which is greatly 
confusing, since in all other cases it is the FIRST plugins that decide. 
Also, it requires all plugins to play nicely with all other plugins, and 
I'm not sure I like that.

One possible implementation that solves those issues is this:

for plugin in plugins:
     status, headers, body = plugin.challenge(request)
     if not status or status == 200: # This plugin did not challenge
     if response.status == 200: # This plugin is the first to challenge.
     elif status != response.status: # A status is already set.
         # ignoring all plugins that do not go with this status:
     if body and response.body: # Somebody already set the body.
         # Ignoring this plugin
     if body:
     # This plugin agrees with the status and does not override the body:
     for key, value in headers.items():
          response.addHeader(key, value)

Note that none of the plugins fiddle with response any more.

And as you see, this DOES get kinda complicated. And figuring out why 
the heck your plugin isn't challenging is a, well, challenge. ;)

So, I'm gonna suggest this implementation:

for plugin in plugins:
     if plugin.challenge(request, response):
         # This plugin challenged:

Simpler eh? ;-)

So, how to get several WWW-Authenticate header with this implementation? 
Well, two ways:

Either plugins that ONLY set WWW-Authenticate headers return 0, and are 
placed first in line. They can set 401 too, that's fine. A plugin that 
redirects will make the client ignore those headers. So it's not a problem.

OR, even simpler:

We extend the HTTPBasicAuth to add more headers.
All WWW-Authenticate challenges except Digest and Basic seem only to be 
a simple string. That way one plugin does all the WWW-Authenticate 
setting, and no intra-plugin fiddling is needed.



More information about the Zope-PAS mailing list