Changeset 4205

Show
Ignore:
Timestamp:
03/07/08 11:08:59 (6 months ago)
Author:
chrisz
Message:

Improved fix for #1729, introduced visit.cookie.permanent setting.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.0/turbogears/identity/tests/test_visit.py

    r4203 r4205  
    2323        config.update({'visit.on': True}) 
    2424        self._visit_timeout = config.get('visit.timeout', 20) 
    25         config.update({'visit.timeout': 60}) 
     25        config.update({'visit.timeout': 50}) 
    2626        self.cookie_name = config.get("visit.cookie.name", 'tg-visit') 
    2727        cherrypy.root = VisitRoot() 
     
    5252    def test_cookie_expires(self): 
    5353        """Test if the visit timeout mechanism works.""" 
    54         # set expiration to one second 
    55         config.update({'visit.timeout': 1.0/60}) 
    56         testutil.create_request("/") 
    57         morsel = cherrypy.response.simple_cookie[self.cookie_name] 
    58         time.sleep(3) # 3 seconds 
    59         testutil.create_request("/", headers=cookie_header(morsel)) 
    60         assert cherrypy.response.simple_cookie[self.cookie_name].value != morsel.value, \ 
     54        timeout = config.get('visit.timeout', 50) 
     55        try: 
     56            # set expiration to one second for this test only 
     57            config.update({'visit.timeout': 1.0/60}) 
     58            testutil.create_request("/") 
     59            morsel = cherrypy.response.simple_cookie[self.cookie_name] 
     60            time.sleep(2) # 2 seconds 
     61            testutil.create_request("/", headers=cookie_header(morsel)) 
     62        finally: 
     63            config.update({'visit.timeout': timeout}) 
     64        assert cherrypy.response.simple_cookie[ 
     65                self.cookie_name].value != morsel.value, \ 
    6166            'cookie values should not match' 
    6267        assert visit.current().is_new, \ 
    6368            'this should be a new visit, as the cookie has expired' 
    6469 
    65     def test_cookie_max_age(self): 
    66         """Test whether the visit cookie has max age set correctly.""" 
    67         # set expiration to 42 minutes 
    68         config.update({'visit.timeout': 42}) 
     70    def test_cookie_not_permanent(self): 
     71        """Check that by default the visit cookie is not permanent.""" 
    6972        testutil.create_request('/') 
    7073        morsel = cherrypy.response.simple_cookie[self.cookie_name] 
    71         # we don't want visit cookies to be permanent 
    72         assert not morsel['expires'] 
    73         # but they should have set max age correctly (in seconds) 
    74         assert morsel['max-age'] == 42*60 
     74        assert not morsel['expires'] and not morsel['max-age'] 
     75 
     76    def test_cookie_permanent(self): 
     77        """Check that the visit cookie can be made permanent.""" 
     78        permanent = config.get('visit.cookie.permanent', False) 
     79        try: 
     80            # set cookie permanent for this test only (needs restart) 
     81            startup.stopTurboGears() 
     82            config.update({'visit.cookie.permanent': True}) 
     83            startup.startTurboGears() 
     84            testutil.create_request('/') 
     85            morsel = cherrypy.response.simple_cookie[self.cookie_name] 
     86        finally: 
     87            config.update({'visit.cookie.permanent': permanent}) 
     88        assert morsel['max-age'] == 3000 
     89        expires = time.mktime(time.strptime(morsel['expires'], 
     90            '%a, %d-%b-%Y %H:%M:%S GMT')) 
     91        should_expire = time.mktime(time.gmtime()) + morsel['max-age'] 
     92        assert abs(should_expire - expires) < 3 
  • branches/1.0/turbogears/visit/api.py

    r4204 r4205  
    44from random import random 
    55from datetime import timedelta, datetime 
     6import time 
    67import pkg_resources 
    78import cherrypy 
     
    174175        log.info("Visit filter initialised") 
    175176        get = config.get 
    176  
    177177        # Get the name to use for the identity cookie. 
    178178        self.cookie_name = get("visit.cookie.name", "tg-visit") 
     
    185185        # By default, I don't specify the cookie domain. 
    186186        self.cookie_domain = get("visit.cookie.domain", None) 
    187         self.cookie_max_age = int(get("visit.timeout", "20")) * 60 
    188187        assert self.cookie_domain != "localhost", "localhost" \ 
    189188            " is not a valid value for visit.cookie.domain. Try None instead." 
     189        # Use max age only if the cookie shall explicitly be permanent 
     190        self.cookie_max_age = get("visit.cookie.permanent", 
     191            False) and int(get("visit.timeout", "20")) * 60 or None 
    190192 
    191193    def before_main(self): 
     
    235237        cookies[self.cookie_name] = '' 
    236238        cookies[self.cookie_name]['path'] = self.cookie_path 
     239        cookies[self.cookie_name]['expires'] = '' 
    237240        cookies[self.cookie_name]['max-age'] = 0 
    238241 
     
    242245        cookies[self.cookie_name] = visit_key 
    243246        cookies[self.cookie_name]['path'] = self.cookie_path 
    244         # Note: We don't use 'expires' here, because the cookie will then 
    245         # be treated as a permanent cookie, not as a session cookie. 
    246         # Though this may be convenient, it is a security risk, 
    247         # it may block the cookie completely depending on the security 
    248         # level the browser is using, and it creates problems if times 
    249         # and timezones on the server and the client are not in sync. 
    250         cookies[self.cookie_name]['max-age']= self.cookie_max_age 
    251247        if self.cookie_secure: 
    252248            cookies[self.cookie_name]['secure'] = True 
    253249        if self.cookie_domain: 
    254250            cookies[self.cookie_name]['domain'] = self.cookie_domain 
     251        max_age = self.cookie_max_age 
     252        if max_age: 
     253            # use 'expires' because MSIE ignores 'max-age' 
     254            cookies[self.cookie_name]['expires'] = time.strftime( 
     255                "%a, %d-%b-%Y %H:%M:%S GMT", 
     256                time.gmtime(time.time() + max_age)) 
     257            # 'max-age' takes precedence on standard conformant browsers 
     258            # (this is better because there of no time sync issues here) 
     259            cookies[self.cookie_name]['max-age'] = max_age 
    255260        log.debug("Sending visit ID cookie: %s", 
    256                    cookies[self.cookie_name].output()) 
     261            cookies[self.cookie_name].output()) 
    257262 
    258263 
  • branches/1.1/turbogears/identity/tests/test_visit.py

    r4203 r4205  
    2323        config.update({'visit.on': True}) 
    2424        self._visit_timeout = config.get('visit.timeout', 20) 
    25         config.update({'visit.timeout': 60}) 
     25        config.update({'visit.timeout': 50}) 
    2626        self.cookie_name = config.get("visit.cookie.name", 'tg-visit') 
    2727        cherrypy.root = VisitRoot() 
     
    5252    def test_cookie_expires(self): 
    5353        """Test if the visit timeout mechanism works.""" 
    54         # set expiration to one second 
    55         config.update({'visit.timeout': 1.0/60}) 
    56         testutil.create_request("/") 
    57         morsel = cherrypy.response.simple_cookie[self.cookie_name] 
    58         time.sleep(3) # 3 seconds 
    59         testutil.create_request("/", headers=cookie_header(morsel)) 
    60         assert cherrypy.response.simple_cookie[self.cookie_name].value != morsel.value, \ 
     54        timeout = config.get('visit.timeout', 50) 
     55        try: 
     56            # set expiration to one second for this test only 
     57            config.update({'visit.timeout': 1.0/60}) 
     58            testutil.create_request("/") 
     59            morsel = cherrypy.response.simple_cookie[self.cookie_name] 
     60            time.sleep(2) # 2 seconds 
     61            testutil.create_request("/", headers=cookie_header(morsel)) 
     62        finally: 
     63            config.update({'visit.timeout': timeout}) 
     64        assert cherrypy.response.simple_cookie[ 
     65                self.cookie_name].value != morsel.value, \ 
    6166            'cookie values should not match' 
    6267        assert visit.current().is_new, \ 
    6368            'this should be a new visit, as the cookie has expired' 
    6469 
    65     def test_cookie_max_age(self): 
    66         """Test whether the visit cookie has max age set correctly.""" 
    67         # set expiration to 42 minutes 
    68         config.update({'visit.timeout': 42}) 
     70    def test_cookie_not_permanent(self): 
     71        """Check that by default the visit cookie is not permanent.""" 
    6972        testutil.create_request('/') 
    7073        morsel = cherrypy.response.simple_cookie[self.cookie_name] 
    71         # we don't want visit cookies to be permanent 
    72         assert not morsel['expires'] 
    73         # but they should have set max age correctly (in seconds) 
    74         assert morsel['max-age'] == 42*60 
     74        assert not morsel['expires'] and not morsel['max-age'] 
     75 
     76    def test_cookie_permanent(self): 
     77        """Check that the visit cookie can be made permanent.""" 
     78        permanent = config.get('visit.cookie.permanent', False) 
     79        try: 
     80            # set cookie permanent for this test only (needs restart) 
     81            startup.stopTurboGears() 
     82            config.update({'visit.cookie.permanent': True}) 
     83            startup.startTurboGears() 
     84            testutil.create_request('/') 
     85            morsel = cherrypy.response.simple_cookie[self.cookie_name] 
     86        finally: 
     87            config.update({'visit.cookie.permanent': permanent}) 
     88        assert morsel['max-age'] == 3000 
     89        expires = time.mktime(time.strptime(morsel['expires'], 
     90            '%a, %d-%b-%Y %H:%M:%S GMT')) 
     91        should_expire = time.mktime(time.gmtime()) + morsel['max-age'] 
     92        assert abs(should_expire - expires) < 3 
  • branches/1.1/turbogears/visit/api.py

    r4204 r4205  
    44from random import random 
    55from datetime import timedelta, datetime 
     6import time 
    67import pkg_resources 
    78import cherrypy 
     
    174175        log.info("Visit filter initialised") 
    175176        get = config.get 
    176  
    177177        # Get the name to use for the identity cookie. 
    178178        self.cookie_name = get("visit.cookie.name", "tg-visit") 
     
    185185        # By default, I don't specify the cookie domain. 
    186186        self.cookie_domain = get("visit.cookie.domain", None) 
    187         self.cookie_max_age = int(get("visit.timeout", "20")) * 60 
    188187        assert self.cookie_domain != "localhost", "localhost" \ 
    189188            " is not a valid value for visit.cookie.domain. Try None instead." 
     189        # Use max age only if the cookie shall explicitly be permanent 
     190        self.cookie_max_age = get("visit.cookie.permanent", 
     191            False) and int(get("visit.timeout", "20")) * 60 or None 
    190192 
    191193    def before_main(self): 
     
    235237        cookies[self.cookie_name] = '' 
    236238        cookies[self.cookie_name]['path'] = self.cookie_path 
     239        cookies[self.cookie_name]['expires'] = '' 
    237240        cookies[self.cookie_name]['max-age'] = 0 
    238241 
     
    242245        cookies[self.cookie_name] = visit_key 
    243246        cookies[self.cookie_name]['path'] = self.cookie_path 
    244         # Note: We don't use 'expires' here, because the cookie will then 
    245         # be treated as a permanent cookie, not as a session cookie. 
    246         # Though this may be convenient, it is a security risk, 
    247         # it may block the cookie completely depending on the security 
    248         # level the browser is using, and it creates problems if times 
    249         # and timezones on the server and the client are not in sync. 
    250         cookies[self.cookie_name]['max-age']= self.cookie_max_age 
    251247        if self.cookie_secure: 
    252248            cookies[self.cookie_name]['secure'] = True 
    253249        if self.cookie_domain: 
    254250            cookies[self.cookie_name]['domain'] = self.cookie_domain 
     251        max_age = self.cookie_max_age 
     252        if max_age: 
     253            # use 'expires' because MSIE ignores 'max-age' 
     254            cookies[self.cookie_name]['expires'] = time.strftime( 
     255                "%a, %d-%b-%Y %H:%M:%S GMT", 
     256                time.gmtime(time.time() + max_age)) 
     257            # 'max-age' takes precedence on standard conformant browsers 
     258            # (this is better because there of no time sync issues here) 
     259            cookies[self.cookie_name]['max-age'] = max_age 
    255260        log.debug("Sending visit ID cookie: %s", 
    256                    cookies[self.cookie_name].output()) 
     261            cookies[self.cookie_name].output()) 
    257262 
    258263