Bug Fixes
---------
- Ensure that ``secure`` flag for AuthTktAuthenticationPolicy
constructor does what it's documented to do (merge Daniel Holth's
fancy-cookies-2 branch).
New Features
------------
- Add ``path`` and ``http_only`` options to
AuthTktAuthenticationPolicy constructor (merge Daniel Holth's
fancy-cookies-2 branch).
| | |
| | | Next release |
| | | ============ |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | | - Ensure that ``secure`` flag for AuthTktAuthenticationPolicy |
| | | constructor does what it's documented to do (merge Daniel Holth's |
| | | fancy-cookies-2 branch). |
| | | |
| | | New Features |
| | | ------------ |
| | | |
| | | - Add ``path`` and ``http_only`` options to |
| | | AuthTktAuthenticationPolicy constructor (merge Daniel Holth's |
| | | fancy-cookies-2 branch). |
| | | |
| | | Backwards Incompatibilities |
| | | --------------------------- |
| | | |
| | | - Remove ``view_header``, ``view_accept``, ``view_xhr``, |
| | | ``view_path_info``, ``view_request_method``, ``view_request_param``, |
| | | and ``view_containment`` predicate arguments from the |
| | |
| | | with a route using the ``route_name`` attribute of the ``view`` ZCML |
| | | directive instead. |
| | | |
| | | Dependencies |
| | | ------------ |
| | | |
| | | - Remove dependency on ``sourcecodegen`` (not depended upon by |
| | | Chameleon 1.1.1+). |
| | | |
| | |
| | | timeout="86400" |
| | | reissue_time="600" |
| | | max_age="31536000" |
| | | path="/" |
| | | http_only="False" |
| | | /> |
| | | |
| | | See :ref:`authtktauthenticationpolicy_directive` for details about |
| | |
| | | to set this to a value that is lower than ``timeout`` or |
| | | ``reissue_time``, although it is not explicitly prevented. |
| | | Optional. |
| | | |
| | | ``path`` |
| | | |
| | | Default: ``/``. The path for which the auth_tkt cookie is valid. |
| | | May be desirable if the application only serves part of a domain. |
| | | Optional. |
| | | |
| | | ``http_only`` |
| | | |
| | | Default: ``False``. Hide cookie from JavaScript by setting the |
| | | HttpOnly flag. Not honored by all browsers. |
| | | Optional. |
| | | """ |
| | | implements(IAuthenticationPolicy) |
| | | def __init__(self, |
| | |
| | | include_ip=False, |
| | | timeout=None, |
| | | reissue_time=None, |
| | | max_age=None): |
| | | max_age=None, |
| | | path="/", |
| | | http_only=False, |
| | | ): |
| | | self.cookie = AuthTktCookieHelper( |
| | | secret, |
| | | cookie_name=cookie_name, |
| | |
| | | timeout=timeout, |
| | | reissue_time=reissue_time, |
| | | max_age=max_age, |
| | | http_only=http_only, |
| | | path=path, |
| | | ) |
| | | self.callback = callback |
| | | |
| | |
| | | |
| | | def __init__(self, secret, cookie_name='auth_tkt', secure=False, |
| | | include_ip=False, timeout=None, reissue_time=None, |
| | | max_age=None): |
| | | max_age=None, http_only=False, path="/"): |
| | | self.secret = secret |
| | | self.cookie_name = cookie_name |
| | | self.include_ip = include_ip |
| | |
| | | raise ValueError('reissue_time must be lower than timeout') |
| | | self.reissue_time = reissue_time |
| | | self.max_age = max_age |
| | | self.http_only = http_only |
| | | self.path = path |
| | | |
| | | static_flags = [] |
| | | if self.secure: |
| | | static_flags.append('; Secure') |
| | | if self.http_only: |
| | | static_flags.append('; HttpOnly') |
| | | self.static_flags = "".join(static_flags) |
| | | |
| | | def _get_cookies(self, environ, value, max_age=None): |
| | | if max_age is EXPIRE: |
| | |
| | | |
| | | cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME')) |
| | | wild_domain = '.' + cur_domain |
| | | |
| | | cookies = [ |
| | | ('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)) |
| | | ('Set-Cookie', '%s="%s"; Path=%s%s%s' % ( |
| | | self.cookie_name, value, self.path, max_age, self.static_flags)), |
| | | ('Set-Cookie', '%s="%s"; Path=%s; Domain=%s%s%s' % ( |
| | | self.cookie_name, value, self.path, cur_domain, max_age, |
| | | self.static_flags)), |
| | | ('Set-Cookie', '%s="%s"; Path=%s; Domain=%s%s%s' % ( |
| | | self.cookie_name, value, self.path, wild_domain, max_age, |
| | | self.static_flags)) |
| | | ] |
| | | |
| | | return cookies |
| | | |
| | | def identify(self, request): |
| | |
| | | self.failUnless(result[2][1].endswith('; Path=/; Domain=.localhost')) |
| | | self.failUnless(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_path(self): |
| | | plugin = self._makeOne('secret', include_ip=True, |
| | | path="/cgi-bin/bfg.cgi/") |
| | | request = self._makeRequest() |
| | | result = plugin.remember(request, 'other') |
| | | self.assertEqual(len(result), 3) |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | self.failUnless(result[0][1].endswith('; Path=/cgi-bin/bfg.cgi/')) |
| | | self.failUnless(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.failUnless(result[1][1].endswith( |
| | | '; Path=/cgi-bin/bfg.cgi/; Domain=localhost')) |
| | | self.failUnless(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.failUnless(result[2][1].endswith( |
| | | '; Path=/cgi-bin/bfg.cgi/; Domain=.localhost')) |
| | | self.failUnless(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_http_only(self): |
| | | plugin = self._makeOne('secret', include_ip=True, http_only=True) |
| | | request = self._makeRequest() |
| | | result = plugin.remember(request, 'other') |
| | | self.assertEqual(len(result), 3) |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | self.failUnless(result[0][1].endswith('; HttpOnly')) |
| | | self.failUnless(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.failUnless(result[1][1].endswith('; HttpOnly')) |
| | | self.failUnless(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.failUnless(result[2][1].endswith('; HttpOnly')) |
| | | self.failUnless(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_secure(self): |
| | | plugin = self._makeOne('secret', include_ip=True, secure=True) |
| | | request = self._makeRequest() |
| | | result = plugin.remember(request, 'other') |
| | | self.assertEqual(len(result), 3) |
| | | |
| | | self.assertEqual(result[0][0], 'Set-Cookie') |
| | | self.failUnless('; Secure' in result[0][1]) |
| | | self.failUnless(result[0][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[1][0], 'Set-Cookie') |
| | | self.failUnless('; Secure' in result[1][1]) |
| | | self.failUnless(result[1][1].startswith('auth_tkt=')) |
| | | |
| | | self.assertEqual(result[2][0], 'Set-Cookie') |
| | | self.failUnless('; Secure' in result[2][1]) |
| | | self.failUnless(result[2][1].startswith('auth_tkt=')) |
| | | |
| | | def test_remember_string_userid(self): |
| | | plugin = self._makeOne('secret') |
| | | request = self._makeRequest() |
| | |
| | | self._callFUT(context, 'sosecret', callback=callback, |
| | | cookie_name='repoze.bfg.auth_tkt', |
| | | secure=True, include_ip=True, timeout=100, |
| | | reissue_time=60) |
| | | reissue_time=60, http_only=True, path="/sub/") |
| | | actions = context.actions |
| | | self.assertEqual(len(actions), 1) |
| | | regadapt = actions[0] |
| | |
| | | self.assertEqual(regadapt['callable'], None) |
| | | self.assertEqual(regadapt['args'], ()) |
| | | policy = reg.getUtility(IAuthenticationPolicy) |
| | | self.assertEqual(policy.cookie.path, '/sub/') |
| | | self.assertEqual(policy.cookie.http_only, True) |
| | | self.assertEqual(policy.cookie.secret, 'sosecret') |
| | | self.assertEqual(policy.callback, callback) |
| | | |
| | |
| | | context, 'sosecret', callback=callback, |
| | | cookie_name='repoze.bfg.auth_tkt', |
| | | secure=True, include_ip=True, timeout=100, |
| | | reissue_time=500) |
| | | reissue_time=500, http_only=True, |
| | | path="/cgi-bin/bfg.cgi/") |
| | | |
| | | class TestACLAuthorizationPolicyDirective(unittest.TestCase): |
| | | def setUp(self): |
| | |
| | | timeout = Int(title=u"timeout", required=False, default=None) |
| | | reissue_time = Int(title=u"reissue_time", required=False, default=None) |
| | | max_age = Int(title=u"max_age", required=False, default=None) |
| | | path = ASCIILine(title=u"path", required=False, default='/') |
| | | http_only = Bool(title=u"http_only", required=False, default=False) |
| | | |
| | | def authtktauthenticationpolicy(_context, |
| | | secret, |
| | |
| | | include_ip=False, |
| | | timeout=None, |
| | | reissue_time=None, |
| | | max_age=None): |
| | | max_age=None, |
| | | http_only=False, |
| | | path='/'): |
| | | try: |
| | | policy = AuthTktAuthenticationPolicy(secret, |
| | | callback=callback, |
| | |
| | | include_ip = include_ip, |
| | | timeout = timeout, |
| | | reissue_time = reissue_time, |
| | | max_age=max_age) |
| | | max_age=max_age, |
| | | http_only=http_only, |
| | | path=path) |
| | | except ValueError, why: |
| | | raise ConfigurationError(str(why)) |
| | | # authentication policies must be registered eagerly so they can |