Revision 912:5e80956cc792 extra
| 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