[Checkins] SVN: zope.session/trunk/ Fix Python 2.4 compatibility issue when using third-party hashlib. Also, use CookieClientIdManager's secret as the hmac key and the client id as the hmac message, instead of the other way around, since it is the client id's authenticity we are verifying.

Patrick Strawderman patrick at zope.com
Mon Nov 23 10:19:22 EST 2009


Log message for revision 105964:
  Fix Python 2.4 compatibility issue when using third-party hashlib.  Also, use CookieClientIdManager's secret as the hmac key and the client id as the hmac message, instead of the other way around, since it is the client id's authenticity we are verifying.

Changed:
  U   zope.session/trunk/CHANGES.txt
  U   zope.session/trunk/src/zope/session/http.py

-=-
Modified: zope.session/trunk/CHANGES.txt
===================================================================
--- zope.session/trunk/CHANGES.txt	2009-11-23 14:55:03 UTC (rev 105963)
+++ zope.session/trunk/CHANGES.txt	2009-11-23 15:19:21 UTC (rev 105964)
@@ -4,13 +4,19 @@
 3.9.2 (unreleased)
 ------------------
 
+- Fix Python 2.4 hmac compatibility issue by only using hashlib in
+  Python versions 2.5 and above.
+
+- Use the CookieClientIdManager's secret as the hmac key instead of the
+  message when constructing and verifying client ids.
+
 - Make it possible to construct CookieClientIdManager passing cookie namespace
   and/or secret as constructor's arguments.
 
 - Use zope.schema.fieldproperty.FieldProperty for "namespace" attribute of
   CookieClientIdManager, just like for other attributes in its interface.
   Also, make ICookieClientIdManager's "namespace" field an ASCIILine, so
-  it accepts only non-unicode strings for cookie names. 
+  it accepts only non-unicode strings for cookie names.
 
 3.9.1 (2009-04-20)
 ------------------
@@ -24,7 +30,7 @@
 
 - Drop dependency on ``zope.annotation``. Instead, we make classes implement
   `IAttributeAnnotatable` in ZCML configuration, only if ``zope.annotation``
-  is available. If your code relies on annotatable `CookieClientIdManager` 
+  is available. If your code relies on annotatable `CookieClientIdManager`
   and `PersistentSessionDataContainer` and you don't include the zcml classes
   configuration of this package, you'll need to use `classImplements` function
   from ``zope.interface`` to make those classes implement `IAttributeAnnotatable`
@@ -35,7 +41,7 @@
 
 - Zope 3 application bootstrapping code for session utilities was moved into
   zope.app.appsetup package, thus drop dependency on zope.app.appsetup in this
-  package. 
+  package.
 
 - Drop testing dependencies, as we don't need anything behind zope.testing and
   previous dependencies was simply migrated from zope.app.session before.
@@ -93,7 +99,7 @@
 
 - Only set the client-id cookie if it isn't already set and try to
   prevent the header from being cached.  This is to minimize risk from
-  broken caches handing the same client id out to multiple users. 
+  broken caches handing the same client id out to multiple users.
 
 3.5.2 (2008-06-12)
 ------------------

Modified: zope.session/trunk/src/zope/session/http.py
===================================================================
--- zope.session/trunk/src/zope/session/http.py	2009-11-23 14:55:03 UTC (rev 105963)
+++ zope.session/trunk/src/zope/session/http.py	2009-11-23 15:19:21 UTC (rev 105964)
@@ -20,17 +20,15 @@
 import random
 import re
 import string
+import sys
 import time
 from cStringIO import StringIO
-try:
+
+if sys.version_info[:2] >= (2, 5):
     from hashlib import sha1
-except ImportError:
-    # Python 2.4
-    import sha as sha1
-try:
     from email.utils import formatdate
-except ImportError:
-    # Python 2.4
+else:
+    import sha as sha1
     from email.Utils import formatdate
 
 import zope.location
@@ -141,43 +139,43 @@
 
     def __init__(self, namespace=None, secret=None):
         """Create the cookie-based cleint id manager
-        
+
         We can pass namespace (cookie name) and/or secret string
         for generating client unique ids.
-        
+
         If we don't pass either of them, they will be generated
         automatically, this is very handy when storing id manager
         in the persistent database, so they are saved between
         application restarts.
-        
+
           >>> manager1 = CookieClientIdManager()
           >>> len(manager1.namespace) > 0
           True
           >>> len(manager1.secret) > 0
           True
-        
+
         We can specify cookie name by hand.
-        
+
           >>> manager2 = CookieClientIdManager('service_cookie')
           >>> manager2.namespace
           'service_cookie'
-        
+
         If we want to use CookieClientIdManager object as a non-persistent
         utility, we need to specify some constant secret, so it won't be
         recreated on each application restart.
-        
+
           >>> manager3 = CookieClientIdManager(secret='some_secret')
           >>> manager3.secret
           'some_secret'
-        
+
         Of course, we can specify both cookie name and secret.
-        
+
           >>> manager4 = CookieClientIdManager('service_cookie', 'some_secret')
           >>> manager4.namespace
           'service_cookie'
           >>> manager4.secret
           'some_secret'
-        
+
         """
         if namespace is None:
             namespace = "zope3_cs_%x" % (int(time.time()) - 1000000000)
@@ -228,7 +226,7 @@
         An exception to this is if the cookieLifetime is set to a
         non-zero integer value, in which case we do set it on every
         request, regardless of when it was last set:
-        
+
           >>> bim.cookieLifetime = 3600 # one hour
           >>> id == bim.getClientId(request2)
           True
@@ -248,12 +246,12 @@
 
           >>> print request.response.getCookie(bim.namespace)
           None
-        
+
           >>> request = HTTPRequest(StringIO(''), {'REQUEST_METHOD': 'POST'})
           >>> id = bim.getClientId(request)
           >>> id == bim.getClientId(request)
           True
-          
+
           >>> request.response.getCookie(bim.namespace) is not None
           True
 
@@ -311,7 +309,7 @@
         s = digestEncode(digest)
         # we store a HMAC of the random value together with it, which makes
         # our session ids unforgeable.
-        mac = hmac.new(s, self.secret, digestmod=sha1).digest()
+        mac = hmac.new(self.secret, s, digestmod=sha1).digest()
         return s + digestEncode(mac)
 
     def getRequestId(self, request):
@@ -361,7 +359,7 @@
           >>> bim.setRequestId(request, id_uni)
           >>> bim.getRequestId(request) == id_uni
           True
-        
+
         If another server is managing the ClientId cookies (Apache, Nginx)
         we're returning their value without checking:
 
@@ -371,7 +369,7 @@
           >>> request3._cookies = {'uid': 'AQAAf0Y4gjgAAAQ3AwMEAg=='}
           >>> bim.getRequestId(request3)
           'AQAAf0Y4gjgAAAQ3AwMEAg=='
-        
+
         """
         response_cookie = request.response.getCookie(self.namespace)
         if response_cookie:
@@ -382,7 +380,7 @@
         if self.thirdparty:
             return sid
         else:
-            
+
             # If there is an id set on the response, use that but
             # don't trust it.  We need to check the response in case
             # there has already been a new session created during the
@@ -391,11 +389,11 @@
             if sid is None or len(sid) != 54:
                 return None
             s, mac = sid[:27], sid[27:]
-            
+
             # call encode() on value s a workaround a bug where the hmac
             # module only accepts str() types in Python 2.6
             if (digestEncode(hmac.new(
-                    s.encode(), self.secret, digestmod=sha1
+                    self.secret, s.encode(), digestmod=sha1
                 ).digest()) != mac):
                 return None
             else:
@@ -460,7 +458,7 @@
 
         If the secure attribute is set to a true value, then the
         secure cookie option is included.
-        
+
           >>> bim.thirdparty = False
           >>> bim.cookieLifetime = None
           >>> request = HTTPRequest(StringIO(''), {}, None)



More information about the checkins mailing list