[PATCH] allow http authentication information to be specified in the configuration (3)

Sune Foldager sune.foldager at edlund.dk
Tue Apr 7 05:16:36 CDT 2009


The patch below is based on the second version (posted previously), after Benoit's initial suggestions, where the changes are in the class passwordmgr. As I see it, it has the following advantages over the first version (where the changes were in getauthinfo):

1. No need to change other files for it to work.
2. No need to change the arguments to any existing methods.
3. Http auth debug output works correctly.
4. The code is only activated if we receive a challenge, and credentials weren't given on the command line.

The code uses my original loop-through-all-config-items approach, since I find it easier to expand later on, if we were, for example, to introduce special ways to constraint the matching, wildcards or similar. The patch incorporates Benoit's use of netlocsplit to properly handle usernames and passwords containing ':'.

Before matching, I have to strip off the scheme part of the URI, and perform the matching without it. While this has the advantage of not needing to specify multiple identical auth lines for different schemes, it has the potential disadvantage of sending in the wrong auth information in case of a poorly configured server which challenges on HTTP as well as HTTPS (on WAN), or in the unlikely case that the requires auths are different.

The real reason for the strip, though, is a limitation in the configuration format; The ':' character, along with '=', is used to separate keys from values, and there doesn't seem to be any way to escape it unless we invent something. At any rate, I would like to keep the possibility of being able to specify the auth-lines without scheme. This should not be hard to do the way the code is structured.

The patch passes all existing tests.

-- 
Sune Foldager.


# HG changeset patch
# User Sune Foldager <cryo at cyanite.org>
# Date 1239095492 -7200
# Node ID cd26bb06d52ad08f216ad12ac960c1aa4af9fa20
# Parent  685ce2f7ee35dfe29d296f80ba2dff124a1caa63
allow http authentication information to be specified in the configuration

diff -r 685ce2f7ee35 -r cd26bb06d52a mercurial/url.py
--- a/mercurial/url.py	Mon Apr 06 20:11:00 2009 +0200
+++ b/mercurial/url.py	Tue Apr 07 11:11:32 2009 +0200
@@ -105,24 +105,44 @@
             self, realm, authuri)
         user, passwd = authinfo
         if user and passwd:
+            self._writedebug(user, passwd)
             return (user, passwd)
 
-        if not self.ui.interactive:
-            raise util.Abort(_('http authorization required'))
+        user, passwd = self._readauthtoken(authuri)
+        if not user or not passwd:
+            if not self.ui.interactive:
+                raise util.Abort(_('http authorization required'))
 
-        self.ui.write(_("http authorization required\n"))
-        self.ui.status(_("realm: %s\n") % realm)
-        if user:
-            self.ui.status(_("user: %s\n") % user)
-        else:
-            user = self.ui.prompt(_("user:"), default=None)
+            self.ui.write(_("http authorization required\n"))
+            self.ui.status(_("realm: %s\n") % realm)
+            if user:
+                self.ui.status(_("user: %s\n") % user)
+            else:
+                user = self.ui.prompt(_("user:"), default=None)
 
-        if not passwd:
-            passwd = self.ui.getpass()
+            if not passwd:
+                passwd = self.ui.getpass()
 
         self.add_password(realm, authuri, user, passwd)
+        self._writedebug(user, passwd)
         return (user, passwd)
 
+    def _writedebug(self, user, passwd):
+        self.ui.debug(_('http auth: user %s, password %s\n') %
+                 (user, passwd and '*' * len(passwd) or 'not set'))
+
+    def _readauthtoken(self, uri):
+        uri = uri[uri.index('://')+3:]
+        bestlen = 0
+        bestauth = None
+        for prefix, auth in self.ui.configitems('auth'):
+            if (prefix == '*' or uri.startswith(prefix)) and len(prefix) > bestlen:
+                bestlen = len(prefix)
+                bestauth = auth
+        if bestauth:
+            return netlocsplit(bestauth + '@dummy')[2:4]
+        return None, None
+
 class proxyhandler(urllib2.ProxyHandler):
     def __init__(self, ui):
         proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
@@ -285,9 +305,6 @@
     passmgr = passwordmgr(ui)
     if authinfo is not None:
         passmgr.add_password(*authinfo)
-        user, passwd = authinfo[2:4]
-        ui.debug(_('http auth: user %s, password %s\n') %
-                 (user, passwd and '*' * len(passwd) or 'not set'))
 
     handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
                      httpdigestauthhandler(passmgr)))



More information about the Mercurial-devel mailing list