[Zope-PAS] Cookie Auth Monopolizes Challenge?

Chris McDonough chrism at plope.com
Thu Aug 11 15:18:43 EDT 2005


Hi Sidnei,

I had to deal with this at some point and I wrote a PAS multiplugin that
implemented the "unauthorized" method (forget which interface that
belongs to)... here it is along with a helper method to figure out if a
request came from a DAV client:


    security.declarePublic('unauthorized')
    def unauthorized(self):
        """ Override cookieauthplugin unauthorized to deal properly
        with DAV requests """
        req = self.REQUEST
        resp = req['RESPONSE']

        # If we set the auth cookie before, delete it now.
        if resp.cookies.has_key(self.cookie_name):
            del resp.cookies[self.cookie_name]

        if self.isDAVRequest(req):
            # DAV clients/EE can't deal with form-based auth, so
            # we give them a basic auth 401 response code
            realm = resp.realm
            if realm:
                resp.addHeader('WWW-Authenticate',
                               'basic realm="%s"' % realm)
            m = "You are not authorized to access this resource."
            if resp.debug_mode:
                if resp._auth:
                    m = m + '<p>\nUsername and password are not
correct.'
                else:
                    m = m + '<p>\nNo Authorization header found.'

            resp.setBody(m, is_error=1)
            resp.setStatus(401)
            return 1

        # Redirect if desired.
        url = self.getLoginURL()
        if url is not None:
            came_from = req.get('came_from', None)
            
            if came_from is None:
                came_from = req.get('URL', '')
                query = req.get('QUERY_STRING')
                if query:
                    if not query.startswith('?'):
                        query = '?' + query
                    came_from = came_from + query
            else:
                # If came_from contains a value it means the user
                # must be coming through here a second time
                # Reasons could be typos when providing credentials
                # or a redirect loop (see below)
                req_url = req.get('URL', '')

                if req_url and req_url == url:
                    # Oops... The login_form cannot be reached by the
user -
                    # it might be protected itself due to
misconfiguration -
                    # the only sane thing to do is to give up because we
are
                    # in an endless redirect loop.
                    return 0
                
            url = url + '?came_from=%s' % quote(came_from)
            resp.redirect(url, lock=1)
            return 1

        # Could not challenge.
        return 0

    security.declarePublic('isDAVRequest')
    def isDAVRequest(self, request):
        method = request.get('REQUEST_METHOD', 'GET')
        if method in DAV_METHODS:
            return True

        if request.maybe_webdav_client and not method in ('GET',
'POST'):
            return True

        useragent = request.get_header('User-Agent') or ''
        for agent in DAV_USERAGENTS:
            if useragent.find(agent) != -1:
                return True

        return False



On Thu, 2005-08-11 at 15:46 -0300, Sidnei da Silva wrote:
> So, leaving other issues aside *wink*, I'm no puzzled by the challenge
> code in PAS. It looks like there was some attempt at distinguishing
> challenging by some sort of 'protocol', but it leaves a lot to be
> desired, or I don't understand how it's supposed to work.
> 
> The problem I'm facing now is that using the Cookie Auth plugin
> effectively breaks WebDAV (and possibly FTP and XML-RPC), because as
> soon as the Cookie Auth plugin is hit on challenge, it does a redirect
> to the login form.
> 
> Changing the Cookie Auth to come after Basic Auth doesn't help either,
> as then instead of a browser client being directed to the login form
> it gets a basic auth dialog instead.
> 
> Is it possible that nobody noticed this yet? Or is it just me not
> getting enough sleep last night?
> 



More information about the Zope-PAS mailing list