Project

General

Profile

Patch #4905 » 0001-Redmine.pm-add-Git-smart-HTTP-support-use-location.patch

Patch which uses the path in the <Location> block as the prefix for all regexps - Antonio García-Domínguez, 2010-07-19 23:55

View differences:

extra/svn/Redmine.pm
93 93

  
94 94
And you need to upgrade at least reposman.rb (after r860).
95 95

  
96
=head1 GIT SMART HTTP SUPPORT
97

  
98
Git's smart HTTP protocol will not work with the above settings. Redmine.pm
99
normally does access control depending on the HTTP method used: read-only
100
methods are OK for everyone in public projects and members with read rights
101
in private projects. The rest require membership with commit rights in the
102
project.
103

  
104
However, this scheme doesn't work for Git's smart HTTP protocol, as it will use
105
POST even for a simple clone. Instead, read-only requests must be detected
106
using the full URL (including the query string): anything that doesn't belong
107
to the git-receive-pack service is read-only.
108

  
109
To activate this mode of operation, add this line inside your <Location /git>
110
block:
111

  
112
  RedmineGitSmartHttp yes
113

  
114
Here's a sample Apache configuration which integrates git-http-backend with
115
a MySQL database and this new option. Please make sure that your Location path
116
does not have a trailing slash, as in this example, or it won't work:
117

  
118
   SetEnv GIT_PROJECT_ROOT /var/www/git/
119
   SetEnv GIT_HTTP_EXPORT_ALL
120
   ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
121
   <Location /git>
122
       Order allow,deny
123
       Allow from all
124

  
125
       AuthType Basic
126
       AuthName Git
127
       Require valid-user
128

  
129
       PerlAccessHandler Apache::Authn::Redmine::access_handler
130
       PerlAuthenHandler Apache::Authn::Redmine::authen_handler
131
       # for mysql
132
       RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
133
       RedmineDbUser "redmine"
134
       RedmineDbPass "xxx"
135
       RedmineGitSmartHttp yes
136
    </Location>
137

  
138
Make sure that all the names of the repositories under /var/www/git/ match
139
exactly the identifier for some project: /var/www/git/myproject.git won't work,
140
due to the way this module extracts the identifier from the URL.
141
/var/www/git/myproject will work, though. You can put both bare and non-bare
142
repositories in /var/www/git.
143

  
144
Once you have activated this option, you have two options when cloning a
145
repository. Cloning using "http://user@host/git/repo" works, but will ask for
146
the password all the time. To avoid being pestered by password requests, it's
147
best to create a ~/.netrc file with your username and password, and clone using
148
"http://host/git/repo" instead.
149

  
150
IMPORTANT NOTE: It is *very important* that the file cannot be read by other
151
users, as it will contain your password in cleartext. To create the file, you
152
can use the following commands, replacing yourhost, youruser and yourpassword
153
with the right values:
154

  
155
  touch ~/.netrc
156
  chmod 600 .netrc
157
  echo -e "machine yourhost\nlogin youruser\npassword yourpassword" > ~/.netrc
158

  
96 159
=cut
97 160

  
98 161
use strict;
......
142 205
    args_how => TAKE1,
143 206
    errmsg => 'RedmineCacheCredsMax must be decimal number',
144 207
  },
208
  {
209
    name => 'RedmineGitSmartHttp',
210
    req_override => OR_AUTHCFG,
211
    args_how => TAKE1,
212
  },
145 213
);
146 214

  
147 215
sub RedmineDSN { 
......
178 246
  }
179 247
}
180 248

  
249
sub RedmineGitSmartHttp {
250
  my ($self, $parms, $arg) = @_;
251
  $arg = lc $arg;
252

  
253
  if ($arg eq "yes" || $arg eq "true") {
254
    $self->{RedmineGitSmartHttp} = 1;
255
  } else {
256
    $self->{RedmineGitSmartHttp} = 0;
257
  }
258
}
259

  
181 260
sub trim {
182 261
  my $string = shift;
183 262
  $string =~ s/\s{2,}/ /g;
......
194 273

  
195 274
my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
196 275

  
276
sub request_is_read_only {
277
  my ($r) = @_;
278
  my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
279

  
280
  # Do we use Git's smart HTTP protocol, or not?
281
  if (defined $cfg->{RedmineGitSmartHttp} and $cfg->{RedmineGitSmartHttp}) {
282
    my $uri = $r->unparsed_uri;
283
    my $location = $r->location;
284
    my $is_read_only = $uri !~ m{^$location/.*/[^/]*git\-receive\-pack$}o;
285
    return $is_read_only;
286
  } else {
287
    # Old behaviour: check the HTTP method
288
    my $method = $r->method;
289
    return defined $read_only_methods{$method};
290
  }
291
}
292

  
197 293
sub access_handler {
198 294
  my $r = shift;
199 295

  
......
202 298
      return FORBIDDEN;
203 299
  }
204 300

  
205
  my $method = $r->method;
206
  return OK unless defined $read_only_methods{$method};
301
  return OK unless request_is_read_only($r);
207 302

  
208 303
  my $project_id = get_project_identifier($r);
209 304

  
......
320 415

  
321 416
      unless ($auth_source_id) {
322 417
	  my $method = $r->method;
323
          if ($hashed_password eq $pass_digest && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
418
          if ($hashed_password eq $pass_digest && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
324 419
              $ret = 1;
325 420
              last;
326 421
          }
......
339 434
                filter  =>      "(".$rowldap[6]."=%s)"
340 435
            );
341 436
            my $method = $r->method;
342
            $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
437
            $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass)
438
			 && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
343 439

  
344 440
          }
345 441
          $sthldap->finish();
(8-8/24)