Skip to content

Commit

Permalink
Merge pull request #18 from jurov/userdata_dict
Browse files Browse the repository at this point in the history
Make identity['userdata'] actually usable
  • Loading branch information
tseaver committed Dec 16, 2014
2 parents 8345b4c + 6e8328b commit 9689d4e
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 51 deletions.
7 changes: 7 additions & 0 deletions docs/plugins.rst
Expand Up @@ -88,6 +88,13 @@ authentication, identification, challenge and metadata provision.
<http://westpoint.ltd.uk/advisories/Paul_Johnston_GSEC.pdf>`_ reports
that as many as 3% of users change their IP addresses legitimately
during a session.

.. note::
Plugin supports remembering user data in the cookie by saving user dict into ``identity['userdata']``
parameter of ``remember`` method. They are sent unencrypted and protected by checksum.
Data will then be returned every time by ``identify``. This dict must be compatible with
``urllib.urlencode`` function (``urllib.urlparse.urlencode`` in python 3).
Saving keys/values with unicode characters is supported only under python 3.

.. module:: repoze.who.plugins.basicauth

Expand Down
31 changes: 18 additions & 13 deletions repoze/who/plugins/auth_tkt.py
Expand Up @@ -7,6 +7,11 @@
import time
from wsgiref.handlers import _monthname # Locale-independent, RFC-2616
from wsgiref.handlers import _weekdayname # Locale-independent, RFC-2616
try:
from urllib.parse import urlencode, parse_qsl
except ImportError:
from urllib import urlencode
from urlparse import parse_qsl

from zope.interface import implementer

Expand All @@ -27,6 +32,7 @@ def _utcnow(): #pragma NO COVERAGE
@implementer(IIdentifier, IAuthenticator)
class AuthTktCookiePlugin(object):

userid_typename = 'userid_type'
userid_type_decoders = {'int': int,
'unicode': lambda x: utf_8_decode(x)[0],
}
Expand Down Expand Up @@ -79,14 +85,12 @@ def identify(self, environ):
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):
if datum.startswith(userid_typename):
userid_type = datum[len(userid_typename):]
decoder = self.userid_type_decoders.get(userid_type)
if decoder:
userid = decoder(userid)
user_data_dict = dict(parse_qsl(user_data))
userid_type = user_data_dict.get(self.userid_typename)
if userid_type:
decoder = self.userid_type_decoders.get(userid_type)
if decoder:
userid = decoder(userid)

environ['REMOTE_USER_TOKENS'] = tokens
environ['REMOTE_USER_DATA'] = user_data
Expand All @@ -96,7 +100,7 @@ def identify(self, environ):
identity['timestamp'] = timestamp
identity['repoze.who.plugins.auth_tkt.userid'] = userid
identity['tokens'] = tokens
identity['userdata'] = user_data
identity['userdata'] = user_data_dict
return identity

# IIdentifier
Expand Down Expand Up @@ -129,15 +133,16 @@ def remember(self, environ, identity):

who_userid = identity['repoze.who.userid']
who_tokens = tuple(identity.get('tokens', ()))
who_userdata = identity.get('userdata', '')
who_userdata_dict = identity.get('userdata', {})

encoding_data = self.userid_type_encoders.get(type(who_userid))
if encoding_data:
encoding, encoder = encoding_data
who_userid = encoder(who_userid)
# XXX we are discarding the userdata passed in the identity?
who_userdata = 'userid_type:%s' % encoding

who_userdata_dict[self.userid_typename] = encoding

who_userdata = urlencode(who_userdata_dict)

old_data = (userid, tokens, userdata)
new_data = (who_userid, who_tokens, who_userdata)

Expand Down
76 changes: 38 additions & 38 deletions repoze/who/plugins/tests/test_authtkt.py
Expand Up @@ -93,58 +93,58 @@ def test_identify_nocookie(self):

def test_identify_good_cookie_include_ip(self):
plugin = self._makeOne('secret', include_ip=True)
val = self._makeTicket(remote_addr='1.1.1.1')
val = self._makeTicket(remote_addr='1.1.1.1', userdata='foo=123')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val})
result = plugin.identify(environ)
self.assertEqual(len(result), 4)
self.assertEqual(result['tokens'], [''])
self.assertEqual(result['repoze.who.plugins.auth_tkt.userid'], 'userid')
self.assertEqual(result['userdata'], 'userdata')
self.assertEqual(result['userdata'], {'foo': '123'})
self.assertTrue('timestamp' in result)
self.assertEqual(environ['REMOTE_USER_TOKENS'], [''])
self.assertEqual(environ['REMOTE_USER_DATA'],'userdata')
self.assertEqual(environ['REMOTE_USER_DATA'],'foo=123')
self.assertEqual(environ['AUTH_TYPE'],'cookie')

def test_identify_good_cookie_dont_include_ip(self):
plugin = self._makeOne('secret', include_ip=False)
val = self._makeTicket()
val = self._makeTicket(userdata='foo=123')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val})
result = plugin.identify(environ)
self.assertEqual(len(result), 4)
self.assertEqual(result['tokens'], [''])
self.assertEqual(result['repoze.who.plugins.auth_tkt.userid'], 'userid')
self.assertEqual(result['userdata'], 'userdata')
self.assertEqual(result['userdata'], {'foo': '123'})
self.assertTrue('timestamp' in result)
self.assertEqual(environ['REMOTE_USER_TOKENS'], [''])
self.assertEqual(environ['REMOTE_USER_DATA'],'userdata')
self.assertEqual(environ['REMOTE_USER_DATA'],'foo=123')
self.assertEqual(environ['AUTH_TYPE'],'cookie')

def test_identify_good_cookie_int_useridtype(self):
plugin = self._makeOne('secret', include_ip=False)
val = self._makeTicket(userid='1', userdata='userid_type:int')
val = self._makeTicket(userid='1', userdata='userid_type=int')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val})
result = plugin.identify(environ)
self.assertEqual(len(result), 4)
self.assertEqual(result['tokens'], [''])
self.assertEqual(result['repoze.who.plugins.auth_tkt.userid'], 1)
self.assertEqual(result['userdata'], 'userid_type:int')
self.assertEqual(result['userdata'], {'userid_type': 'int'})
self.assertTrue('timestamp' in result)
self.assertEqual(environ['REMOTE_USER_TOKENS'], [''])
self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type:int')
self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type=int')
self.assertEqual(environ['AUTH_TYPE'],'cookie')

def test_identify_good_cookie_unknown_useridtype(self):
plugin = self._makeOne('secret', include_ip=False)
val = self._makeTicket(userid='userid', userdata='userid_type:unknown')
val = self._makeTicket(userid='userid', userdata='userid_type=unknown')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val})
result = plugin.identify(environ)
self.assertEqual(len(result), 4)
self.assertEqual(result['tokens'], [''])
self.assertEqual(result['repoze.who.plugins.auth_tkt.userid'], 'userid')
self.assertEqual(result['userdata'], 'userid_type:unknown')
self.assertEqual(result['userdata'], {'userid_type':'unknown'})
self.assertTrue('timestamp' in result)
self.assertEqual(environ['REMOTE_USER_TOKENS'], [''])
self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type:unknown')
self.assertEqual(environ['REMOTE_USER_DATA'],'userid_type=unknown')
self.assertEqual(environ['AUTH_TYPE'],'cookie')

def test_identify_bad_cookie(self):
Expand All @@ -163,32 +163,32 @@ def test_identify_bad_cookie_expired(self):

def test_identify_with_checker_and_existing_account(self):
plugin = self._makeOne('secret', userid_checker=dummy_userid_checker)
val = self._makeTicket(userid='existing')
val = self._makeTicket(userid='existing', userdata='foo=123')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val})
result = plugin.identify(environ)
self.assertEqual(len(result), 4)
self.assertEqual(result['tokens'], [''])
self.assertEqual(result['repoze.who.plugins.auth_tkt.userid'], 'existing')
self.assertEqual(result['userdata'], 'userdata')
self.assertEqual(result['userdata'], {'foo': '123'})
self.assertTrue('timestamp' in result)
self.assertEqual(environ['REMOTE_USER_TOKENS'], [''])
self.assertEqual(environ['REMOTE_USER_DATA'],'userdata')
self.assertEqual(environ['REMOTE_USER_DATA'],'foo=123')
self.assertEqual(environ['AUTH_TYPE'],'cookie')

def test_remember_creds_same(self):
plugin = self._makeOne('secret')
val = self._makeTicket(userid='userid')
val = self._makeTicket(userid='userid', userdata='foo=123')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val})
result = plugin.remember(environ, {'repoze.who.userid':'userid',
'userdata':'userdata'})
'userdata':{'foo': '123'}})
self.assertEqual(result, None)

def test_remember_creds_secure(self):
plugin = self._makeOne('secret', secure=True)
val = self._makeTicket(userid='userid', secure=True)
val = self._makeTicket(userid='userid', secure=True, userdata='foo=123')
environ = self._makeEnviron()
result = plugin.remember(environ, {'repoze.who.userid':'userid',
'userdata':'userdata'})
'userdata':{'foo':'123'}})
self.assertEqual(len(result), 3)
self.assertEqual(result[0],
('Set-Cookie',
Expand All @@ -215,9 +215,9 @@ def test_remember_creds_different(self):
plugin = self._makeOne('secret')
old_val = self._makeTicket(userid='userid')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val})
new_val = self._makeTicket(userid='other', userdata='userdata')
new_val = self._makeTicket(userid='other', userdata='foo=123')
result = plugin.remember(environ, {'repoze.who.userid':'other',
'userdata':'userdata'})
'userdata':{'foo':'123'}})
self.assertEqual(len(result), 3)
self.assertEqual(result[0],
('Set-Cookie',
Expand All @@ -242,9 +242,9 @@ def test_remember_creds_different_strips_port(self):
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val,
'HTTP_HOST': 'localhost:8080',
})
new_val = self._makeTicket(userid='other', userdata='userdata')
new_val = self._makeTicket(userid='other', userdata='foo=123')
result = plugin.remember(environ, {'repoze.who.userid':'other',
'userdata':'userdata'})
'userdata':{'foo': '123'}})
self.assertEqual(len(result), 3)
self.assertEqual(result[0],
('Set-Cookie',
Expand All @@ -268,10 +268,10 @@ def test_remember_creds_different_include_ip(self):
old_val = self._makeTicket(userid='userid', remote_addr='1.1.1.1')
environ = self._makeEnviron({'HTTP_COOKIE': 'auth_tkt=%s' % old_val})
new_val = self._makeTicket(userid='other',
userdata='userdata',
userdata='foo=123',
remote_addr='1.1.1.1')
result = plugin.remember(environ, {'repoze.who.userid':'other',
'userdata':'userdata'})
'userdata':{'foo': '123'}})
self.assertEqual(len(result), 3)
self.assertEqual(result[0],
('Set-Cookie',
Expand All @@ -294,9 +294,9 @@ def test_remember_creds_different_bad_old_cookie(self):
plugin = self._makeOne('secret')
old_val = 'BOGUS'
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val})
new_val = self._makeTicket(userid='other', userdata='userdata')
new_val = self._makeTicket(userid='other', userdata='foo=123')
result = plugin.remember(environ, {'repoze.who.userid':'other',
'userdata':'userdata'})
'userdata':{'foo': '123'}})
self.assertEqual(len(result), 3)
self.assertEqual(result[0],
('Set-Cookie',
Expand All @@ -320,11 +320,11 @@ def test_remember_creds_different_with_tokens(self):
old_val = self._makeTicket(userid='userid')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val})
new_val = self._makeTicket(userid='userid',
userdata='userdata',
userdata='foo=123',
tokens=['foo', 'bar'],
)
result = plugin.remember(environ, {'repoze.who.userid': 'userid',
'userdata': 'userdata',
'userdata': {'foo': '123'},
'tokens': ['foo', 'bar'],
})
self.assertEqual(len(result), 3)
Expand All @@ -349,11 +349,11 @@ def test_remember_creds_different_with_tuple_tokens(self):
old_val = self._makeTicket(userid='userid')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val})
new_val = self._makeTicket(userid='userid',
userdata='userdata',
userdata='foo=123',
tokens=['foo', 'bar'],
)
result = plugin.remember(environ, {'repoze.who.userid': 'userid',
'userdata': 'userdata',
'userdata': {'foo': '123'},
'tokens': ('foo', 'bar'),
})
self.assertEqual(len(result), 3)
Expand All @@ -378,10 +378,10 @@ def test_remember_creds_different_int_userid(self):
plugin = self._makeOne('secret')
old_val = self._makeTicket(userid='userid')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val})
new_val = self._makeTicket(userid='1', userdata='userid_type:int')
new_val = self._makeTicket(userid='1', userdata='userid_type=int')
result = plugin.remember(environ, {'repoze.who.userid':1,
'userdata':''})
'userdata':{}})

self.assertEqual(len(result), 3)
self.assertEqual(result[0],
('Set-Cookie',
Expand All @@ -395,9 +395,9 @@ def test_remember_creds_different_long_userid(self):
plugin = self._makeOne('secret')
old_val = self._makeTicket(userid='userid')
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val})
new_val = self._makeTicket(userid='1', userdata='userid_type:int')
new_val = self._makeTicket(userid='1', userdata='userid_type=int')
result = plugin.remember(environ, {'repoze.who.userid':long(1),
'userdata':''})
'userdata':{}})
self.assertEqual(len(result), 3)
self.assertEqual(result[0],
('Set-Cookie',
Expand All @@ -409,13 +409,13 @@ def test_remember_creds_different_unicode_userid(self):
environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % old_val})
userid = b'\xc2\xa9'.decode('utf-8')
if type(b'') == type(''):
userdata = 'userid_type:unicode'
userdata = 'userid_type=unicode'
else: # pragma: no cover Py3k
userdata = ''
new_val = self._makeTicket(userid=userid.encode('utf-8'),
userdata=userdata)
result = plugin.remember(environ, {'repoze.who.userid':userid,
'userdata':''})
'userdata':{}})
self.assertEqual(type(result[0][1]), str)
self.assertEqual(len(result), 3)
self.assertEqual(result[0],
Expand Down

0 comments on commit 9689d4e

Please sign in to comment.