diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-06-18 07:56:09 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-06-18 07:56:09 +0000 |
| commit | 3ea1ede5d72fa6d51accc32d36665f3a48546a57 (patch) | |
| tree | 4459334b47378b9c417b106f8630591998175207 | |
| parent | 947b8bb21235cdaaa7d1b203ef74c814a59c31ed (diff) | |
| download | pyramid-3ea1ede5d72fa6d51accc32d36665f3a48546a57.tar.gz pyramid-3ea1ede5d72fa6d51accc32d36665f3a48546a57.tar.bz2 pyramid-3ea1ede5d72fa6d51accc32d36665f3a48546a57.zip | |
- Add ``reissue_time`` and ``timeout`` parameters to
``repoze.bfg.authentication.AuthTktAuthenticationPolicy``
constructor. If these are passed, cookies will be reset every so
often (cadged from the same change to repoze.who lately).
| -rw-r--r-- | CHANGES.txt | 5 | ||||
| -rw-r--r-- | repoze/bfg/authentication.py | 30 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_authentication.py | 30 |
3 files changed, 60 insertions, 5 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 2851f61ad..3b2772523 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,6 +4,11 @@ Next release Features -------- +- Add ``reissue_time`` and ``timeout`` parameters to + ``repoze.bfg.authentication.AuthTktAuthenticationPolicy`` + constructor. If these are passed, cookies will be reset every so + often (cadged from the same change to repoze.who lately). + - The matchdict related to the matching of a Routes route is available on the request as the ``matchdict`` attribute: ``request.matchdict``. If no route matched, this attribute will be diff --git a/repoze/bfg/authentication.py b/repoze/bfg/authentication.py index 6be27f47e..5aca0c110 100644 --- a/repoze/bfg/authentication.py +++ b/repoze/bfg/authentication.py @@ -1,3 +1,5 @@ +import time + from codecs import utf_8_decode from codecs import utf_8_encode from paste.request import get_cookies @@ -183,6 +185,18 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): Default: ``False``. Make the requesting IP address part of the authentication data in the cookie. Optional. + ``timeout`` + + Default: ``None``. Maximum age in seconds allowed for a cookie + to live. If ``timeout`` is specified, you must also set + ``reissue_time`` to a lower value. + + ``reissue_time`` + + Default: ``None``. If ``reissue_time`` is specified, when we + encounter a cookie that is older than the reissue time (in + seconds), but younger that the ``timeout``, a new cookie will + be issued. """ implements(IAuthenticationPolicy) def __init__(self, @@ -190,12 +204,16 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): callback=None, cookie_name='repoze.bfg.auth_tkt', secure=False, - include_ip=False): + include_ip=False, + timeout=None, + reissue_time=None): self.cookie = AuthTktCookieHelper( secret, cookie_name=cookie_name, secure=secure, include_ip=include_ip, + timeout=timeout, + reissue_time=reissue_time, ) self.callback = callback @@ -223,11 +241,16 @@ class AuthTktCookieHelper(object): } def __init__(self, secret, cookie_name='auth_tkt', secure=False, - include_ip=False): + include_ip=False, timeout=None, reissue_time=None): self.secret = secret self.cookie_name = cookie_name self.include_ip = include_ip self.secure = secure + if timeout and ( (not reissue_time) or (reissue_time > timeout) ): + raise ValueError('When timeout is specified, reissue_time must ' + 'be set to a lower value') + self.timeout = timeout + self.reissue_time = reissue_time # IIdentifier def identify(self, request): @@ -249,6 +272,9 @@ class AuthTktCookieHelper(object): except auth_tkt.BadTicket: return None + if self.timeout and ( (timestamp + self.timeout) < time.time() ): + return None + userid_typename = 'userid_type:' user_data_info = user_data.split('|') for datum in filter(None, user_data_info): diff --git a/repoze/bfg/tests/test_authentication.py b/repoze/bfg/tests/test_authentication.py index 258fadfd2..f3df22005 100644 --- a/repoze/bfg/tests/test_authentication.py +++ b/repoze/bfg/tests/test_authentication.py @@ -177,11 +177,19 @@ class TestAutkTktAuthenticationPolicy(unittest.TestCase): from repoze.bfg.authentication import AuthTktAuthenticationPolicy return AuthTktAuthenticationPolicy - def _makeOne(self, callback, cookieidentity): - inst = self._getTargetClass()('secret', callback) + def _makeOne(self, callback, cookieidentity, **kw): + inst = self._getTargetClass()('secret', callback, **kw) inst.cookie = DummyCookieHelper(cookieidentity) return inst + def test_allargs(self): + # pass all known args + inst = self._getTargetClass()( + 'secret', callback=None, cookie_name=None, secure=False, + include_ip=False, timeout=None, reissue_time=None, + ) + self.assertEqual(inst.callback, None) + def test_class_implements_IAuthenticationPolicy(self): from zope.interface.verify import verifyClass from repoze.bfg.interfaces import IAuthenticationPolicy @@ -266,7 +274,8 @@ class TestAuthTktCookieHelper(unittest.TestCase): def _makeTicket(self, userid='userid', remote_addr='0.0.0.0', tokens = [], userdata='userdata', - cookie_name='auth_tkt', secure=False): + cookie_name='auth_tkt', secure=False, + time=None): from paste.auth import auth_tkt ticket = auth_tkt.AuthTicket( 'secret', @@ -274,6 +283,7 @@ class TestAuthTktCookieHelper(unittest.TestCase): remote_addr, tokens=tokens, user_data=userdata, + time=time, cookie_name=cookie_name, secure=secure) return ticket.cookie_value() @@ -499,6 +509,20 @@ class TestAuthTktCookieHelper(unittest.TestCase): self.assertEqual(name, 'Set-Cookie') self.assertEqual(value, 'auth_tkt=""""; Path=/; Domain=.localhost') + def test_timeout_no_reissue(self): + self.assertRaises(ValueError, self._makeOne, 'userid', timeout=1) + + def test_timeout_lower_than_reissue(self): + self.assertRaises(ValueError, self._makeOne, 'userid', timeout=1, + reissue_time=2) + + def test_identify_bad_cookie_expired(self): + import time + helper = self._makeOne('secret', timeout=2, reissue_time=1) + val = self._makeTicket(userid='userid', time=time.time()-3) + request = self._makeRequest({'HTTP_COOKIE':'auth_tkt=%s' % val}) + result = helper.identify(request) + self.assertEqual(result, None) class DummyContext: pass |
