Revision 912:5e80956cc792 extra

View differences:

extra/mail_handler/rdm-mailhandler.rb
22 22
#                                  create: create a user account
23 23
#       --no-permission-check      disable permission checking when receiving
24 24
#                                  the email
25
#       --key-file=PATH            path to a file that contains the Redmine
26
#                                  API key (use this option instead of --key
27
#                                  if you don't the key to appear in the
28
#                                  command line)
29
#       --no-check-certificate     do not check server certificate
25 30
#   -h, --help                     show this help
26 31
#   -v, --verbose                  show extra information
27 32
#   -V, --version                  show version information and exit
......
57 62

  
58 63
module Net
59 64
  class HTTPS < HTTP
60
    def self.post_form(url, params, headers)
65
    def self.post_form(url, params, headers, options={})
61 66
      request = Post.new(url.path)
62 67
      request.form_data = params
63 68
      request.basic_auth url.user, url.password if url.user
64 69
      request.initialize_http_header(headers)
65 70
      http = new(url.host, url.port)
66 71
      http.use_ssl = (url.scheme == 'https')
72
      if options[:no_check_certificate]
73
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
74
      end
67 75
      http.start {|h| h.request(request) }
68 76
    end
69 77
  end
......
72 80
class RedmineMailHandler
73 81
  VERSION = '0.1'
74 82
  
75
  attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key
83
  attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key, :no_check_certificate
76 84

  
77 85
  def initialize
78 86
    self.issue_attributes = {}
......
83 91
      [ '--verbose',        '-v', GetoptLong::NO_ARGUMENT ],
84 92
      [ '--url',            '-u', GetoptLong::REQUIRED_ARGUMENT ],
85 93
      [ '--key',            '-k', GetoptLong::REQUIRED_ARGUMENT],
94
      [ '--key-file',             GetoptLong::REQUIRED_ARGUMENT],
86 95
      [ '--project',        '-p', GetoptLong::REQUIRED_ARGUMENT ],
87 96
      [ '--status',         '-s', GetoptLong::REQUIRED_ARGUMENT ],
88 97
      [ '--tracker',        '-t', GetoptLong::REQUIRED_ARGUMENT],
......
90 99
      [ '--priority',             GetoptLong::REQUIRED_ARGUMENT],
91 100
      [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT],
92 101
      [ '--unknown-user',         GetoptLong::REQUIRED_ARGUMENT],
93
      [ '--no-permission-check',  GetoptLong::NO_ARGUMENT]
102
      [ '--no-permission-check',  GetoptLong::NO_ARGUMENT],
103
      [ '--no-check-certificate', GetoptLong::NO_ARGUMENT]
94 104
    )
95 105

  
96 106
    opts.each do |opt, arg|
......
99 109
        self.url = arg.dup
100 110
      when '--key'
101 111
        self.key = arg.dup
112
      when '--key-file'
113
        begin
114
          self.key = File.read(arg).strip
115
        rescue Exception => e
116
          $stderr.puts "Unable to read the key from #{arg}: #{e.message}"
117
          exit 1
118
        end
102 119
      when '--help'
103 120
        usage
104 121
      when '--verbose'
......
113 130
        self.unknown_user = arg.dup
114 131
      when '--no-permission-check'
115 132
        self.no_permission_check = '1'
133
      when '--no-check-certificate'
134
        self.no_check_certificate = true
116 135
      end
117 136
    end
118 137
    
......
131 150
    issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
132 151
             
133 152
    debug "Posting to #{uri}..."
134
    response = Net::HTTPS.post_form(URI.parse(uri), data, headers)
153
    response = Net::HTTPS.post_form(URI.parse(uri), data, headers, :no_check_certificate => no_check_certificate)
135 154
    debug "Response received: #{response.code}"
136 155
    
137 156
    case response.code.to_i
extra/soundsoftware/reposman-soundsoftware.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
#
......
50 51
#                             and subversion.
51 52
#   --http-user=USER          User for HTTP Basic authentication with Redmine WS
52 53
#   --http-pass=PASSWORD      Password for Basic authentication with Redmine WS
54
#       --key-file=PATH       path to a file that contains the Redmine API key
55
#                             (use this option instead of --key if you don't 
56
#                             the key to appear in the command line)
53 57
#   -t, --test                only show what should be done
54 58
#   -h, --help                show help and exit
55 59
#   -v, --verbose             verbose
......
73 77
                      ['--scm-dir',      '-s', GetoptLong::REQUIRED_ARGUMENT],
74 78
                      ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
75 79
                      ['--key',          '-k', GetoptLong::REQUIRED_ARGUMENT],
80
                      ['--key-file',           GetoptLong::REQUIRED_ARGUMENT],
76 81
                      ['--owner',        '-o', GetoptLong::REQUIRED_ARGUMENT],
77 82
                      ['--group',        '-g', GetoptLong::REQUIRED_ARGUMENT],
78 83
                      ['--url',          '-u', GetoptLong::REQUIRED_ARGUMENT],
......
136 141
    when '--scm-dir';        $repos_base   = arg.dup
137 142
    when '--redmine-host';   $redmine_host = arg.dup
138 143
    when '--key';            $api_key      = arg.dup
144
    when '--key-file'
145
      begin
146
        $api_key = File.read(arg).strip
147
      rescue Exception => e
148
        $stderr.puts "Unable to read the key from #{arg}: #{e.message}"
149
        exit 1
150
      end
139 151
    when '--owner';          $svn_owner    = arg.dup; $use_groupid = false;
140 152
    when '--group';          $svn_group    = arg.dup; $use_groupid = false;
141 153
    when '--url';            $svn_url      = arg.dup
......
185 197

  
186 198
class Project < ActiveResource::Base
187 199
  self.headers["User-agent"] = "SoundSoftware repository manager/#{Version}"
200
  self.format = :xml
188 201
end
189 202

  
190 203
log("querying Redmine for projects...", :level => 1);
......
199 212
begin
200 213
  # Get all active projects that have the Repository module enabled
201 214
  projects = Project.find(:all, :params => {:key => $api_key})
215
rescue ActiveResource::ForbiddenAccess
216
  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.")
202 217
rescue => e
203 218
  log("Unable to connect to #{Project.site}: #{e}", :exit => true)
204 219
end
205 220

  
206 221
if projects.nil?
207
  log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
222
  log('No project found, perhaps you forgot to "Enable WS for repository management"', :exit => true)
208 223
end
209 224

  
210 225
log("retrieved #{projects.size} projects", :level => 1)
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