| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | package Apache::Authn::Redmine; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 Apache::Authn::Redmine | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Redmine - a mod_perl module to authenticate webdav subversion users | 
					
						
							|  |  |  | against redmine database | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 SYNOPSIS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This module allow anonymous users to browse public project and | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  | registred users to browse and commit their project. Authentication is | 
					
						
							|  |  |  | done against the redmine database or the LDAP configured in redmine. | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This method is far simpler than the one with pam_* and works with all | 
					
						
							|  |  |  | database without an hassle but you need to have apache/mod_perl on the | 
					
						
							|  |  |  | svn server. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 INSTALLATION | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For this to automagically work, you need to have a recent reposman.rb | 
					
						
							|  |  |  | (after r860) and if you already use reposman, read the last section to | 
					
						
							|  |  |  | migrate. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Sorry ruby users but you need some perl modules, at least mod_perl2, | 
					
						
							|  |  |  | DBI and DBD::mysql (or the DBD driver for you database as it should | 
					
						
							|  |  |  | work on allmost all databases). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | On debian/ubuntu you must do : | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  | If your Redmine users use LDAP authentication, you will also need | 
					
						
							| 
									
										
										
										
											2008-04-07 17:03:02 +00:00
										 |  |  | Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | =head1 CONFIGURATION | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |    ## This module has to be in your perl path | 
					
						
							|  |  |  |    ## eg:  /usr/lib/perl5/Apache/Authn/Redmine.pm | 
					
						
							|  |  |  |    PerlLoadModule Apache::Authn::Redmine | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |    <Location /svn> | 
					
						
							|  |  |  |      DAV svn | 
					
						
							|  |  |  |      SVNParentPath "/var/svn" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      AuthType Basic | 
					
						
							|  |  |  |      AuthName redmine | 
					
						
							|  |  |  |      Require valid-user | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      PerlAccessHandler Apache::Authn::Redmine::access_handler | 
					
						
							|  |  |  |      PerlAuthenHandler Apache::Authn::Redmine::authen_handler | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |      ## for mysql | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |      RedmineDSN "DBI:mysql:database=databasename;host=my.db.server" | 
					
						
							| 
									
										
										
										
											2008-05-19 12:41:40 +00:00
										 |  |  |      ## for postgres | 
					
						
							|  |  |  |      # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server" | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |      RedmineDbUser "redmine" | 
					
						
							|  |  |  |      RedmineDbPass "password" | 
					
						
							|  |  |  |      ## Optional where clause (fulltext search would be slow and | 
					
						
							|  |  |  |      ## database dependant). | 
					
						
							|  |  |  |      # RedmineDbWhereClause "and members.role_id IN (1,2)" | 
					
						
							|  |  |  |      ## Optional credentials cache size | 
					
						
							|  |  |  |      # RedmineCacheCredsMax 50 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |   </Location> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To be able to browse repository inside redmine, you must add something | 
					
						
							|  |  |  | like that : | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    <Location /svn-private> | 
					
						
							|  |  |  |      DAV svn | 
					
						
							|  |  |  |      SVNParentPath "/var/svn" | 
					
						
							|  |  |  |      Order deny,allow | 
					
						
							|  |  |  |      Deny from all | 
					
						
							|  |  |  |      # only allow reading orders | 
					
						
							|  |  |  |      <Limit GET PROPFIND OPTIONS REPORT> | 
					
						
							|  |  |  |        Allow from redmine.server.ip | 
					
						
							|  |  |  |      </Limit> | 
					
						
							|  |  |  |    </Location> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | and you will have to use this reposman.rb command line to create repository : | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-24 13:21:43 +00:00
										 |  |  | =head1 REPOSITORIES NAMING | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A projet repository must be named with the projet identifier. In case | 
					
						
							|  |  |  | of multiple repositories for the same project, use the project identifier | 
					
						
							|  |  |  | and the repository identifier separated with a dot: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /var/svn/foo | 
					
						
							|  |  |  |   /var/svn/foo.otherrepo | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | =head1 MIGRATION FROM OLDER RELEASES | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you use an older reposman.rb (r860 or before), you need to change | 
					
						
							|  |  |  | rights on repositories to allow the apache user to read and write | 
					
						
							|  |  |  | S<them :> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   sudo chown -R www-data /var/svn/* | 
					
						
							|  |  |  |   sudo chmod -R u+w /var/svn/* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | And you need to upgrade at least reposman.rb (after r860). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =cut | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use strict; | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  | use warnings FATAL => 'all', NONFATAL => 'redefine'; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | use DBI; | 
					
						
							| 
									
										
										
										
											2012-02-15 19:25:16 +00:00
										 |  |  | use Digest::SHA; | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  | # optional module for LDAP authentication | 
					
						
							|  |  |  | my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1"); | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | use Apache2::Module; | 
					
						
							|  |  |  | use Apache2::Access; | 
					
						
							|  |  |  | use Apache2::ServerRec qw(); | 
					
						
							|  |  |  | use Apache2::RequestRec qw(); | 
					
						
							|  |  |  | use Apache2::RequestUtil qw(); | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  | use Apache2::Const qw(:common :override :cmd_how); | 
					
						
							|  |  |  | use APR::Pool (); | 
					
						
							|  |  |  | use APR::Table (); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | # use Apache2::Directive qw(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  | my @directives = ( | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     name => 'RedmineDSN', | 
					
						
							|  |  |  |     req_override => OR_AUTHCFG, | 
					
						
							|  |  |  |     args_how => TAKE1, | 
					
						
							|  |  |  |     errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"', | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     name => 'RedmineDbUser', | 
					
						
							|  |  |  |     req_override => OR_AUTHCFG, | 
					
						
							|  |  |  |     args_how => TAKE1, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     name => 'RedmineDbPass', | 
					
						
							|  |  |  |     req_override => OR_AUTHCFG, | 
					
						
							|  |  |  |     args_how => TAKE1, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     name => 'RedmineDbWhereClause', | 
					
						
							|  |  |  |     req_override => OR_AUTHCFG, | 
					
						
							|  |  |  |     args_how => TAKE1, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     name => 'RedmineCacheCredsMax', | 
					
						
							|  |  |  |     req_override => OR_AUTHCFG, | 
					
						
							|  |  |  |     args_how => TAKE1, | 
					
						
							|  |  |  |     errmsg => 'RedmineCacheCredsMax must be decimal number', | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | sub RedmineDSN { | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |   my ($self, $parms, $arg) = @_; | 
					
						
							|  |  |  |   $self->{RedmineDSN} = $arg; | 
					
						
							|  |  |  |   my $query = "SELECT  | 
					
						
							| 
									
										
										
										
											2011-02-23 17:27:31 +00:00
										 |  |  |                  hashed_password, salt, auth_source_id, permissions | 
					
						
							| 
									
										
										
										
											2011-11-18 17:28:40 +00:00
										 |  |  |               FROM projects, users, roles | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |               WHERE  | 
					
						
							| 
									
										
										
										
											2011-11-18 17:28:40 +00:00
										 |  |  |                 users.login=?  | 
					
						
							|  |  |  |                 AND projects.identifier=? | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |                 AND users.status=1  | 
					
						
							| 
									
										
										
										
											2011-11-18 17:28:40 +00:00
										 |  |  |                 AND ( | 
					
						
							|  |  |  |                   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) | 
					
						
							|  |  |  |                   OR | 
					
						
							|  |  |  |                   (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1')) | 
					
						
							|  |  |  |                 ) "; | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |   $self->{RedmineQuery} = trim($query); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-12 16:56:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  | sub RedmineDbUser { set_val('RedmineDbUser', @_); } | 
					
						
							|  |  |  | sub RedmineDbPass { set_val('RedmineDbPass', @_); } | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | sub RedmineDbWhereClause { | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |   my ($self, $parms, $arg) = @_; | 
					
						
							|  |  |  |   $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." "); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | sub RedmineCacheCredsMax { | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |   my ($self, $parms, $arg) = @_; | 
					
						
							|  |  |  |   if ($arg) { | 
					
						
							|  |  |  |     $self->{RedmineCachePool} = APR::Pool->new; | 
					
						
							|  |  |  |     $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg); | 
					
						
							|  |  |  |     $self->{RedmineCacheCredsCount} = 0; | 
					
						
							|  |  |  |     $self->{RedmineCacheCredsMax} = $arg; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub trim { | 
					
						
							|  |  |  |   my $string = shift; | 
					
						
							|  |  |  |   $string =~ s/\s{2,}/ /g; | 
					
						
							|  |  |  |   return $string; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub set_val { | 
					
						
							|  |  |  |   my ($key, $self, $parms, $arg) = @_; | 
					
						
							|  |  |  |   $self->{$key} = $arg; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Apache2::Module::add(__PACKAGE__, \@directives); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub access_handler { | 
					
						
							|  |  |  |   my $r = shift; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   unless ($r->some_auth_required) { | 
					
						
							|  |  |  |       $r->log_reason("No authentication has been configured"); | 
					
						
							|  |  |  |       return FORBIDDEN; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my $method = $r->method; | 
					
						
							| 
									
										
										
										
											2008-08-31 12:11:49 +00:00
										 |  |  |   return OK unless defined $read_only_methods{$method}; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   my $project_id = get_project_identifier($r); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   $r->set_handlers(PerlAuthenHandler => [\&OK]) | 
					
						
							| 
									
										
										
										
											2011-10-04 21:47:55 +00:00
										 |  |  |       if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r); | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return OK | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub authen_handler { | 
					
						
							|  |  |  |   my $r = shift; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |   my ($res, $redmine_pass) =  $r->get_basic_auth_pw(); | 
					
						
							|  |  |  |   return $res unless $res == OK; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |   if (is_member($r->user, $redmine_pass, $r)) { | 
					
						
							|  |  |  |       return OK; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |       $r->note_auth_failure(); | 
					
						
							|  |  |  |       return AUTH_REQUIRED; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 03:46:14 +00:00
										 |  |  | # check if authentication is forced | 
					
						
							|  |  |  | sub is_authentication_forced { | 
					
						
							|  |  |  |   my $r = shift; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my $dbh = connect_database($r); | 
					
						
							|  |  |  |   my $sth = $dbh->prepare( | 
					
						
							|  |  |  |     "SELECT value FROM settings where settings.name = 'login_required';" | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   $sth->execute(); | 
					
						
							|  |  |  |   my $ret = 0; | 
					
						
							|  |  |  |   if (my @row = $sth->fetchrow_array) { | 
					
						
							|  |  |  |     if ($row[0] eq "1" || $row[0] eq "t") { | 
					
						
							|  |  |  |       $ret = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   $sth->finish(); | 
					
						
							|  |  |  |   undef $sth; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-08 03:46:14 +00:00
										 |  |  |   $dbh->disconnect(); | 
					
						
							|  |  |  |   undef $dbh; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   $ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | sub is_public_project { | 
					
						
							|  |  |  |     my $project_id = shift; | 
					
						
							|  |  |  |     my $r = shift; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-15 18:02:10 +00:00
										 |  |  |     if (is_authentication_forced($r)) { | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     my $dbh = connect_database($r); | 
					
						
							|  |  |  |     my $sth = $dbh->prepare( | 
					
						
							| 
									
										
										
										
											2009-12-26 12:02:24 +00:00
										 |  |  |         "SELECT is_public FROM projects WHERE projects.identifier = ?;" | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $sth->execute($project_id); | 
					
						
							| 
									
										
										
										
											2009-12-26 12:02:24 +00:00
										 |  |  |     my $ret = 0; | 
					
						
							|  |  |  |     if (my @row = $sth->fetchrow_array) { | 
					
						
							|  |  |  |     	if ($row[0] eq "1" || $row[0] eq "t") { | 
					
						
							|  |  |  |     		$ret = 1; | 
					
						
							|  |  |  |     	} | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-06-15 09:43:53 +00:00
										 |  |  |     $sth->finish(); | 
					
						
							| 
									
										
										
										
											2010-01-10 10:17:27 +00:00
										 |  |  |     undef $sth; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |     $dbh->disconnect(); | 
					
						
							| 
									
										
										
										
											2010-01-10 10:17:27 +00:00
										 |  |  |     undef $dbh; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     $ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-15 18:02:10 +00:00
										 |  |  | sub anonymous_role_allows_browse_repository { | 
					
						
							| 
									
										
										
										
											2011-10-04 21:47:55 +00:00
										 |  |  |   my $r = shift; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 21:47:55 +00:00
										 |  |  |   my $dbh = connect_database($r); | 
					
						
							|  |  |  |   my $sth = $dbh->prepare( | 
					
						
							| 
									
										
										
										
											2011-11-15 18:02:10 +00:00
										 |  |  |       "SELECT permissions FROM roles WHERE builtin = 2;" | 
					
						
							| 
									
										
										
										
											2011-10-04 21:47:55 +00:00
										 |  |  |   ); | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-15 18:02:10 +00:00
										 |  |  |   $sth->execute(); | 
					
						
							| 
									
										
										
										
											2011-10-04 21:47:55 +00:00
										 |  |  |   my $ret = 0; | 
					
						
							|  |  |  |   if (my @row = $sth->fetchrow_array) { | 
					
						
							|  |  |  |     if ($row[0] =~ /:browse_repository/) { | 
					
						
							|  |  |  |       $ret = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   $sth->finish(); | 
					
						
							|  |  |  |   undef $sth; | 
					
						
							|  |  |  |   $dbh->disconnect(); | 
					
						
							|  |  |  |   undef $dbh; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-04 21:47:55 +00:00
										 |  |  |   $ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | # perhaps we should use repository right (other read right) to check public access. | 
					
						
							|  |  |  | # it could be faster BUT it doesn't work for the moment. | 
					
						
							|  |  |  | # sub is_public_project_by_file { | 
					
						
							|  |  |  | #     my $project_id = shift; | 
					
						
							|  |  |  | #     my $r = shift; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #     my $tree = Apache2::Directive::conftree(); | 
					
						
							|  |  |  | #     my $node = $tree->lookup('Location', $r->location); | 
					
						
							|  |  |  | #     my $hash = $node->as_hash; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #     my $svnparentpath = $hash->{SVNParentPath}; | 
					
						
							|  |  |  | #     my $repos_path = $svnparentpath . "/" . $project_id; | 
					
						
							|  |  |  | #     return 1 if (stat($repos_path))[2] & 00007; | 
					
						
							|  |  |  | # } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub is_member { | 
					
						
							|  |  |  |   my $redmine_user = shift; | 
					
						
							|  |  |  |   my $redmine_pass = shift; | 
					
						
							|  |  |  |   my $r = shift; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my $dbh         = connect_database($r); | 
					
						
							|  |  |  |   my $project_id  = get_project_identifier($r); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-15 19:25:16 +00:00
										 |  |  |   my $pass_digest = Digest::SHA::sha1_hex($redmine_pass); | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-14 22:11:24 +00:00
										 |  |  |   my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W"; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |   my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); | 
					
						
							|  |  |  |   my $usrprojpass; | 
					
						
							|  |  |  |   if ($cfg->{RedmineCacheCredsMax}) { | 
					
						
							| 
									
										
										
										
											2011-11-14 22:11:24 +00:00
										 |  |  |     $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode); | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |     return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   my $query = $cfg->{RedmineQuery}; | 
					
						
							|  |  |  |   my $sth = $dbh->prepare($query); | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |   $sth->execute($redmine_user, $project_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   my $ret; | 
					
						
							| 
									
										
										
										
											2011-02-23 17:27:31 +00:00
										 |  |  |   while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) { | 
					
						
							| 
									
										
										
										
											2008-09-13 16:31:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       unless ($auth_source_id) { | 
					
						
							| 
									
										
										
										
											2011-02-23 17:27:31 +00:00
										 |  |  | 	  			my $method = $r->method; | 
					
						
							| 
									
										
										
										
											2012-02-15 19:25:16 +00:00
										 |  |  |           my $salted_password = Digest::SHA::sha1_hex($salt.$pass_digest); | 
					
						
							| 
									
										
										
										
											2011-11-14 22:11:24 +00:00
										 |  |  | 					if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) { | 
					
						
							| 
									
										
										
										
											2008-04-06 17:29:09 +00:00
										 |  |  |               $ret = 1; | 
					
						
							|  |  |  |               last; | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  |       } elsif ($CanUseLDAPAuth) { | 
					
						
							| 
									
										
										
										
											2008-04-06 17:29:09 +00:00
										 |  |  |           my $sthldap = $dbh->prepare( | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  |               "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;" | 
					
						
							| 
									
										
										
										
											2008-04-06 17:29:09 +00:00
										 |  |  |           ); | 
					
						
							| 
									
										
										
										
											2008-09-13 16:31:11 +00:00
										 |  |  |           $sthldap->execute($auth_source_id); | 
					
						
							| 
									
										
										
										
											2008-04-06 17:29:09 +00:00
										 |  |  |           while (my @rowldap = $sthldap->fetchrow_array) { | 
					
						
							| 
									
										
										
										
											2012-06-03 08:49:46 +00:00
										 |  |  |             my $bind_as = $rowldap[3] ? $rowldap[3] : ""; | 
					
						
							|  |  |  |             my $bind_pw = $rowldap[4] ? $rowldap[4] : ""; | 
					
						
							|  |  |  |             if ($bind_as =~ m/\$login/) { | 
					
						
							|  |  |  |               # replace $login with $redmine_user and use $redmine_pass | 
					
						
							|  |  |  |               $bind_as =~ s/\$login/$redmine_user/g; | 
					
						
							|  |  |  |               $bind_pw = $redmine_pass | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-04-06 17:29:09 +00:00
										 |  |  |             my $ldap = Authen::Simple::LDAP->new( | 
					
						
							| 
									
										
										
										
											2010-10-29 22:55:50 +00:00
										 |  |  |                 host    =>      ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0], | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  |                 port    =>      $rowldap[1], | 
					
						
							|  |  |  |                 basedn  =>      $rowldap[5], | 
					
						
							| 
									
										
										
										
											2012-06-03 08:49:46 +00:00
										 |  |  |                 binddn  =>      $bind_as, | 
					
						
							|  |  |  |                 bindpw  =>      $bind_pw, | 
					
						
							| 
									
										
										
										
											2008-04-06 17:36:26 +00:00
										 |  |  |                 filter  =>      "(".$rowldap[6]."=%s)" | 
					
						
							|  |  |  |             ); | 
					
						
							| 
									
										
										
										
											2010-07-08 03:46:19 +00:00
										 |  |  |             my $method = $r->method; | 
					
						
							| 
									
										
										
										
											2011-11-14 22:11:24 +00:00
										 |  |  |             $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/)); | 
					
						
							| 
									
										
										
										
											2010-07-08 03:46:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-06 17:29:09 +00:00
										 |  |  |           } | 
					
						
							|  |  |  |           $sthldap->finish(); | 
					
						
							| 
									
										
										
										
											2010-01-10 10:17:27 +00:00
										 |  |  |           undef $sthldap; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |       } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2008-04-06 17:29:09 +00:00
										 |  |  |   $sth->finish(); | 
					
						
							| 
									
										
										
										
											2010-01-10 10:17:27 +00:00
										 |  |  |   undef $sth; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |   $dbh->disconnect(); | 
					
						
							| 
									
										
										
										
											2010-01-10 10:17:27 +00:00
										 |  |  |   undef $dbh; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |   if ($cfg->{RedmineCacheCredsMax} and $ret) { | 
					
						
							|  |  |  |     if (defined $usrprojpass) { | 
					
						
							| 
									
										
										
										
											2011-11-14 22:11:24 +00:00
										 |  |  |       $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest); | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) { | 
					
						
							| 
									
										
										
										
											2011-11-14 22:11:24 +00:00
										 |  |  |         $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest); | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |         $cfg->{RedmineCacheCredsCount}++; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         $cfg->{RedmineCacheCreds}->clear(); | 
					
						
							|  |  |  |         $cfg->{RedmineCacheCredsCount} = 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |   $ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub get_project_identifier { | 
					
						
							|  |  |  |     my $r = shift; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |     my $location = $r->location; | 
					
						
							| 
									
										
										
										
											2012-03-24 13:21:43 +00:00
										 |  |  |     my ($identifier) = $r->uri =~ m{$location/*([^/.]+)}; | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  |     $identifier; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub connect_database { | 
					
						
							|  |  |  |     my $r = shift; | 
					
						
							| 
									
										
										
										
											2011-12-01 05:27:04 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 09:41:19 +00:00
										 |  |  |     my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); | 
					
						
							|  |  |  |     return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass}); | 
					
						
							| 
									
										
										
										
											2007-11-18 18:51:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1; |