Tres Seaver
2010-07-13 76e95124632a98bea84d4d81a5e0b322d56806fa
Make the InsecureCookiePlugin take a ``charset`` argument

If provided, use the charset, to encode / decode the login and password.

See http://bugs.repoze.org/issue155

4 files modified
73 ■■■■ changed files
CHANGES.txt 4 ●●●● patch | view | raw | blame | history
docs/plugins.rst 7 ●●●● patch | view | raw | blame | history
repoze/who/plugins/cookie.py 19 ●●●● patch | view | raw | blame | history
repoze/who/plugins/tests/test_cookie.py 43 ●●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -4,6 +4,10 @@
After 2.0a2 (unreleased)
-----------------------
- Make the ``repoze.who.plugins.cookie.InsecureCookiePlugin`` take a
  ``charset`` argument, and use to to encode / decode login and password.
  See http://bugs.repoze.org/issue155
- In ``repoze.who.restrict``, return headers as a list, to keep ``wsgiref``
  from complaining.
docs/plugins.rst
@@ -108,9 +108,12 @@
  A :class:`InsecureCookiePlugin` is an ``IIdentifier`` plugin.  It
  stores identification information in an insecure form (the base64
  value of the username and password separated by a colon) in a
  client-side cookie.  It accepts a single argument named
  client-side cookie.  It accepts a single required argument named
  *cookie_name*.  This is the cookie name of the cookie used to store
  the identification information.
  the identification information.  The plugin also accepts two optional
  arguments:  *cookie_path* is the URL path root which scopes the cookie,
  and *charset* is the name of a codec used to convert the login and password
  to and from unicode.
.. module:: repoze.who.plugins.form
repoze/who/plugins/cookie.py
@@ -10,9 +10,10 @@
    implements(IIdentifier)
    
    def __init__(self, cookie_name, cookie_path='/'):
    def __init__(self, cookie_name, cookie_path='/', charset=None):
        self.cookie_name = cookie_name
        self.cookie_path = cookie_path
        self.charset = charset
    # IIdentifier
    def identify(self, environ):
@@ -29,6 +30,9 @@
        try:
            login, password = auth.split(':', 1)
            if self.charset is not None:
                login = login.decode(self.charset)
                password = password.decode(self.charset)
            return {'login':login, 'password':password}
        except ValueError: # not enough values to unpack
            return None
@@ -42,7 +46,12 @@
    
    # IIdentifier
    def remember(self, environ, identity):
        cookie_value = '%(login)s:%(password)s' % identity
        login = identity['login']
        password = identity['password']
        if self.charset is not None:
            login = login.encode(self.charset)
            password = password.encode(self.charset)
        cookie_value = '%s:%s' % (login, password)
        cookie_value = cookie_value.encode('base64').rstrip()
        cookies = get_cookies(environ)
        existing = cookies.get(self.cookie_name)
@@ -57,7 +66,9 @@
        return '<%s %s>' % (self.__class__.__name__,
                            id(self)) #pragma NO COVERAGE
def make_plugin(cookie_name='repoze.who.plugins.cookie', cookie_path='/'):
    plugin = InsecureCookiePlugin(cookie_name, cookie_path)
def make_plugin(cookie_name='repoze.who.plugins.cookie',
                cookie_path='/',
                charset=None):
    plugin = InsecureCookiePlugin(cookie_name, cookie_path, charset)
    return plugin
repoze/who/plugins/tests/test_cookie.py
@@ -49,6 +49,16 @@
        result = plugin.identify(environ)
        self.assertEqual(result, {'login':'foo', 'password':'password'})
    def test_identify_encoded(self):
        LOGIN = 'tr\xc3\xa9sbien'       # UTF-8 encoded e-acute
        PASSWORD = 'p\xc3\x80ssword'    # UTF-8 encoded capital A grave
        plugin = self._makeOne('oatmeal', charset='utf-8')
        auth = ('%s:%s' % (LOGIN, PASSWORD)).encode('base64').rstrip()
        environ = self._makeEnviron({'HTTP_COOKIE':'oatmeal=%s;' % auth})
        result = plugin.identify(environ)
        self.assertEqual(result, {'login': LOGIN.decode('utf8'),
                                  'password': PASSWORD.decode('utf8')})
    def test_remember_creds_same(self):
        plugin = self._makeOne('oatmeal')
        creds = {'login':'foo', 'password':'password'}
@@ -68,10 +78,17 @@
        expected = 'oatmeal=%s; Path=/;' % creds_auth
        self.assertEqual(result, [('Set-Cookie', expected)])
    def test_factory(self):
        from repoze.who.plugins.cookie import make_plugin
        plugin = make_plugin('foo')
        self.assertEqual(plugin.cookie_name, 'foo')
    def test_remember_encoded(self):
        LOGIN = 'tr\xc3\xa9sbien'       # UTF-8 encoded e-acute
        PASSWORD = 'p\xc3\x80ssword'    # UTF-8 encoded capital A grave
        plugin = self._makeOne('oatmeal', charset='utf-8')
        creds = {'login': LOGIN.decode('utf8'),
                 'password': PASSWORD.decode('utf8')}
        creds_auth = ('%s:%s' % (LOGIN, PASSWORD)).encode('base64').rstrip()
        environ = self._makeEnviron()
        result = plugin.remember(environ, creds)
        expected = 'oatmeal=%s; Path=/;' % creds_auth
        self.assertEqual(result, [('Set-Cookie', expected)])
    def test_forget(self):
        plugin = self._makeOne('oatmeal')
@@ -82,3 +99,21 @@
        self.assertEqual(name, 'Set-Cookie')
        self.assertEqual(value,
            'oatmeal=""; Path=/; Expires=Sun, 10-May-1971 11:59:00 GMT')
    def test_factory(self):
        from repoze.who.plugins.cookie import make_plugin
        plugin = make_plugin('foo')
        self.assertEqual(plugin.cookie_name, 'foo')
        self.assertEqual(plugin.charset, None)
    def test_factory_with_cookie_path(self):
        from repoze.who.plugins.cookie import make_plugin
        plugin = make_plugin('foo', '/bar')
        self.assertEqual(plugin.cookie_name, 'foo')
        self.assertEqual(plugin.cookie_path, '/bar')
    def test_factory_with_charset(self):
        from repoze.who.plugins.cookie import make_plugin
        plugin = make_plugin('foo', charset='utf8')
        self.assertEqual(plugin.cookie_name, 'foo')
        self.assertEqual(plugin.charset, 'utf8')