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