[Zope-CVS] CVS: Products/CookieCrumbler - CookieCrumbler.py:1.2 logged_in.dtml:1.2 login_form.dtml:1.2

Shane Hathaway shane@digicool.com
Thu, 1 Nov 2001 18:02:30 -0500


Update of /cvs-repository/Products/CookieCrumbler
In directory cvs.zope.org:/tmp/cvs-serv27928

Modified Files:
	CookieCrumbler.py logged_in.dtml login_form.dtml 
Log Message:
- The unauthorized() call now cancels the setting of the authentication cookie
  "just in time".  This should be good enough for now.

- Nested CookieCrumblers should work now: you can place a cookie crumbler
  in any folder to display a different login form.


=== Products/CookieCrumbler/CookieCrumbler.py 1.1.1.1 => 1.2 ===
 
 # Constants.
-ATTEMPT_DISABLED = -1
-ATTEMPT_NONE = 0
-ATTEMPT_LOGIN = 1
-ATTEMPT_CONT = 2
+ATTEMPT_DISABLED = -1  # Disable cookie crumbler
+ATTEMPT_NONE = 0       # No attempt at authentication
+ATTEMPT_LOGIN = 1      # Attempt to log in
+ATTEMPT_RESUME = 2     # Attempt to resume session
 
 ModifyCookieCrumblers = 'Modify Cookie Crumblers'
 
@@ -178,14 +178,17 @@
         if not req[ 'REQUEST_METHOD' ] in ( 'GET', 'PUT', 'POST' ):
             return ATTEMPT_DISABLED
 
-        if not req._auth:
-            if (req.has_key(self.pw_cookie) and
-                req.has_key(self.name_cookie)):
+        if req._auth and not getattr(req, '_cookie_auth', 0):
+            # Using basic auth.
+            return ATTEMPT_DISABLED
+        else:
+            if req.has_key(self.pw_cookie) and req.has_key(self.name_cookie):
                 # Attempt to log in and set cookies.
                 name = req[self.name_cookie]
                 pw = req[self.pw_cookie]
                 ac = encodestring('%s:%s' % (name, pw))
                 req._auth = 'basic %s' % ac
+                req._cookie_auth = 1
                 resp._auth = 1
                 if req.get(self.persist_cookie, 0):
                     # Persist the user name (but not the pw or session)
@@ -205,10 +208,11 @@
                 # Copy __ac to the auth header.
                 ac = unquote(req[self.auth_cookie])
                 req._auth = 'basic %s' % ac
+                req._cookie_auth = 1
                 resp._auth = 1
                 self.delRequestVar(req, self.auth_cookie)
-                return ATTEMPT_CONT
-        return ATTEMPT_NONE
+                return ATTEMPT_RESUME
+            return ATTEMPT_NONE
 
     def __call__(self, container, req):
         '''The __before_publishing_traverse__ hook.'''
@@ -216,17 +220,13 @@
         attempt = self.modifyRequest(req, resp)
         if attempt == ATTEMPT_DISABLED:
             return
-        if self.auto_login_page:
-            if not req.get('disable_cookie_login__', 0):
-                if (attempt == ATTEMPT_LOGIN or
-                    not getattr(resp, '_auth', 0)):
-                    page = getattr(container, self.auto_login_page, None)
-                    if page is not None:
-                        # Provide a login page.
-                        req._hold(ResponseCleanup(resp))
-                        resp.unauthorized = self.unauthorized
-                        resp._unauthorized = self._unauthorized
-        if attempt:
+        if not req.get('disable_cookie_login__', 0):
+            if attempt == ATTEMPT_LOGIN or attempt == ATTEMPT_NONE:
+                # Modify the "unauthorized" response.
+                req._hold(ResponseCleanup(resp))
+                resp.unauthorized = self.unauthorized
+                resp._unauthorized = self._unauthorized
+        if attempt != ATTEMPT_NONE:
             phys_path = self.getPhysicalPath()
             if self.logout_page:
                 # Cookies are in use.
@@ -255,22 +255,29 @@
 
     security.declarePrivate('unauthorized')
     def unauthorized(self):
+        resp = self._cleanupResponse()
+        # If we set the auth cookie before, delete it now.
+        if resp.cookies.has_key(self.auth_cookie):
+            del resp.cookies[self.auth_cookie]
+        # Redirect if desired.
         url = self.getLoginURL()
-        if url:
+        if url is not None:
             raise 'Redirect', url
-        # Use the standard unauthorized() call.
-        resp = self._cleanupResponse()
+        # Fall through to the standard unauthorized() call.
         resp.unauthorized()
 
     def _unauthorized(self):
+        resp = self._cleanupResponse()
+        # If we set the auth cookie before, delete it now.
+        if resp.cookies.has_key(self.auth_cookie):
+            del resp.cookies[self.auth_cookie]
+        # Redirect if desired.
         url = self.getLoginURL()
-        if url:
-            resp = self.REQUEST['RESPONSE']
+        if url is not None:
             resp.redirect(url, lock=1)
             # We don't need to raise an exception.
             return
-        # Use the standard _unauthorized() call.
-        resp = self._cleanupResponse()
+        # Fall through to the standard _unauthorized() call.
         resp._unauthorized()
 
     security.declarePublic('getLoginURL')
@@ -284,10 +291,13 @@
             iself = getattr(self, 'aq_inner', self)
             parent = getattr(iself, 'aq_parent', None)
             page = getattr(parent, self.auto_login_page, None)
-            if page:
+            if page is not None:
                 retry = getattr(resp, '_auth', 0) and '1' or ''
+                came_from = req.get('came_from', None)
+                if came_from is None:
+                    came_from = req['URL']
                 url = '%s?came_from=%s&retry=%s' % (
-                    page.absolute_url(), quote(req['URL']), retry)
+                    page.absolute_url(), quote(came_from), retry)
                 return url
         return None
 


=== Products/CookieCrumbler/logged_in.dtml 1.1.1.1 => 1.2 ===
 <dtml-let came_from="REQUEST.get('came_from', '')">
 <dtml-if expr="_.SecurityGetUser().getUserName() == 'Anonymous User'">
+ <!-- Redirect or generate an unauthorized response -->
+ <dtml-call expr="REQUEST['RESPONSE'].unauthorized()">
 
  <h3>Login failure</h3>
  <p>Please <a href="login_form?came_from=&dtml.url_quote-came_from;"


=== Products/CookieCrumbler/login_form.dtml 1.1.1.1 => 1.2 ===
 </h1>
 
-<form action="logged_in" method="POST">
+<dtml-let came_from="REQUEST.get('came_from', '')"
+          action_url="came_from or 'logged_in'">
+
+<form action="&dtml-action_url;" method="POST">
+
+<dtml-if expr="REQUEST.get('retry', 0)">
+<font color="red">Please try again.</font>
+</dtml-if>
 
-<dtml-let came_from="REQUEST.get('came_from', '')">
 <dtml-if came_from>
   <input type="hidden" name="came_from" value="&dtml-came_from;">
 </dtml-if>
-</dtml-let>
 
 <table class="FormLayout">
 <tr>
@@ -48,9 +53,10 @@
 
 </table>
 </form>
+</dtml-let>
 
 <p>
-Having trouble logging in? Make sure to enable cookies in your web browser.
+Having trouble logging in? Be sure to enable cookies in your web browser.
 </p>
 
 <p>Don't forget to logout or exit your browser when you're done.