[Zope-PAS] Struggling with 'challenge' support.

Mark Hammond mhammond at skippinet.com.au
Fri Sep 24 01:07:34 EDT 2004

Upon reflection, I don't believe a simple 'challenge' concept will give us
what we need.

Most sites don't want to use HTTP auth - they prefer web-based
authentication.  As far as I can tell, this is how Plone works out of the
box (via the CookieCrumbler).  As far as I can tell, this is also how your
CAS plugin wants to work.

However, let's assume a site actually *wanted* to prefer HTTP
authentication, and if that failed, fall back to a web-based login screen.
(This makes sense if the scheme is NTLM/Kerebros, which can authenticate
without any UI)

The question is how we handle this second scenario, and the cause of my
confusion about your 'challenge' implementation and mine.

Consider a new category of plugin - along with 'challenge', we have a new
'redirector'.  'challenge' is used to initiate true challenge/response
schemes.  'redirector' is used to explicitly acquire credentials handles via
redirects.  It is used *only* when no challengers have issued a challenge -
if challenges have been issued, we want to give the client a chance to
choose one and offer the appropriate response.

The process is roughly this:
  num_challenges = 0
  for plugin in challengers:
    if plugin.challenge():
      num_challenges += 1
  if num_challengers == 0: # no one issued a challenge.
    for plugin in redirectors:
      if plugin.redirect():
        # A redirector redirected!

The CAS plugin would look roughly like:

  def challenge(self, resp):
    # For 'challenge', we set the response body to point
    # to the login page.
    # This will only ever been seen by the user if another challenger
    # issued a challenge (eg, http auth), but the response was invalid
    # (eg, no username, user cancelled login dialog).  In that case,
    # the user sees the original 404, and our link in the body.
    # If no other challengers configured, we will end up redirecting
    # so this will not be seen.
    url = self.getLoginURL()
    response.setBody('You may logon manually <a href="%s">here</a>' % url)
    return 0 # we did not issue a challenge (just screwed with resp!)

  def redirect(self, resp):
    # do the actual redirection - this means there were no challengers.

The HTTPAuthHelper and the NTLM plugins *only* challenge.  They do not
implement redirect().

This allows you to configure PAS exactly as you want, and you still get a
good result.  So long as you did *not* enable HTTPAuth, CAS/Cookie sites
still operate correctly (there are no 'challengers' configured, so we always
redirect).  If you do enable HTTP auth, you will first be prompted for a
password by the browser.  If that fails, the 404 page will include a link to
the CAS logon page.  This way, HTTP auth can 'override' CAS authentication.

Does that make sense?  Am I barking mad?  At least I understand the problem
a bit more now, even if I don't quite have the solution :)


More information about the Zope-PAS mailing list