threads / rfc / 16154

RFC patchgitweb: Support filtering projects by .htaccess files.

Subject: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

## tl;dr

14 messages between Nov 3, 2008 and Nov 6, 2008. Diffs are folded; open one to read it.

replies: 13people: 3as markdown or json

Alexander Gavrilov· Nov 3, 2008, 16:43 UTC · lore

Some environments may require selective limiting of read access to repositories. While even dumb http transport supports it through .htaccess files, gitweb currently does not implement discretionary access control.

This patch adds a configuration-contolled check that matches simple 'Reguire user'/'Reguire group' lines in the .htaccess files with the authenticated user name. Using group authentication requires specifying a path to the Apache group file in the configuration.

Using htaccess has an additional bonus that the same authentication data can be used both for gitweb and the dumb http transport.

Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
	I also created a gitosis fork that can generate the necessary files:
		http://repo.or.cz/w/gitosis/httpauth.git
	-- Alexander
 gitweb/INSTALL     |   14 ++++++++++
 gitweb/gitweb.perl |   68 +++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 79 insertions(+), 3 deletions(-)
Show changes to 2 files +79 −3

gitweb/INSTALL, gitweb/gitweb.perl

diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 26967e2..0841db6 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -166,6 +166,20 @@ Gitweb repositories
   shows repositories only if this file exists in its object database
   (if directory has the magic file named $export_ok).
 
+- Finally, it is possible to use primitive .htaccess authentication by
+  enabling the $check_htaccess variable in the config file. Gitweb
+  recognizes the following htaccess commands:
+
+    Require user name1 name2 ...     # grant access to the listed users
+    Require group group1 group2 ...  # grant access to the listed groups
+    Deny from all                    # deny unless overridden by a Require
+
+  Access is granted if the currently authenticated user matches one
+  of the Require lines, or if the file does not contain any of the listed
+  commands, or if .htaccess does not exist. If the file exists but cannot
+  be opened, access is denied. To use group authentication you have to
+  point $auth_group_file to the group list in Apache format.
+
 Generating projects list using gitweb
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 63c793e..4b962c3 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -98,6 +98,12 @@ our $export_ok = "++GITWEB_EXPORT_OK++";
 # only allow viewing of repositories also shown on the overview page
 our $strict_export = "++GITWEB_STRICT_EXPORT++";
 
+# check basic authentication rules in .htaccess
+our $check_htaccess  = 0;
+
+# name of the file that lists groups for htaccess check
+our $auth_group_file = "";
+
 # list of git base URLs used for URL to where fetch project from,
 # i.e. full URL is "$git_base_url/$project"
 our @git_base_url_list = grep { $_ ne '' } ("++GITWEB_BASE_URL++");
@@ -397,10 +403,64 @@ sub check_head_link {
 		(-l $headfile && readlink($headfile) =~ /^refs\/heads\//));
 }
 
+# set of htaccess groups for the current user
+our %cur_auth_groups = ();
+
+sub find_current_groups($$) {
+	my ($gfile, $user) = @_;
+	return () unless $gfile && $user;
+
+	my @groups;
+	open my $gf, $gfile or return ();
+
+	while(<$gf>) {
+		next unless /^\s*(\S+)\s*:\s*(\S.*\S)\s*$/;
+		my ($grp, $usrs) = ($1, $2);
+		push @groups, $grp if grep { $_ eq $user } split (' ', $usrs);
+	}
+
+	close $gf;
+	return @groups;
+}
+
+sub check_htaccess_files($) {
+	my ($dir) = @_;
+	my $user = $cgi->remote_user() || ' ';
+
+	while (length $dir >= length $projectroot) {
+		my $file = "$dir/.htaccess";
+		next unless -e $file;
+		open my $htf, $file or return 0;
+
+		my $ok = 0;
+		my $need_ok = 0;
+		while (<$htf>) {
+			if (/^\s*Require\s+user\s+(\S.*\S)\s*$/i) {
+				$ok++ if grep { $_ eq $user; } split (' ', $1);
+				$need_ok++;
+			} elsif (/^\s*Require\s+group\s+(\S.*\S)\s*$/i) {
+				$ok++ if grep { $cur_auth_groups{$_}; } split(' ', $1);
+				$need_ok++;
+			} elsif (/^\s*Deny\s+from\s+all\s*$/ix) {
+				$need_ok++;
+			}
+		}
+		close $htf;
+
+		return $ok if $need_ok;
+		last;
+	} continue {
+		$dir =~ s/\/[^\/]*$// or last;
+	}
+
+	return 1;
+}
+
 sub check_export_ok {
 	my ($dir) = @_;
 	return (check_head_link($dir) &&
-		(!$export_ok || -e "$dir/$export_ok"));
+		(!$export_ok || -e "$dir/$export_ok") &&
+		(!$check_htaccess || check_htaccess_files($dir)));
 }
 
 # process alternate names for backward compatibility
@@ -626,6 +686,9 @@ if (defined $action) {
 	}
 }
 
+# compute authenticated groups
+$cur_auth_groups{$_}++ for find_current_groups($auth_group_file, $cgi->remote_user());
+
 # parameters which are pathnames
 our $project = $input_params{'project'};
 if (defined $project) {
@@ -853,8 +916,7 @@ sub validate_project {
 	my $input = shift || return undef;
 	if (!validate_pathname($input) ||
 		!(-d "$projectroot/$input") ||
-		!check_head_link("$projectroot/$input") ||
-		($export_ok && !(-e "$projectroot/$input/$export_ok")) ||
+		!check_export_ok("$projectroot/$input") ||
 		($strict_export && !project_in_list($input))) {
 		return undef;
 	} else {
-- 
1.6.0.3.15.gb8d36
Francis Galiegue· Nov 3, 2008, 16:54 UTC · re: Alexander Gavrilov · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Le Monday 03 November 2008 17:43:29, vous avez écrit :
Show 13 quoted lines
> Some environments may require selective limiting of read access to
> repositories. While even dumb http transport supports it through .htaccess
> files, gitweb currently does not implement discretionary access control.
> 
> This patch adds a configuration-contolled check that matches simple
> 'Reguire user'/'Reguire group' lines in the .htaccess files with the
> authenticated user name. Using group authentication requires specifying
> a path to the Apache group file in the configuration.
> 
> Using htaccess has an additional bonus that the same authentication
> data can be used both for gitweb and the dumb http transport.
> 
> Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
It just seems to me that this is emulating functionality that multiple Web servers already provide...
What's more, knowledge about these Web servers are _much_ more widespread than knowledge about gitweb.
Why reinvent the wheel?
Just a thought,
-- 
fge
Alexander Gavrilov· Nov 3, 2008, 17:26 UTC · re: Francis Galiegue · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

On Mon, Nov 3, 2008 at 7:54 PM, Francis Galiegue <fg@one2team.net> wrote:
Show 5 quoted lines
> It just seems to me that this is emulating functionality that multiple Web servers already provide...
>
> What's more, knowledge about these Web servers are _much_ more widespread than knowledge about gitweb.
>
> Why reinvent the wheel?

If you are speaking of web servers as in 'GitHub', then it is irrelevant, because its server software is nonfree.

If you are speaking of web servers as in 'Apache', then how would it know which files are going to be accessed when it executes cgi-bin/gitweb.cgi?p=very/private/project.git to check permissions?

Alexander
Francis Galiegue· Nov 3, 2008, 17:45 UTC · re: Alexander Gavrilov · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Le Monday 03 November 2008 18:26:44 Alexander Gavrilov, vous avez écrit :
Show 10 quoted lines
> On Mon, Nov 3, 2008 at 7:54 PM, Francis Galiegue <fg@one2team.net> wrote:
> > It just seems to me that this is emulating functionality that multiple Web servers already provide...
> >
> > What's more, knowledge about these Web servers are _much_ more widespread than knowledge about gitweb.
> >
> > Why reinvent the wheel?
> 
> If you are speaking of web servers as in 'GitHub', then it is
> irrelevant, because its server software is nonfree.
> 
I didn't even account for these.
> If you are speaking of web servers as in 'Apache', then how would it
> know which files are going to be accessed when it executes
> cgi-bin/gitweb.cgi?p=very/private/project.git to check permissions?
> 
Well, as far as Apache is concerned, it can do:
* basic .htpasswd authentication,
* LDAP,
* PAM,
* SSL certificate check (via mod_ssl),
* probably others.
Plenty of possibilities.

Well, that's just mho. But if ever I complete my current work on git-cvsimport (or using git2(svn|git)), I'll go for option 2: my LDAP database has all the info, and Apache knows about Cache-Control, not gitweb...

NOTE: I'm just saying here that your patch is of no use as far as _I_
am concerned. I'm basically saying that git cannot account for all
authentication schemes out there. Neither can Apache, but it supports a
buckload of them already.
-- 
fge
Jakub Narebski· Nov 3, 2008, 18:18 UTC · re: Francis Galiegue · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Francis Galiegue <fg@one2team.net> writes:
Show 10 quoted lines
> Le Monday 03 November 2008 18:26:44 Alexander Gavrilov, vous avez écrit :
>> On Mon, Nov 3, 2008 at 7:54 PM, Francis Galiegue <fg@one2team.net> wrote:
>>>
>>> It just seems to me that this is emulating functionality that
>>> multiple Web servers already provide...
>>>
>>> What's more, knowledge about these Web servers are _much_ more
>>> widespread than knowledge about gitweb.
>>>
>>> Why reinvent the wheel?
[...]
Show 14 quoted lines
>> If you are speaking of web servers as in 'Apache', then how would it
>> know which files are going to be accessed when it executes
>> cgi-bin/gitweb.cgi?p=very/private/project.git to check permissions?
>> 
> 
> Well, as far as Apache is concerned, it can do:
> 
> * basic .htpasswd authentication,
> * LDAP,
> * PAM,
> * SSL certificate check (via mod_ssl),
> * probably others.
> 
> Plenty of possibilities.
[...]

Well, the question is if Apache (and other web servers used with gitweb) can do authentication based on path_info or on query-string. Because it is encoded in gitweb (via $projectroot) where to find git repositories...

-- 
Jakub Narebski
Poland
ShadeHawk on #git
Francis Galiegue· Nov 3, 2008, 18:44 UTC · re: Jakub Narebski · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Le Monday 03 November 2008 19:18:56 Jakub Narebski, vous avez écrit :
Show 17 quoted lines
> > 
> > Well, as far as Apache is concerned, it can do:
> > 
> > * basic .htpasswd authentication,
> > * LDAP,
> > * PAM,
> > * SSL certificate check (via mod_ssl),
> > * probably others.
> > 
> > Plenty of possibilities.
> [...]
> 
> Well, the question is if Apache (and other web servers used with
> gitweb) can do authentication based on path_info or on query-string.
> Because it is encoded in gitweb (via $projectroot) where to find git
> repositories...
> 

Can you expand on path_info and query-string? Keep in mind that Apache has mod_rewrite, which can rewrite URLs in any way before it gets actually sent to the underlying program (whether it be a CGI or anything else), even badly (or mischievously).

-- 
fge
Jakub Narebski· Nov 3, 2008, 19:17 UTC · re: Francis Galiegue · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Dnia poniedziałek 3. listopada 2008 19:44, Francis Galiegue napisał:
> Le Monday 03 November 2008 19:18:56 Jakub Narebski, vous avez écrit :
Show 21 quoted lines
> > > Well, as far as Apache is concerned, it can do:
> > > 
> > > * basic .htpasswd authentication,
> > > * LDAP,
> > > * PAM,
> > > * SSL certificate check (via mod_ssl),
> > > * probably others.
> > > 
> > > Plenty of possibilities.
> > [...]
> > 
> > Well, the question is if Apache (and other web servers used with
> > gitweb) can do authentication based on path_info or on query-string.
> > Because it is encoded in gitweb (via $projectroot) where to find git
> > repositories...
> > 
> 
> Can you expand on path_info and query-string? Keep in mind that Apache
> has mod_rewrite, which can rewrite URLs in any way before it gets
> actually sent to the underlying program (whether it be a CGI or
> anything else), even badly (or mischievously).
What I mean here that the following example gitweb URLs
  http://example.com/gitweb.cgi?p=some/project.git;a=commit;h=HEAD
  http://example.com/gitweb.cgi/some/project.git/commit/HEAD
with the following gitweb configuration
  $projectroot = /var/scm
both refer to git repository (directory) at
  /var/scm/some/project.git

Apache (or other web server) would have to somehow decide based on URL that it refers to some project, and based on project and authentication decide whether to grant access to it.

What is more, and what cannot be done by web server alone, is that we would want to not show projects which you don't have access to in the 'projects_list' page, i.e. at

  http://example.com/gitweb.cgi
-- 
Jakub Narebski
Poland
Francis Galiegue· Nov 3, 2008, 21:59 UTC · re: Jakub Narebski · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Le Monday 03 November 2008 20:17:47 Jakub Narebski, vous avez écrit :
Show 49 quoted lines
> Dnia poniedziałek 3. listopada 2008 19:44, Francis Galiegue napisał:
> > Le Monday 03 November 2008 19:18:56 Jakub Narebski, vous avez écrit :
> 
> > > > Well, as far as Apache is concerned, it can do:
> > > > 
> > > > * basic .htpasswd authentication,
> > > > * LDAP,
> > > > * PAM,
> > > > * SSL certificate check (via mod_ssl),
> > > > * probably others.
> > > > 
> > > > Plenty of possibilities.
> > > [...]
> > > 
> > > Well, the question is if Apache (and other web servers used with
> > > gitweb) can do authentication based on path_info or on query-string.
> > > Because it is encoded in gitweb (via $projectroot) where to find git
> > > repositories...
> > > 
> > 
> > Can you expand on path_info and query-string? Keep in mind that Apache
> > has mod_rewrite, which can rewrite URLs in any way before it gets
> > actually sent to the underlying program (whether it be a CGI or
> > anything else), even badly (or mischievously).
> 
> What I mean here that the following example gitweb URLs
> 
>   http://example.com/gitweb.cgi?p=some/project.git;a=commit;h=HEAD
>   http://example.com/gitweb.cgi/some/project.git/commit/HEAD
> 
> with the following gitweb configuration
> 
>   $projectroot = /var/scm
> 
> both refer to git repository (directory) at
> 
>   /var/scm/some/project.git
> 
> Apache (or other web server) would have to somehow decide based on URL
> that it refers to some project, and based on project and authentication
> decide whether to grant access to it.
> 
> 
> What is more, and what cannot be done by web server alone, is that we
> would want to not show projects which you don't have access to in the
> 'projects_list' page, i.e. at
> 
>   http://example.com/gitweb.cgi
> 
I see the point. Note that the second URL can be converted into the first one with mod_rewrite, and probably the first to the second as well.
As to what repository is accessible to whom, does gitweb really have an internal mechanism for this? Wouldn't it be "better" is privately accessible projects were available on another website to start with?
Jakub Narebski· Nov 4, 2008, 00:24 UTC · re: Francis Galiegue · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

On Mon, 3 Nov 2008, Francis Galiegue wrote:
> Le Monday 03 November 2008 20:17:47 Jakub Narebski, vous avez écrit :
> > Dnia poniedziałek 3. listopada 2008 19:44, Francis Galiegue napisał:
> > > Le Monday 03 November 2008 19:18:56 Jakub Narebski, vous avez écrit :
Show 35 quoted lines
> > > > Well, the question is if Apache (and other web servers used with
> > > > gitweb) can do authentication based on path_info or on query-string.
> > > > Because it is encoded in gitweb (via $projectroot) where to find git
> > > > repositories...
> > > > 
> > > 
> > > Can you expand on path_info and query-string? Keep in mind that Apache
> > > has mod_rewrite, which can rewrite URLs in any way before it gets
> > > actually sent to the underlying program (whether it be a CGI or
> > > anything else), even badly (or mischievously).
> > 
> > What I mean here that the following example gitweb URLs
> > 
> >   http://example.com/gitweb.cgi?p=some/project.git;a=commit;h=HEAD
> >   http://example.com/gitweb.cgi/some/project.git/commit/HEAD
> > 
> > with the following gitweb configuration
> > 
> >   $projectroot = /var/scm
> > 
> > both refer to git repository (directory) at
> > 
> >   /var/scm/some/project.git
> > 
> > Apache (or other web server) would have to somehow decide based on URL
> > that it refers to some project, and based on project and authentication
> > decide whether to grant access to it.
> > 
> > 
> > What is more, and what cannot be done by web server alone, is that we
> > would want to not show projects which you don't have access to in the
> > 'projects_list' page, i.e. at
> > 
> >   http://example.com/gitweb.cgi
> > 
On the other hand we can decide to display projects for which user
doesn't have access (via HTTP authentication) for, just like
directories in *Index* directive can be shown even if they cannot be
accessed.
 
Show 6 quoted lines
> I see the point. Note that the second URL can be converted into the first
> one with mod_rewrite, and probably the first to the second as well. 
> 
> As to what repository is accessible to whom, does gitweb really have
> an internal mechanism for this? Wouldn't it be "better" is privately
> accessible projects were available on another website to start with?  

The problem is that Apache has to decide whether to deny or grant access based on URL, not on path in filesystem. Perhaps that is possible...

As to having in gitweb mechanism for this... even now gitweb supports
bare-bones access control in terms of $export_ok. BTW you can have
 not displayed but still accessible.project
-- 
Jakub Narebski
Poland
Francis Galiegue· Nov 4, 2008, 07:42 UTC · re: Jakub Narebski · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Le mardi 04 novembre 2008, Jakub Narebski a écrit : [...]

Show 8 quoted lines
> > 
> > As to what repository is accessible to whom, does gitweb really have
> > an internal mechanism for this? Wouldn't it be "better" is privately
> > accessible projects were available on another website to start with?  
> 
> The problem is that Apache has to decide whether to deny or grant access
> based on URL, not on path in filesystem. Perhaps that is possible...
> 

It is, with <Location> or <LocationMatch>. You can use mod_access directives within these (or mod_auth* ones).

-- 
Francis Galiegue, fg@one2team.com
[ATTENTION - CHANGEMENT D'ADRESSE !]
40 av Raymond Poincaré, 75016 PARIS
+33178945570, +33683877875
Jakub Narebski· Nov 3, 2008, 22:57 UTC · re: Alexander Gavrilov · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Nice idea, but for now certainly an RFC
On Mon, 3 Nov 2008, Alexander Gavrilov wrote:
Show 6 quoted lines
> Some environments may require selective limiting of read access to
> repositories. While even dumb http transport supports it through .htaccess
> files, gitweb currently does not implement discretionary access control.
> 
> This patch adds a configuration-contolled check that matches simple
> 'Reguire user'/'Reguire group' lines in the .htaccess files with the
Typo: Reguire -> Require
Show 5 quoted lines
> authenticated user name. Using group authentication requires specifying
> a path to the Apache group file in the configuration.
> 
> Using .htaccess has an additional bonus that the same authentication
> data can be used both for gitweb and the dumb http transport.

I'm not sure if it wouldn't be a better solution to try to ask web server to do authentication, for example in MOD_PERL case via $r object (if I remember correctly)...

Show 62 quoted lines
> 
> Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
> ---
> 
> 	I also created a gitosis fork that can generate the necessary files:
> 
> 		http://repo.or.cz/w/gitosis/httpauth.git
> 
> 	-- Alexander
> 
>  gitweb/INSTALL     |   14 ++++++++++
>  gitweb/gitweb.perl |   68 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 79 insertions(+), 3 deletions(-)
> 
> diff --git a/gitweb/INSTALL b/gitweb/INSTALL
> index 26967e2..0841db6 100644
> --- a/gitweb/INSTALL
> +++ b/gitweb/INSTALL
> @@ -166,6 +166,20 @@ Gitweb repositories
>    shows repositories only if this file exists in its object database
>    (if directory has the magic file named $export_ok).
>  
> +- Finally, it is possible to use primitive .htaccess authentication by
> +  enabling the $check_htaccess variable in the config file. Gitweb
> +  recognizes the following htaccess commands:
> +
> +    Require user name1 name2 ...     # grant access to the listed users
> +    Require group group1 group2 ...  # grant access to the listed groups
> +    Deny from all                    # deny unless overridden by a Require
> +
> +  Access is granted if the currently authenticated user matches one
> +  of the Require lines, or if the file does not contain any of the listed
> +  commands, or if .htaccess does not exist. If the file exists but cannot
> +  be opened, access is denied. To use group authentication you have to
> +  point $auth_group_file to the group list in Apache format.
> +
>  Generating projects list using gitweb
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  
> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
> index 63c793e..4b962c3 100755
> --- a/gitweb/gitweb.perl
> +++ b/gitweb/gitweb.perl
> @@ -98,6 +98,12 @@ our $export_ok = "++GITWEB_EXPORT_OK++";
>  # only allow viewing of repositories also shown on the overview page
>  our $strict_export = "++GITWEB_STRICT_EXPORT++";
>  
> +# check basic authentication rules in .htaccess
> +our $check_htaccess  = 0;
> +
> +# name of the file that lists groups for htaccess check
> +our $auth_group_file = "";
> +
>  # list of git base URLs used for URL to where fetch project from,
>  # i.e. full URL is "$git_base_url/$project"
>  our @git_base_url_list = grep { $_ ne '' } ("++GITWEB_BASE_URL++");
> @@ -397,10 +403,64 @@ sub check_head_link {
>  		(-l $headfile && readlink($headfile) =~ /^refs\/heads\//));
>  }
>  
> +# set of htaccess groups for the current user
> +our %cur_auth_groups = ();
Why it is hash, and not list? What are the keys, and what are values?
> +
> +sub find_current_groups($$) {
Style: I think we prefer not using function prototypes.
> +	my ($gfile, $user) = @_;
> +	return () unless $gfile && $user;
Style: you can use simple "return" which means '()' in list context,
and 'undef' in scalar context.
So it could have been written as:
+	($gfile && $user) or return;
But I'd rather someone better in Perl decided...
Show 8 quoted lines
> +
> +	my @groups;
> +	open my $gf, $gfile or return ();
> +
> +	while(<$gf>) {
> +		next unless /^\s*(\S+)\s*:\s*(\S.*\S)\s*$/;
> +		my ($grp, $usrs) = ($1, $2);
> +		push @groups, $grp if grep { $_ eq $user } split (' ', $usrs);

Wouldn't it be better to use regexp match instead of this split+grep pipeline?

Show 7 quoted lines
> +	}
> +
> +	close $gf;
> +	return @groups;
> +}
> +
> +sub check_htaccess_files($) {
Style: I think we prefer not using function prototypes.

This function lack description: where it tries to find '.htaccess' files, what does it return, etc.

> +	my ($dir) = @_;
> +	my $user = $cgi->remote_user() || ' ';
Why "|| ' '" here?
Show 26 quoted lines
> +
> +	while (length $dir >= length $projectroot) {
> +		my $file = "$dir/.htaccess";
> +		next unless -e $file;
> +		open my $htf, $file or return 0;
> +
> +		my $ok = 0;
> +		my $need_ok = 0;
> +		while (<$htf>) {
> +			if (/^\s*Require\s+user\s+(\S.*\S)\s*$/i) {
> +				$ok++ if grep { $_ eq $user; } split (' ', $1);
> +				$need_ok++;
> +			} elsif (/^\s*Require\s+group\s+(\S.*\S)\s*$/i) {
> +				$ok++ if grep { $cur_auth_groups{$_}; } split(' ', $1);
> +				$need_ok++;
> +			} elsif (/^\s*Deny\s+from\s+all\s*$/ix) {
> +				$need_ok++;
> +			}
> +		}
> +		close $htf;
> +
> +		return $ok if $need_ok;
> +		last;
> +	} continue {
> +		$dir =~ s/\/[^\/]*$// or last;
> +	}

First, this loop is IMHO very hacky and unclean, using 'continue' block (which is not very visible on first glance) to advance through loop.

Second, while this loop might be good for _single_ repository, it is cleanly suboptimal in the case of 'projects_list' action... unless you want to list projects which are not accessible (I think it is the case for accessing static pages / static files).

Third, again there is split+grep (well, this is at least consistent).
Show 11 quoted lines
> +
> +	return 1;
> +}
> +
>  sub check_export_ok {
>  	my ($dir) = @_;
>  	return (check_head_link($dir) &&
> -		(!$export_ok || -e "$dir/$export_ok"));
> +		(!$export_ok || -e "$dir/$export_ok") &&
> +		(!$check_htaccess || check_htaccess_files($dir)));
>  }
O.K. Nice and clean.
Show 9 quoted lines
>  
>  # process alternate names for backward compatibility
> @@ -626,6 +686,9 @@ if (defined $action) {
>  	}
>  }
>  
> +# compute authenticated groups
> +$cur_auth_groups{$_}++ for find_current_groups($auth_group_file, $cgi->remote_user());
> +
This is a bit hacky. And I am not sure if its place should be here...
Show 13 quoted lines
>  # parameters which are pathnames
>  our $project = $input_params{'project'};
>  if (defined $project) {
> @@ -853,8 +916,7 @@ sub validate_project {
>  	my $input = shift || return undef;
>  	if (!validate_pathname($input) ||
>  		!(-d "$projectroot/$input") ||
> -		!check_head_link("$projectroot/$input") ||
> -		($export_ok && !(-e "$projectroot/$input/$export_ok")) ||
> +		!check_export_ok("$projectroot/$input") ||
>  		($strict_export && !project_in_list($input))) {
>  		return undef;
>  	} else {

And this is independent change, and should be in separate patch... ...or should be dropped (I'd have to examine this code better).

> -- 
> 1.6.0.3.15.gb8d36
> 
-- 
Jakub Narebski
Poland
Alexander Gavrilov· Nov 5, 2008, 22:36 UTC · re: Jakub Narebski · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Show 9 quoted lines
> > authenticated user name. Using group authentication requires specifying
> > a path to the Apache group file in the configuration.
> > 
> > Using .htaccess has an additional bonus that the same authentication
> > data can be used both for gitweb and the dumb http transport.
> 
> I'm not sure if it wouldn't be a better solution to try to ask web
> server to do authentication, for example in MOD_PERL case via $r
> object (if I remember correctly)...
You are right. I never used mod_perl before, so I didn't know that it's possible.

How about the following patch, that simply adds a hook, and provides an example using mod_perl in the documentation?

--- >8 ---
Subject: [PATCH] gitweb: Add a per-repository authorization hook.

Add a configuration variable that can be used to specify an arbitrary subroutine that will be called in the same situations where $export_ok is checked, and its return value used to decide whether the repository is to be shown.

This allows the user to implement custom authentication schemes, for example by issuing a subrequest through mod_perl and checking if Apache will authorize it.

Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
 gitweb/INSTALL     |   21 +++++++++++++++++++++
 gitweb/gitweb.perl |    8 +++++++-
 2 files changed, 28 insertions(+), 1 deletions(-)
Show changes to 2 files +28 −1

gitweb/INSTALL, gitweb/gitweb.perl

diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 26967e2..fa5917a 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -166,6 +166,27 @@ Gitweb repositories
   shows repositories only if this file exists in its object database
   (if directory has the magic file named $export_ok).
 
+- Finally, it is possible to specify an arbitrary perl subroutine that
+  will be called for each project to determine if it can be exported.
+  The subroutine receives an absolute path to the project as its only
+  parameter.
+
+  For example, if you use mod_perl to run the script, and have dumb
+  http protocol authentication configured for your repositories, you
+  can use the following hook to allow access only if the user is
+  authorized to read the files:
+
+    $export_auth_hook = sub {
+        use Apache2::SubRequest ();
+        use Apache2::Const -compile => qw(HTTP_OK);
+        my $path = "$_[0]/HEAD";
+        my $r    = Apache2::RequestUtil->request;
+        my $sub  = $r->lookup_file($path);
+        return $sub->filename eq $path 
+            && $sub->status == Apache2::Const::HTTP_OK;
+    };
+
+
 Generating projects list using gitweb
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 172ea6b..9329880 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -95,6 +95,11 @@ our $default_projects_order = "project";
 # (only effective if this variable evaluates to true)
 our $export_ok = "++GITWEB_EXPORT_OK++";
 
+# show repository only if this subroutine returns true
+# when given the path to the project, for example:
+#    sub { return -e "$_[0]/git-daemon-export-ok"; }
+our $export_auth_hook = undef;
+
 # only allow viewing of repositories also shown on the overview page
 our $strict_export = "++GITWEB_STRICT_EXPORT++";
 
@@ -400,7 +405,8 @@ sub check_head_link {
 sub check_export_ok {
 	my ($dir) = @_;
 	return (check_head_link($dir) &&
-		(!$export_ok || -e "$dir/$export_ok"));
+		(!$export_ok || -e "$dir/$export_ok") &&
+		(!$export_auth_hook || $export_auth_hook->($dir)));
 }
 
 # process alternate names for backward compatibility
-- 
tg: (0d4f9de..) t/authenticate/hook (depends on: t/authenticate/unify-exportok)
Jakub Narebski· Nov 5, 2008, 23:26 UTC · re: Alexander Gavrilov · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

Alexander Gavrilov wrote:
 
> How about the following patch, that simply adds a hook, and provides
> an example using mod_perl in the documentation?
Very nice, simple yet powerfull solution.
 
Show 13 quoted lines
> --- >8 ---
> Subject: [PATCH] gitweb: Add a per-repository authorization hook.
> 
> Add a configuration variable that can be used to specify an
> arbitrary subroutine that will be called in the same situations
> where $export_ok is checked, and its return value used
> to decide whether the repository is to be shown.
> 
> This allows the user to implement custom authentication
> schemes, for example by issuing a subrequest through mod_perl
> and checking if Apache will authorize it.
> 
> Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
If somebody could check out example given for this feature, I'd add
Acked-by: Jakub Narebski <jnareb@gmail.com>
Show 32 quoted lines
> ---
>  gitweb/INSTALL     |   21 +++++++++++++++++++++
>  gitweb/gitweb.perl |    8 +++++++-
>  2 files changed, 28 insertions(+), 1 deletions(-)
> 
> diff --git a/gitweb/INSTALL b/gitweb/INSTALL
> index 26967e2..fa5917a 100644
> --- a/gitweb/INSTALL
> +++ b/gitweb/INSTALL
> @@ -166,6 +166,27 @@ Gitweb repositories
>    shows repositories only if this file exists in its object database
>    (if directory has the magic file named $export_ok).
>  
> +- Finally, it is possible to specify an arbitrary perl subroutine that
> +  will be called for each project to determine if it can be exported.
> +  The subroutine receives an absolute path to the project as its only
> +  parameter.
> +
> +  For example, if you use mod_perl to run the script, and have dumb
> +  http protocol authentication configured for your repositories, you
> +  can use the following hook to allow access only if the user is
> +  authorized to read the files:
> +
> +    $export_auth_hook = sub {
> +        use Apache2::SubRequest ();
> +        use Apache2::Const -compile => qw(HTTP_OK);
> +        my $path = "$_[0]/HEAD";
> +        my $r    = Apache2::RequestUtil->request;
> +        my $sub  = $r->lookup_file($path);
> +        return $sub->filename eq $path 
> +            && $sub->status == Apache2::Const::HTTP_OK;
> +    };
Can anybody check this? Or was it checked by author?
Show 18 quoted lines
> +
> +
>  Generating projects list using gitweb
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  
> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
> index 172ea6b..9329880 100755
> --- a/gitweb/gitweb.perl
> +++ b/gitweb/gitweb.perl
> @@ -95,6 +95,11 @@ our $default_projects_order = "project";
>  # (only effective if this variable evaluates to true)
>  our $export_ok = "++GITWEB_EXPORT_OK++";
>  
> +# show repository only if this subroutine returns true
> +# when given the path to the project, for example:
> +#    sub { return -e "$_[0]/git-daemon-export-ok"; }
> +our $export_auth_hook = undef;
> +
Simple, yet powerfull. Nice short example.
Show 10 quoted lines
>  # only allow viewing of repositories also shown on the overview page
>  our $strict_export = "++GITWEB_STRICT_EXPORT++";
>  
> @@ -400,7 +405,8 @@ sub check_head_link {
>  sub check_export_ok {
>  	my ($dir) = @_;
>  	return (check_head_link($dir) &&
> -		(!$export_ok || -e "$dir/$export_ok"));
> +		(!$export_ok || -e "$dir/$export_ok") &&
> +		(!$export_auth_hook || $export_auth_hook->($dir)));
Nice.
Show 6 quoted lines
>  }
>  
>  # process alternate names for backward compatibility
> -- 
> tg: (0d4f9de..) t/authenticate/hook (depends on: t/authenticate/unify-exportok)
> 
P.S. Why doesn't TopGit add git and TopGit version to signature?
-- 
Jakub Narebski
Poland
Alexander Gavrilov· Nov 6, 2008, 19:43 UTC · re: Jakub Narebski · lore

Re: [RFC PATCH] gitweb: Support filtering projects by .htaccess files.

On Thursday 06 November 2008 02:26:58 Jakub Narebski wrote:
Show 17 quoted lines
> Alexander Gavrilov wrote:
> > +  For example, if you use mod_perl to run the script, and have dumb
> > +  http protocol authentication configured for your repositories, you
> > +  can use the following hook to allow access only if the user is
> > +  authorized to read the files:
> > +
> > +    $export_auth_hook = sub {
> > +        use Apache2::SubRequest ();
> > +        use Apache2::Const -compile => qw(HTTP_OK);
> > +        my $path = "$_[0]/HEAD";
> > +        my $r    = Apache2::RequestUtil->request;
> > +        my $sub  = $r->lookup_file($path);
> > +        return $sub->filename eq $path 
> > +            && $sub->status == Apache2::Const::HTTP_OK;
> > +    };
> 
> Can anybody check this? Or was it checked by author?

Well, it seems to do what is intended on my home server, although it has a known limitation, so here is an updated version that warns about it.

By the way, do you know how to deal with Apache or ModPerl's urge to append standard error messages to the script output, other than adding a bunch of lines like the following to the config?

  ErrorMessage 400 " "
I couldn't find any solutions so far.
--- >8 ---
Subject: [PATCH] gitweb: Add a per-repository authorization hook.

Add a configuration variable that can be used to specify an arbitrary subroutine that will be called in the same situations where $export_ok is checked, and its return value will be used to decide whether the repository is to be shown.

This allows the user to implement custom authentication schemes, for example by issuing a subrequest through mod_perl and checking if Apache will authorize it.

Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
 gitweb/INSTALL     |   23 +++++++++++++++++++++++
 gitweb/gitweb.perl |    8 +++++++-
 2 files changed, 30 insertions(+), 1 deletions(-)
Show changes to 2 files +30 −1

gitweb/INSTALL, gitweb/gitweb.perl

diff --git a/gitweb/INSTALL b/gitweb/INSTALL
index 26967e2..72a1322 100644
--- a/gitweb/INSTALL
+++ b/gitweb/INSTALL
@@ -166,6 +166,29 @@ Gitweb repositories
   shows repositories only if this file exists in its object database
   (if directory has the magic file named $export_ok).
 
+- Finally, it is possible to specify an arbitrary perl subroutine that
+  will be called for each project to determine if it can be exported.
+  The subroutine receives an absolute path to the project as its only
+  parameter.
+
+  For example, if you use mod_perl to run the script, and have dumb
+  http protocol authentication configured for your repositories, you
+  can use the following hook to allow access only if the user is
+  authorized to read the files:
+
+    $export_auth_hook = sub {
+        use Apache2::SubRequest ();
+        use Apache2::Const -compile => qw(HTTP_OK);
+        my $path = "$_[0]/HEAD";
+        my $r    = Apache2::RequestUtil->request;
+        my $sub  = $r->lookup_file($path);
+        return $sub->filename eq $path 
+            && $sub->status == Apache2::Const::HTTP_OK;
+    };
+
+  Note that since this sample works exclusively in the filesystem
+  namespace, <Location> sections of the configuration have no effect.
+
 Generating projects list using gitweb
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 172ea6b..9329880 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -95,6 +95,11 @@ our $default_projects_order = "project";
 # (only effective if this variable evaluates to true)
 our $export_ok = "++GITWEB_EXPORT_OK++";
 
+# show repository only if this subroutine returns true
+# when given the path to the project, for example:
+#    sub { return -e "$_[0]/git-daemon-export-ok"; }
+our $export_auth_hook = undef;
+
 # only allow viewing of repositories also shown on the overview page
 our $strict_export = "++GITWEB_STRICT_EXPORT++";
 
@@ -400,7 +405,8 @@ sub check_head_link {
 sub check_export_ok {
 	my ($dir) = @_;
 	return (check_head_link($dir) &&
-		(!$export_ok || -e "$dir/$export_ok"));
+		(!$export_ok || -e "$dir/$export_ok") &&
+		(!$export_auth_hook || $export_auth_hook->($dir)));
 }
 
 # process alternate names for backward compatibility
-- 
tg: (0d4f9de..) t/authenticate/hook (depends on: t/authenticate/unify-exportok)

← back to recent threads