diff 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
line wrap: on
line diff
--- a/extra/svn/Redmine.pm	Fri Feb 24 18:36:29 2012 +0000
+++ b/extra/svn/Redmine.pm	Fri Feb 24 19:09:32 2012 +0000
@@ -49,7 +49,7 @@
 
      PerlAccessHandler Apache::Authn::Redmine::access_handler
      PerlAuthenHandler Apache::Authn::Redmine::authen_handler
-  
+
      ## for mysql
      RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
      ## for postgres
@@ -144,31 +144,32 @@
   },
 );
 
-sub RedmineDSN { 
+sub RedmineDSN {
   my ($self, $parms, $arg) = @_;
   $self->{RedmineDSN} = $arg;
   my $query = "SELECT 
                  hashed_password, salt, auth_source_id, permissions
-              FROM members, projects, users, roles, member_roles
+              FROM projects, users, roles
               WHERE 
-                projects.id=members.project_id
-                AND member_roles.member_id=members.id
-                AND users.id=members.user_id 
-                AND roles.id=member_roles.role_id
+                users.login=? 
+                AND projects.identifier=?
                 AND users.status=1 
-                AND login=? 
-                AND identifier=? ";
+                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'))
+                ) ";
   $self->{RedmineQuery} = trim($query);
 }
 
 sub RedmineDbUser { set_val('RedmineDbUser', @_); }
 sub RedmineDbPass { set_val('RedmineDbPass', @_); }
-sub RedmineDbWhereClause { 
+sub RedmineDbWhereClause {
   my ($self, $parms, $arg) = @_;
   $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
 }
 
-sub RedmineCacheCredsMax { 
+sub RedmineCacheCredsMax {
   my ($self, $parms, $arg) = @_;
   if ($arg) {
     $self->{RedmineCachePool} = APR::Pool->new;
@@ -208,17 +209,17 @@
   my $project_id = get_project_identifier($r);
 
   $r->set_handlers(PerlAuthenHandler => [\&OK])
-      if is_public_project($project_id, $r);
+      if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r);
 
   return OK
 }
 
 sub authen_handler {
   my $r = shift;
-  
+
   my ($res, $redmine_pass) =  $r->get_basic_auth_pw();
   return $res unless $res == OK;
-  
+
   if (is_member($r->user, $redmine_pass, $r)) {
       return OK;
   } else {
@@ -245,7 +246,7 @@
   }
   $sth->finish();
   undef $sth;
-  
+
   $dbh->disconnect();
   undef $dbh;
 
@@ -255,7 +256,7 @@
 sub is_public_project {
     my $project_id = shift;
     my $r = shift;
-    
+
     if (is_authentication_forced($r)) {
       return 0;
     }
@@ -280,6 +281,29 @@
     $ret;
 }
 
+sub anonymous_role_allows_browse_repository {
+  my $r = shift;
+
+  my $dbh = connect_database($r);
+  my $sth = $dbh->prepare(
+      "SELECT permissions FROM roles WHERE builtin = 2;"
+  );
+
+  $sth->execute();
+  my $ret = 0;
+  if (my @row = $sth->fetchrow_array) {
+    if ($row[0] =~ /:browse_repository/) {
+      $ret = 1;
+    }
+  }
+  $sth->finish();
+  undef $sth;
+  $dbh->disconnect();
+  undef $dbh;
+
+  $ret;
+}
+
 # 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 {
@@ -305,10 +329,12 @@
 
   my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
 
+  my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
+
   my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
   my $usrprojpass;
   if ($cfg->{RedmineCacheCredsMax}) {
-    $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id);
+    $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
     return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
   }
   my $query = $cfg->{RedmineQuery};
@@ -321,7 +347,7 @@
       unless ($auth_source_id) {
 	  			my $method = $r->method;
           my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
-					if ($hashed_password eq $salted_password && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
+					if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
               $ret = 1;
               last;
           }
@@ -340,7 +366,7 @@
                 filter  =>      "(".$rowldap[6]."=%s)"
             );
             my $method = $r->method;
-            $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
+            $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
 
           }
           $sthldap->finish();
@@ -354,10 +380,10 @@
 
   if ($cfg->{RedmineCacheCredsMax} and $ret) {
     if (defined $usrprojpass) {
-      $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
+      $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
     } else {
       if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
-        $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
+        $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
         $cfg->{RedmineCacheCredsCount}++;
       } else {
         $cfg->{RedmineCacheCreds}->clear();
@@ -371,7 +397,7 @@
 
 sub get_project_identifier {
     my $r = shift;
-    
+
     my $location = $r->location;
     my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
     $identifier;
@@ -379,7 +405,7 @@
 
 sub connect_database {
     my $r = shift;
-    
+
     my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
     return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
 }