Mercurial > public > mercurial-scm > hg-stable
annotate tests/httpserverauth.py @ 41602:46432c04f010
tests: enable HTTP digest testing
I suppose we could spin the client side extension off to a *.py file if it gets
more use. I was basically just looking to avoid killing the server and
relaunching it just to change authentication schemes, because that doesn't
always work on Windows.
The test changes capture the problem with py3.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Tue, 05 Feb 2019 16:47:19 -0500 |
parents | ccaa52865fac |
children | 2372284d9457 |
rev | line source |
---|---|
41598
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 |
41600
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
4 import hashlib |
41598
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 |
41600
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
diff
changeset
|
8 node, |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
9 ) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
10 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
diff
changeset
|
13 parsed = {} |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
19 return parsed |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
20 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
24 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
30 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
31 h = _md5sum |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
32 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
diff
changeset
|
35 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
40 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
46 nonce) |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
47 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
diff
changeset
|
50 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
diff
changeset
|
53 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
61 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
66 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
71 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
76 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
diff
changeset
|
79 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
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:
41598
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:
41598
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:
41598
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:
41598
diff
changeset
|
84 return False |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
85 |
ccaa52865fac
tests: add code to handle HTTP digests on the server side
Matt Harbison <matt_harbison@yahoo.com>
parents:
41598
diff
changeset
|
86 return True |
41598
549af2fa089f
tests: extract the http server authentication extension to a single module
Matt Harbison <matt_harbison@yahoo.com>
parents:
diff
changeset
|
87 |
41602
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
88 digest = digestauthserver() |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
89 |
41598
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') |
41602
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
92 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
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:
41600
diff
changeset
|
94 if not auth: |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
95 challenge = digest.makechallenge(b'mercurial') |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
96 raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, b'who', |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
97 [(b'WWW-Authenticate', b'Digest %s' % challenge)]) |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
98 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
99 if not digest.checkauth(req, auth[7:]): |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
100 raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no') |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
101 |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
102 return |
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
103 |
41598
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) |
41602
46432c04f010
tests: enable HTTP digest testing
Matt Harbison <matt_harbison@yahoo.com>
parents:
41600
diff
changeset
|
113 digest.adduser(b'user', b'pass', b'mercurial') |