Commits

Eric Blood committed 651673d

Hook into the http auth handlers in order to get access to the http request object and use that object to differentiate between an authentication failure and a new request to the same url.

  • Participants
  • Parent commits eff81be

Comments (0)

Files changed (1)

File mercurial_keyring.py

     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
 
 ############################################################
 
-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
 
         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.
         # 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))
 
         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,
                 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:
                 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)
                 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"))
 
         _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):
     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
 
 ############################################################