Finer-grained access restrictions to hgwebdir

Alexis S. L. Carvalho alexis at cecm.usp.br
Mon Oct 22 00:16:59 CDT 2007


Thus spake Nilton Volpato:
> Hi,
> 
> I've implemented, inspired a bit by svn_authz, finer-grained access
> restrictions to hgwebdir.cgi. The syntax for hgweb.conf files, is
> like:

I think I'm +0 (i.e. other opinions are welcome) on the general idea of
adding a way for hgweb to disallow reading (and pulling) a repo on a
per-user basis, but I think hgweb.conf is the wrong place for this:

- it wouldn't work with hgweb.cgi

- right now hgweb.conf affects only the repository index page, but with
  this change it would also affect the repos

- if you have a setup where you're serving repos from many different
  people, the repo owners would have to contact the admin (or whoever
  owns hgweb.conf) every time they wanted to change the access
  restrictions

So I think this should go into a regular .hgrc file (e.g. in an [access]
section).

There's also the question of whether it's better to add this new section
or add some kind of allow_read setting to the [web] section to
complement allow_push (there is allowpull, but that doesn't prevent
browsing the repo and is not a per-user setting).

Some comments on the patch itself:


> # HG changeset patch
> # User Nilton Volpato <nilton.volpato at gmail.com>
> # Date 1192843686 10800
> # Node ID 5eb898e196f50ab3ed58b98d27520898fcf605fb
> # Parent  5d8f5ad45c1260c7ec2e4ea77d8a877cd7a1db14
> implemented finer-grained per-repository access restrictions to hgwebdir and hgweb
> 
> diff -r 5d8f5ad45c12 -r 5eb898e196f5 mercurial/hgweb/hgweb_mod.py
> --- a/mercurial/hgweb/hgweb_mod.py	Fri Oct 19 18:25:28 2007 -0500
> +++ b/mercurial/hgweb/hgweb_mod.py	Fri Oct 19 22:28:06 2007 -0300

> @@ -840,19 +841,29 @@ class hgweb(object):
>                                                 })
>  
>          try:
> -            if not req.form.has_key('cmd'):
> -                req.form['cmd'] = [self.t.cache['default']]
> +            if not self.auth_allow_user(req, 'r'):
> +                req.httphdr("text/html", headers={'status': '403 Forbidden'})
> +                req.write("""<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
> +                          <html><head>
> +                          <title>403 Forbidden</title>
> +                          </head><body>
> +                          <h1>Forbidden</h1>
> +                          <p>User "%s" don't have permission to access repository "%s".</p>
> +                          </body></html>\n""" % (req.env.get('REMOTE_USER'), self.reponame))

Hmm... just use a simple text/plain message here for the time being -
HTML should be kept in template files.  Ideally we would just reuse the
"error" template here, but I don't think we can specify a status right
now.

> @@ -1076,6 +1087,23 @@ class hgweb(object):
>          allow = self.configlist('web', 'allow_' + op)
>          return (allow and (allow == ['*'] or user in allow)) or default
>  
> +    def auth_allow_user(self, req, mode):
> +        assert mode in ('r', 'rw')
> +        user = req.env.get('REMOTE_USER')
> +        deny_user = self.access and (self.access.get(user) == '')
> +        if deny_user:
> +            return False
> +        if mode == 'r':
> +            allow_user = not self.access or \
> +                         (self.access.get('*') in ('r', 'rw')) or \
> +                         (self.access.get(user) in ('r', 'rw'))
> +        else: # mode == 'rw':
> +            allow_user = not self.access or \
> +                         (self.access.get('*') == 'rw') or \
> +                         (self.access.get(user) == 'rw')
> +        if allow_user:
> +            return True
> +

This should go into common.py so that you can avoid duplicating the code
in hgwebdir.py.

(If we go with an [access] section you should give a ui object (probably
self.repo.ui) to this function and then use:

- ui.has_section("access") to see if there's an [access] section

- ui.config("access", "*", untrusted=True) to get the value of the "*"
  setting
)


> diff -r 5d8f5ad45c12 -r 5eb898e196f5 mercurial/hgweb/hgwebdir_mod.py
> --- a/mercurial/hgweb/hgwebdir_mod.py	Fri Oct 19 18:25:28 2007 -0500
> +++ b/mercurial/hgweb/hgwebdir_mod.py	Fri Oct 19 22:28:06 2007 -0300
> @@ -139,6 +147,16 @@ class hgwebdir(object):
>              rows = []
>              parity = paritygen(self.stripecount)
>              for name, path in self.repos:
> +                # test access restrictions
> +                user = req.env.get('REMOTE_USER')
> +                repo_access = self.access.get(name)
> +                deny_user = repo_access and (repo_access.get(user) == '')
> +                if deny_user: continue
> +                allow_user = not repo_access or \
> +                             (repo_access.get('*') in ('r', 'rw')) or \
> +                             (repo_access.get(user) in ('r', 'rw'))
> +                if not allow_user: continue
> +
>                  if not name.startswith(subdir):
>                      continue
>                  name = name[len(subdir):]

Reuse auth_allow_user.

(Right after this block we create a ui object that you can pass to
a modified auth_allow_user.)

Alexis


More information about the Mercurial-devel mailing list