Project

General

Profile

Patch #4905 » Redmine.pm-update-patch-4905-to-Redmine-1.4.1-support-multiscm.patch

Takashi Okamoto, 2012-04-27 18:27

View differences:

extra/svn/Redmine.pm 2012-04-28 01:19:58.665343304 +0900
102 102

  
103 103
And you need to upgrade at least reposman.rb (after r860).
104 104

  
105
=head1 GIT SMART HTTP SUPPORT
106

  
107
Git's smart HTTP protocol (available since Git 1.7.0) will not work with the
108
above settings. Redmine.pm normally does access control depending on the HTTP
109
method used: read-only methods are OK for everyone in public projects and
110
members with read rights in private projects. The rest require membership with
111
commit rights in the project.
112

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

  
118
To activate this mode of operation, add this line inside your <Location /git>
119
block:
120

  
121
  RedmineGitSmartHttp yes
122

  
123
Here's a sample Apache configuration which integrates git-http-backend with
124
a MySQL database and this new option:
125

  
126
   SetEnv GIT_PROJECT_ROOT /var/www/git/
127
   SetEnv GIT_HTTP_EXPORT_ALL
128
   ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
129
   <Location /git>
130
       Order allow,deny
131
       Allow from all
132

  
133
       AuthType Basic
134
       AuthName Git
135
       Require valid-user
136

  
137
       PerlAccessHandler Apache::Authn::Redmine::access_handler
138
       PerlAuthenHandler Apache::Authn::Redmine::authen_handler
139
       # for mysql
140
       RedmineDSN "DBI:mysql:database=redmine;host=127.0.0.1"
141
       RedmineDbUser "redmine"
142
       RedmineDbPass "xxx"
143
       RedmineGitSmartHttp yes
144
    </Location>
145

  
146
Make sure that all the names of the repositories under /var/www/git/ have a
147
matching identifier for some project: /var/www/git/myproject and
148
/var/www/git/myproject.git will work. You can put both bare and non-bare
149
repositories in /var/www/git, though bare repositories are strongly
150
recommended. You should create them with the rights of the user running Redmine,
151
like this:
152

  
153
  cd /var/www/git
154
  sudo -u user-running-redmine mkdir myproject
155
  cd myproject
156
  sudo -u user-running-redmine git init --bare
157

  
158
Once you have activated this option, you have three options when cloning a
159
repository:
160

  
161
- Cloning using "http://user@host/git/repo(.git)" works, but will ask for the password
162
  all the time.
163

  
164
- Cloning with "http://user:pass@host/git/repo(.git)" does not have this problem, but
165
  this could reveal accidentally your password to the console in some versions
166
  of Git, and you would have to ensure that .git/config is not readable except
167
  by the owner for each of your projects.
168

  
169
- Use "http://host/git/repo(.git)", and store your credentials in the ~/.netrc
170
  file. This is the recommended solution, as you only have one file to protect
171
  and passwords will not be leaked accidentally to the console.
172

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

  
178
    touch ~/.netrc
179
    chmod 600 ~/.netrc
180
    echo -e "machine yourhost\nlogin youruser\npassword yourpassword" > ~/.netrc
181

  
105 182
=cut
106 183

  
107 184
use strict;
......
151 228
    args_how => TAKE1,
152 229
    errmsg => 'RedmineCacheCredsMax must be decimal number',
153 230
  },
231
  {
232
    name => 'RedmineGitSmartHttp',
233
    req_override => OR_AUTHCFG,
234
    args_how => TAKE1,
235
  },
154 236
);
155 237

  
156 238
sub RedmineDSN {
......
188 270
  }
189 271
}
190 272

  
273
sub RedmineGitSmartHttp {
274
  my ($self, $parms, $arg) = @_;
275
  $arg = lc $arg;
276

  
277
  if ($arg eq "yes" || $arg eq "true") {
278
    $self->{RedmineGitSmartHttp} = 1;
279
  } else {
280
    $self->{RedmineGitSmartHttp} = 0;
281
  }
282
}
283

  
191 284
sub trim {
192 285
  my $string = shift;
193 286
  $string =~ s/\s{2,}/ /g;
......
204 297

  
205 298
my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
206 299

  
300
sub request_is_read_only {
301
  my ($r) = @_;
302
  my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
303

  
304
  # Do we use Git's smart HTTP protocol, or not?
305
  if (defined $cfg->{RedmineGitSmartHttp} and $cfg->{RedmineGitSmartHttp}) {
306
    my $uri = $r->unparsed_uri;
307
    my $location = $r->location;
308
    my $is_read_only = $uri !~ m{^$location/*[^/]+/+(info/refs\?service=)?git\-receive\-pack$}o;
309
    return $is_read_only;
310
  } else {
311
    # Old behaviour: check the HTTP method
312
    my $method = $r->method;
313
    return defined $read_only_methods{$method};
314
  }
315
}
316

  
207 317
sub access_handler {
208 318
  my $r = shift;
209 319

  
......
212 322
      return FORBIDDEN;
213 323
  }
214 324

  
215
  my $method = $r->method;
216
  return OK unless defined $read_only_methods{$method};
325
  return OK unless request_is_read_only($r);
217 326

  
218 327
  my $project_id = get_project_identifier($r);
219 328

  
......
338 447

  
339 448
  my $pass_digest = Digest::SHA::sha1_hex($redmine_pass);
340 449

  
341
  my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
450
  my $access_mode = request_is_read_only($r) ? "R" : "W";
342 451

  
343 452
  my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
344 453
  my $usrprojpass;
......
409 518

  
410 519
    my $location = $r->location;
411 520
    my ($identifier) = $r->uri =~ m{$location/*([^/.]+)};
412
    $identifier;
521
    my $dbh = connect_database($r);
522
    my $sth = $dbh->prepare(
523
        "SELECT name FROM projects WHERE id = (SELECT project_id FROM repositories WHERE URL LIKE ?);"
524
    );
525
    $sth->execute('%/'.$identifier);
526
    my @row = $sth->fetchrow_array;
527
    $sth->finish();
528
    $dbh->disconnect();
529
    $row[0];
413 530
}
414 531

  
415 532
sub connect_database {
(17-17/24)