Revision 912:5e80956cc792 extra/svn

View differences:

extra/svn/Redmine.pm
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
}
extra/svn/reposman.rb
19 19
#                             -r redmine.example.net
20 20
#                             -r http://redmine.example.net
21 21
#                             -r https://example.net/redmine
22
#   -k, --key=KEY             use KEY as the Redmine API key
22
#   -k, --key=KEY             use KEY as the Redmine API key (you can use the
23
#                             --key-file option as an alternative)
23 24
#
24 25
# == Options
25 26
#
......
52 53
#   --http-pass=PASSWORD      Password for Basic authentication with Redmine WS
53 54
#   -f, --force               force repository creation even if the project
54 55
#                             repository is already declared in Redmine
56
#       --key-file=PATH       path to a file that contains the Redmine API key
57
#                             (use this option instead of --key if you don't 
58
#                             the key to appear in the command line)
55 59
#   -t, --test                only show what should be done
56 60
#   -h, --help                show help and exit
57 61
#   -v, --verbose             verbose
......
75 79
                      ['--svn-dir',      '-s', GetoptLong::REQUIRED_ARGUMENT],
76 80
                      ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
77 81
                      ['--key',          '-k', GetoptLong::REQUIRED_ARGUMENT],
82
                      ['--key-file',           GetoptLong::REQUIRED_ARGUMENT],
78 83
                      ['--owner',        '-o', GetoptLong::REQUIRED_ARGUMENT],
79 84
                      ['--group',        '-g', GetoptLong::REQUIRED_ARGUMENT],
80 85
                      ['--url',          '-u', GetoptLong::REQUIRED_ARGUMENT],
......
140 145
    when '--svn-dir';        $repos_base   = arg.dup
141 146
    when '--redmine-host';   $redmine_host = arg.dup
142 147
    when '--key';            $api_key      = arg.dup
148
    when '--key-file'
149
      begin
150
        $api_key = File.read(arg).strip
151
      rescue Exception => e
152
        $stderr.puts "Unable to read the key from #{arg}: #{e.message}"
153
        exit 1
154
      end
143 155
    when '--owner';          $svn_owner    = arg.dup; $use_groupid = false;
144 156
    when '--group';          $svn_group    = arg.dup; $use_groupid = false;
145 157
    when '--url';            $svn_url      = arg.dup
......
190 202

  
191 203
class Project < ActiveResource::Base
192 204
  self.headers["User-agent"] = "Redmine repository manager/#{Version}"
205
  self.format = :xml
193 206
end
194 207

  
195 208
log("querying Redmine for projects...", :level => 1);
......
204 217
begin
205 218
  # Get all active projects that have the Repository module enabled
206 219
  projects = Project.find(:all, :params => {:key => $api_key})
220
rescue ActiveResource::ForbiddenAccess
221
  log("Request was denied by your Redmine server. Make sure that 'WS for repository management' is enabled in application settings and that you provided the correct API key.")
207 222
rescue => e
208 223
  log("Unable to connect to #{Project.site}: #{e}", :exit => true)
209 224
end
210 225

  
211 226
if projects.nil?
212
  log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
227
  log('No project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
213 228
end
214 229

  
215 230
log("retrieved #{projects.size} projects", :level => 1)

Also available in: Unified diff