Project

General

Profile

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

Antonio García-Domínguez, 2010-02-23 13:36

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
99
normally does access control depending on the HTTP method used: read-only
100
methods are OK for public repositories but not for private ones, and the
101
rest require member access.
102

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

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

  
111
  RedmineGitSmartHttp yes
112

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

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

  
124
  touch ~/.netrc
125
  chmod 600 .netrc
126
  echo -e "machine yourhost\nlogin youruser\npassword yourpassword"
127

  
96 128
=cut
97 129

  
98 130
use strict;
......
142 174
    args_how => TAKE1,
143 175
    errmsg => 'RedmineCacheCredsMax must be decimal number',
144 176
  },
177
  {
178
    name => 'RedmineGitSmartHttp',
179
    req_override => OR_AUTHCFG,
180
    args_how => TAKE1,
181
  },
145 182
);
146 183

  
147 184
sub RedmineDSN { 
......
178 215
  }
179 216
}
180 217

  
218
sub RedmineGitSmartHttp {
219
  my ($self, $parms, $arg) = @_;
220
  $arg = lc $arg;
221

  
222
  if ($arg eq "yes" || $arg eq "true") {
223
    $self->{RedmineGitSmartHttp} = 1;
224
  } else {
225
    $self->{RedmineGitSmartHttp} = 0;
226
  }
227
}
228

  
181 229
sub trim {
182 230
  my $string = shift;
183 231
  $string =~ s/\s{2,}/ /g;
......
191 239

  
192 240
Apache2::Module::add(__PACKAGE__, \@directives);
193 241

  
194 242

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

  
245
sub request_is_read_only {
246
  my ($r) = @_;
247
  my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
248

  
249
  # Do we use Git's smart HTTP protocol, or not?
250
  if (defined $cfg->{RedmineGitSmartHttp} and $cfg->{RedmineGitSmartHttp}) {
251
    my $uri = $r->unparsed_uri;
252
    my $is_read_only = $uri !~ /^\/git\/.*\/[^\/]*git\-receive\-pack$/o;
253
    return $is_read_only;
254
  } else {
255
    # Old behaviour: check the HTTP method
256
    my $method = $r->method;
257
    return defined $read_only_methods{$method};
258
  }
259
}
260

  
197 261
sub access_handler {
198 262
  my $r = shift;
199 263

  
......
202 265
      return FORBIDDEN;
203 266
  }
204 267

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

  
208 270
  my $project_id = get_project_identifier($r);
209 271

  
......
291 353

  
292 354
      unless ($auth_source_id) {
293 355
	  my $method = $r->method;
294
          if ($hashed_password eq $pass_digest && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
356
          if ($hashed_password eq $pass_digest && ((request_is_read_only($r) && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
295 357
              $ret = 1;
296 358
              last;
297 359
          }
(1-1/24)