[Zope-PAS] Struggling with 'challenge' support.
Lennart Regebro
regebro at nuxeo.com
Thu Sep 23 12:55:47 EDT 2004
Lennart Regebro wrote:
> Hmmm.... I just realized, it might be possible to wrap exception instead
> of changing it, that woudl be neater. And then to the challenge
> *afterwards* and make the plugins write to response *last*. That could
> actaully work, if nothing else works. Hmm....
OK, that works. Problem: The headers are already scribbled on, so you
may have to UN-scribble them. Solution: Only call response.exception
when it is NOT an Unauthorized exception that is being thrown. That MAY
have side effects of which I am not aware.
The code gets pretty simple, which feels good:
PluggableAuthService now looks like this:
def __call__(self, container, req):
""" The __before_publishing_traverse__ hook. """
resp = req['RESPONSE']
resp.exception = self.exception
return
#
# Response overrides
#
def exception(self, fatal=0, info=None,
absuri_match=re.compile(r'\w+://[\w\.]+').match,
tag_search=re.compile('[a-zA-Z]>').search,
abort=1
):
req = self.REQUEST
resp = req['RESPONSE']
try: del resp.exception
except: pass
if type(info) is type(()) and len(info) == 3:
t, v, tb = info
else:
t, v, tb = sys.exc_info()
if t == 'Unauthorized' or t == Unauthorized or (
isinstance(t, types.ClassType) and issubclass(t,
Unauthorized)):
t = 'Unauthorized'
self.challenge(req, resp)
return resp
return resp.exception(fatal, info, absuri_match, tag_search, abort)
def challenge(self, request, response):
# Go through all challenge plugins
plugins = self._getOb('plugins')
challengers = plugins.listPlugins( IChallengePlugin )
for challenger_id, challenger in challengers:
if challenger.challenge(request, response):
break
Note that we can't call all challengers at once, that will just mess up
the headers beyond recognition, instead, a challenger returns 1 if it
wants to do the challenge.
HTTPBasicAuthHelper:
def challenge( self, request, response, **kw ):
""" Challenge the user for credentials.
"""
realm = response.realm
if realm:
response.setHeader('WWW-Authenticate', 'basic realm="%s"' %
realm, 1)
m = "<strong>You are not authorized to access this
resource.</strong>"
if response.debug_mode:
if response._auth:
m = m + '<p>\nUsername and password are not correct.'
else:
m = m + '<p>\nNo Authorization header found.'
response.setBody(m, is_error=1)
response.setStatus(401)
return 1
CasAuthHelper (does aredirect):
security.declarePrivate('challenge')
def challenge(self, request, response, **kw):
""" Challenge the user for credentials. """
# Redirect if desired.
url = self.getLoginURL()
if url:
came_from = request.get('came_from', None)
if came_from is None:
came_from = request['URL']
query = urllib.urlencode({'service': came_from})
#del response.headers['WWW-Authenticate']
response.redirect('%s?%s' % (url, query))
return 1
# Fall through to the standard unauthorized() call.
return 0
This seems to work fine for me. Screamif it is stupid, or I'll check
this in tomorrow. It's a bug today too, we can discuss it then.
//Lennart
More information about the Zope-PAS
mailing list