##// END OF EJS Templates
tests: fix test-sparse-revlog...
tests: fix test-sparse-revlog This one is not covered by the CIbecause I requires an expensive artifact to be cached. So it goes out of think on regular basis (we should fix that…) The test ouput was affected by e706bb41fdb3 as we filtering now happens sooner, removing for the output.

File last commit:

r49801:642e31cb default
r50521:da636e7a default
Show More
httpserverauth.py
125 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 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
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class digestauthserver:
Matt Harbison
tests: add code to handle HTTP digests on the server side...
r41727 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')