##// END OF EJS Templates
tests: finally fix up test-fuzz-targets.t...
tests: finally fix up test-fuzz-targets.t It's been failing on my workstation for a while, since I have a new enough LLVM that I had the fuzzer goo, but not so new that I actually had FuzzedDataProvider. This is a better solution all around in my opinion. I _believe_ this should let us run these tests on most systems, even those using GCC instead of clang. That said, my one attempt to test this on my macOS laptop failed miserably, and I don't feel like doing more work on this right now. Differential Revision: https://phab.mercurial-scm.org/D7566

File last commit:

r43346:2372284d default
r44267:19da643d default
Show More
httpserverauth.py
127 lines | 3.8 KiB | text/x-python | PythonLexer
/ tests / httpserverauth.py
Matt Harbison
tests: extract the http server authentication extension to a single module...
r41725 from __future__ import absolute_import
import base64
Matt Harbison
tests: add code to handle HTTP digests on the server side...
r41727 import hashlib
Matt Harbison
tests: extract the http server authentication extension to a single module...
r41725
from mercurial.hgweb import common
Augie Fackler
formatting: blacken the codebase...
r43346 from mercurial import node
Matt Harbison
tests: add code to handle HTTP digests on the server side...
r41727
def parse_keqv_list(req, l):
"""Parse list of key=value strings where keys are not duplicated."""
parsed = {}
for elt in l:
k, v = elt.split(b'=', 1)
if v[0:1] == b'"' and v[-1:] == b'"':
v = v[1:-1]
parsed[k] = v
return parsed
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
tests: add code to handle HTTP digests on the server side...
r41727 class digestauthserver(object):
def __init__(self):
self._user_hashes = {}
def gethashers(self):
def _md5sum(x):
m = hashlib.md5()
m.update(x)
return node.hex(m.digest())
h = _md5sum
kd = lambda s, d, h=h: h(b"%s:%s" % (s, d))
return h, kd
def adduser(self, user, password, realm):
h, kd = self.gethashers()
a1 = h(b'%s:%s:%s' % (user, realm, password))
self._user_hashes[(user, realm)] = a1
def makechallenge(self, realm):
# We aren't testing the protocol here, just that the bytes make the
# proper round trip. So hardcoded seems fine.
nonce = b'064af982c5b571cea6450d8eda91c20d'
Augie Fackler
formatting: blacken the codebase...
r43346 return b'realm="%s", nonce="%s", algorithm=MD5, qop="auth"' % (
realm,
nonce,
)
Matt Harbison
tests: add code to handle HTTP digests on the server side...
r41727
def checkauth(self, req, header):
log = req.rawenv[b'wsgi.errors']
h, kd = self.gethashers()
resp = parse_keqv_list(req, header.split(b', '))
if resp.get(b'algorithm', b'MD5').upper() != b'MD5':
log.write(b'Unsupported algorithm: %s' % resp.get(b'algorithm'))
Augie Fackler
formatting: blacken the codebase...
r43346 raise common.ErrorResponse(
common.HTTP_FORBIDDEN, b"unknown algorithm"
)
Matt Harbison
tests: add code to handle HTTP digests on the server side...
r41727 user = resp[b'username']
realm = resp[b'realm']
nonce = resp[b'nonce']
ha1 = self._user_hashes.get((user, realm))
if not ha1:
log.write(b'No hash found for user/realm "%s/%s"' % (user, realm))
raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"bad user")
qop = resp.get(b'qop', b'auth')
if qop != b'auth':
log.write(b"Unsupported qop: %s" % qop)
raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"bad qop")
cnonce, ncvalue = resp.get(b'cnonce'), resp.get(b'nc')
if not cnonce or not ncvalue:
log.write(b'No cnonce (%s) or ncvalue (%s)' % (cnonce, ncvalue))
raise common.ErrorResponse(common.HTTP_FORBIDDEN, b"no cnonce")
a2 = b'%s:%s' % (req.method, resp[b'uri'])
noncebit = b"%s:%s:%s:%s:%s" % (nonce, ncvalue, cnonce, qop, h(a2))
respdig = kd(ha1, noncebit)
if respdig != resp[b'response']:
Augie Fackler
formatting: blacken the codebase...
r43346 log.write(
b'User/realm "%s/%s" gave %s, but expected %s'
% (user, realm, resp[b'response'], respdig)
)
Matt Harbison
tests: add code to handle HTTP digests on the server side...
r41727 return False
return True
Matt Harbison
tests: extract the http server authentication extension to a single module...
r41725
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
tests: enable HTTP digest testing...
r41729 digest = digestauthserver()
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
tests: extract the http server authentication extension to a single module...
r41725 def perform_authentication(hgweb, req, op):
auth = req.headers.get(b'Authorization')
Matt Harbison
tests: enable HTTP digest testing...
r41729
if req.headers.get(b'X-HgTest-AuthType') == b'Digest':
if not auth:
challenge = digest.makechallenge(b'mercurial')
Augie Fackler
formatting: blacken the codebase...
r43346 raise common.ErrorResponse(
common.HTTP_UNAUTHORIZED,
b'who',
[(b'WWW-Authenticate', b'Digest %s' % challenge)],
)
Matt Harbison
tests: enable HTTP digest testing...
r41729
if not digest.checkauth(req, auth[7:]):
raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no')
return
Matt Harbison
tests: extract the http server authentication extension to a single module...
r41725 if not auth:
Augie Fackler
formatting: blacken the codebase...
r43346 raise common.ErrorResponse(
common.HTTP_UNAUTHORIZED,
b'who',
[(b'WWW-Authenticate', b'Basic Realm="mercurial"')],
)
Matt Harbison
tests: extract the http server authentication extension to a single module...
r41725
if base64.b64decode(auth.split()[1]).split(b':', 1) != [b'user', b'pass']:
raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no')
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
tests: extract the http server authentication extension to a single module...
r41725 def extsetup(ui):
common.permhooks.insert(0, perform_authentication)
Matt Harbison
tests: enable HTTP digest testing...
r41729 digest.adduser(b'user', b'pass', b'mercurial')