Add git-smart-http support to apache perl module #245
Latest patch from http://www.redmine.org/issues/4905 and other changes improvements, compare also with https://orga.fachschaften.org/projects/redmine-fsenorg/repository/revisions/fsenorg/changes/extra/svn/Redmine.pm .
This commit is contained in:
parent
904897ac90
commit
9fe45cfe1f
|
@ -93,6 +93,84 @@ S<them :>
|
|||
|
||||
And you need to upgrade at least reposman.rb (after r860).
|
||||
|
||||
=head1 GIT SMART HTTP SUPPORT
|
||||
|
||||
Git's smart HTTP protocol (available since Git 1.7.0) will not work with the
|
||||
above settings. Redmine.pm normally does access control depending on the HTTP
|
||||
method used: read-only methods are OK for everyone in public projects and
|
||||
members with read rights in private projects. The rest require membership with
|
||||
commit rights in the project.
|
||||
|
||||
However, this scheme doesn't work for Git's smart HTTP protocol, as it will use
|
||||
POST even for a simple clone. Instead, read-only requests must be detected using
|
||||
the full URL (including the query string): anything that doesn't belong to the
|
||||
git-receive-pack service is read-only.
|
||||
|
||||
To activate this mode of operation, add this line inside your <Location /git>
|
||||
block:
|
||||
|
||||
RedmineGitSmartHttp yes
|
||||
|
||||
Here's a sample Apache configuration which integrates git-http-backend with
|
||||
a MySQL database and this new option:
|
||||
|
||||
SetEnv GIT_PROJECT_ROOT /var/www/git/
|
||||
SetEnv GIT_HTTP_EXPORT_ALL
|
||||
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
|
||||
<Location /git>
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
|
||||
AuthType Basic
|
||||
AuthName Git
|
||||
Require valid-user
|
||||
|
||||
PerlAccessHandler Apache::Authn::Redmine::access_handler
|
||||
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
|
||||
# for mysql
|
||||
RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
|
||||
RedmineDbUser "redmine"
|
||||
RedmineDbPass "xxx"
|
||||
RedmineGitSmartHttp yes
|
||||
</Location>
|
||||
|
||||
Make sure that all the names of the repositories under /var/www/git/ match
|
||||
exactly the identifier for some project: /var/www/git/myproject.git won't work,
|
||||
due to the way this module extracts the identifier from the URL.
|
||||
/var/www/git/myproject will work, though. You can put both bare and non-bare
|
||||
repositories in /var/www/git, though bare repositories are strongly
|
||||
recommended. You should create them with the rights of the user running Redmine,
|
||||
like this:
|
||||
|
||||
cd /var/www/git
|
||||
sudo -u user-running-redmine mkdir myproject
|
||||
cd myproject
|
||||
sudo -u user-running-redmine git init --bare
|
||||
|
||||
Once you have activated this option, you have three options when cloning a
|
||||
repository:
|
||||
|
||||
- Cloning using "http://user@host/git/repo" works, but will ask for the password
|
||||
all the time.
|
||||
|
||||
- Cloning with "http://user:pass@host/git/repo" does not have this problem, but
|
||||
this could reveal accidentally your password to the console in some versions
|
||||
of Git, and you would have to ensure that .git/config is not readable except
|
||||
by the owner for each of your projects.
|
||||
|
||||
- Use "http://host/git/repo", and store your credentials in the ~/.netrc
|
||||
file. This is the recommended solution, as you only have one file to protect
|
||||
and passwords will not be leaked accidentally to the console.
|
||||
|
||||
IMPORTANT NOTE: It is *very important* that the file cannot be read by other
|
||||
users, as it will contain your password in cleartext. To create the file, you
|
||||
can use the following commands, replacing yourhost, youruser and yourpassword
|
||||
with the right values:
|
||||
|
||||
touch ~/.netrc
|
||||
chmod 600 ~/.netrc
|
||||
echo -e "machine yourhost\nlogin youruser\npassword yourpassword" > ~/.netrc
|
||||
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
|
@ -142,6 +220,11 @@ my @directives = (
|
|||
args_how => TAKE1,
|
||||
errmsg => 'RedmineCacheCredsMax must be decimal number',
|
||||
},
|
||||
{
|
||||
name => 'RedmineGitSmartHttp',
|
||||
req_override => OR_AUTHCFG,
|
||||
args_how => TAKE1,
|
||||
},
|
||||
);
|
||||
|
||||
sub RedmineDSN {
|
||||
|
@ -178,6 +261,17 @@ sub RedmineCacheCredsMax {
|
|||
}
|
||||
}
|
||||
|
||||
sub RedmineGitSmartHttp {
|
||||
my ($self, $parms, $arg) = @_;
|
||||
$arg = lc $arg;
|
||||
|
||||
if ($arg eq "yes" || $arg eq "true") {
|
||||
$self->{RedmineGitSmartHttp} = 1;
|
||||
} else {
|
||||
$self->{RedmineGitSmartHttp} = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub trim {
|
||||
my $string = shift;
|
||||
$string =~ s/\s{2,}/ /g;
|
||||
|
@ -194,6 +288,23 @@ Apache2::Module::add(__PACKAGE__, \@directives);
|
|||
|
||||
my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
|
||||
|
||||
sub request_is_read_only {
|
||||
my ($r) = @_;
|
||||
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
|
||||
|
||||
# Do we use Git's smart HTTP protocol, or not?
|
||||
if (defined $cfg->{RedmineGitSmartHttp} and $cfg->{RedmineGitSmartHttp}) {
|
||||
my $uri = $r->unparsed_uri;
|
||||
my $location = $r->location;
|
||||
my $is_read_only = $uri !~ m{^$location/*[^/]+/+(info/refs\?service=)?git\-receive\-pack$}o;
|
||||
return $is_read_only;
|
||||
} else {
|
||||
# Old behaviour: check the HTTP method
|
||||
my $method = $r->method;
|
||||
return defined $read_only_methods{$method};
|
||||
}
|
||||
}
|
||||
|
||||
sub access_handler {
|
||||
my $r = shift;
|
||||
|
||||
|
@ -202,8 +313,7 @@ sub access_handler {
|
|||
return FORBIDDEN;
|
||||
}
|
||||
|
||||
my $method = $r->method;
|
||||
return OK unless defined $read_only_methods{$method};
|
||||
return OK unless request_is_read_only($r);
|
||||
|
||||
my $project_id = get_project_identifier($r);
|
||||
|
||||
|
@ -320,7 +430,7 @@ sub is_member {
|
|||
|
||||
unless ($auth_source_id) {
|
||||
my $method = $r->method;
|
||||
if ($hashed_password eq $pass_digest && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
|
||||
if ($hashed_password eq $pass_digest && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
|
||||
$ret = 1;
|
||||
last;
|
||||
}
|
||||
|
@ -338,9 +448,7 @@ sub is_member {
|
|||
bindpw => $rowldap[4] ? $rowldap[4] : "",
|
||||
filter => "(".$rowldap[6]."=%s)"
|
||||
);
|
||||
my $method = $r->method;
|
||||
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
|
||||
|
||||
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
|
||||
}
|
||||
$sthldap->finish();
|
||||
undef $sthldap;
|
||||
|
|
Loading…
Reference in New Issue