Permalink
Browse files

Merge branch 'bugfix/ipv6_compat' of bertjwregeer/pyramid into fix.831

  • Loading branch information...
2 parents 5491a8e + 4b71102 commit 813eb45a18fb040bf211b5bf1b0164d5dbca678c @mmerickel mmerickel committed Mar 19, 2013
Showing with 67 additions and 5 deletions.
  1. +2 −0 CONTRIBUTORS.txt
  2. +15 −3 pyramid/authentication.py
  3. +50 −2 pyramid/tests/test_authentication.py
View
2 CONTRIBUTORS.txt
@@ -192,3 +192,5 @@ Contributors
- Robert Jackiewicz, 2012/11/12
- John Anderson, 2012/11/14
+
+- Bert JW Regeer, 2013/02/01
View
18 pyramid/authentication.py
@@ -450,6 +450,10 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy):
Default: ``False``. Make the requesting IP address part of
the authentication data in the cookie. Optional.
+ For IPv6 this option is not recommended. It ties the authentication
+ ticket to that individual's IPv6 address. Depending on the network they
+ are on, the IPv6 address that a user is using may expire quickly.
+
``timeout``
Default: ``None``. Maximum number of seconds which a newly
@@ -736,9 +740,17 @@ def calculate_digest(ip, timestamp, secret, userid, tokens, user_data,
tokens = bytes_(tokens, 'utf-8')
user_data = bytes_(user_data, 'utf-8')
hash_obj = hashlib.new(hashalg)
- hash_obj.update(
- encode_ip_timestamp(ip, timestamp) + secret + userid + b'\0'
- + tokens + b'\0' + user_data)
+
+ # Check to see if this is an IPv6 address
+ if ':' in ip:
+ ip_timestamp = ip + str(int(timestamp))
+ ip_timestamp = bytes_(ip_timestamp)
+ else:
+ # encode_ip_timestamp not required, left in for backwards compatibility
+ ip_timestamp = encode_ip_timestamp(ip, timestamp)
+
+ hash_obj.update(ip_timestamp + secret + userid + b'\0' +
+ tokens + b'\0' + user_data)
digest = hash_obj.hexdigest()
hash_obj2 = hashlib.new(hashalg)
hash_obj2.update(bytes_(digest) + secret)
View
52 pyramid/tests/test_authentication.py
@@ -561,9 +561,13 @@ def _makeOne(self, *arg, **kw):
helper.BadTicket = auth_tkt.BadTicket
return helper
- def _makeRequest(self, cookie=None):
+ def _makeRequest(self, cookie=None, ipv6=False):
environ = {'wsgi.version': (1,0)}
- environ['REMOTE_ADDR'] = '1.1.1.1'
+
+ if ipv6 is False:
+ environ['REMOTE_ADDR'] = '1.1.1.1'
+ else:
+ environ['REMOTE_ADDR'] = '::1'
environ['SERVER_NAME'] = 'localhost'
return DummyRequest(environ, cookie=cookie)
@@ -612,6 +616,23 @@ def test_identify_good_cookie_include_ip(self):
self.assertEqual(environ['REMOTE_USER_DATA'],'')
self.assertEqual(environ['AUTH_TYPE'],'cookie')
+ def test_identify_good_cookie_include_ipv6(self):
+ helper = self._makeOne('secret', include_ip=True)
+ request = self._makeRequest('ticket', ipv6=True)
+ result = helper.identify(request)
+ self.assertEqual(len(result), 4)
+ self.assertEqual(result['tokens'], ())
+ self.assertEqual(result['userid'], 'userid')
+ self.assertEqual(result['userdata'], '')
+ self.assertEqual(result['timestamp'], 0)
+ self.assertEqual(helper.auth_tkt.value, 'ticket')
+ self.assertEqual(helper.auth_tkt.remote_addr, '::1')
+ self.assertEqual(helper.auth_tkt.secret, 'secret')
+ environ = request.environ
+ self.assertEqual(environ['REMOTE_USER_TOKENS'], ())
+ self.assertEqual(environ['REMOTE_USER_DATA'],'')
+ self.assertEqual(environ['AUTH_TYPE'],'cookie')
+
def test_identify_good_cookie_dont_include_ip(self):
helper = self._makeOne('secret', include_ip=False)
request = self._makeRequest('ticket')
@@ -1098,6 +1119,20 @@ def test_cookie_value(self):
self.assertEqual(result,
'66f9cc3e423dc57c91df696cf3d1f0d80000000auserid!a,b!')
+ def test_ipv4(self):
+ ticket = self._makeOne('secret', 'userid', '198.51.100.1',
+ time=10, hashalg='sha256')
+ result = ticket.cookie_value()
+ self.assertEqual(result, 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b'\
+ '798400ecdade8d76c530000000auserid!')
+
+ def test_ipv6(self):
+ ticket = self._makeOne('secret', 'userid', '2001:db8::1',
+ time=10, hashalg='sha256')
+ result = ticket.cookie_value()
+ self.assertEqual(result, 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c8'\
+ '5becf8760cd7a2fa4910000000auserid!')
+
class TestBadTicket(unittest.TestCase):
def _makeOne(self, msg, expected=None):
from pyramid.authentication import BadTicket
@@ -1141,6 +1176,19 @@ def test_correct_with_user_data_sha512(self):
result = self._callFUT('secret', ticket, '0.0.0.0', 'sha512')
self.assertEqual(result, (10, 'userid', ['a', 'b'], ''))
+ def test_ipv4(self):
+ ticket = 'b3e7156db4f8abde4439c4a6499a0668f9e7ffd7fa27b798400ecdade8d7'\
+ '6c530000000auserid!'
+ result = self._callFUT('secret', ticket, '198.51.100.1', 'sha256')
+ self.assertEqual(result, (10, 'userid', [''], ''))
+
+ def test_ipv6(self):
+ ticket = 'd025b601a0f12ca6d008aa35ff3a22b7d8f3d1c1456c85becf8760cd7a2f'\
+ 'a4910000000auserid!'
+ result = self._callFUT('secret', ticket, '2001:db8::1', 'sha256')
+ self.assertEqual(result, (10, 'userid', [''], ''))
+ pass
+
class TestSessionAuthenticationPolicy(unittest.TestCase):
def _getTargetClass(self):
from pyramid.authentication import SessionAuthenticationPolicy

0 comments on commit 813eb45

Please sign in to comment.