Rev 3165: (Balint Aradi) Add contrib/bzr_access to allow some access control in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Jan 4 02:49:18 GMT 2008


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 3165
revision-id:pqm at pqm.ubuntu.com-20080104024907-k4ld11wri0m0tvxq
parent: pqm at pqm.ubuntu.com-20080103231814-wymg8td870lqfzkv
parent: john at arbash-meinel.com-20080104014832-1xwbcbueft0cyqtc
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2008-01-04 02:49:07 +0000
message:
  (Balint Aradi) Add contrib/bzr_access to allow some access control
  	via a single user based on ssh-keys.
added:
  contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3112.1.5
    revision-id:john at arbash-meinel.com-20080104014832-1xwbcbueft0cyqtc
    parent: aradi at bccms.uni-bremen.de-20071214233159-ott7hpnq3jwblr3o
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: contrib_bzr_access
    timestamp: Thu 2008-01-03 19:48:32 -0600
    message:
      a small bit of cleanup.
    modified:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3112.1.4
    revision-id:aradi at bccms.uni-bremen.de-20071214233159-ott7hpnq3jwblr3o
    parent: aradi at bccms.uni-bremen.de-20071214231005-2b2guucng6z5vidx
    committer: Balint Aradi <aradi at bccms.uni-bremen.de>
    branch nick: bzr_access
    timestamp: Sat 2007-12-15 00:31:59 +0100
    message:
      Changing example to show comma separated user names.
    modified:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3112.1.3
    revision-id:aradi at bccms.uni-bremen.de-20071214231005-2b2guucng6z5vidx
    parent: aradi at bccms.uni-bremen.de-20071214223842-ktu2id82afv0sqk2
    committer: Balint Aradi <aradi at bccms.uni-bremen.de>
    branch nick: bzr_access
    timestamp: Sat 2007-12-15 00:10:05 +0100
    message:
      Tiny changes for more readable code and better compliance with bzr style.
    modified:
      contrib/bzr_access*            bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3112.1.2
    revision-id:aradi at bccms.uni-bremen.de-20071214223842-ktu2id82afv0sqk2
    parent: aradi at bccms.uni-bremen.de-20071214221155-1d4cn0qh6xtoca3z
    parent: john at arbash-meinel.com-20071211144709-t4q1mofuropktm7p
    committer: Balint Aradi <aradi at bccms.uni-bremen.de>
    branch nick: bzr_access
    timestamp: Fri 2007-12-14 23:38:42 +0100
    message:
      Applying John Arbash Meinel's changes.
    modified:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
        ------------------------------------------------------------
        revno: 3099.4.7
        revision-id:john at arbash-meinel.com-20071211144709-t4q1mofuropktm7p
        parent: john at arbash-meinel.com-20071211143929-qvyl5apn5d8hs139
        committer: John Arbash Meinel <john at arbash-meinel.com>
        branch nick: contrib_bzr_access
        timestamp: Tue 2007-12-11 08:47:09 -0600
        message:
          Add a comment about using configobj instead of ConfigParser
        modified:
          contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
        ------------------------------------------------------------
        revno: 3099.4.6
        revision-id:john at arbash-meinel.com-20071211143929-qvyl5apn5d8hs139
        parent: john at arbash-meinel.com-20071210165508-u2osnibvzvkb3zxp
        committer: John Arbash Meinel <john at arbash-meinel.com>
        branch nick: contrib_bzr_access
        timestamp: Tue 2007-12-11 08:39:29 -0600
        message:
          Add GPL license to bzr_access script
        modified:
          contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3112.1.1
    revision-id:aradi at bccms.uni-bremen.de-20071214221155-1d4cn0qh6xtoca3z
    parent: pqm at pqm.ubuntu.com-20071214143021-aus9m0gqj1u9gr7n
    parent: john at arbash-meinel.com-20071210165508-u2osnibvzvkb3zxp
    committer: Balint Aradi <aradi at bccms.uni-bremen.de>
    branch nick: bzr_access
    timestamp: Fri 2007-12-14 23:11:55 +0100
    message:
      Applying John Arbash Meinel's changes
    added:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3099.4.5
    revision-id:john at arbash-meinel.com-20071210165508-u2osnibvzvkb3zxp
    parent: john at arbash-meinel.com-20071210165036-0b7x8wdc9rjyfxhp
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: contrib_bzr_access
    timestamp: Mon 2007-12-10 10:55:08 -0600
    message:
      A bit more documentation cleanup
    modified:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3099.4.4
    revision-id:john at arbash-meinel.com-20071210165036-0b7x8wdc9rjyfxhp
    parent: john at arbash-meinel.com-20071210164600-xcvl9fto3gn5aqtj
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: contrib_bzr_access
    timestamp: Mon 2007-12-10 10:50:36 -0600
    message:
      Change initial comment into the docstring, and update snippets to be proper ReST
    modified:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3099.4.3
    revision-id:john at arbash-meinel.com-20071210164600-xcvl9fto3gn5aqtj
    parent: john at arbash-meinel.com-20071210164221-3hulymrjzcd9hso5
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: contrib_bzr_access
    timestamp: Mon 2007-12-10 10:46:00 -0600
    message:
      Change the indentation to 4 spaces according to Bazaar style guidelines.
    modified:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3099.4.2
    revision-id:john at arbash-meinel.com-20071210164221-3hulymrjzcd9hso5
    parent: john at arbash-meinel.com-20071210163156-lr415galj8b1670t
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: contrib_bzr_access
    timestamp: Mon 2007-12-10 10:42:21 -0600
    message:
      Some simple spelling fixes, and switch to using subprocess since that is space-in-filename safe
    modified:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
    ------------------------------------------------------------
    revno: 3099.4.1
    revision-id:john at arbash-meinel.com-20071210163156-lr415galj8b1670t
    parent: pqm at pqm.ubuntu.com-20071210120611-a3j02d26cbzvlyju
    author: Bálint Aradi <aradi at bccms.uni-bremen.de>
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: contrib_bzr_access
    timestamp: Mon 2007-12-10 10:31:56 -0600
    message:
      Add a bzr_access script for allowing custom access control over bzr+ssh
    added:
      contrib/bzr_access             bzr_access-20071210163004-c9lb1renhra2ncg0-1
=== added file 'contrib/bzr_access'
--- a/contrib/bzr_access	1970-01-01 00:00:00 +0000
+++ b/contrib/bzr_access	2008-01-04 01:48:32 +0000
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+###############################################################################
+#
+#  bzr_access:
+#    Simple access control for shared bazaar repository accessed over ssh.
+#
+# Copyright (C) 2007 Balint Aradi
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+###############################################################################
+"""
+Invocation: bzr_access <bzr_executable> <repo_collection> <user>
+
+The script extracts from the SSH_ORIGINAL_COMMAND environment variable the
+repository, which bazaar tries to access through the bzr+ssh protocol. The
+repository is assumed to be relative to <repo_collection>. Based
+on the configuration file <repo_collection>/bzr_access.conf it determines
+the access rights (denied, read-only, read-write) for the specified user.
+If the user has read-only or read-write access a bazaar smart server is
+started for it in read-only or in read-write mode, rsp., using the specified
+bzr executable.
+
+Config file: INI format, pretty much similar to the authfile of subversion.
+
+Groups can be defined in the [groups] section. The options in this block are
+the names of the groups to be defined, the corresponding values the lists of
+the users belonging to the given groups. (User names must be separated by
+commas.)
+
+All other sections names should be path names (starting with '/'), defining
+the permissions for the given path. The options in those sections are user
+names or group references (group name with a leading '@'), the corresponding
+values are the permissions: 'rw', 'r' and '' (without the quotes) for
+read-write, read-only and no access, respectively.
+
+Only the options in the section with the longest matching name are evaluated.
+The last relevant option for the user is used.
+
+Sample bzr_access.conf::
+
+   [groups]
+   admins = alpha
+   devels = beta, gamma, delta
+   
+   [/test/trunk]
+   @admins = rw
+   @devels = r
+   
+   [/test/branches]
+   @admins = rw
+   @devels = rw
+
+
+This allows you to set up a single SSH user, and customize the access based on
+ssh key. Your ``.ssh/authorized_key`` file should look something like this::
+
+   command="/path/to/bzr_access /path/to/bzr /path/to/repository <username>",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-<type> <key>
+"""
+
+import ConfigParser
+import os
+import re
+import subprocess
+import sys
+
+CONFIG_FILE = "bzr_access.conf"
+SCRIPT_NAME = os.path.basename(sys.argv[0])
+
+# Permission constants
+PERM_DENIED = 0
+PERM_READ = 1
+PERM_READWRITE = 2
+PERM_DICT = { "r": PERM_READ, "rw": PERM_READWRITE }
+
+# Exit codes
+EXIT_BAD_NR_ARG = 1
+EXIT_BZR_NOEXEC = 2
+EXIT_REPO_NOREAD = 3
+EXIT_BADENV = 4
+EXIT_BADDIR = 5
+EXIT_NOCONF = 6
+EXIT_NOACCESS = 7
+EXIT_BADUSERNAME = 8
+
+# pattern for the bzr command passed to ssh
+PAT_SSH_COMMAND = re.compile(r"""^bzr\s+
+                             serve\s+
+                             --inet\s+
+                             --directory=(?P<dir>\S+)\s+
+                             --allow-writes\s*$""", re.VERBOSE)
+
+# Command line for starting bzr
+BZR_OPTIONS = ['serve', '--inet', '--directory']
+BZR_READWRITE_FLAGS = ['--allow-writes']
+
+
+
+def error(msg, exit_code):
+    """Prints error message to stdout and exits with given error code."""
+    
+    print >>sys.stderr, "%s::error: %s" % (SCRIPT_NAME, msg)
+    sys.exit(exit_code)
+  
+
+
+class AccessManager(object):
+    """Manages the permissions, can be queried for a specific user and path."""
+    
+    def __init__(self, fp):
+        """:param fp: File like object, containing the configuration options.
+        """
+        # TODO: jam 20071211 Consider switching to bzrlib.util.configobj
+        self.config = ConfigParser.ConfigParser()
+        self.config.readfp(fp)
+        self.groups = {}
+        if self.config.has_section("groups"):
+            for group, users in self.config.items("groups"):
+                self.groups[group] = set([ s.strip() for s in users.split(",")])
+        
+
+    def permission(self, user, path):
+        """Determines the permission for a given user and a given path
+        :param user: user to look for.
+        :param path: path to look for.
+        :return: permission.
+        """
+        if not path.startswith("/"):
+            return PERM_DENIED
+        perm = PERM_DENIED
+        pathFound = False
+        while not pathFound and path != "/":
+            print >>sys.stderr, "DEBUG:", path
+            pathFound = self.config.has_section(path)
+            if (pathFound):
+                options = reversed(self.config.options(path))
+                for option in options:
+                    value = PERM_DICT.get(self.config.get(path, option),
+                                          PERM_DENIED)
+                    if self._is_relevant(option, user):
+                        perm = value
+            else:
+                path = os.path.dirname(path)
+        return perm
+      
+      
+    def _is_relevant(self, option, user):
+        """Decides if a certain option is relevant for a given user.
+      
+        An option is relevant if it is identical with the user or with a
+        reference to a group including the user.
+      
+        :param option: Option to check.
+        :param user: User
+        :return: True if option is relevant for the user, False otherwise.
+        """
+        if option.startswith("@"):
+            result = (user in self.groups.get(option[1:], set()))
+        else:
+            result = (option == user)
+        return result
+
+
+
+def get_directory(command):
+    """Extracts the directory name from the command pass to ssh.
+    :param command: command to parse.
+    :return: Directory name or empty string, if directory was not found or if it
+    does not start with '/'.
+    """
+    match = PAT_SSH_COMMAND.match(command)
+    if not match:
+        return ""
+    directory = match.group("dir")
+    return os.path.normpath(directory)
+
+
+
+############################################################################
+# Main program
+############################################################################
+def main():
+    # Read arguments
+    if len(sys.argv) != 4:
+        error("Invalid number or arguments.", EXIT_BAD_NR_ARG)
+    (bzrExec, repoRoot, user) = sys.argv[1:4]
+    
+    # Sanity checks
+    if not os.access(bzrExec, os.X_OK):
+        error("bzr is not executable.", EXIT_BZR_NOEXEC)
+    if not os.access(repoRoot, os.R_OK):
+        error("Path to repository not readable.", EXIT_REPO_NOREAD)
+    
+    # Extract the repository path from the command passed to ssh.
+    if not os.environ.has_key("SSH_ORIGINAL_COMMAND"):
+        error("Environment variable SSH_ORIGINAL_COMMAND missing.", EXIT_BADENV)
+    directory = get_directory(os.environ["SSH_ORIGINAL_COMMAND"])
+    if len(directory) == 0:
+        error("Bad directory name.", EXIT_BADDIR)
+
+    # Control user name
+    if not user.isalnum():
+        error("Invalid user name", EXIT_BADUSERNAME)
+    
+    # Read in config file.
+    try:
+        fp = open(os.path.join(repoRoot, CONFIG_FILE), "r")
+        try:
+            accessMan = AccessManager(fp)
+        finally:
+            fp.close()
+    except IOError:
+        error("Can't read config file.", EXIT_NOCONF)
+    
+    # Determine permission and execute bzr with appropriate options
+    perm = accessMan.permission(user, directory)
+    absDir = os.path.join(repoRoot, directory)
+    command = [bzrExec] + BZR_OPTIONS + [absDir]
+    if perm == PERM_READ:
+        # Nothing extra needed for readonly operations
+        pass
+    elif perm == PERM_READWRITE:
+        # Add the write flags
+        command.extend(BZR_READWRITE_FLAGS)
+    else:
+        error("Access denied.", EXIT_NOACCESS)
+    return subprocess.call(command)
+
+
+if __name__ == "__main__":
+  main()
+
+
+### Local Variables:
+### mode:python
+### End:




More information about the bazaar-commits mailing list