| 49 |
49 |
|
| 50 |
50 |
PerlAccessHandler Apache::Authn::Redmine::access_handler
|
| 51 |
51 |
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
|
| 52 |
|
|
|
52 |
|
| 53 |
53 |
## for mysql
|
| 54 |
54 |
RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
|
| 55 |
55 |
## for postgres
|
| ... | ... | |
| 144 |
144 |
},
|
| 145 |
145 |
);
|
| 146 |
146 |
|
| 147 |
|
sub RedmineDSN {
|
|
147 |
sub RedmineDSN {
|
| 148 |
148 |
my ($self, $parms, $arg) = @_;
|
| 149 |
149 |
$self->{RedmineDSN} = $arg;
|
| 150 |
150 |
my $query = "SELECT
|
| 151 |
151 |
hashed_password, salt, auth_source_id, permissions
|
| 152 |
|
FROM members, projects, users, roles, member_roles
|
|
152 |
FROM projects, users, roles
|
| 153 |
153 |
WHERE
|
| 154 |
|
projects.id=members.project_id
|
| 155 |
|
AND member_roles.member_id=members.id
|
| 156 |
|
AND users.id=members.user_id
|
| 157 |
|
AND roles.id=member_roles.role_id
|
|
154 |
users.login=?
|
|
155 |
AND projects.identifier=?
|
| 158 |
156 |
AND users.status=1
|
| 159 |
|
AND login=?
|
| 160 |
|
AND identifier=? ";
|
|
157 |
AND (
|
|
158 |
roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
|
|
159 |
OR
|
|
160 |
(roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
|
|
161 |
) ";
|
| 161 |
162 |
$self->{RedmineQuery} = trim($query);
|
| 162 |
163 |
}
|
| 163 |
164 |
|
| 164 |
165 |
sub RedmineDbUser { set_val('RedmineDbUser', @_); }
|
| 165 |
166 |
sub RedmineDbPass { set_val('RedmineDbPass', @_); }
|
| 166 |
|
sub RedmineDbWhereClause {
|
|
167 |
sub RedmineDbWhereClause {
|
| 167 |
168 |
my ($self, $parms, $arg) = @_;
|
| 168 |
169 |
$self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
|
| 169 |
170 |
}
|
| 170 |
171 |
|
| 171 |
|
sub RedmineCacheCredsMax {
|
|
172 |
sub RedmineCacheCredsMax {
|
| 172 |
173 |
my ($self, $parms, $arg) = @_;
|
| 173 |
174 |
if ($arg) {
|
| 174 |
175 |
$self->{RedmineCachePool} = APR::Pool->new;
|
| ... | ... | |
| 208 |
209 |
my $project_id = get_project_identifier($r);
|
| 209 |
210 |
|
| 210 |
211 |
$r->set_handlers(PerlAuthenHandler => [\&OK])
|
| 211 |
|
if is_public_project($project_id, $r);
|
|
212 |
if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r);
|
| 212 |
213 |
|
| 213 |
214 |
return OK
|
| 214 |
215 |
}
|
| 215 |
216 |
|
| 216 |
217 |
sub authen_handler {
|
| 217 |
218 |
my $r = shift;
|
| 218 |
|
|
|
219 |
|
| 219 |
220 |
my ($res, $redmine_pass) = $r->get_basic_auth_pw();
|
| 220 |
221 |
return $res unless $res == OK;
|
| 221 |
|
|
|
222 |
|
| 222 |
223 |
if (is_member($r->user, $redmine_pass, $r)) {
|
| 223 |
224 |
return OK;
|
| 224 |
225 |
} else {
|
| ... | ... | |
| 245 |
246 |
}
|
| 246 |
247 |
$sth->finish();
|
| 247 |
248 |
undef $sth;
|
| 248 |
|
|
|
249 |
|
| 249 |
250 |
$dbh->disconnect();
|
| 250 |
251 |
undef $dbh;
|
| 251 |
252 |
|
| ... | ... | |
| 255 |
256 |
sub is_public_project {
|
| 256 |
257 |
my $project_id = shift;
|
| 257 |
258 |
my $r = shift;
|
| 258 |
|
|
|
259 |
|
| 259 |
260 |
if (is_authentication_forced($r)) {
|
| 260 |
261 |
return 0;
|
| 261 |
262 |
}
|
| ... | ... | |
| 280 |
281 |
$ret;
|
| 281 |
282 |
}
|
| 282 |
283 |
|
|
284 |
sub anonymous_role_allows_browse_repository {
|
|
285 |
my $r = shift;
|
|
286 |
|
|
287 |
my $dbh = connect_database($r);
|
|
288 |
my $sth = $dbh->prepare(
|
|
289 |
"SELECT permissions FROM roles WHERE builtin = 2;"
|
|
290 |
);
|
|
291 |
|
|
292 |
$sth->execute();
|
|
293 |
my $ret = 0;
|
|
294 |
if (my @row = $sth->fetchrow_array) {
|
|
295 |
if ($row[0] =~ /:browse_repository/) {
|
|
296 |
$ret = 1;
|
|
297 |
}
|
|
298 |
}
|
|
299 |
$sth->finish();
|
|
300 |
undef $sth;
|
|
301 |
$dbh->disconnect();
|
|
302 |
undef $dbh;
|
|
303 |
|
|
304 |
$ret;
|
|
305 |
}
|
|
306 |
|
| 283 |
307 |
# perhaps we should use repository right (other read right) to check public access.
|
| 284 |
308 |
# it could be faster BUT it doesn't work for the moment.
|
| 285 |
309 |
# sub is_public_project_by_file {
|
| ... | ... | |
| 305 |
329 |
|
| 306 |
330 |
my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
|
| 307 |
331 |
|
|
332 |
my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
|
|
333 |
|
| 308 |
334 |
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
|
| 309 |
335 |
my $usrprojpass;
|
| 310 |
336 |
if ($cfg->{RedmineCacheCredsMax}) {
|
| 311 |
|
$usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id);
|
|
337 |
$usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
|
| 312 |
338 |
return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
|
| 313 |
339 |
}
|
| 314 |
340 |
my $query = $cfg->{RedmineQuery};
|
| ... | ... | |
| 321 |
347 |
unless ($auth_source_id) {
|
| 322 |
348 |
my $method = $r->method;
|
| 323 |
349 |
my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
|
| 324 |
|
if ($hashed_password eq $salted_password && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
|
|
350 |
if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
|
| 325 |
351 |
$ret = 1;
|
| 326 |
352 |
last;
|
| 327 |
353 |
}
|
| ... | ... | |
| 340 |
366 |
filter => "(".$rowldap[6]."=%s)"
|
| 341 |
367 |
);
|
| 342 |
368 |
my $method = $r->method;
|
| 343 |
|
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
|
|
369 |
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
|
| 344 |
370 |
|
| 345 |
371 |
}
|
| 346 |
372 |
$sthldap->finish();
|
| ... | ... | |
| 354 |
380 |
|
| 355 |
381 |
if ($cfg->{RedmineCacheCredsMax} and $ret) {
|
| 356 |
382 |
if (defined $usrprojpass) {
|
| 357 |
|
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
|
|
383 |
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
|
| 358 |
384 |
} else {
|
| 359 |
385 |
if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
|
| 360 |
|
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
|
|
386 |
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
|
| 361 |
387 |
$cfg->{RedmineCacheCredsCount}++;
|
| 362 |
388 |
} else {
|
| 363 |
389 |
$cfg->{RedmineCacheCreds}->clear();
|
| ... | ... | |
| 371 |
397 |
|
| 372 |
398 |
sub get_project_identifier {
|
| 373 |
399 |
my $r = shift;
|
| 374 |
|
|
|
400 |
|
| 375 |
401 |
my $location = $r->location;
|
| 376 |
402 |
my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
|
| 377 |
403 |
$identifier;
|
| ... | ... | |
| 379 |
405 |
|
| 380 |
406 |
sub connect_database {
|
| 381 |
407 |
my $r = shift;
|
| 382 |
|
|
|
408 |
|
| 383 |
409 |
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
|
| 384 |
410 |
return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
|
| 385 |
411 |
}
|