Mercurial > hg > soundsoftware-site
comparison extra/svn/Redmine.pm @ 909:cbb26bc654de redmine-1.3
Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author | Chris Cannam |
---|---|
date | Fri, 24 Feb 2012 19:09:32 +0000 |
parents | 051f544170fe |
children | 5f33065ddc4b |
comparison
equal
deleted
inserted
replaced
908:c6c2cbd0afee | 909:cbb26bc654de |
---|---|
47 AuthName redmine | 47 AuthName redmine |
48 Require valid-user | 48 Require valid-user |
49 | 49 |
50 PerlAccessHandler Apache::Authn::Redmine::access_handler | 50 PerlAccessHandler Apache::Authn::Redmine::access_handler |
51 PerlAuthenHandler Apache::Authn::Redmine::authen_handler | 51 PerlAuthenHandler Apache::Authn::Redmine::authen_handler |
52 | 52 |
53 ## for mysql | 53 ## for mysql |
54 RedmineDSN "DBI:mysql:database=databasename;host=my.db.server" | 54 RedmineDSN "DBI:mysql:database=databasename;host=my.db.server" |
55 ## for postgres | 55 ## for postgres |
56 # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server" | 56 # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server" |
57 | 57 |
142 args_how => TAKE1, | 142 args_how => TAKE1, |
143 errmsg => 'RedmineCacheCredsMax must be decimal number', | 143 errmsg => 'RedmineCacheCredsMax must be decimal number', |
144 }, | 144 }, |
145 ); | 145 ); |
146 | 146 |
147 sub RedmineDSN { | 147 sub RedmineDSN { |
148 my ($self, $parms, $arg) = @_; | 148 my ($self, $parms, $arg) = @_; |
149 $self->{RedmineDSN} = $arg; | 149 $self->{RedmineDSN} = $arg; |
150 my $query = "SELECT | 150 my $query = "SELECT |
151 hashed_password, salt, auth_source_id, permissions | 151 hashed_password, salt, auth_source_id, permissions |
152 FROM members, projects, users, roles, member_roles | 152 FROM projects, users, roles |
153 WHERE | 153 WHERE |
154 projects.id=members.project_id | 154 users.login=? |
155 AND member_roles.member_id=members.id | 155 AND projects.identifier=? |
156 AND users.id=members.user_id | |
157 AND roles.id=member_roles.role_id | |
158 AND users.status=1 | 156 AND users.status=1 |
159 AND login=? | 157 AND ( |
160 AND identifier=? "; | 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 $self->{RedmineQuery} = trim($query); | 162 $self->{RedmineQuery} = trim($query); |
162 } | 163 } |
163 | 164 |
164 sub RedmineDbUser { set_val('RedmineDbUser', @_); } | 165 sub RedmineDbUser { set_val('RedmineDbUser', @_); } |
165 sub RedmineDbPass { set_val('RedmineDbPass', @_); } | 166 sub RedmineDbPass { set_val('RedmineDbPass', @_); } |
166 sub RedmineDbWhereClause { | 167 sub RedmineDbWhereClause { |
167 my ($self, $parms, $arg) = @_; | 168 my ($self, $parms, $arg) = @_; |
168 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." "); | 169 $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." "); |
169 } | 170 } |
170 | 171 |
171 sub RedmineCacheCredsMax { | 172 sub RedmineCacheCredsMax { |
172 my ($self, $parms, $arg) = @_; | 173 my ($self, $parms, $arg) = @_; |
173 if ($arg) { | 174 if ($arg) { |
174 $self->{RedmineCachePool} = APR::Pool->new; | 175 $self->{RedmineCachePool} = APR::Pool->new; |
175 $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg); | 176 $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg); |
176 $self->{RedmineCacheCredsCount} = 0; | 177 $self->{RedmineCacheCredsCount} = 0; |
206 return OK unless defined $read_only_methods{$method}; | 207 return OK unless defined $read_only_methods{$method}; |
207 | 208 |
208 my $project_id = get_project_identifier($r); | 209 my $project_id = get_project_identifier($r); |
209 | 210 |
210 $r->set_handlers(PerlAuthenHandler => [\&OK]) | 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 return OK | 214 return OK |
214 } | 215 } |
215 | 216 |
216 sub authen_handler { | 217 sub authen_handler { |
217 my $r = shift; | 218 my $r = shift; |
218 | 219 |
219 my ($res, $redmine_pass) = $r->get_basic_auth_pw(); | 220 my ($res, $redmine_pass) = $r->get_basic_auth_pw(); |
220 return $res unless $res == OK; | 221 return $res unless $res == OK; |
221 | 222 |
222 if (is_member($r->user, $redmine_pass, $r)) { | 223 if (is_member($r->user, $redmine_pass, $r)) { |
223 return OK; | 224 return OK; |
224 } else { | 225 } else { |
225 $r->note_auth_failure(); | 226 $r->note_auth_failure(); |
226 return AUTH_REQUIRED; | 227 return AUTH_REQUIRED; |
243 $ret = 1; | 244 $ret = 1; |
244 } | 245 } |
245 } | 246 } |
246 $sth->finish(); | 247 $sth->finish(); |
247 undef $sth; | 248 undef $sth; |
248 | 249 |
249 $dbh->disconnect(); | 250 $dbh->disconnect(); |
250 undef $dbh; | 251 undef $dbh; |
251 | 252 |
252 $ret; | 253 $ret; |
253 } | 254 } |
254 | 255 |
255 sub is_public_project { | 256 sub is_public_project { |
256 my $project_id = shift; | 257 my $project_id = shift; |
257 my $r = shift; | 258 my $r = shift; |
258 | 259 |
259 if (is_authentication_forced($r)) { | 260 if (is_authentication_forced($r)) { |
260 return 0; | 261 return 0; |
261 } | 262 } |
262 | 263 |
263 my $dbh = connect_database($r); | 264 my $dbh = connect_database($r); |
278 undef $dbh; | 279 undef $dbh; |
279 | 280 |
280 $ret; | 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 # perhaps we should use repository right (other read right) to check public access. | 307 # perhaps we should use repository right (other read right) to check public access. |
284 # it could be faster BUT it doesn't work for the moment. | 308 # it could be faster BUT it doesn't work for the moment. |
285 # sub is_public_project_by_file { | 309 # sub is_public_project_by_file { |
286 # my $project_id = shift; | 310 # my $project_id = shift; |
287 # my $r = shift; | 311 # my $r = shift; |
303 my $dbh = connect_database($r); | 327 my $dbh = connect_database($r); |
304 my $project_id = get_project_identifier($r); | 328 my $project_id = get_project_identifier($r); |
305 | 329 |
306 my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); | 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 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); | 334 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); |
309 my $usrprojpass; | 335 my $usrprojpass; |
310 if ($cfg->{RedmineCacheCredsMax}) { | 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 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest)); | 338 return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest)); |
313 } | 339 } |
314 my $query = $cfg->{RedmineQuery}; | 340 my $query = $cfg->{RedmineQuery}; |
315 my $sth = $dbh->prepare($query); | 341 my $sth = $dbh->prepare($query); |
316 $sth->execute($redmine_user, $project_id); | 342 $sth->execute($redmine_user, $project_id); |
319 while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) { | 345 while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) { |
320 | 346 |
321 unless ($auth_source_id) { | 347 unless ($auth_source_id) { |
322 my $method = $r->method; | 348 my $method = $r->method; |
323 my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest); | 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 $ret = 1; | 351 $ret = 1; |
326 last; | 352 last; |
327 } | 353 } |
328 } elsif ($CanUseLDAPAuth) { | 354 } elsif ($CanUseLDAPAuth) { |
329 my $sthldap = $dbh->prepare( | 355 my $sthldap = $dbh->prepare( |
338 binddn => $rowldap[3] ? $rowldap[3] : "", | 364 binddn => $rowldap[3] ? $rowldap[3] : "", |
339 bindpw => $rowldap[4] ? $rowldap[4] : "", | 365 bindpw => $rowldap[4] ? $rowldap[4] : "", |
340 filter => "(".$rowldap[6]."=%s)" | 366 filter => "(".$rowldap[6]."=%s)" |
341 ); | 367 ); |
342 my $method = $r->method; | 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 $sthldap->finish(); | 372 $sthldap->finish(); |
347 undef $sthldap; | 373 undef $sthldap; |
348 } | 374 } |
352 $dbh->disconnect(); | 378 $dbh->disconnect(); |
353 undef $dbh; | 379 undef $dbh; |
354 | 380 |
355 if ($cfg->{RedmineCacheCredsMax} and $ret) { | 381 if ($cfg->{RedmineCacheCredsMax} and $ret) { |
356 if (defined $usrprojpass) { | 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 } else { | 384 } else { |
359 if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) { | 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 $cfg->{RedmineCacheCredsCount}++; | 387 $cfg->{RedmineCacheCredsCount}++; |
362 } else { | 388 } else { |
363 $cfg->{RedmineCacheCreds}->clear(); | 389 $cfg->{RedmineCacheCreds}->clear(); |
364 $cfg->{RedmineCacheCredsCount} = 0; | 390 $cfg->{RedmineCacheCredsCount} = 0; |
365 } | 391 } |
369 $ret; | 395 $ret; |
370 } | 396 } |
371 | 397 |
372 sub get_project_identifier { | 398 sub get_project_identifier { |
373 my $r = shift; | 399 my $r = shift; |
374 | 400 |
375 my $location = $r->location; | 401 my $location = $r->location; |
376 my ($identifier) = $r->uri =~ m{$location/*([^/]+)}; | 402 my ($identifier) = $r->uri =~ m{$location/*([^/]+)}; |
377 $identifier; | 403 $identifier; |
378 } | 404 } |
379 | 405 |
380 sub connect_database { | 406 sub connect_database { |
381 my $r = shift; | 407 my $r = shift; |
382 | 408 |
383 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); | 409 my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); |
384 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass}); | 410 return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass}); |
385 } | 411 } |
386 | 412 |
387 1; | 413 1; |