-
Notifications
You must be signed in to change notification settings - Fork 4
/
test_httpauth.py
144 lines (109 loc) · 4.22 KB
/
test_httpauth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import re
try: # Python 3
from io import StringIO
from urllib.request import parse_http_list, parse_keqv_list
PY2 = False
except ImportError: # Python 2
from StringIO import StringIO
from urllib2 import parse_http_list, parse_keqv_list
PY2 = True
from httpauth import DictHttpAuthMiddleware, DigestFileHttpAuthMiddleware, md5_str
import pytest
def parse_dict_header(value):
return parse_keqv_list(parse_http_list(value))
def make_auth_response(http_method, uri, realm, nonce, user, password):
HA1 = md5_str(':'.join([user, realm, password]))
HA2 = md5_str(':'.join([http_method, uri]))
return md5_str(':'.join([HA1, nonce, HA2]))
class Response:
"""
Attributes:
- status_code
- headers
- body
"""
def get_nonce(self):
return self.headers['WWW-Authenticate'][-64-1:-1]
def wsgi_app(environ, start_response):
start_response('200 OK', [])
return [environ['PATH_INFO'].encode('ascii')]
def make_dict_app(**kwargs):
return DictHttpAuthMiddleware(
{'user': 'password'},
wsgi_app=wsgi_app,
**kwargs
)
def make_digest_app(**kwargs):
return DigestFileHttpAuthMiddleware(
StringIO('user:myrealm:04cb1ff8d2b798abd28d64db0fffe896\n'),
wsgi_app=wsgi_app,
**kwargs
)
def request(app, url, nonce=None, username=None, password=None, method='GET'):
response = Response()
def start_response(status_code, headers):
response.status_code = int(status_code.split(' ')[0])
response.headers = dict(headers)
env = {
'REQUEST_METHOD': method,
'PATH_INFO': url.split('?')[0] if '?' in url else url,
'QUERY_STRING': url.split('?')[1] if '?' in url else '',
}
if nonce:
env['HTTP_AUTHORIZATION'] = 'Digest username="%s", nonce="%s", response="%s"' \
% (username, nonce, make_auth_response(method, url, app.realm,
nonce, username, password))
iterable = app(env, start_response)
response.body = b''.join(iterable)
return response
def test_no_routes():
app1 = make_dict_app(realm='myrealm')
app2 = make_digest_app()
for app in [app1, app2]:
# Without username/password
response = request(app, '/foo/?a=b')
assert response.status_code == 401
assert re.match('Digest realm="myrealm", nonce="[a-z0-9]{64}"',
response.headers['WWW-Authenticate'])
assert b'Authentication Required' in response.body
assert b'/foo/' not in response.body
# Wrong username/password
for username, password in [
('user', 'wrong password'),
('wrong user', 'password'),
('', 'password'),
('user', ''),
]:
nonce = response.get_nonce()
assert len(nonce) == 64
response = request(app, '/foo/', nonce, username, password)
assert response.status_code == 401
# Correct credentials
response = request(app, '/foo/?a=b', nonce, 'user', 'password')
assert response.status_code == 200
assert b'foo' in response.body
def test_with_routes():
app = make_dict_app(routes=['^/a'])
assert request(app, '/a').status_code == 401
assert request(app, '/b').status_code == 200
def test_without_realm():
app = DictHttpAuthMiddleware({'user': 'password'}, wsgi_app=wsgi_app)
response = request(app, '/')
assert response.status_code == 401
assert 'Digest realm=""' in response.headers['WWW-Authenticate']
def test_invalid_digestfile_1():
with pytest.raises(ValueError):
DigestFileHttpAuthMiddleware(StringIO('u::realm:hash'),
wsgi_app=wsgi_app)
def test_invalid_digestfile_2():
with pytest.raises(ValueError):
DigestFileHttpAuthMiddleware(StringIO('u:realm:hash\nu2:realm2:hash2'),
wsgi_app=wsgi_app)
def test_ticket_1():
""" Reject non-existent users if empty password is sent """
app1 = make_dict_app()
app2 = make_digest_app()
for app in [app1, app2]:
response = request(app, '/')
nonce = response.get_nonce()
assert request(app, '/', nonce, 'not-a-user', '').status_code == 401