diff --git a/mercurial_keyring.py b/mercurial_keyring.py --- a/mercurial_keyring.py +++ b/mercurial_keyring.py @@ -17,6 +17,7 @@ except: from mercurial.httprepo import passwordmgr from mercurial.httprepo import httprepository from mercurial import mail +from urllib2 import AbstractBasicAuthHandler, AbstractDigestAuthHandler # mercurial.demandimport incompatibility workaround, # would cause gnomekeyring, one of the possible @@ -35,9 +36,13 @@ KEYRING_SERVICE = "Mercurial" ############################################################ -def monkeypatch_method(cls): +def monkeypatch_method(cls,fname=None): def decorator(func): - setattr(cls, func.__name__, func) + local_fname = fname + if local_fname is None: + local_fname = func.__name__ + setattr(func, "orig", getattr(cls, local_fname, None)) + setattr(cls, local_fname, func) return func return decorator @@ -100,7 +105,7 @@ class HTTPPasswordHandler(object): self.pwd_cache = {} self.last_reply = None - def find_auth(self, pwmgr, realm, authuri): + def find_auth(self, pwmgr, realm, authuri, req): """ Actual implementation of find_user_password - different ways of obtaining the username and password. @@ -113,7 +118,8 @@ class HTTPPasswordHandler(object): # reusing bad password indifinitely). after_bad_auth = (self.last_reply \ and (self.last_reply['realm'] == realm) \ - and (self.last_reply['authuri'] == authuri)) + and (self.last_reply['authuri'] == authuri) \ + and (self.last_reply['req'] == req)) if after_bad_auth: _debug(ui, _("Working after bad authentication, cached passwords not used %s") % str(self.last_reply)) @@ -127,7 +133,7 @@ class HTTPPasswordHandler(object): if user and pwd: _debug_reply(ui, _("Auth data found in repository URL"), base_url, user, pwd) - self.last_reply = dict(realm=realm,authuri=authuri,user=user) + self.last_reply = dict(realm=realm,authuri=authuri,user=user,req=req) return user, pwd # Loading .hg/hgrc [auth] section contents. If prefix is given, @@ -147,7 +153,7 @@ class HTTPPasswordHandler(object): user, pwd = cached_auth _debug_reply(ui, _("Cached auth data found"), base_url, user, pwd) - self.last_reply = dict(realm=realm,authuri=authuri,user=user) + self.last_reply = dict(realm=realm,authuri=authuri,user=user,req=req) return user, pwd if auth_user: @@ -158,7 +164,7 @@ class HTTPPasswordHandler(object): self.pwd_cache[cache_key] = user, pwd _debug_reply(ui, _("Auth data set in .hg/hgrc"), base_url, user, pwd) - self.last_reply = dict(realm=realm,authuri=authuri,user=user) + self.last_reply = dict(realm=realm,authuri=authuri,user=user,req=req) return user, pwd else: _debug(ui, _("Username found in .hg/hgrc: %s") % user) @@ -173,7 +179,7 @@ class HTTPPasswordHandler(object): self.pwd_cache[cache_key] = user, pwd _debug_reply(ui, _("Keyring password found"), base_url, user, pwd) - self.last_reply = dict(realm=realm,authuri=authuri,user=user) + self.last_reply = dict(realm=realm,authuri=authuri,user=user,req=req) return user, pwd else: _debug(ui, _("Password not present in the keyring")) @@ -209,7 +215,7 @@ class HTTPPasswordHandler(object): _debug_reply(ui, _("Manually entered password"), base_url, user, pwd) - self.last_reply = dict(realm=realm,authuri=authuri,user=user) + self.last_reply = dict(realm=realm,authuri=authuri,user=user,req=req) return user, pwd def load_hgrc_auth(self, ui, base_url, user): @@ -312,7 +318,28 @@ def find_user_password(self, realm, auth if not hasattr(self, '_pwd_handler'): self._pwd_handler = HTTPPasswordHandler() - return self._pwd_handler.find_auth(self, realm, authuri) + if hasattr(self, '_http_req'): + req = self._http_req + else: + req = None + + return self._pwd_handler.find_auth(self, realm, authuri, req) + +@monkeypatch_method(AbstractBasicAuthHandler, "http_error_auth_reqed") +def basic_http_error_auth_reqed(self, authreq, host, req, headers): + self.passwd._http_req = req + try: + return basic_http_error_auth_reqed.orig(self, authreq, host, req, headers) + finally: + self.passwd._http_req = None + +@monkeypatch_method(AbstractDigestAuthHandler, "http_error_auth_reqed") +def digest_http_error_auth_reqed(self, authreq, host, req, headers): + self.passwd._http_req = req + try: + return digest_http_error_auth_reqed.orig(self, authreq, host, req, headers) + finally: + self.passwd._http_req = None ############################################################