From 76e95124632a98bea84d4d81a5e0b322d56806fa Mon Sep 17 00:00:00 2001
From: Tres Seaver <tseaver@agendaless.com>
Date: Tue, 13 Jul 2010 18:29:12 +0200
Subject: [PATCH] Make the InsecureCookiePlugin take a ``charset`` argument

---
 docs/plugins.rst                        |    7 ++-
 repoze/who/plugins/cookie.py            |   19 +++++++--
 repoze/who/plugins/tests/test_cookie.py |   43 +++++++++++++++++++--
 CHANGES.txt                             |    4 ++
 4 files changed, 63 insertions(+), 10 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index ac5a72c..5db21d0 100644
--- a/CHANGES.txt
+++ b/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.
 
diff --git a/docs/plugins.rst b/docs/plugins.rst
index 4b57564..d155397 100644
--- a/docs/plugins.rst
+++ b/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
 
diff --git a/repoze/who/plugins/cookie.py b/repoze/who/plugins/cookie.py
index 3280ac6..b6945a1 100644
--- a/repoze/who/plugins/cookie.py
+++ b/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
 
diff --git a/repoze/who/plugins/tests/test_cookie.py b/repoze/who/plugins/tests/test_cookie.py
index 74e3a54..cba2545 100644
--- a/repoze/who/plugins/tests/test_cookie.py
+++ b/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')

--
Gitblit v1.9.3