hgext/acl.py
author Joel Rosdahl <joel@rosdahl.net>
Sat, 25 Oct 2008 19:05:52 +0200
changeset 7253 8b81d1e2dc04
parent 6766 e81d2bd66908
child 8142 912bfef12ba6
permissions -rw-r--r--
bookmarks: Only save undo.bookmarks if bookmarks exist Otherwise the command will abort when there is no .hg/bookmarks file.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2344
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     1
# acl.py - changeset access control for mercurial
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     2
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     3
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     4
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     6
# of the GNU General Public License, incorporated herein by reference.
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     7
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     8
# this hook allows to allow or deny access to parts of a repo when
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
     9
# taking incoming changesets.
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    10
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    11
# authorization is against local user name on system where hook is
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    12
# run, not committer of original changeset (since that is easy to
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    13
# spoof).
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    14
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    15
# acl hook is best to use if you use hgsh to set up restricted shells
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    16
# for authenticated users to only push to / pull from.  not safe if
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    17
# user has interactive shell access, because they can disable hook.
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    18
# also not safe if remote users share one local account, because then
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    19
# no way to tell remote users apart.
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    20
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    21
# to use, configure acl extension in hgrc like this:
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    22
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    23
#   [extensions]
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    24
#   hgext.acl =
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    25
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    26
#   [hooks]
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    27
#   pretxnchangegroup.acl = python:hgext.acl.hook
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    28
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    29
#   [acl]
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    30
#   sources = serve        # check if source of incoming changes in this list
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    31
#                          # ("serve" == ssh or http, "push", "pull", "bundle")
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    32
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    33
# allow and deny lists have subtree pattern (default syntax is glob)
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    34
# on left, user names on right. deny list checked before allow list.
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    35
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    36
#   [acl.allow]
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    37
#   # if acl.allow not present, all users allowed by default
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    38
#   # empty acl.allow = no users allowed
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    39
#   docs/** = doc_writer
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    40
#   .hgtags = release_engineer
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    41
#
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    42
#   [acl.deny]
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    43
#   # if acl.deny not present, no users denied by default
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    44
#   # empty acl.deny = all users allowed
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    45
#   glob pattern = user4, user5
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    46
#   ** = user6
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    47
3891
6b4127c7d52a Simplify i18n imports
Matt Mackall <mpm@selenic.com>
parents: 3877
diff changeset
    48
from mercurial.i18n import _
3877
abaee83ce0a6 Replace demandload with new demandimport
Matt Mackall <mpm@selenic.com>
parents: 3436
diff changeset
    49
from mercurial import util
abaee83ce0a6 Replace demandload with new demandimport
Matt Mackall <mpm@selenic.com>
parents: 3436
diff changeset
    50
import getpass
2344
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    51
6766
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    52
def buildmatch(ui, repo, user, key):
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    53
    '''return tuple of (match function, list enabled).'''
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    54
    if not ui.has_section(key):
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    55
        ui.debug(_('acl: %s not enabled\n') % key)
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    56
        return None
2344
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    57
6766
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    58
    pats = [pat for pat, users in ui.configitems(key)
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    59
            if user in users.replace(',', ' ').split()]
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    60
    ui.debug(_('acl: %s enabled, %d entries for user %s\n') %
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    61
             (key, len(pats), user))
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    62
    if pats:
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    63
        return util.matcher(repo.root, names=pats)[1]
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    64
    return util.never
2344
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    65
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    66
def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    67
    if hooktype != 'pretxnchangegroup':
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    68
        raise util.Abort(_('config error - hook type "%s" cannot stop '
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    69
                           'incoming changesets') % hooktype)
6766
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    70
    if source not in ui.config('acl', 'sources', 'serve').split():
2344
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    71
        ui.debug(_('acl: changes have source "%s" - skipping\n') % source)
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    72
        return
ae12e5a2c4a3 add acl extension, to limit who can push to subdirs of central repo.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
diff changeset
    73
6766
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    74
    user = getpass.getuser()
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    75
    cfg = ui.config('acl', 'config')
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    76
    if cfg:
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    77
        ui.readsections(cfg, 'acl.allow', 'acl.deny')
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    78
    allow = buildmatch(ui, repo, user, 'acl.allow')
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    79
    deny = buildmatch(ui, repo, user, 'acl.deny')
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    80
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    81
    for rev in xrange(repo[node], len(repo)):
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    82
        ctx = repo[rev]
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    83
        for f in ctx.files():
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    84
            if deny and deny(f):
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    85
                ui.debug(_('acl: user %s denied on %s\n') % (user, f))
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    86
                raise util.Abort(_('acl: access denied for changeset %s') % ctx)
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    87
            if allow and not allow(f):
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    88
                ui.debug(_('acl: user %s not allowed on %s\n') % (user, f))
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    89
                raise util.Abort(_('acl: access denied for changeset %s') % ctx)
e81d2bd66908 acl: refactoring
Matt Mackall <mpm@selenic.com>
parents: 6750
diff changeset
    90
        ui.debug(_('acl: allowing changeset %s\n') % ctx)