From db0485fa7e92fa2f0164c778df23499d80d4bbb9 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 7 Oct 2010 16:36:14 +0530 Subject: [PATCH] new method for passing usergroup info (warning: minor backward compat breakage) The old method of passing in usergroup info had some problems, which are now fixed. It is also much easier to use now -- no more "wrapper" script, plus it should work identially whether you use sshd or httpd. See doc/big-config.mkd for details on the new method. ---- Notes on problems with the old method: The old method for passing in usergroup info consisted of tacking them on as extra arguments to gl-auth-command, after the username. However, there are some problems with this method. Some actions in gitolite look for permissions for users other than the invoking user. Determining permissions for gitweb and daemon is one. An admin asking for "info" on some other user, is another. However, the list of groups sent in via the command line pertains only to the invoking user, so these actions don't work correctly. They may even pick up the wrong permissions. What it all boils down to is that we need group information for any user dynamically, instead of being passed a (static) list just for the invoking user. --- conf/example.gitolite.rc | 12 +++++++ doc/big-config.mkd | 71 ++++++++++++++++++++++------------------ src/gitolite.pm | 18 +++++++--- src/gl-auth-command | 4 --- 4 files changed, 65 insertions(+), 40 deletions(-) diff --git a/conf/example.gitolite.rc b/conf/example.gitolite.rc index e189595..c563e81 100644 --- a/conf/example.gitolite.rc +++ b/conf/example.gitolite.rc @@ -273,6 +273,18 @@ $GL_WILDREPOS = 0; # $GL_SITE_INFO = ""; # $GL_SITE_INFO = "XYZ.COM DEVELOPERS: PLEASE SEE http://xyz.com/gitolite/help first"; +# -------------------------------------- +# USERGROUP HANDLING + +# Some sites would like to store group membership outside gitolite, because +# they already have it in (usually) their LDAP server, and it doesn't make +# sense to be forced to duplicate this information. + +# Set the following variable to the name of a script that, given a username as +# argument, will return a list of groups that she is a member of. + +# $GL_GET_MEMBERSHIPS_PGM = "/usr/local/bin/expand-ldap-user-to-groups" + # -------------------------------------- # per perl rules, this should be the last line in such a file: 1; diff --git a/doc/big-config.mkd b/doc/big-config.mkd index b2f35b0..c4ea551 100644 --- a/doc/big-config.mkd +++ b/doc/big-config.mkd @@ -6,7 +6,9 @@ In this document: * how do we use it? * other optimisations * what are the downsides? - * (extra coolness) usergroups and LDAP/similar tools + * storing usergroup information outside gitolite (like in LDAP) + * why + * how @@ -190,51 +192,58 @@ subset of the allowed @fragname, which would work normally, do not work now). (If you didn't understand all that, you're probably not using delegation, so feel free to ignore it!) - + -### (extra coolness) usergroups and LDAP/similar tools +### storing usergroup information outside gitolite (like in LDAP) [Please NOTE: this is all about *user* groups, not *repo* groups] -Gitolite now allows usergroup information to be passed in from outside. The -`gl-auth-commmand` can now take an optional list of usergroup names after the -first argument (which is the username). +[WARNING: the earlier method of doing this has been discontinued; please see +the commit message for details] -To understand why this is useful, consider the following: +Gitolite now allows usergroup information to be stored outside its own config +file. We'll see "why" first, then the "how". -Some people have an LDAP-backed ssh daemon (or some other similar mechanism -that can speak "ssh" to the client), with pubkeys stored in LDAP, etc., and -some way (not using `~/.ssh/authorized_keys`) of invoking gitolite. + -Such setups also have "usergroups", and a way to tell, for each user, what -groups he/she is a member of. So let's say "alice" works on projects "foo" -and "bar", while "bob" works on project "bar" and is a member of the -`L3_support` team. +#### why -You can use those group names in the gitolite config file for access control -as "@foo", "@bar", `@L3_support`, etc.; please note the "@" prefix because -gitolite requires it. +Large sites often have LDAP servers that already contain user and group +information, including group membership details. Such sites may prefer that +gitolite just pick up that info instead of having to redundantly put it in +gitolite's config file. -However, that still leaves a wee little inconvenience. You still have to add -lines like this to the gitolite config file: +Consider this example config for one repo: - @foo = alice - @bar = alice bob - @L3_support = bob + repo foo + RW+ = @lead_devs + RW = @devs + R = @interns -You don't need to do that anymore now. Tell your authentication system that, -after authenticating alice, instead of running: +Normally, you would also need to specify: - /some/path/to/gl-auth-command alice + @lead_devs = dilbert alice + @devs = wally + @interns = ashok -it should first find the groups that alice is a member of, and then run: +However, if the corporate LDAP server already tags these people correctly, and +if there is some way of getting that information out **at run time**, that +would be cool. - /some/path/to/gl-auth-command alice foo bar + -That's it. Internally, gitolite will behave as if the config file had also -specified: +#### how - @foo = alice - @bar = alice +All you need is a script that, given a username, queries your LDAP or similar +server, and returns a space-separated list of all the groups she is a member +of. If an invalid user name is sent in, or the user is valid but is not part +of any groups, it should print nothing. + +This script will probably be specific to your site. [**Help wanted**: I don't +know LDAP, so if someone wants to contribute some sample code I'd be happy to +put it in contrib/, with credit of course!] + +Then set the `$GL_GET_MEMBERSHIPS_PGM` variable in the rc file to the full +path to this program, set `$GL_BIG_CONFIG` to 1, and that will be that. [gwd]: http://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#gwd diff --git a/src/gitolite.pm b/src/gitolite.pm index 80210d5..d689f88 100644 --- a/src/gitolite.pm +++ b/src/gitolite.pm @@ -40,7 +40,7 @@ our $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z[][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/-]*$); our $ADC_CMD_ARGS_PATT=qr(^[0-9a-zA-Z._\@/+-]*$); # these come from the RC file -our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE, $GL_CONF_COMPILED, $GL_BIG_CONFIG, $GL_PERFLOGT, $PROJECTS_LIST, $GL_ALL_INCLUDES_SPECIAL, $GL_SITE_INFO); +our ($REPO_UMASK, $GL_WILDREPOS, $GL_PACKAGE_CONF, $GL_PACKAGE_HOOKS, $REPO_BASE, $GL_CONF_COMPILED, $GL_BIG_CONFIG, $GL_PERFLOGT, $PROJECTS_LIST, $GL_ALL_INCLUDES_SPECIAL, $GL_SITE_INFO, $GL_GET_MEMBERSHIPS_PGM); our %repos; our %groups; our %repo_config; @@ -932,6 +932,7 @@ sub special_cmd # - (only for repos) as an indirect wildcard (@g = foo/.*; repo @g). # note: the wildcard stuff does not apply to username memberships +our %extgroups_cache; sub get_memberships { my $base = shift; # reponame or username my $is_repo = shift; # some true value means a repo name has been passed @@ -969,10 +970,17 @@ sub get_memberships { # deal with returning user info first unless ($is_repo) { - # add in group membership info sent in via second and subsequent - # arguments to gl-auth-command; be sure to prefix the "@" sign to each - # of them! - push @ret, map { s/^/@/; $_; } split(' ', $ENV{GL_GROUP_LIST}) if $ENV{GL_GROUP_LIST}; + # bring in group membership info stored externally, by running + # $GL_GET_MEMBERSHIPS_PGM if it is defined + + if ($extgroups_cache{$base}) { + push @ret, @{ $extgroups_cache{$base} }; + } elsif ($GL_GET_MEMBERSHIPS_PGM) { + my @extgroups = map { s/^/@/; $_; } split ' ', `$GL_GET_MEMBERSHIPS_PGM $base`; + $extgroups_cache{$base} = \@extgroups; + push @ret, @extgroups; + } + return (@ret); } diff --git a/src/gl-auth-command b/src/gl-auth-command index 2a6ab02..dabfa71 100755 --- a/src/gl-auth-command +++ b/src/gl-auth-command @@ -114,10 +114,6 @@ if ($ENV{REQUEST_URI}) { $user=$ENV{GL_USER}=shift; } -# if there are any more arguments, they're a list of group names that the user -# is a member of -$ENV{GL_GROUP_LIST} = join(" ", @ARGV) if @ARGV; - # ---------------------------------------------------------------------------- # logging, timestamp env vars # ----------------------------------------------------------------------------