[issue3336] HTTP push should use credentials if supplied or ask for them if POST fails with 401 after GET got 200

Daniel Neugebauer bugs at mercurial.selenic.com
Sun Mar 25 10:59:57 CDT 2012


New submission from Daniel Neugebauer <energiequant at energiequant.de>:

I'm serving a semi-public repository through Apache + mod_wsgi + hgwebdir 
which has write access restricted in Apache by using the following 
directives:

  <Location /repos/hg/main/>
    AuthType Basic
    AuthName "Mercurial repository"
    AuthUserFile /mnt/data/hg/access/users
    AuthGroupFile /mnt/data/hg/access/groups

    <Limit GET>
      Allow from all
    </Limit>

    <Limit POST PUT>
      Require group main-rw
    </Limit>
  </Location>

This allows read access for anonymous users while it restricts write 
operations (not in Mercurial but Apache) to logged-in users of group "main-
rw".

If I clone a repository, I'm not asked for credentials (as intended). If I 
try to push, I'm only getting "abort: authorization failed", no matter if I 
specify credentials in the URL or not (tried directly on the command line 
and also in hgrc as default path).

On server-side, I can see the commands "capabilities", "heads" and 
"branchmap" being run through GET requests, then one POST request with 
command "unbundle" which fails with HTTP status code 401. The client aborts 
at this point. The access log would show the username supplied in a request 
if present but doesn't list anything for these requests, so the client 
simply doesn't send credentials although they are explicitely included in 
the URL I supply to it (http://user:pass@repository.domain.com/repos/hg/
main).

Looking at the source code, there currently doesn't seem to be a way to ask 
for credentials when GETs were successful but a later POST fails. It surely 
would be nice if Mercurial would do so or at least try to use the already 
supplied credentials (I don't really understand why they are omitted in the 
request, especially since I get a message "pushing to http://user:***@..." 
nevertheless which just isn't what actually appears to happen).

The following traceback is for Mercurial 2.1.1:

$ hg push --trace http://user:pass@repository.domain.com/repos/hg/main
pushing to http://user:***@repository.domain.com/repos/hg/main
searching for changes
Traceback (most recent call last):
  File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 87, 
in _runcatch
    return _dispatch(req)
  File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 
683, in _dispatch
    cmdpats, cmdoptions)
  File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 
465, in runcommand
    ret = _runcommand(ui, options, cmd, d)
  File "/usr/lib64/python2.7/site-packages/mercurial/extensions.py", line 
184, in wrap
    return wrapper(origfn, *args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/hgext/zeroconf/__init__.py", 
line 171, in cleanupafterdispatch
    return orig(ui, options, cmd, cmdfunc)
  File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 
737, in _runcommand
    return checkargs()
  File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 
691, in checkargs
    return cmdfunc()
  File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 
680, in <lambda>
    d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
  File "/usr/lib64/python2.7/site-packages/mercurial/util.py", line 456, in 
check
    return func(*args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/mercurial/extensions.py", line 
139, in wrap
    util.checksignature(origfn), *args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/mercurial/util.py", line 456, in 
check
    return func(*args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/hgext/mq.py", line 3337, in 
mqcommand
    return orig(ui, repo, *args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/mercurial/util.py", line 456, in 
check
    return func(*args, **kwargs)
  File "/usr/lib64/python2.7/site-packages/mercurial/commands.py", line 
4431, in push
    newbranch=opts.get('new_branch'))
  File "/usr/lib64/python2.7/site-packages/mercurial/localrepo.py", line 
1669, in push
    ret = remote.unbundle(cg, remoteheads, 'push')
  File "/usr/lib64/python2.7/site-packages/mercurial/wireproto.py", line 
304, in unbundle
    ret, output = self._callpush("unbundle", cg, heads=heads)
  File "/usr/lib64/python2.7/site-packages/mercurial/httprepo.py", line 
199, in _callpush
    r = self._call(cmd, data=fp, headers=headers, **args)
  File "/usr/lib64/python2.7/site-packages/mercurial/httprepo.py", line 
169, in _call
    fp = self._callstream(cmd, **args)
  File "/usr/lib64/python2.7/site-packages/mercurial/httprepo.py", line 
120, in _callstream
    raise util.Abort(_('authorization failed'))
Abort: authorization failed
abort: authorization failed

----------
messages: 19452
nosy: dneuge
priority: feature
status: unread
title: HTTP push should use credentials if supplied or ask for them if POST fails with 401 after GET got 200

____________________________________________________
Mercurial issue tracker <bugs at mercurial.selenic.com>
<http://mercurial.selenic.com/bts/issue3336>
____________________________________________________


More information about the Mercurial-devel mailing list