Skip to content

Commit

Permalink
pep8
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Sep 23, 2014
1 parent c7a5994 commit 4657d5b
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 71 deletions.
18 changes: 13 additions & 5 deletions flask_httpauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
from random import Random, SystemRandom
from flask import request, make_response, session


class HTTPAuth(object):
def __init__(self):
def default_get_password(username):
return None

def default_auth_error():
return "Unauthorized Access"

Expand Down Expand Up @@ -61,6 +63,7 @@ def decorated(*args, **kwargs):
def username(self):
return request.authorization.username


class HTTPBasicAuth(HTTPAuth):
def __init__(self):
super(HTTPBasicAuth, self).__init__()
Expand All @@ -76,7 +79,7 @@ def verify_password(self, f):
return f

def authenticate_header(self):
return 'Basic realm="' + self.realm + '"'
return 'Basic realm="{0}"'.format(self.realm)

def authenticate(self, auth, stored_password):
client_password = auth.password
Expand All @@ -86,9 +89,11 @@ def authenticate(self, auth, stored_password):
try:
client_password = self.hash_password_callback(client_password)
except TypeError:
client_password = self.hash_password_callback(auth.username, client_password)
client_password = self.hash_password_callback(auth.username,
client_password)
return client_password == stored_password


class HTTPDigestAuth(HTTPAuth):
def __init__(self):
super(HTTPDigestAuth, self).__init__()
Expand All @@ -104,12 +109,15 @@ def get_nonce(self):
def authenticate_header(self):
session["auth_nonce"] = self.get_nonce()
session["auth_opaque"] = self.get_nonce()
return 'Digest realm="' + self.realm + '",nonce="' + session["auth_nonce"] + '",opaque="' + session["auth_opaque"] + '"'
return 'Digest realm="{0}",nonce="{1}",opaque="{2}"'.format(
self.realm, session["auth_nonce"], session["auth_opaque"])

def authenticate(self, auth, password):
if not auth.username or not auth.realm or not auth.uri or not auth.nonce or not auth.response or not password:
if not auth.username or not auth.realm or not auth.uri \
or not auth.nonce or not auth.response or not password:
return False
if auth.nonce != session.get("auth_nonce") or auth.opaque != session.get("auth_opaque"):
if auth.nonce != session.get("auth_nonce") or \
auth.opaque != session.get("auth_opaque"):
return False
a1 = auth.username + ":" + auth.realm + ":" + password
ha1 = md5(a1.encode('utf-8')).hexdigest()
Expand Down
181 changes: 115 additions & 66 deletions test_httpauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
from flask.ext.httpauth import HTTPBasicAuth, HTTPDigestAuth
from werkzeug.http import parse_dict_header


def md5(str):
if type(str).__name__ == 'str':
str = str.encode('utf-8')
return basic_md5(str)


class HTTPAuthTestCase(unittest.TestCase):
def setUp(self):
app = Flask(__name__)
Expand All @@ -35,7 +37,7 @@ def get_basic_password(username):
return None

@basic_auth_my_realm.get_password
def get_basic_password(username):
def get_basic_password_2(username):
if username == 'john':
return 'johnhello'
elif username == 'susan':
Expand Down Expand Up @@ -82,7 +84,7 @@ def get_digest_password(username):
return None

@digest_auth_my_realm.get_password
def get_digest_password(username):
def get_digest_password_2(username):
if username == 'susan':
return 'hello'
elif username == 'john':
Expand Down Expand Up @@ -134,86 +136,103 @@ def digest_auth_my_realm_route():

def test_no_auth(self):
response = self.client.get('/')
self.assertTrue(response.data.decode('utf-8') == 'index')
self.assertEqual(response.data.decode('utf-8'), 'index')

def test_basic_auth_prompt(self):
response = self.client.get('/basic')
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(response.headers['WWW-Authenticate'] == 'Basic realm="Authentication Required"')
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertEqual(response.headers['WWW-Authenticate'],
'Basic realm="Authentication Required"')

def test_basic_auth_ignore_options(self):
response = self.client.options('/basic')
self.assertTrue(response.status_code == 200)
self.assertEqual(response.status_code, 200)
self.assertTrue('WWW-Authenticate' not in response.headers)

def test_basic_auth_prompt_with_custom_realm(self):
response = self.client.get('/basic-with-realm')
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(response.headers['WWW-Authenticate'] == 'Basic realm="My Realm"')
self.assertTrue(response.data.decode('utf-8') == 'custom error')
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertEqual(response.headers['WWW-Authenticate'],
'Basic realm="My Realm"')
self.assertEqual(response.data.decode('utf-8'), 'custom error')

def test_basic_auth_login_valid(self):
response = self.client.get('/basic',
headers = { 'Authorization': 'Basic ' + base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n') })
self.assertTrue(response.data.decode('utf-8') == 'basic_auth:john')
creds = base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic', headers={'Authorization': 'Basic ' + creds})
self.assertEqual(response.data.decode('utf-8'), 'basic_auth:john')

def test_basic_auth_login_valid_with_hash1(self):
response = self.client.get('/basic-custom',
headers = { 'Authorization': 'Basic ' + base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n') })
self.assertTrue(response.data.decode('utf-8') == 'basic_custom_auth:john')
creds = base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic-custom', headers={'Authorization': 'Basic ' + creds})
self.assertEqual(response.data.decode('utf-8'),
'basic_custom_auth:john')

def test_basic_auth_login_valid_with_hash2(self):
response = self.client.get('/basic-with-realm',
headers = { 'Authorization': 'Basic ' + base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n') })
self.assertTrue(response.data.decode('utf-8') == 'basic_auth_my_realm:john')
creds = base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic-with-realm', headers={'Authorization': 'Basic ' + creds})
self.assertEqual(response.data.decode('utf-8'),
'basic_auth_my_realm:john')

def test_basic_auth_login_invalid(self):
response = self.client.get('/basic-with-realm',
headers = { 'Authorization': 'Basic ' + base64.b64encode(b'john:bye').decode('utf-8').strip('\r\n') })
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(response.headers['WWW-Authenticate'] == 'Basic realm="My Realm"')
creds = base64.b64encode(b'john:bye').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic-with-realm', headers={'Authorization': 'Basic ' + creds})
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertEqual(response.headers['WWW-Authenticate'],
'Basic realm="My Realm"')

def test_basic_custom_auth_login_valid(self):
response = self.client.get('/basic-custom',
headers = { 'Authorization': 'Basic ' + base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n') })
self.assertTrue(response.data == b'basic_custom_auth:john')
creds = base64.b64encode(b'john:hello').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic-custom', headers={'Authorization': 'Basic ' + creds})
self.assertEqual(response.data, b'basic_custom_auth:john')

def test_basic_custom_auth_login_invalid(self):
response = self.client.get('/basic-custom',
headers = { "Authorization": "Basic " + base64.b64encode(b'john:bye').decode('utf-8').strip('\r\n') })
self.assertTrue(response.status_code == 401)
self.assertTrue("WWW-Authenticate" in response.headers)
creds = base64.b64encode(b'john:bye').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic-custom', headers={"Authorization": "Basic " + creds})
self.assertEqual(response.status_code, 401)
self.assertIn("WWW-Authenticate", response.headers)

def test_verify_auth_login_valid(self):
response = self.client.get('/basic-verify',
headers = { 'Authorization': 'Basic ' + base64.b64encode(b'susan:bye').decode('utf-8').strip('\r\n') })
self.assertTrue(response.data == b'basic_verify_auth:susan')
creds = base64.b64encode(b'susan:bye').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic-verify', headers={'Authorization': 'Basic ' + creds})
self.assertEqual(response.data, b'basic_verify_auth:susan')

def test_verify_auth_login_invalid(self):
response = self.client.get('/basic-verify',
headers = { 'Authorization': 'Basic ' + base64.b64encode(b'john:bye').decode('utf-8').strip('\r\n') })
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
creds = base64.b64encode(b'john:bye').decode('utf-8').strip('\r\n')
response = self.client.get(
'/basic-verify', headers={'Authorization': 'Basic ' + creds})
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)

def test_digest_auth_prompt(self):
response = self.client.get('/digest')
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(re.match(r'^Digest realm="Authentication Required",nonce="[0-9a-f]+",opaque="[0-9a-f]+"$', response.headers['WWW-Authenticate']))
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertTrue(re.match(r'^Digest realm="Authentication Required",'
r'nonce="[0-9a-f]+",opaque="[0-9a-f]+"$',
response.headers['WWW-Authenticate']))

def test_digest_auth_ignore_options(self):
response = self.client.options('/digest')
self.assertTrue(response.status_code == 200)
self.assertEqual(response.status_code, 200)
self.assertTrue('WWW-Authenticate' not in response.headers)

def test_digest_auth_prompt_with_custom_realm(self):
response = self.client.get('/digest-with-realm')
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(re.match(r'^Digest realm="My Realm",nonce="[0-9a-f]+",opaque="[0-9a-f]+"$', response.headers['WWW-Authenticate']))
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertTrue(re.match(r'^Digest realm="My Realm",nonce="[0-9a-f]+",'
r'opaque="[0-9a-f]+"$',
response.headers['WWW-Authenticate']))

def test_digest_auth_login_valid(self):
response = self.client.get('/digest')
Expand All @@ -229,9 +248,15 @@ def test_digest_auth_login_valid(self):
a3 = ha1 + ':' + d['nonce'] + ':' + ha2
auth_response = md5(a3).hexdigest()

response = self.client.get('/digest',
headers = { 'Authorization': 'Digest username="john",realm="' + d['realm'] + '",nonce="' + d['nonce'] + '",uri="/digest",response="' + auth_response + '",opaque="' + d['opaque'] + '"' })
self.assertTrue(response.data == b'digest_auth:john')
response = self.client.get(
'/digest', headers={
'Authorization': 'Digest username="john",realm="{0}",'
'nonce="{1}",uri="/digest",response="{2}",'
'opaque="{3}"'.format(d['realm'],
d['nonce'],
auth_response,
d['opaque'])})
self.assertEqual(response.data, b'digest_auth:john')

def test_digest_auth_login_bad_realm(self):
response = self.client.get('/digest')
Expand All @@ -247,22 +272,37 @@ def test_digest_auth_login_bad_realm(self):
a3 = ha1 + ':' + d['nonce'] + ':' + ha2
auth_response = md5(a3).hexdigest()

response = self.client.get('/digest',
headers = { 'Authorization': 'Digest username="john",realm="' + d['realm'] + '",nonce="' + d['nonce'] + '",uri="/digest",response="' + auth_response + '",opaque="' + d['opaque'] + '"' })
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(re.match(r'^Digest realm="Authentication Required",nonce="[0-9a-f]+",opaque="[0-9a-f]+"$', response.headers['WWW-Authenticate']))
response = self.client.get(
'/digest', headers={
'Authorization': 'Digest username="john",realm="{0}",'
'nonce="{1}",uri="/digest",response="{2}",'
'opaque="{3}"'.format(d['realm'],
d['nonce'],
auth_response,
d['opaque'])})
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertTrue(re.match(r'^Digest realm="Authentication Required",'
r'nonce="[0-9a-f]+",opaque="[0-9a-f]+"$',
response.headers['WWW-Authenticate']))

def test_digest_auth_login_invalid(self):
response = self.client.get('/digest-with-realm',
headers = { "Authorization": 'Digest username="susan",realm="My Realm",nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",uri="/digest-with-realm",response="ca306c361a9055b968810067a37fb8cb",opaque="5ccc069c403ebaf9f0171e9517f40e41"' })
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(re.match(r'^Digest realm="My Realm",nonce="[0-9a-f]+",opaque="[0-9a-f]+"$', response.headers['WWW-Authenticate']))
response = self.client.get(
'/digest-with-realm', headers={
"Authorization": 'Digest username="susan",realm="My Realm",'
'nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",'
'uri="/digest-with-realm",'
'response="ca306c361a9055b968810067a37fb8cb",'
'opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertTrue(re.match(r'^Digest realm="My Realm",nonce="[0-9a-f]+",'
r'opaque="[0-9a-f]+"$',
response.headers['WWW-Authenticate']))

def test_digest_auth_login_invalid2(self):
response = self.client.get('/digest')
self.assertTrue(response.status_code == 401)
self.assertEqual(response.status_code, 401)
header = response.headers.get('WWW-Authenticate')
auth_type, auth_info = header.split(None, 1)
d = parse_dict_header(auth_info)
Expand All @@ -274,14 +314,23 @@ def test_digest_auth_login_invalid2(self):
a3 = ha1 + ':' + d['nonce'] + ':' + ha2
auth_response = md5(a3).hexdigest()

response = self.client.get('/digest',
headers = { 'Authorization': 'Digest username="david",realm="' + d['realm'] + '",nonce="' + d['nonce'] + '",uri="/digest",response="' + auth_response + '",opaque="' + d['opaque'] + '"' })
self.assertTrue(response.status_code == 401)
self.assertTrue('WWW-Authenticate' in response.headers)
self.assertTrue(re.match(r'^Digest realm="Authentication Required",nonce="[0-9a-f]+",opaque="[0-9a-f]+"$', response.headers['WWW-Authenticate']))
response = self.client.get(
'/digest', headers={
'Authorization': 'Digest username="david",realm="{0}",'
'nonce="{1}",uri="/digest",response="{2}",'
'opaque="{3}"'.format(d['realm'],
d['nonce'],
auth_response,
d['opaque'])})
self.assertEqual(response.status_code, 401)
self.assertIn('WWW-Authenticate', response.headers)
self.assertTrue(re.match(r'^Digest realm="Authentication Required",'
r'nonce="[0-9a-f]+",opaque="[0-9a-f]+"$',
response.headers['WWW-Authenticate']))


def suite():
return unittest.makeSuite(HTTPAuthTestCase)

if __name__ == '__main__':
unittest.main(defaultTest = 'suite')
unittest.main(defaultTest='suite')

0 comments on commit 4657d5b

Please sign in to comment.