From 3bef31e78563997ecaec0bf6bf1715ce66f5605b Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 25 Jun 2009 07:07:55 +0000 Subject: - Add optional ``max_age`` keyword value to the ``remember`` method of ``repoze.bfg.authentication.AuthTktAuthenticationPolicy``; if this value is passed to ``remember``, the generated cookie will have a corresponding Max-Age value. --- CHANGES.txt | 8 +++++++ repoze/bfg/authentication.py | 34 ++++++++++++++++++++--------- repoze/bfg/tests/test_authentication.py | 38 +++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 45ba8752c..783349c81 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,14 @@ Next release ============ +Features +-------- + +- Add optional ``max_age`` keyword value to the ``remember`` method of + ``repoze.bfg.authentication.AuthTktAuthenticationPolicy``; if this + value is passed to ``remember``, the generated cookie will have a + corresponding Max-Age value. + Documentation ------------- diff --git a/repoze/bfg/authentication.py b/repoze/bfg/authentication.py index 154934c45..90c6ca90b 100644 --- a/repoze/bfg/authentication.py +++ b/repoze/bfg/authentication.py @@ -1,3 +1,4 @@ +import datetime import time from codecs import utf_8_decode @@ -226,7 +227,9 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): return result['userid'] def remember(self, request, principal, **kw): - return self.cookie.remember(request, principal) + """ Accepts the following kw args: ``tokens``, ``userdata``, + ``max_age``.""" + return self.cookie.remember(request, principal, **kw) def forget(self, request): return self.cookie.forget(request) @@ -298,16 +301,27 @@ class AuthTktCookieHelper(object): identity['userdata'] = user_data return identity - def _get_cookies(self, environ, value): + def _get_cookies(self, environ, value, max_age=None): + if max_age is not None: + later = datetime.datetime.now() + datetime.timedelta( + seconds=int(max_age)) + # Wdy, DD-Mon-YY HH:MM:SS GMT + expires = later.strftime('%a, %d %b %Y %H:%M:%S') + # the Expires header is *required* at least for IE7 (IE7 does + # not respect Max-Age) + max_age = "; Max-Age=%s; Expires=%s" % (max_age, expires) + else: + max_age = '' + cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME')) wild_domain = '.' + cur_domain cookies = [ - ('Set-Cookie', '%s="%s"; Path=/' % ( - self.cookie_name, value)), - ('Set-Cookie', '%s="%s"; Path=/; Domain=%s' % ( - self.cookie_name, value, cur_domain)), - ('Set-Cookie', '%s="%s"; Path=/; Domain=%s' % ( - self.cookie_name, value, wild_domain)) + ('Set-Cookie', '%s="%s"; Path=/%s' % ( + self.cookie_name, value, max_age)), + ('Set-Cookie', '%s="%s"; Path=/; Domain=%s%s' % ( + self.cookie_name, value, cur_domain, max_age)), + ('Set-Cookie', '%s="%s"; Path=/; Domain=%s%s' % ( + self.cookie_name, value, wild_domain, max_age)) ] return cookies @@ -318,7 +332,7 @@ class AuthTktCookieHelper(object): return self._get_cookies(environ, '""') # IIdentifier - def remember(self, request, userid, tokens='', userdata=''): + def remember(self, request, userid, tokens='', userdata='', max_age=None): environ = request.environ if self.include_ip: remote_addr = environ['REMOTE_ADDR'] @@ -368,5 +382,5 @@ class AuthTktCookieHelper(object): wild_domain = '.' + cur_domain if old_cookie_value != new_cookie_value: # return a set of Set-Cookie headers - return self._get_cookies(environ, new_cookie_value) + return self._get_cookies(environ, new_cookie_value, max_age) diff --git a/repoze/bfg/tests/test_authentication.py b/repoze/bfg/tests/test_authentication.py index 2032f53c3..12ecb6b16 100644 --- a/repoze/bfg/tests/test_authentication.py +++ b/repoze/bfg/tests/test_authentication.py @@ -248,6 +248,13 @@ class TestAutkTktAuthenticationPolicy(unittest.TestCase): policy = self._makeOne(None, None) result = policy.remember(request, 'fred') self.assertEqual(result, []) + + def test_remember_with_extra_kargs(self): + request = DummyRequest({}) + policy = self._makeOne(None, None) + result = policy.remember(request, 'fred', a=1, b=2) + self.assertEqual(policy.cookie.kw, {'a':1, 'b':2}) + self.assertEqual(result, []) def test_forget(self): request = DummyRequest({}) @@ -491,6 +498,36 @@ class TestAuthTktCookieHelper(unittest.TestCase): ('Set-Cookie', 'auth_tkt="%s"; Path=/' % new_val)) + def test_remember_max_age(self): + plugin = self._makeOne('secret') + environ = {'HTTP_HOST':'example.com'} + tkt = self._makeTicket(userid='chris', userdata='') + request = self._makeRequest(environ) + result = plugin.remember(request, 'chris', max_age='500') + + name,value = result.pop(0) + self.assertEqual('Set-Cookie', name) + self.failUnless( + value.startswith('auth_tkt="%s"; Path=/; Max-Age=500' % tkt), + value) + self.failUnless('; Expires=' in value) + + name,value = result.pop(0) + self.assertEqual('Set-Cookie', name) + self.failUnless( + value.startswith( + 'auth_tkt="%s"; Path=/; Domain=example.com; Max-Age=500' + % tkt), value) + self.failUnless('; Expires=' in value) + + name,value = result.pop(0) + self.assertEqual('Set-Cookie', name) + self.failUnless( + value.startswith( + 'auth_tkt="%s"; Path=/; Domain=.example.com; Max-Age=500' % tkt), + value) + self.failUnless('; Expires=' in value) + def test_forget(self): plugin = self._makeOne('secret') request = self._makeRequest() @@ -546,6 +583,7 @@ class DummyCookieHelper: return self.result def remember(self, *arg, **kw): + self.kw = kw return [] def forget(self, *arg): -- cgit v1.2.3