Add support for Apache Digest authentication for repo init.

repo tool supports only Basic authentication for now. For those
who want to use this tool to manage their own projects, in case
the administrator has configured the Apache server with Digest
authentication method, users will fail to be authenticated when
they run the command 'repo init'.
Add the digest authentication password manager to the handler
list will fix this issue.

Since Git HTTP protocol will require the user be authenticated
for fetch operation first before pushing commits to the remote,
it is unlikely for the administrator to implement anonymous
read (aka pull) access and write access (aka push) for
authenticated user. Both read and write have to be authenticated.
Be aware that the user may have to add an extra line in his
~/.netrc file:
-------------------
account example.com
-------------------
where 'example.com' is the realm for Apache Digest authentication.

Change-Id: I76eb27b205554426d9ce1965deaaf727b87916cd
Signed-off-by: Xiaodong Xu <stid.smth@gmail.com>
This commit is contained in:
Xiaodong Xu 2012-01-31 11:10:09 +08:00 committed by Shawn O. Pearce
parent 76abcc1d1e
commit ae0a36c9a5
2 changed files with 26 additions and 6 deletions

23
main.py
View File

@ -295,6 +295,24 @@ class _BasicAuthHandler(urllib2.HTTPBasicAuthHandler):
self.retried = 0 self.retried = 0
raise raise
class _DigestAuthHandler(urllib2.HTTPDigestAuthHandler):
def http_error_auth_reqed(self, auth_header, host, req, headers):
try:
old_add_header = req.add_header
def _add_header(name, val):
val = val.replace('\n', '')
old_add_header(name, val)
req.add_header = _add_header
return urllib2.AbstractDigestAuthHandler.http_error_auth_reqed(
self, auth_header, host, req, headers)
except:
reset = getattr(self, 'reset_retry_count', None)
if reset is not None:
reset()
elif getattr(self, 'retried', None):
self.retried = 0
raise
def init_http(): def init_http():
handlers = [_UserAgentHandler()] handlers = [_UserAgentHandler()]
@ -303,13 +321,14 @@ def init_http():
n = netrc.netrc() n = netrc.netrc()
for host in n.hosts: for host in n.hosts:
p = n.hosts[host] p = n.hosts[host]
mgr.add_password(None, 'http://%s/' % host, p[0], p[2]) mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
mgr.add_password(None, 'https://%s/' % host, p[0], p[2]) mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
except netrc.NetrcParseError: except netrc.NetrcParseError:
pass pass
except IOError: except IOError:
pass pass
handlers.append(_BasicAuthHandler(mgr)) handlers.append(_BasicAuthHandler(mgr))
handlers.append(_DigestAuthHandler(mgr))
if 'http_proxy' in os.environ: if 'http_proxy' in os.environ:
url = os.environ['http_proxy'] url = os.environ['http_proxy']

9
repo
View File

@ -28,7 +28,7 @@ if __name__ == '__main__':
del magic del magic
# increment this whenever we make important changes to this script # increment this whenever we make important changes to this script
VERSION = (1, 13) VERSION = (1, 14)
# increment this if the MAINTAINER_KEYS block is modified # increment this if the MAINTAINER_KEYS block is modified
KEYRING_VERSION = (1,0) KEYRING_VERSION = (1,0)
@ -154,7 +154,7 @@ def _Init(args):
"""Installs repo by cloning it over the network. """Installs repo by cloning it over the network.
""" """
opt, args = init_optparse.parse_args(args) opt, args = init_optparse.parse_args(args)
if args or not opt.manifest_url: if args:
init_optparse.print_usage() init_optparse.print_usage()
sys.exit(1) sys.exit(1)
@ -311,11 +311,12 @@ def _InitHttp():
n = netrc.netrc() n = netrc.netrc()
for host in n.hosts: for host in n.hosts:
p = n.hosts[host] p = n.hosts[host]
mgr.add_password(None, 'http://%s/' % host, p[0], p[2]) mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
mgr.add_password(None, 'https://%s/' % host, p[0], p[2]) mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
except: except:
pass pass
handlers.append(urllib2.HTTPBasicAuthHandler(mgr)) handlers.append(urllib2.HTTPBasicAuthHandler(mgr))
handlers.append(urllib2.HTTPDigestAuthHandler(mgr))
if 'http_proxy' in os.environ: if 'http_proxy' in os.environ:
url = os.environ['http_proxy'] url = os.environ['http_proxy']