Mercurial > hg
annotate tests/httpserverauth.py @ 42016:b900b392c1cc
perf: document perfparents
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Mon, 25 Mar 2019 08:41:02 -0700 |
parents | 46432c04f010 |
children | 2372284d9457 |
rev | line source |
---|---|
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
1 from __future__ import absolute_import |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
2 |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
3 import base64 |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
4 import hashlib |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
5 |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
6 from mercurial.hgweb import common |
41587
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
7 from mercurial import ( |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
8 node, |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
9 ) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
10 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
11 def parse_keqv_list(req, l): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
12 """Parse list of key=value strings where keys are not duplicated.""" |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
13 parsed = {} |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
14 for elt in l: |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
15 k, v = elt.split(b'=', 1) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
16 if v[0:1] == b'"' and v[-1:] == b'"': |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
17 v = v[1:-1] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
18 parsed[k] = v |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
19 return parsed |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
20 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
21 class digestauthserver(object): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
22 def __init__(self): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
23 self._user_hashes = {} |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
24 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
25 def gethashers(self): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
26 def _md5sum(x): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
27 m = hashlib.md5() |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
28 m.update(x) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
29 return node.hex(m.digest()) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
30 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
31 h = _md5sum |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
32 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
33 kd = lambda s, d, h=h: h(b"%s:%s" % (s, d)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
34 return h, kd |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
35 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
36 def adduser(self, user, password, realm): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
37 h, kd = self.gethashers() |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
38 a1 = h(b'%s:%s:%s' % (user, realm, password)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
39 self._user_hashes[(user, realm)] = a1 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
40 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
41 def makechallenge(self, realm): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
42 # We aren't testing the protocol here, just that the bytes make the |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
43 # proper round trip. So hardcoded seems fine. |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
44 nonce = b'064af982c5b571cea6450d8eda91c20d' |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
45 return b'realm="%s", nonce="%s", algorithm=MD5, qop="auth"' % (realm, |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
46 nonce) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
47 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
48 def checkauth(self, req, header): |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
49 log = req.rawenv[b'wsgi.errors'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
50 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
51 h, kd = self.gethashers() |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
52 resp = parse_keqv_list(req, header.split(b', ')) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
53 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
54 if resp.get(b'algorithm', b'MD5').upper() != b'MD5': |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
55 log.write(b'Unsupported algorithm: %s' % resp.get(b'algorithm')) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
56 raise common.ErrorResponse(common.HTTP_FORBIDDEN, |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
57 b"unknown algorithm") |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
58 user = resp[b'username'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
59 realm = resp[b'realm'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
60 nonce = resp[b'nonce'] |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
61 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
62 ha1 = self._user_hashes.get((user, realm)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
63 if not ha1: |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
64 log.write(b'No hash found for user/realm "%s/%s"' % (user, realm)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
65 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"bad user") |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
66 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
67 qop = resp.get(b'qop', b'auth') |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
68 if qop != b'auth': |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
69 log.write(b"Unsupported qop: %s" % qop) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
70 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"bad qop") |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
71 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
72 cnonce, ncvalue = resp.get(b'cnonce'), resp.get(b'nc') |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
73 if not cnonce or not ncvalue: |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
74 log.write(b'No cnonce (%s) or ncvalue (%s)' % (cnonce, ncvalue)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
75 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"no cnonce") |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
76 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
77 a2 = b'%s:%s' % (req.method, resp[b'uri']) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
78 noncebit = b"%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, h(a2)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
79 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
80 respdig = kd(ha1, noncebit) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
81 if respdig != resp[b'response']: |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
82 log.write(b'User/realm "%s/%s" gave %s, but expected %s' |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
83 % (user, realm, resp[b'response'], respdig)) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
84 return False |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
85 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41585
diff
changeset
|
86 return True |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
87 |
41589
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
88 digest = digestauthserver() |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
89 |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
90 def perform_authentication(hgweb, req, op): |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
91 auth = req.headers.get(b'Authorization') |
41589
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
92 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
93 if req.headers.get(b'X-HgTest-AuthType') == b'Digest': |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
94 if not auth: |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
95 challenge = digest.makechallenge(b'mercurial') |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
96 raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, b'who', |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
97 [(b'WWW-Authenticate', b'Digest %s' % challenge)]) |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
98 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
99 if not digest.checkauth(req, auth[7:]): |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
100 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no') |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
101 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
102 return |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
103 |
41585
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
104 if not auth: |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
105 raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, b'who', |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
106 [(b'WWW-Authenticate', b'Basic Realm="mercurial"')]) |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
107 |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
108 if base64.b64decode(auth.split()[1]).split(b':', 1) != [b'user', b'pass']: |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
109 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no') |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
110 |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
111 def extsetup(ui): |
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
112 common.permhooks.insert(0, perform_authentication) |
41589
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41587
diff
changeset
|
113 digest.adduser(b'user', b'pass', b'mercurial') |