[PATCH] hgweb: do not ignore [auth] if url has a username (issue2822)

Augie Fackler durin42 at gmail.com
Mon Aug 1 18:13:53 CDT 2011


On Aug 1, 2011, at 5:18 PM, Patrick Mezard wrote:

> # HG changeset patch
> # User Patrick Mezard <pmezard at gmail.com>
> # Date 1312235930 -7200
> # Branch stable
> # Node ID ef091681811b15c5fdd818d2d74231f772230e6a
> # Parent  dd74cd1e5d49cdedfd2a0cf142a9ce1178e4b748
> hgweb: do not ignore [auth] if url has a username (issue2822)

Nit: I think I might say http or httpconnection rather than hgweb, since the logic changes are in httpconnection and friends.

> 
> The [auth] section was ignored when handling URLs like:
> 
>  http://user@example.com/foo
> 
> Instead, we look in [auth] for an entry matching the URL and supplied user
> name. Entries without username can match URL with a username. Prefix length
> ties are resolved in favor of entries matching the username. With:
> 
>  foo.prefix = http://example.org
>  foo.username = user
>  foo.password = password
>  bar.prefix = http://example.org/bar
> 
> and the input URL:
> 
>  http://user@example.org/bar
> 
> the 'bar' entry will be selected because of prefix length, therefore prompting
> for a password. This behaviour ensure that entries selection is consistent when
> looking for credentials or for certificates, and that certificates can be
> picked even if their entries do no define usernames while the URL does.
> Additionally, entries without a username matched against a username are
> returned as if they did have requested username set to avoid prompting again
> for a username if the password is not set.
> 
> v2: reparse the URL in readauthforuri() to handle HTTP and HTTPS similarly.
> v3: allow unset usernames to match URL usernames to pick certificates. Resolve
> prefix length ties in favor of entries with usernames.
> 
> diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
> --- a/mercurial/help/config.txt
> +++ b/mercurial/help/config.txt
> @@ -262,7 +262,9 @@
>     Optional. Username to authenticate with. If not given, and the
>     remote site requires basic or digest authentication, the user will
>     be prompted for it. Environment variables are expanded in the
> -    username letting you do ``foo.username = $USER``.
> +    username letting you do ``foo.username = $USER``. If the URI
> +    includes a username, only ``[auth]`` entries with a matching
> +    username or without a username will be considered.
> 
> ``password``
>     Optional. Password to authenticate with. If not given, and the
> diff --git a/mercurial/httpconnection.py b/mercurial/httpconnection.py
> --- a/mercurial/httpconnection.py
> +++ b/mercurial/httpconnection.py
> @@ -72,10 +72,19 @@
>         gdict[setting] = val
> 
>     # Find the best match
> +    uri = util.url(uri)
> +    user = uri.user
> +    uri.user = uri.password = None
> +    uri = str(uri)
>     scheme, hostpath = uri.split('://', 1)
> +    bestuser = None
>     bestlen = 0
>     bestauth = None
>     for group, auth in config.iteritems():
> +        if user and user != auth.get('username', user):
> +            # If a username was set in the URI, the entry username
> +            # must either match it or be unset
> +            continue
>         prefix = auth.get('prefix')
>         if not prefix:
>             continue
> @@ -85,9 +94,14 @@
>         else:
>             schemes = (auth.get('schemes') or 'https').split()
>         if (prefix == '*' or hostpath.startswith(prefix)) and \
> -            len(prefix) > bestlen and scheme in schemes:
> +            (len(prefix) > bestlen or (len(prefix) == bestlen and \
> +                not bestuser and 'username' in auth)) \
> +             and scheme in schemes:
>             bestlen = len(prefix)
>             bestauth = group, auth
> +            bestuser = auth.get('username')
> +            if user and not bestuser:
> +                auth['username'] = user
>     return bestauth
> 
> # Mercurial (at least until we can remove the old codepath) requires
> diff --git a/mercurial/url.py b/mercurial/url.py
> --- a/mercurial/url.py
> +++ b/mercurial/url.py
> @@ -25,7 +25,7 @@
>             self._writedebug(user, passwd)
>             return (user, passwd)
> 
> -        if not user:
> +        if not user or not passwd:
>             res = httpconnectionmod.readauthforuri(self.ui, authuri)
>             if res:
>                 group, auth = res
> 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
> @@ -1,5 +1,5 @@
> from mercurial import demandimport; demandimport.enable()
> -from mercurial import ui
> +from mercurial import ui, util
> from mercurial import url
> from mercurial.error import Abort
> 
> @@ -19,13 +19,16 @@
>     return '{' + ', '.join(['%s: %s' % (k, dict[k])
>                             for k in sorted(dict.iterkeys())]) + '}'
> 
> -def test(auth):
> +def test(auth, urls=None):
>     print 'CFG:', dumpdict(auth)
>     prefixes = set()
>     for k in auth:
>         prefixes.add(k.split('.', 1)[0])
>     for p in prefixes:
> -        auth.update({p + '.username': p, p + '.password': p})
> +        for name in ('.username', '.password'):
> +            if (p + name) not in auth:
> +                auth[p + name] = p
> +    auth = dict((k, v) for k, v in auth.iteritems() if v is not None)
> 
>     ui = writeauth(auth)
> 
> @@ -33,16 +36,26 @@
>         print 'URI:', uri
>         try:
>             pm = url.passwordmgr(ui)
> +            authinfo = util.url(uri).authinfo()[1]
> +            if authinfo is not None:
> +                pm.add_password(*authinfo)
>             print '    ', pm.find_user_password('test', uri)
>         except Abort, e:
>             print 'abort'
> 
> -    _test('http://example.org/foo')
> -    _test('http://example.org/foo/bar')
> -    _test('http://example.org/bar')
> -    _test('https://example.org/foo')
> -    _test('https://example.org/foo/bar')
> -    _test('https://example.org/bar')
> +    if not urls:
> +        urls = [
> +            'http://example.org/foo',
> +            'http://example.org/foo/bar',
> +            'http://example.org/bar',
> +            'https://example.org/foo',
> +            'https://example.org/foo/bar',
> +            'https://example.org/bar',
> +            'https://x@example.org/bar',
> +            'https://y@example.org/bar',
> +            ]
> +    for u in urls:
> +        _test(u)
> 
> 
> print '\n*** Test in-uri schemes\n'
> @@ -62,3 +75,23 @@
> test({'x.prefix': 'http://example.org/foo',
>       'y.prefix': 'http://example.org/foo/bar'})
> test({'x.prefix': '*', 'y.prefix': 'https://example.org/bar'})
> +
> +print '\n*** Test user matching\n'
> +test({'x.prefix': 'http://example.org/foo',
> +      'x.username': None,
> +      'x.password': 'xpassword'},
> +     urls=['http://y@example.org/foo'])
> +test({'x.prefix': 'http://example.org/foo',
> +      'x.username': None,
> +      'x.password': 'xpassword',
> +      'y.prefix': 'http://example.org/foo',
> +      'y.username': 'y',
> +      'y.password': 'ypassword'},
> +     urls=['http://y@example.org/foo'])
> +test({'x.prefix': 'http://example.org/foo/bar',
> +      'x.username': None,
> +      'x.password': 'xpassword',
> +      'y.prefix': 'http://example.org/foo',
> +      'y.username': 'y',
> +      'y.password': 'ypassword'},
> +     urls=['http://y@example.org/foo/bar'])
> 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
> @@ -14,6 +14,10 @@
>      abort
> URI: https://example.org/bar
>      abort
> +URI: https://x@example.org/bar
> +     abort
> +URI: https://y@example.org/bar
> +     abort
> CFG: {x.prefix: https://example.org}
> URI: http://example.org/foo
>      abort
> @@ -27,6 +31,10 @@
>      ('x', 'x')
> URI: https://example.org/bar
>      ('x', 'x')
> +URI: https://x@example.org/bar
> +     ('x', 'x')
> +URI: https://y@example.org/bar
> +     abort
> CFG: {x.prefix: http://example.org, x.schemes: https}
> URI: http://example.org/foo
>      ('x', 'x')
> @@ -40,6 +48,10 @@
>      abort
> URI: https://example.org/bar
>      abort
> +URI: https://x@example.org/bar
> +     abort
> +URI: https://y@example.org/bar
> +     abort
> CFG: {x.prefix: https://example.org, x.schemes: http}
> URI: http://example.org/foo
>      abort
> @@ -53,6 +65,10 @@
>      ('x', 'x')
> URI: https://example.org/bar
>      ('x', 'x')
> +URI: https://x@example.org/bar
> +     ('x', 'x')
> +URI: https://y@example.org/bar
> +     abort
> 
> *** Test separately configured schemes
> 
> @@ -69,6 +85,10 @@
>      abort
> URI: https://example.org/bar
>      abort
> +URI: https://x@example.org/bar
> +     abort
> +URI: https://y@example.org/bar
> +     abort
> CFG: {x.prefix: example.org, x.schemes: https}
> URI: http://example.org/foo
>      abort
> @@ -82,6 +102,10 @@
>      ('x', 'x')
> URI: https://example.org/bar
>      ('x', 'x')
> +URI: https://x@example.org/bar
> +     ('x', 'x')
> +URI: https://y@example.org/bar
> +     abort
> CFG: {x.prefix: example.org, x.schemes: http https}
> URI: http://example.org/foo
>      ('x', 'x')
> @@ -95,6 +119,10 @@
>      ('x', 'x')
> URI: https://example.org/bar
>      ('x', 'x')
> +URI: https://x@example.org/bar
> +     ('x', 'x')
> +URI: https://y@example.org/bar
> +     abort
> 
> *** Test prefix matching
> 
> @@ -111,6 +139,10 @@
>      abort
> URI: https://example.org/bar
>      abort
> +URI: https://x@example.org/bar
> +     abort
> +URI: https://y@example.org/bar
> +     abort
> CFG: {x.prefix: http://example.org/foo, y.prefix: http://example.org/foo/bar}
> URI: http://example.org/foo
>      ('x', 'x')
> @@ -124,6 +156,10 @@
>      abort
> URI: https://example.org/bar
>      abort
> +URI: https://x@example.org/bar
> +     abort
> +URI: https://y@example.org/bar
> +     abort
> CFG: {x.prefix: *, y.prefix: https://example.org/bar}
> URI: http://example.org/foo
>      abort
> @@ -137,3 +173,19 @@
>      ('x', 'x')
> URI: https://example.org/bar
>      ('y', 'y')
> +URI: https://x@example.org/bar
> +     ('x', 'x')
> +URI: https://y@example.org/bar
> +     ('y', 'y')
> +
> +*** Test user matching
> +
> +CFG: {x.password: xpassword, x.prefix: http://example.org/foo, x.username: None}
> +URI: http://y@example.org/foo
> +     ('y', 'xpassword')
> +CFG: {x.password: xpassword, x.prefix: http://example.org/foo, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y}
> +URI: http://y@example.org/foo
> +     ('y', 'ypassword')
> +CFG: {x.password: xpassword, x.prefix: http://example.org/foo/bar, x.username: None, y.password: ypassword, y.prefix: http://example.org/foo, y.username: y}
> +URI: http://y@example.org/foo/bar
> +     ('y', 'xpassword')
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel



More information about the Mercurial-devel mailing list