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 all require membership with write 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 |
Once you have activated this option, you have two options when cloning a
|
|
115 |
repository. Cloning using "http://user@host/git/repo" works, but will ask for
|
|
116 |
the password all the time. To avoid being pestered by password requests, it's
|
|
117 |
best to create a ~/.netrc file with your username and password, and clone using
|
|
118 |
"http://host/git/repo" instead.
|
|
119 |
|
|
120 |
IMPORTANT NOTE: It is *very important* that the file cannot be read by other
|
|
121 |
users, as it will contain your password in cleartext. To create the file, you
|
|
122 |
can use the following commands, replacing yourhost, youruser and yourpassword
|
|
123 |
with the right values:
|
|
124 |
|
|
125 |
touch ~/.netrc
|
|
126 |
chmod 600 .netrc
|
|
127 |
echo -e "machine yourhost\nlogin youruser\npassword yourpassword" > ~/.netrc
|
|
128 |
|
96 |
129 |
=cut
|
97 |
130 |
|
98 |
131 |
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 |
}
|