Permalink
Browse files

Merge remote branch 'simon/master'

  • Loading branch information...
2 parents 610590b + 5b7e0fb commit 8abfe3ee1850a743d3cded703b28a4547970c11a @brosner committed Nov 29, 2009
View
@@ -208,7 +208,7 @@ def show_associate(self, request, openid=None):
return self.need_authenticated_user(request)
try:
next = signed.loads(
- request.REQUEST.get('next', ''), extra_salt=self.salt_next
+ request.REQUEST.get('next', ''), extra_key=self.salt_next
)
except ValueError:
next = ''
@@ -218,9 +218,9 @@ def show_associate(self, request, openid=None):
'specific_openid': openid,
'next': next and request.REQUEST.get('next', '') or None,
'openid_token': signed.dumps(
- # Use user.id as part of extra_salt to prevent attackers from
+ # Use user.id as part of extra_key to prevent attackers from
# creating their own openid_token for use in CSRF attack
- openid, extra_salt = self.associate_salt + str(request.user.id)
+ openid, extra_key = self.associate_salt + str(request.user.id)
),
})
@@ -229,7 +229,7 @@ def do_associate(self, request):
try:
openid = signed.loads(
request.POST.get('openid_token', ''),
- extra_salt = self.associate_salt + str(request.user.id)
+ extra_key = self.associate_salt + str(request.user.id)
)
except signed.BadSignature:
return self.show_error(request, self.csrf_failed_message)
@@ -262,7 +262,7 @@ def do_associations(self, request):
try:
todelete = signed.loads(
request.POST['todelete'],
- extra_salt = self.associate_delete_salt
+ extra_key = self.associate_delete_salt
)
if todelete['user_id'] != request.user.id:
message = self.associate_tampering_message
@@ -285,7 +285,7 @@ def do_associations(self, request):
'user_id': request.user.id,
'association_id': association.id,
'openid': association.openid,
- }, extra_salt = self.associate_delete_salt),
+ }, extra_key = self.associate_delete_salt),
})
return self.render(request, self.associations_template, {
'openids': openids,
View
@@ -115,7 +115,7 @@ def __init__(self, persist_class=CookiePersist):
self.persist = persist_class()
def sign_next(self, url):
- return signed.dumps(url, extra_salt = self.salt_next)
+ return signed.dumps(url, extra_key = self.salt_next)
def render(self, request, template, context=None):
context = context or {}
@@ -159,7 +159,7 @@ def do_index(self, request, extra_message=None):
def show_login(self, request, message=None):
try:
next = signed.loads(
- request.REQUEST.get('next', ''), extra_salt=self.salt_next
+ request.REQUEST.get('next', ''), extra_key=self.salt_next
)
except ValueError:
next = ''
@@ -207,7 +207,7 @@ def get_on_complete_url(self, request, on_complete_url=None):
on_complete_url = self.ensure_absolute_url(request, on_complete_url)
try:
next = signed.loads(
- request.POST.get('next', ''), extra_salt=self.salt_next
+ request.POST.get('next', ''), extra_key=self.salt_next
)
except ValueError:
return on_complete_url
@@ -304,7 +304,7 @@ def redirect_if_valid_next(self, request):
"Logic for checking if a signed ?next= token is included in request"
try:
next = signed.loads(
- request.REQUEST.get('next', ''), extra_salt=self.salt_next
+ request.REQUEST.get('next', ''), extra_key=self.salt_next
)
return HttpResponseRedirect(next)
except ValueError:
@@ -435,7 +435,7 @@ def persist_openid(self, request, response, openid_object):
response.set_cookie(
key = self.cookie_key,
value = signed.dumps(
- openid_object, compress = True, extra_salt = self.extra_salt
+ openid_object, compress = True, extra_key = self.extra_salt
),
max_age = self.cookie_max_age,
expires = self.cookie_expires,
@@ -455,7 +455,7 @@ def do_debug(self, request):
raise Http404
if self.cookie_key in request.COOKIES:
obj = signed.loads(
- request.COOKIES[self.cookie_key], extra_salt = self.extra_salt
+ request.COOKIES[self.cookie_key], extra_key = self.extra_salt
)
assert False, (obj, obj.__dict__)
assert False, 'no cookie named %s' % self.cookie_key
@@ -469,7 +469,7 @@ def process_request(self, request):
if cookie_value:
try:
request.openid = signed.loads(
- cookie_value, extra_salt = self.extra_salt
+ cookie_value, extra_key = self.extra_salt
)
request.openids = [request.openid]
except ValueError: # Signature failed
@@ -69,7 +69,7 @@ def show_landing_page(self, request, orequest):
def stash_incomplete_orequest(self, request, response, orequest):
response.set_cookie(
self.incomplete_orequest_cookie_key, signed.dumps(
- orequest, extra_salt = self.orequest_salt
+ orequest, extra_key = self.orequest_salt
)
)
@@ -137,7 +137,7 @@ def extract_incomplete_orequest(self, request):
try:
return signed.loads(request.COOKIES.get(
self.incomplete_orequest_cookie_key, ''
- ), extra_salt = self.orequest_salt)
+ ), extra_key = self.orequest_salt)
except signed.BadSignature:
return None
View
@@ -8,7 +8,7 @@
There are two components here, separatad by a '.'. The first component is a
URLsafe base64 encoded pickle of the object passed to dumps(). The second
-component is a base64 encoded SHA1 hash of "$first_component.$secret"
+component is a base64 encoded hmac/SHA1 hash of "$first_component.$secret"
Calling signed.loads(s) checks the signature BEFORE unpickling the object -
this protects against malformed pickle attacks. If the signature fails, a
@@ -37,17 +37,18 @@
import pickle, base64
from django.conf import settings
from django.utils.hashcompat import sha_constructor
+import hmac
-def dumps(obj, secret = None, compress = False, extra_salt = ''):
+def dumps(obj, key = None, compress = False, extra_key = ''):
"""
- Returns URL-safe, sha1 signed base64 compressed pickle. If secret is
+ Returns URL-safe, sha1 signed base64 compressed pickle. If key is
None, settings.SECRET_KEY is used instead.
If compress is True (not the default) checks if compressing using zlib can
save some space. Prepends a '.' to signify compression. This is included
in the signature, to protect against zip bombs.
- extra_salt can be used to further salt the hash, in case you're worried
+ extra_key can be used to further salt the hash, in case you're worried
that the NSA might try to brute-force your SHA-1 protected secret.
"""
pickled = pickle.dumps(obj)
@@ -61,14 +62,14 @@ def dumps(obj, secret = None, compress = False, extra_salt = ''):
base64d = encode(pickled).strip('=')
if is_compressed:
base64d = '.' + base64d
- return sign(base64d, (secret or settings.SECRET_KEY) + extra_salt)
+ return sign(base64d, (key or settings.SECRET_KEY) + extra_key)
-def loads(s, secret = None, extra_salt = ''):
+def loads(s, key = None, extra_key = ''):
"Reverse of dumps(), raises ValueError if signature fails"
if isinstance(s, unicode):
s = s.encode('utf8') # base64 works on bytestrings, not on unicodes
try:
- base64d = unsign(s, (secret or settings.SECRET_KEY) + extra_salt)
+ base64d = unsign(s, (key or settings.SECRET_KEY) + extra_key)
except ValueError:
raise
decompress = False
@@ -99,7 +100,7 @@ def sign(value, key = None):
'sign() needs bytestring, not unicode: %s' % repr(value)
if key is None:
key = settings.SECRET_KEY
- return value + '.' + base64_sha1(value + key)
+ return value + '.' + base64_hmac(value, key)
def unsign(signed_value, key = None):
if isinstance(signed_value, unicode):
@@ -109,10 +110,10 @@ def unsign(signed_value, key = None):
if not '.' in signed_value:
raise BadSignature, 'Missing sig (no . found in value)'
value, sig = signed_value.rsplit('.', 1)
- if base64_sha1(value + key) == sig:
+ if base64_hmac(value, key) == sig:
return value
else:
raise BadSignature, 'Signature failed: %s' % sig
-def base64_sha1(s):
- return encode(sha_constructor(s).digest())
+def base64_hmac(value, key):
+ return encode(hmac.new(key, value, sha_constructor).digest())
@@ -162,7 +162,7 @@ def testLogin(self):
# Decrypt the cookie and check it's the right thing
cookie = response.cookies['openid'].value
openid = signed.loads(
- cookie, extra_salt = MyCookieConsumer().extra_salt
+ cookie, extra_key = MyCookieConsumer().extra_salt
)
self.assertEqual(openid.openid, 'http://simonwillison.net/')
@@ -15,11 +15,11 @@ def test_sign_uses_correct_key(self):
s = 'This is a string'
self.assertEqual(
signed.sign(s),
- s + '.' + signed.base64_sha1(s + settings.SECRET_KEY)
+ s + '.' + signed.base64_hmac(s, settings.SECRET_KEY)
)
self.assertEqual(
signed.sign(s, 'sekrit'),
- s + '.' + signed.base64_sha1(s + 'sekrit')
+ s + '.' + signed.base64_hmac(s, 'sekrit')
)
def sign_is_reversible(self):

0 comments on commit 8abfe3e

Please sign in to comment.