[PATCH] largefiles: prevent excessive password prompt connecting to server (WIP)

liscju piotr.listkiewicz at gmail.com
Thu May 19 16:42:11 UTC 2016


# HG changeset patch
# User liscju <piotr.listkiewicz at gmail.com>
# Date 1463607605 -7200
#      Wed May 18 23:40:05 2016 +0200
# Node ID ae4392266c41d05391e11bac06136db0abb95016
# Parent  90d84e1e427a9d65aedd870cdb7283f84bb30141
largefiles: prevent excessive password prompt connecting to server (WIP)

This commit is just an idea of the solution to issue4883, its not
production ready at all, im just looking forward to opinions about
it.

The problem is largefiles creates own httppeer object to connect to the
server, not reusing existing one created by commands from core. Every httppeer
object has own password manager, so when user fills login information
it is only visible to this one httppeer.

The idea of this commit is to make password manager singleton object so
when mercurial extension creates own httppeer object for the same url and user
it reuses remembered password in connection authentication.

diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -27,7 +27,17 @@ stringio = util.stringio
 urlerr = util.urlerr
 urlreq = util.urlreq
 
-class passwordmgr(urlreq.httppasswordmgrwithdefaultrealm):
+passwdmgr = None
+
+def passwordmgr(ui):
+    global passwdmgr
+    if passwdmgr is None:
+        passwdmgr = _passwordmgr(ui)
+    else:
+        passwdmgr.ui = ui
+    return passwdmgr
+
+class _passwordmgr(urlreq.httppasswordmgrwithdefaultrealm):
     def __init__(self, ui):
         urlreq.httppasswordmgrwithdefaultrealm.__init__(self)
         self.ui = ui
@@ -487,8 +497,10 @@ def opener(ui, authinfo=None):
 
     passmgr = passwordmgr(ui)
     if authinfo is not None:
-        passmgr.add_password(*authinfo)
         user, passwd = authinfo[2:4]
+        saveduser, savedpass = passmgr.find_stored_password(authinfo[1][0])
+        if user != saveduser or not savedpass:
+            passmgr.add_password(*authinfo)
         ui.debug('http auth: user %s, password %s\n' %
                  (user, passwd and '*' * len(passwd) or 'not set'))
 
diff --git a/tests/test-hgweb-auth.py b/tests/test-hgweb-auth.py
--- a/tests/test-hgweb-auth.py
+++ b/tests/test-hgweb-auth.py
@@ -43,7 +43,7 @@ def test(auth, urls=None):
     def _test(uri):
         print('URI:', uri)
         try:
-            pm = url.passwordmgr(ui)
+            pm = url._passwordmgr(ui)
             u, authinfo = util.url(uri).authinfo()
             if authinfo is not None:
                 pm.add_password(*authinfo)
diff --git a/tests/test-largefiles-wireproto.t b/tests/test-largefiles-wireproto.t
--- a/tests/test-largefiles-wireproto.t
+++ b/tests/test-largefiles-wireproto.t
@@ -348,4 +348,54 @@ largefiles should batch verify remote ca
 
   $ killdaemons.py
 
+largefiles should not ask for password again after succesfull authorization
+
+  $ hg init credentialmain
+  $ cd credentialmain
+  $ echo "aaa" >> a
+  $ hg add --large a
+  $ hg commit -m "a"
+  Invoking status precommit hook
+  A a
+  $ cd ..
+  $ cat << EOT > userpass.py
+  > import base64
+  > from mercurial.hgweb import common
+  > def perform_authentication(hgweb, req, op):
+  >     auth = req.env.get('HTTP_AUTHORIZATION')
+  >     if not auth:
+  >         raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
+  >                 [('WWW-Authenticate', 'Basic Realm="mercurial"')])
+  >     if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
+  >         raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
+  > def extsetup():
+  >     common.permhooks.insert(0, perform_authentication)
+  > EOT
+  $ hg serve --config extensions.x=userpass.py -R credentialmain \
+  >          -d -p $HGPORT --pid-file hg.pid -A access.log
+  $ cat hg.pid >> $DAEMON_PIDS
+  $ cat << EOF > get_pass.py
+  > import getpass
+  > def newgetpass(arg):
+  >   return "pass"
+  > getpass.getpass = newgetpass
+  > EOF
+  $ hg clone --config ui.interactive=true --config extensions.getpass=get_pass.py \
+  >          http://user@localhost:$HGPORT credentialclone
+  requesting all changes
+  http authorization required for http://localhost:$HGPORT/
+  realm: mercurial
+  user: user
+  password: adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  updating to branch default
+  getting changed largefiles
+  1 largefiles updated, 0 removed
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ rm hg.pid access.log
+  $ killdaemons.py
+
 #endif


More information about the Mercurial-devel mailing list