summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-04-21 15:57:41 +0200
committerVictor Stinner <victor.stinner@gmail.com>2015-04-21 15:57:41 +0200
commitbdd1b0d7eec75e3a29564d11ac92b6588ea7eba5 (patch)
tree6ee1e8ba1d6834f343d960aaa3b3868b594d1d29
parent8bd799e33c874f88091b3a16b5307ead22f1ee3a (diff)
downloadpaste-git-bdd1b0d7eec75e3a29564d11ac92b6588ea7eba5.tar.gz
Port paste.auth to Python 3
* md5() and hmac expects bytes: on Python 3, encode text to utf-8 * Don't compare None with int * HTTP body must be bytes
-rw-r--r--paste/auth/cookie.py17
-rw-r--r--paste/auth/digest.py29
-rw-r--r--tests/test_auth/test_auth_cookie.py6
-rw-r--r--tests/test_auth/test_auth_digest.py8
4 files changed, 46 insertions, 14 deletions
diff --git a/paste/auth/cookie.py b/paste/auth/cookie.py
index 14b1fd8..8f11d1b 100644
--- a/paste/auth/cookie.py
+++ b/paste/auth/cookie.py
@@ -74,7 +74,10 @@ class CookieTooLarge(RuntimeError):
_all_chars = ''.join([chr(x) for x in range(0, 255)])
def new_secret():
""" returns a 64 byte secret """
- return ''.join(random.sample(_all_chars, 64))
+ secret = ''.join(random.sample(_all_chars, 64))
+ if six.PY3:
+ secret = secret.encode('utf8')
+ return secret
class AuthCookieSigner(object):
"""
@@ -137,12 +140,16 @@ class AuthCookieSigner(object):
need to be escaped and quoted). The expiration of this
cookie is handled server-side in the auth() function.
"""
+ timestamp = make_time(time.time() + 60*self.timeout)
+ if six.PY3:
+ content = content.encode('utf8')
+ timestamp = timestamp.encode('utf8')
cookie = base64.encodestring(
hmac.new(self.secret, content, sha1).digest() +
- make_time(time.time() + 60*self.timeout) +
+ timestamp +
content)
- cookie = cookie.replace("/", "_").replace("=", "~")
- cookie = cookie.replace('\n', '').replace('\r', '')
+ cookie = cookie.replace(b"/", b"_").replace(b"=", b"~")
+ cookie = cookie.replace(b'\n', b'').replace(b'\r', b'')
if len(cookie) > self.maxlen:
raise CookieTooLarge(content, cookie)
return cookie
@@ -298,6 +305,8 @@ class AuthCookieHandler(object):
if content:
content = ";".join(content)
content = self.signer.sign(content)
+ if six.PY3:
+ content = content.decode('utf8')
cookie = '%s=%s; Path=/;' % (self.cookie_name, content)
if 'https' == environ['wsgi.url_scheme']:
cookie += ' secure;'
diff --git a/paste/auth/digest.py b/paste/auth/digest.py
index 798f447..85e0362 100644
--- a/paste/auth/digest.py
+++ b/paste/auth/digest.py
@@ -37,6 +37,7 @@ except ImportError:
from md5 import md5
import time, random
from six.moves.urllib.parse import quote as url_quote
+import six
def _split_auth_string(auth_string):
""" split a digest auth string into individual key=value strings """
@@ -68,7 +69,10 @@ def _auth_to_kv_pairs(auth_string):
def digest_password(realm, username, password):
""" construct the appropriate hashcode needed for HTTP digest """
- return md5("%s:%s:%s" % (username, realm, password)).hexdigest()
+ content = "%s:%s:%s" % (username, realm, password)
+ if six.PY3:
+ content = content.encode('utf8')
+ return md5(content).hexdigest()
class AuthDigestAuthenticator(object):
""" implementation of RFC 2617 - HTTP Digest Authentication """
@@ -79,10 +83,16 @@ class AuthDigestAuthenticator(object):
def build_authentication(self, stale = ''):
""" builds the authentication error """
- nonce = md5(
- "%s:%s" % (time.time(), random.random())).hexdigest()
- opaque = md5(
- "%s:%s" % (time.time(), random.random())).hexdigest()
+ content = "%s:%s" % (time.time(), random.random())
+ if six.PY3:
+ content = content.encode('utf-8')
+ nonce = md5(content).hexdigest()
+
+ content = "%s:%s" % (time.time(), random.random())
+ if six.PY3:
+ content = content.encode('utf-8')
+ opaque = md5(content).hexdigest()
+
self.nonce[nonce] = None
parts = {'realm': self.realm, 'qop': 'auth',
'nonce': nonce, 'opaque': opaque }
@@ -97,17 +107,22 @@ class AuthDigestAuthenticator(object):
""" computes the authentication, raises error if unsuccessful """
if not ha1:
return self.build_authentication()
- ha2 = md5('%s:%s' % (method, path)).hexdigest()
+ content = '%s:%s' % (method, path)
+ if six.PY3:
+ content = content.encode('utf8')
+ ha2 = md5(content).hexdigest()
if qop:
chk = "%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)
else:
chk = "%s:%s:%s" % (ha1, nonce, ha2)
+ if six.PY3:
+ chk = chk.encode('utf8')
if response != md5(chk).hexdigest():
if nonce in self.nonce:
del self.nonce[nonce]
return self.build_authentication()
pnc = self.nonce.get(nonce,'00000000')
- if nc <= pnc:
+ if pnc is not None and nc <= pnc:
if nonce in self.nonce:
del self.nonce[nonce]
return self.build_authentication(stale = True)
diff --git a/tests/test_auth/test_auth_cookie.py b/tests/test_auth/test_auth_cookie.py
index 3bff2d8..67465f4 100644
--- a/tests/test_auth/test_auth_cookie.py
+++ b/tests/test_auth/test_auth_cookie.py
@@ -10,6 +10,7 @@ try:
except ImportError:
# Python 2
from Cookie import SimpleCookie
+import six
from paste.auth import cookie
from paste.wsgilib import raw_interactive, dump_environ
@@ -41,7 +42,10 @@ def test_basic(key='key', val='bingles'):
cookie = value.split(";")[0]
(status,headers,content,errors) = \
raw_interactive(app,{'HTTP_COOKIE': cookie})
- assert ("%s: %s" % (key,val.replace("\n","\n "))) in content
+ expected = ("%s: %s" % (key,val.replace("\n","\n ")))
+ if six.PY3:
+ expected = expected.encode('utf8')
+ assert expected in content
def test_roundtrip():
roundtrip = str('').join(map(chr, xrange(256)))
diff --git a/tests/test_auth/test_auth_digest.py b/tests/test_auth/test_auth_digest.py
index a821720..5657782 100644
--- a/tests/test_auth/test_auth_digest.py
+++ b/tests/test_auth/test_auth_digest.py
@@ -8,12 +8,16 @@ from paste.response import header_value
from paste.httpexceptions import *
from paste.httpheaders import AUTHORIZATION, WWW_AUTHENTICATE, REMOTE_USER
import os
+import six
def application(environ, start_response):
content = REMOTE_USER(environ)
start_response("200 OK",(('Content-Type', 'text/plain'),
('Content-Length', len(content))))
- return content
+
+ if six.PY3:
+ content = content.encode('utf8')
+ return [content]
realm = "tag:clarkevans.com,2005:testing"
@@ -46,7 +50,7 @@ def check(username, password, path="/"):
assert False, "Unexpected Status: %s" % status
def test_digest():
- assert 'bing' == check("bing","gnib")
+ assert b'bing' == check("bing","gnib")
assert check("bing","bad") is None
#