def test_no_notListed(): cfg = RawConfigParser() cfg.add_section("group hackers") cfg.set("group hackers", "members", "wsmith") gen = group.getMembership(config=cfg, user="******") eq(gen.next(), "all") assert_raises(StopIteration, gen.next)
def test_no_notListed(): cfg = RawConfigParser() cfg.add_section('group hackers') cfg.set('group hackers', 'members', 'wsmith') gen = group.getMembership(config=cfg, user='******') eq(next(gen), 'all') assert_raises(StopIteration, gen.__next__)
def test_no_notListed(): cfg = RawConfigParser() cfg.add_section('group hackers') cfg.set('group hackers', 'members', 'wsmith') gen = group.getMembership(config=cfg, user='******') eq(gen.next(), 'all') assert_raises(StopIteration, gen.next)
def test_yes_middle(): cfg = RawConfigParser() cfg.add_section('group hackers') cfg.set('group hackers', 'members', 'wsmith jdoe danny') gen = group.getMembership(config=cfg, user='******') eq(gen.next(), 'hackers') eq(gen.next(), 'all') assert_raises(StopIteration, gen.next)
def test_no_recurse_loop(): cfg = RawConfigParser() cfg.add_section('group hackers') cfg.set('group hackers', 'members', '@smackers') cfg.add_section('group smackers') cfg.set('group smackers', 'members', '@hackers') gen = group.getMembership(config=cfg, user='******') eq(gen.next(), 'all') assert_raises(StopIteration, gen.next)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ log = logging.getLogger('gitosis.access.haveAccess') log.debug('Access check for %(user)r as %(mode)r on %(path)r...' % dict(user=user, mode=mode, path=path)) basename, ext = os.path.splitext(path) if ext == '.git': log.debug('Stripping .git suffix from %(path)r, new value %(basename)r' % dict(path=path, basename=basename,)) path = basename for groupname in group.getMembership(config=config, user=user): try: repos = config.get('group %s' % groupname, mode) except (NoSectionError, NoOptionError): repos = [] else: repos = repos.split() mapping = None if path in repos: log.debug('Access ok for %(user)r as %(mode)r on %(path)r' % dict(user=user, mode=mode, path=path )) mapping = path else: try: mapping = config.get('group %s' % groupname, 'map %s %s' % (mode, path)) except (NoSectionError, NoOptionError): pass else: log.debug('Access ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' % dict(user=user, mode=mode, path=path, mapping=mapping,)) if mapping is not None: prefix = None try: prefix = config.get('group %s' % groupname, 'repositories') except (NoSectionError, NoOptionError): try: prefix = config.get('gitosis', 'repositories') except (NoSectionError, NoOptionError): prefix = 'repositories' log.debug('Using prefix %(prefix)r for %(path)r' % dict(prefix=prefix, path=mapping,)) return (prefix, mapping)
def test_no_recurse_loop(): cfg = RawConfigParser() cfg.add_section("group hackers") cfg.set("group hackers", "members", "@smackers") cfg.add_section("group smackers") cfg.set("group smackers", "members", "@hackers") gen = group.getMembership(config=cfg, user="******") eq(gen.next(), "all") assert_raises(StopIteration, gen.next)
def allowed(config, user, mode, path): """Check if a user is allowed to access a given path. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. :param config: ``gitosis`` config object :param str user: a user to check access rights for :param str mode: access `readonly` or `writable` :param str path: name of the repository to check access rights for (this is what you write in ``[repo ... ]`` section of your ``gitosis.conf``) """ log = logging.getLogger("gitosis.access.allowed") log.debug("Access check for {0} as {1} on {2}...".format(user, mode, path)) basename, ext = os.path.splitext(path) if ext == ".git": log.debug("Stripped `.git` suffix from {0}, new value {1}." .format(path, basename)) path = basename # a) first check if a user is an owner of the repository # == has unlimited access. owner = config.get("repo {0}".format(path), "owner") if owner and owner == user: log.debug("Acces ok for {0!r} as {1!r} on {2!r} (owner)" .format(user, mode, path)) return get_repository_prefix(config), path # b) iterate over user's groups and check if it has requested # pass in any of the sections. ok = False for group in _group.getMembership(config=config, user=user): repos = config.get("group {0}".format(group), mode, default="").split() if path in repos: log.debug("Access ok for {0!r} as {1!r} on {2!r}" .format(user, mode, path)) ok = True elif os.path.join(os.path.dirname(path), "*") in repos: log.debug("Wildcard access ok for {0!r} as {1!r} on {2!r}" .format(user, mode, path)) ok = True else: mapping = config.get("group {0}".format(group), "map {0} {1}".format(mode, path)) if mapping: log.debug("Access ok for {0!r} as {1!r} on {2!r}={3!r}" .format(user, mode, path, mapping)) ok, path = True, mapping if ok: prefix = get_repository_prefix(config, group) log.debug("Using prefix {0!r}for {1!r}".format(prefix, path)) return prefix, path
def test_yes_recurse_one_ordering(): cfg = RawConfigParser() cfg.add_section("group smackers") cfg.set("group smackers", "members", "danny jdoe") cfg.add_section("group hackers") cfg.set("group hackers", "members", "wsmith @smackers") gen = group.getMembership(config=cfg, user="******") eq(gen.next(), "smackers") eq(gen.next(), "hackers") eq(gen.next(), "all") assert_raises(StopIteration, gen.next)
def test_yes_recurse_one_ordering(): cfg = RawConfigParser() cfg.add_section('group smackers') cfg.set('group smackers', 'members', 'danny jdoe') cfg.add_section('group hackers') cfg.set('group hackers', 'members', 'wsmith @smackers') gen = group.getMembership(config=cfg, user='******') eq(next(gen), 'smackers') eq(next(gen), 'hackers') eq(next(gen), 'all') assert_raises(StopIteration, gen.__next__)
def test_yes_recurse_one_ordering(): cfg = RawConfigParser() cfg.add_section('group smackers') cfg.set('group smackers', 'members', 'danny jdoe') cfg.add_section('group hackers') cfg.set('group hackers', 'members', 'wsmith @smackers') gen = group.getMembership(config=cfg, user='******') eq(gen.next(), 'smackers') eq(gen.next(), 'hackers') eq(gen.next(), 'all') assert_raises(StopIteration, gen.next)
def test_yes_recurse_junk(): cfg = RawConfigParser() cfg.add_section('group hackers') cfg.set('group hackers', 'members', '@notexist @smackers') cfg.add_section('group smackers') cfg.set('group smackers', 'members', 'jdoe') gen = group.getMembership(config=cfg, user='******') eq(next(gen), 'smackers') eq(next(gen), 'hackers') eq(next(gen), 'all') assert_raises(StopIteration, gen.__next__)
def test_yes_recurse_three(): cfg = RawConfigParser() cfg.add_section('group hackers') cfg.set('group hackers', 'members', 'wsmith @smackers') cfg.add_section('group smackers') cfg.set('group smackers', 'members', 'danny @snackers') cfg.add_section('group snackers') cfg.set('group snackers', 'members', '@whackers foo') cfg.add_section('group whackers') cfg.set('group whackers', 'members', 'jdoe') gen = group.getMembership(config=cfg, user='******') eq(gen.next(), 'whackers') eq(gen.next(), 'snackers') eq(gen.next(), 'smackers') eq(gen.next(), 'hackers') eq(gen.next(), 'all') assert_raises(StopIteration, gen.next)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ detail = [] log = logging.getLogger('gitosis.access.haveAccess') log.debug( 'Access check for %(user)r as %(mode)r on %(path)r...' % dict( user=user, mode=mode, path=path, )) basename, ext = os.path.splitext(path) if ext == '.git': log.debug( 'Stripping .git suffix from %(path)r, new value %(basename)r' % dict( path=path, basename=basename, )) path = basename repo = None try: repo = config.lookup_repo(path) except GitoliteConfigException: log.exception("When lookup which repo contains '%s'" % path) if not repo: log.warning("No repo contains path '%s'" % path) return mapping = None try: users = config.get_repo(repo, mode) except GitoliteConfigException: log.exception("When get '%s' of '%s':" % (mode, repo)) return if users: if user in users: mapping = path else: for groupname in group.getMembership(config=config, user=user): if groupname in users: mapping = path detail.append("as group '%s'" % groupname) break if mapping is not None: if detail: detail = '(%s)' % ', '.join(detail) else: detail = '' log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r(%(detail)s)' % dict( user=user, mode=mode, path=path, detail=detail )) prefix = config.get_gitosis('repositories') if prefix == None: prefix = 'repositories' log.debug( 'Using prefix %(prefix)r for %(path)r' % dict( prefix=prefix, path=mapping, )) return (prefix, mapping)
def test_no_emptyConfig(): cfg = RawConfigParser() gen = group.getMembership(config=cfg, user='******') eq(next(gen), 'all') assert_raises(StopIteration, gen.__next__)
def test_no_emptyGroup(): cfg = RawConfigParser() cfg.add_section("group hackers") gen = group.getMembership(config=cfg, user="******") eq(gen.next(), "all") assert_raises(StopIteration, gen.next)
def test_no_emptyGroup(): cfg = RawConfigParser() cfg.add_section('group hackers') gen = group.getMembership(config=cfg, user='******') eq(next(gen), 'all') assert_raises(StopIteration, gen.__next__)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ log = logging.getLogger('gitosis.access.haveAccess') log.debug('Access check for %(user)r as %(mode)r on %(path)r...' % dict( user=user, mode=mode, path=path, )) basename, ext = os.path.splitext(path) if ext == '.git': log.debug( 'Stripping .git suffix from %(path)r, new value %(basename)r' % dict( path=path, basename=basename, )) path = basename for groupname in group.getMembership(config=config, user=user): try: repos = config.get('group %s' % groupname, mode) except (NoSectionError, NoOptionError): repos = [] else: repos = repos.split() mapping = None if path in repos or isWildcardAccessible(path, repos): log.debug('Access ok for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) mapping = path else: try: mapping = config.get('group %s' % groupname, 'map %s %s' % (mode, path)) except (NoSectionError, NoOptionError): pass else: log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' % dict( user=user, mode=mode, path=path, mapping=mapping, )) if mapping is not None: prefix = None try: prefix = config.get('group %s' % groupname, 'repositories') except (NoSectionError, NoOptionError): try: prefix = config.get('gitosis', 'repositories') except (NoSectionError, NoOptionError): prefix = 'repositories' log.debug('Using prefix %(prefix)r for %(path)r' % dict( prefix=prefix, path=mapping, )) return (prefix, mapping)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ log = logging.getLogger('gitosis.access.haveAccess') synonyms = {} synonyms['read'] = ['readonly', 'readable'] synonyms['write'] = ['writable', 'writeable'] synonyms['admin'] = ['init','initial'] mode_syns = [] for key, mode_syns in synonyms.items(): if mode == key: break elif mode in mode_syns: if mod != mode_syns[0]: log.warning( 'Provide haveAccess with mode: "' + mode + '" ' + 'for repository %r should be "' + key +'"', path, ) mode = key break if key != mode: log.warning('Unknown acl mode %s, check gitosis config file.' % mode) mode_syns = [mode] else: mode_syns.append(mode) log.debug( 'Access check for %(user)r as %(mode)r on %(path)r...' % dict( user=user, mode=mode, path=path, )) basename, ext = os.path.splitext(path) if ext == '.git': log.debug( 'Stripping .git suffix from %(path)r, new value %(basename)r' % dict( path=path, basename=basename, )) path = basename for groupname in group.getMembership(config=config, user=user): repos = "" try: options = config.options('group %s' % groupname) for syn in mode_syns: if syn in options: if syn != mode and syn != mode_syns[0]: log.warning( 'Repository %r config has typo "' + syn + '", ' +'should be "' + mode +'"', path, ) repos = config.get('group %s' % groupname, syn) break except (NoSectionError, NoOptionError): repos = [] else: repos = repos.split() mapping = None # fnmatch provide glob match support. Jiang Xin <jiangxin AT ossxp.com> for r in repos: if fnmatch(path, r): log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) mapping = path break # Check mapping even if (path,mode) found in this group. try: re_mapping = None for option in config.options('group %s' % groupname): if not option.startswith('map'): continue (_ignore, opt_right) = option.split(' ',1) (opt_mode, opt_path) = opt_right.strip().split(' ',1) opt_path = opt_path.strip() if opt_mode not in mode_syns: continue if fnmatch(path, opt_path): re_mapping = config.get('group %s' % groupname, option) if ':' in re_mapping: (opt_from, opt_to) = re_mapping.split(':',1) re_mapping = re.sub(opt_from, opt_to, path) elif '\\1' in re_mapping: re_mapping = re_mapping.replace('\\1', path) break except (NoSectionError, NoOptionError): pass else: if re_mapping is not None: mapping = re_mapping log.debug( 'Mapping ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' % dict( user=user, mode=mode, path=path, mapping=mapping, )) if mapping is not None: prefix = None try: prefix = config.get( 'group %s' % groupname, 'repositories') except (NoSectionError, NoOptionError): try: prefix = config.get('gitosis', 'repositories') except (NoSectionError, NoOptionError): prefix = 'repositories' log.debug( 'Using prefix %(prefix)r for %(path)r' % dict( prefix=prefix, path=mapping, )) return (prefix, mapping, mode)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ log = logging.getLogger('gitosis.access.haveAccess') synonyms = {} synonyms['read'] = ['readonly', 'readable'] synonyms['write'] = ['writable', 'writeable'] synonyms['admin'] = ['init', 'initial'] mode_syns = [] for key, mode_syns in synonyms.items(): if mode == key: break elif mode in mode_syns: if mod != mode_syns[0]: log.warning( 'Provide haveAccess with mode: "' + mode + '" ' + 'for repository %r should be "' + key + '"', path, ) mode = key break if key != mode: log.warning('Unknown acl mode %s, check gitosis config file.' % mode) mode_syns = [mode] else: mode_syns.append(mode) log.debug('Access check for %(user)r as %(mode)r on %(path)r...' % dict( user=user, mode=mode, path=path, )) basename, ext = os.path.splitext(path) if ext == '.git': log.debug( 'Stripping .git suffix from %(path)r, new value %(basename)r' % dict( path=path, basename=basename, )) path = basename for groupname in group.getMembership(config=config, user=user): repos = "" try: options = config.options('group %s' % groupname) for syn in mode_syns: if syn in options: if syn != mode and syn != mode_syns[0]: log.warning( 'Repository %r config has typo "' + syn + '", ' + 'should be "' + mode + '"', path, ) repos = config.get('group %s' % groupname, syn) break except (NoSectionError, NoOptionError): repos = [] else: repos = repos.split() mapping = None # fnmatch provide glob match support. Jiang Xin <jiangxin AT ossxp.com> for r in repos: if fnmatch(path, r): log.debug('Access ok for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) mapping = path break # Check mapping even if (path,mode) found in this group. try: re_mapping = None for option in config.options('group %s' % groupname): if not option.startswith('map'): continue (_ignore, opt_right) = option.split(' ', 1) (opt_mode, opt_path) = opt_right.strip().split(' ', 1) opt_path = opt_path.strip() if opt_mode not in mode_syns: continue if fnmatch(path, opt_path): re_mapping = config.get('group %s' % groupname, option) if ':' in re_mapping: (opt_from, opt_to) = re_mapping.split(':', 1) re_mapping = re.sub(opt_from, opt_to, path) elif '\\1' in re_mapping: re_mapping = re_mapping.replace('\\1', path) break except (NoSectionError, NoOptionError): pass else: if re_mapping is not None: mapping = re_mapping log.debug( 'Mapping ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' % dict( user=user, mode=mode, path=path, mapping=mapping, )) if mapping is not None: prefix = None try: prefix = config.get('group %s' % groupname, 'repositories') except (NoSectionError, NoOptionError): try: prefix = config.get('gitosis', 'repositories') except (NoSectionError, NoOptionError): prefix = 'repositories' log.debug('Using prefix %(prefix)r for %(path)r' % dict( prefix=prefix, path=mapping, )) return (prefix, mapping, mode)
def test_no_emptyConfig(): cfg = RawConfigParser() gen = group.getMembership(config=cfg, user='******') eq(gen.next(), 'all') assert_raises(StopIteration, gen.next)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ log = logging.getLogger('gitosis.access.haveAccess') log.debug('Access check for %(user)r as %(mode)r on %(path)r...' % dict( user=user, mode=mode, path=path, )) basename, ext = os.path.splitext(path) if ext == '.git': log.debug( 'Stripping .git suffix from %(path)r, new value %(basename)r' % dict( path=path, basename=basename, )) path = basename # First test an explicit '[user %s]' section log.debug( 'Checking for explicit access for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) try: repos = config.get('user %s' % user, mode) except (NoSectionError, NoOptionError): repos = [] else: log.debug('Found section for %(user)r as %(mode)r = %(repos)r' % dict( user=user, mode=mode, repos=repos, )) repos = repos.split() mapping = None groupname = None if path in repos: log.debug('Explicit access ok for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) mapping = path else: # then go in old code for groupname in group.getMembership(config=config, user=user): try: repos = config.get('group %s' % groupname, mode) except (NoSectionError, NoOptionError): repos = [] else: repos = repos.split() mapping = None if path in repos: log.debug('Access ok for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) mapping = path break else: try: mapping = config.get('group %s' % groupname, 'map %s %s' % (mode, path)) except (NoSectionError, NoOptionError): pass else: log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' % dict( user=user, mode=mode, path=path, mapping=mapping, )) break # If we used a [user _] section, we consider being in the 'gitosis' group if groupname is None: groupname = 'gitosis' if mapping is not None: prefix = None try: prefix = config.get('group %s' % groupname, 'repositories') except (NoSectionError, NoOptionError): try: prefix = config.get('gitosis', 'repositories') except (NoSectionError, NoOptionError): prefix = 'repositories' log.debug('Using prefix %(prefix)r for %(path)r' % dict( prefix=prefix, path=mapping, )) return (prefix, mapping)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ log = logging.getLogger('gitosis.access.haveAccess') log.debug( 'Access check for %(user)r as %(mode)r on %(path)r...' % dict( user=user, mode=mode, path=path, )) basename, ext = os.path.splitext(path) if ext == '.git': log.debug( 'Stripping .git suffix from %(path)r, new value %(basename)r' % dict( path=path, basename=basename, )) path = basename try: default_prefix = config.get('gitosis', 'repositories') except (NoSectionError, NoOptionError): default_prefix = 'repositories' sections = ['group %s' % item for item in group.getMembership(config=config, user=user)] sections.insert(0, 'user %s' % user) for sectname in sections: try: repos = config.get(sectname, mode) except (NoSectionError, NoOptionError): repos = [] else: repos = repos.split() mapping = None if path in repos: log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) mapping = path else: try: mapping = config.get(sectname, 'map %s %s' % (mode, path)) except (NoSectionError, NoOptionError): pass else: log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' % dict( user=user, mode=mode, path=path, mapping=mapping, )) if mapping is None and mode == 'readonly': try: if config.getboolean(sectname, 'allow-read-all'): log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r via allow-read-all' % dict(user=user,mode=mode,path=path)) mapping = path except (NoSectionError, NoOptionError): pass if mapping is not None: prefix = None try: prefix = config.get(sectname, 'repositories') except (NoSectionError, NoOptionError): prefix = default_prefix log.debug( 'Using prefix %(prefix)r for %(path)r' % dict( prefix=prefix, path=mapping, )) return (prefix, mapping) owner = getOwnerAccess(config, mode, path) if owner == user: try: prefix = config.get('user %s' % owner, 'repositories') except (NoSectionError, NoOptionError): prefix = default_prefix log.debug( 'Access ok for %(user)r as %(mode)r on owned %(path)r, using prefix %(prefix)r' % dict( prefix=prefix, path=path, user=user, mode=mode, )) return (prefix, path)
def test_no_emptyGroup(): cfg = RawConfigParser() cfg.add_section('group hackers') gen = group.getMembership(config=cfg, user='******') eq(gen.next(), 'all') assert_raises(StopIteration, gen.next)
def haveAccess(config, user, mode, path): """ Map request for write access to allowed path. Note for read-only access, the caller should check for write access too. Returns ``None`` for no access, or a tuple of toplevel directory containing repositories and a relative path to the physical repository. """ log = logging.getLogger('gitosis.access.haveAccess') log.debug( 'Access check for %(user)r as %(mode)r on %(path)r...' % dict( user=user, mode=mode, path=path, )) basename, ext = os.path.splitext(path) if ext == '.git': log.debug( 'Stripping .git suffix from %(path)r, new value %(basename)r' % dict( path=path, basename=basename, )) path = basename sections = ['group %s' % item for item in group.getMembership(config=config, user=user)] sections.insert(0, 'user %s' % user) for sectname in sections: repos = util.getConfigList(config, sectname, mode) mapping = None if pathMatchPatterns(path, repos): log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r' % dict( user=user, mode=mode, path=path, )) mapping = path else: mapping = util.getConfigDefault(config, sectname, 'map %s %s' % (mode, path), None) if mapping: log.debug( 'Access ok for %(user)r as %(mode)r on %(path)r=%(mapping)r' % dict( user=user, mode=mode, path=path, mapping=mapping, )) if mapping is not None: prefix = util.getConfigDefault(config, sectname, 'repositories', 'repositories', 'gitosis') log.debug( 'Using prefix %(prefix)r for %(path)r' % dict( prefix=prefix, path=mapping, )) return (prefix, mapping)