Patchwork http: allow 'auth.prefix' to have a username consistent with the URI

login
register
mail settings
Submitter Matt Harbison
Date Nov. 17, 2018, 2:37 a.m.
Message ID <9cada40ed879ce76c5dd.1542422227@Envy>
Download mbox | patch
Permalink /patch/36630/
State Accepted
Headers show

Comments

Matt Harbison - Nov. 17, 2018, 2:37 a.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1542408996 18000
#      Fri Nov 16 17:56:36 2018 -0500
# Node ID 9cada40ed879ce76c5dd3c44716cff61eecc8f16
# Parent  610eb5c155df5ca300827e10cd2c3426f0ba0842
http: allow 'auth.prefix' to have a username consistent with the URI

It may be a little weird to put a username in the prefix, but the documentation
doesn't disallow it, and silently disallowing it has caused confusion[1].  The
username must match what is passed in (which seems to be from the URI via a
circuitous route), as well as 'auth.username' if it was specified.  I thought
about printing a warning for a mismatch, but we already don't print a warning if
the 'auth.username' and URI username don't match.

This change allows the first and second last new test cases to work as expected.
It looks like this would have been a problem since at least 0593e8f81c71.

[1] https://www.mercurial-scm.org/pipermail/mercurial/2018-November/051069.html
Yuya Nishihara - Nov. 17, 2018, 4:56 a.m.
On Fri, 16 Nov 2018 21:37:07 -0500, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison@yahoo.com>
> # Date 1542408996 18000
> #      Fri Nov 16 17:56:36 2018 -0500
> # Node ID 9cada40ed879ce76c5dd3c44716cff61eecc8f16
> # Parent  610eb5c155df5ca300827e10cd2c3426f0ba0842
> http: allow 'auth.prefix' to have a username consistent with the URI
> 
> It may be a little weird to put a username in the prefix, but the documentation
> doesn't disallow it, and silently disallowing it has caused confusion[1].  The
> username must match what is passed in (which seems to be from the URI via a
> circuitous route), as well as 'auth.username' if it was specified.  I thought
> about printing a warning for a mismatch, but we already don't print a warning if
> the 'auth.username' and URI username don't match.
> 
> This change allows the first and second last new test cases to work as expected.
> It looks like this would have been a problem since at least 0593e8f81c71.
> 
> [1] https://www.mercurial-scm.org/pipermail/mercurial/2018-November/051069.html
> 
> diff --git a/mercurial/httpconnection.py b/mercurial/httpconnection.py
> --- a/mercurial/httpconnection.py
> +++ b/mercurial/httpconnection.py
> @@ -92,6 +92,18 @@ def readauthforuri(ui, uri, user):
>          prefix = auth.get('prefix')
>          if not prefix:
>              continue
> +
> +        prefixurl = util.url(prefix)
> +        if prefixurl.user and prefixurl.user != user:
> +            # If a username was set in the prefix, it must match the username in
> +            # the URI.
> +            continue
> +
> +        # The URI passed in has been stripped of credentials, so erase the user
> +        # here to allow simpler matching.
> +        prefixurl.user = None
> +        prefix = bytes(prefixurl)

Looks good given how we handle the <scheme>:// part embedded in the prefix.
Queued, thanks.

>          p = prefix.split('://', 1)
>          if len(p) > 1:
>              schemes, prefix = [p[0]], p[1]

Perhaps, this can be refactored to use the parsed prefixurl.

Patch

diff --git a/mercurial/httpconnection.py b/mercurial/httpconnection.py
--- a/mercurial/httpconnection.py
+++ b/mercurial/httpconnection.py
@@ -92,6 +92,18 @@  def readauthforuri(ui, uri, user):
         prefix = auth.get('prefix')
         if not prefix:
             continue
+
+        prefixurl = util.url(prefix)
+        if prefixurl.user and prefixurl.user != user:
+            # If a username was set in the prefix, it must match the username in
+            # the URI.
+            continue
+
+        # The URI passed in has been stripped of credentials, so erase the user
+        # here to allow simpler matching.
+        prefixurl.user = None
+        prefix = bytes(prefixurl)
+
         p = prefix.split('://', 1)
         if len(p) > 1:
             schemes, prefix = [p[0]], p[1]
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
@@ -104,6 +104,39 @@  test({'x.prefix': 'http://example.org/fo
       'y.password': 'ypassword'},
      urls=['http://y@example.org/foo/bar'])
 
+print('\n*** Test user matching with name in prefix\n')
+
+# prefix, username and URL have the same user
+test({'x.prefix': 'https://example.org/foo',
+      'x.username': None,
+      'x.password': 'xpassword',
+      'y.prefix': 'http://y@example.org/foo',
+      'y.username': 'y',
+      'y.password': 'ypassword'},
+     urls=['http://y@example.org/foo'])
+# Prefix has a different user from username and URL
+test({'y.prefix': 'http://z@example.org/foo',
+      'y.username': 'y',
+      'y.password': 'ypassword'},
+     urls=['http://y@example.org/foo'])
+# Prefix has a different user from URL; no username
+test({'y.prefix': 'http://z@example.org/foo',
+      'y.password': 'ypassword'},
+     urls=['http://y@example.org/foo'])
+# Prefix and URL have same user, but doesn't match username
+test({'y.prefix': 'http://y@example.org/foo',
+      'y.username': 'z',
+      'y.password': 'ypassword'},
+     urls=['http://y@example.org/foo'])
+# Prefix and URL have the same user; no username
+test({'y.prefix': 'http://y@example.org/foo',
+      'y.password': 'ypassword'},
+     urls=['http://y@example.org/foo'])
+# Prefix user, but no URL user or username
+test({'y.prefix': 'http://y@example.org/foo',
+      'y.password': 'ypassword'},
+     urls=['http://example.org/foo'])
+
 def testauthinfo(fullurl, authurl):
     print('URIs:', fullurl, authurl)
     pm = urlreq.httppasswordmgrwithdefaultrealm()
diff --git a/tests/test-hgweb-auth.py.out b/tests/test-hgweb-auth.py.out
--- a/tests/test-hgweb-auth.py.out
+++ b/tests/test-hgweb-auth.py.out
@@ -190,6 +190,27 @@  CFG: {b'x.password': b'xpassword', b'x.p
 URI: http://y@example.org/foo/bar
      ('y', 'xpassword')
 
+*** Test user matching with name in prefix
+
+CFG: {b'x.password': b'xpassword', b'x.prefix': b'https://example.org/foo', b'x.username': None, b'y.password': b'ypassword', b'y.prefix': b'http://y@example.org/foo', b'y.username': b'y'}
+URI: http://y@example.org/foo
+     ('y', 'ypassword')
+CFG: {b'y.password': b'ypassword', b'y.prefix': b'http://z@example.org/foo', b'y.username': b'y'}
+URI: http://y@example.org/foo
+     abort
+CFG: {b'y.password': b'ypassword', b'y.prefix': b'http://z@example.org/foo'}
+URI: http://y@example.org/foo
+     abort
+CFG: {b'y.password': b'ypassword', b'y.prefix': b'http://y@example.org/foo', b'y.username': b'z'}
+URI: http://y@example.org/foo
+     abort
+CFG: {b'y.password': b'ypassword', b'y.prefix': b'http://y@example.org/foo'}
+URI: http://y@example.org/foo
+     ('y', 'ypassword')
+CFG: {b'y.password': b'ypassword', b'y.prefix': b'http://y@example.org/foo'}
+URI: http://example.org/foo
+     abort
+
 *** Test urllib2 and util.url
 
 URIs: http://user@example.com:8080/foo http://example.com:8080/foo