0001-Redmine.pm-add-Git-smart-HTTP-support-r3840.patch

Felix Schäfer, 2010-07-13 18:31

Download (4.92 KB)

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:
116

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

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

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

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

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

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

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

  
96 158
=cut
97 159

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

  
147 214
sub RedmineDSN { 
......
178 245
  }
179 246
}
180 247

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

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

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

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

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

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

  
197 291
sub access_handler {
198 292
  my $r = shift;
199 293

  
......
202 296
      return FORBIDDEN;
203 297
  }
204 298

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

  
208 301
  my $project_id = get_project_identifier($r);
209 302

  
......
320 413

  
321 414
      unless ($auth_source_id) {
322 415
	  my $method = $r->method;
416
          if ($hashed_password eq $pass_digest && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
417
          if ($hashed_password eq $pass_digest && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
323 418
          if ($hashed_password eq $pass_digest && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
324 419
              $ret = 1;
325 420
              last;