[Zope-PAS] Challengers (and Zope 3)

Lennart Regebro regebro at nuxeo.com
Fri Oct 1 10:07:45 EDT 2004

Jim Fulton wrote:
> Lennart Regebro wrote:
>> 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. ;)
> First, as I said before, I think Mark has a valid use cases that is
> supported by the HTTP authentication spec.
> Second, AFAICT, the conversation involved mainly two people, hald of whom
> thought that support of multiple HTTP challenges was important.

I like discussing politics and do so a lot. So don't try to use 
rhetorics, it doesn't work on me. ;-)

The question was never about having multiple HTTP challenges. That is, 
and has always been, a trivial excercise. The problem is how to in a 
useful and simple manner let separate challenge plugins interact, and 
let separate plugins each provide parts of those multiple challenges.

The conversation involved three people. At least two of them (Mark and 
me) agreeed that wee needed multiple HTTP challenges. Mark and Tino 
convinced me that doing that by letting separate plugins interact was 
too complicated.

I am, as always, willing to be unconvinced. :-)

>> 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.
> No, it doesn't.  The spec says that the client should use the strongest
> type of challenge that it understands.  As I said, I'd like to try this
> myself (or get sprinters to try it) and see how browsers behave in the
> presense of two different kinds of challenges.

OK. Well, I probably can't be bothered to test IE, but Firefox will 
throw up several boxes. And although it breaks the spec, I don't think 
it will actually be a problem.

>> Also, if it gets a challenge it doesn't
>> understand: like NTLM, significantly enough, it will throw up a dialog 
>> box.
> That is not correct behavior.

And it wasn't a correct statement either. My bad. It will however test 
them in the order they find them.

>> 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. 
> Not for Zope 3. In Zope 3, it will generally not be the job of the 
> plugins to set the body.

Oh. OK, so, does that mean that inline-login forms are out of the question?

>> 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
>>         continue
>>     if response.status == 200: # This plugin is the first to challenge.
>>        response.setStatus(status)
>>     elif status != response.status: # A status is already set.
>>         # ignoring all plugins that do not go with this status:
>>         continue
>>     if body and response.body: # Somebody already set the body.
>>         # Ignoring this plugin
>>         continue
>>     if body:
>>         response.setBody(body)
>>     # This plugin agrees with the status and does not override the body:
>>     for key, value in headers.items():
>>          response.addHeader(key, value)
> I think this is way too complicated.

I agree.

>> So, I'm gonna suggest this implementation:
>> for plugin in plugins:
>>     if plugin.challenge(request, response):
>>         # This plugin challenged:
>>         break
>> Simpler eh? ;-)
> This is where we started.

Yup. :)

>> 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.
> That means that plugins that use HTTP authentication always lose if there
> are any non-http challenges.  That's silly.

Not at all. It is the challenger that returns "1" that "wins". 
Basically, the challenger that sets the status or the body.

Now, with Zope3, you say that the challenger should not set the body. 
That makes things easier, and a challenger that sets the status could 
break the loop.

for plugin in plugins:
     plugin.challenge(request, response)
     if response.status != 200:

Hmmm. In Zope2 we could do

for plugin in plugins:
     plugin.challenge(request, response)
     if response.status != 200 or response.body:

That means, you can add WWW-Authenticate headers to your hearts desire, 
but when you change the status or the body, things stop.

Hmm. Not bad. That could work!

>> 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.
> I have no idea what you are saying here.

Let ONE plugin at a time do the challenge. If we are doing a 
WWW-Authenticate challenge, make *one* plugin that does that. Adding 
WWW-Authenticate several header in one plugin is trivial.

Because what made things complicated was the interaction. That is what 
caused the headaches.

More information about the Zope-PAS mailing list