comparison extra/soundsoftware/SoundSoftware.pm @ 524:1248a47e81b3 feature_36

Merge from branch "luisf"
author luisf <luis.figueira@eecs.qmul.ac.uk>
date Mon, 25 Jul 2011 14:39:38 +0100
parents a2192366d309
children 897bc2b63bfe
comparison
equal deleted inserted replaced
519:3be6bc3c2a17 524:1248a47e81b3
22 3. Push to repo for public project: "Permitted" users only (this 22 3. Push to repo for public project: "Permitted" users only (this
23 probably means project members who are also identified in the hgrc web 23 probably means project members who are also identified in the hgrc web
24 section for the repository and so will be approved by hgwebdir?) 24 section for the repository and so will be approved by hgwebdir?)
25 25
26 4. Push to repo for private project: "Permitted" users only (as above) 26 4. Push to repo for private project: "Permitted" users only (as above)
27
28 5. Push to any repo that is tracking an external repo: Refused always
27 29
28 =head1 INSTALLATION 30 =head1 INSTALLATION
29 31
30 Debian/ubuntu: 32 Debian/ubuntu:
31 33
112 114
113 sub SoundSoftwareDSN { 115 sub SoundSoftwareDSN {
114 my ($self, $parms, $arg) = @_; 116 my ($self, $parms, $arg) = @_;
115 $self->{SoundSoftwareDSN} = $arg; 117 $self->{SoundSoftwareDSN} = $arg;
116 my $query = "SELECT 118 my $query = "SELECT
117 hashed_password, auth_source_id, permissions 119 hashed_password, salt, auth_source_id, permissions
118 FROM members, projects, users, roles, member_roles 120 FROM members, projects, users, roles, member_roles
119 WHERE 121 WHERE
120 projects.id=members.project_id 122 projects.id=members.project_id
121 AND member_roles.member_id=members.id 123 AND member_roles.member_id=members.id
122 AND users.id=members.user_id 124 AND users.id=members.user_id
158 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/; 160 my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
159 161
160 sub access_handler { 162 sub access_handler {
161 my $r = shift; 163 my $r = shift;
162 164
163 print STDERR "SoundSoftware.pm: In access handler at " . scalar localtime() . "\n"; 165 print STDERR "SoundSoftware.pm:$$: In access handler at " . scalar localtime() . "\n";
164 166
165 unless ($r->some_auth_required) { 167 unless ($r->some_auth_required) {
166 $r->log_reason("No authentication has been configured"); 168 $r->log_reason("No authentication has been configured");
167 return FORBIDDEN; 169 return FORBIDDEN;
168 } 170 }
169 171
170 my $method = $r->method; 172 my $method = $r->method;
171 173
172 print STDERR "SoundSoftware.pm: Method: $method, uri " . $r->uri . ", location " . $r->location . "\n"; 174 print STDERR "SoundSoftware.pm:$$: Method: $method, uri " . $r->uri . ", location " . $r->location . "\n";
173 print STDERR "SoundSoftware.pm: Accept: " . $r->headers_in->{Accept} . "\n"; 175 print STDERR "SoundSoftware.pm:$$: Accept: " . $r->headers_in->{Accept} . "\n";
174
175 if (!defined $read_only_methods{$method}) {
176 print STDERR "SoundSoftware.pm: Method is not read-only, authentication handler required\n";
177 return OK;
178 }
179 176
180 my $dbh = connect_database($r); 177 my $dbh = connect_database($r);
181 unless ($dbh) { 178 unless ($dbh) {
182 print STDERR "SoundSoftware.pm: Database connection failed!: " . $DBI::errstr . "\n"; 179 print STDERR "SoundSoftware.pm:$$: Database connection failed!: " . $DBI::errstr . "\n";
183 return FORBIDDEN; 180 return FORBIDDEN;
184 } 181 }
185 182
186 183 print STDERR "Connected to db, dbh is " . $dbh . "\n";
187 print STDERR "Connected to db, dbh is " . $dbh . "\n";
188 184
189 my $project_id = get_project_identifier($dbh, $r); 185 my $project_id = get_project_identifier($dbh, $r);
186
187 if (!defined $read_only_methods{$method}) {
188 print STDERR "SoundSoftware.pm:$$: Method is not read-only\n";
189 if (project_repo_is_readonly($dbh, $project_id, $r)) {
190 print STDERR "SoundSoftware.pm:$$: Project repo is read-only, refusing access\n";
191 return FORBIDDEN;
192 } else {
193 print STDERR "SoundSoftware.pm:$$: Project repo is read-write, authentication handler required\n";
194 return OK;
195 }
196 }
197
190 my $status = get_project_status($dbh, $project_id, $r); 198 my $status = get_project_status($dbh, $project_id, $r);
191 199
192 $dbh->disconnect(); 200 $dbh->disconnect();
193 undef $dbh; 201 undef $dbh;
194 202
195 if ($status == 0) { # nonexistent 203 if ($status == 0) { # nonexistent
196 print STDERR "SoundSoftware.pm: Project does not exist, refusing access\n"; 204 print STDERR "SoundSoftware.pm:$$: Project does not exist, refusing access\n";
197 return FORBIDDEN; 205 return FORBIDDEN;
198 } elsif ($status == 1) { # public 206 } elsif ($status == 1) { # public
199 print STDERR "SoundSoftware.pm: Project is public, no restriction here\n"; 207 print STDERR "SoundSoftware.pm:$$: Project is public, no restriction here\n";
200 $r->set_handlers(PerlAuthenHandler => [\&OK]) 208 $r->set_handlers(PerlAuthenHandler => [\&OK])
201 } else { # private 209 } else { # private
202 print STDERR "SoundSoftware.pm: Project is private, authentication handler required\n"; 210 print STDERR "SoundSoftware.pm:$$: Project is private, authentication handler required\n";
203 } 211 }
204 212
205 return OK 213 return OK
206 } 214 }
207 215
208 sub authen_handler { 216 sub authen_handler {
209 my $r = shift; 217 my $r = shift;
210 218
211 print STDERR "SoundSoftware.pm: In authentication handler at " . scalar localtime() . "\n"; 219 print STDERR "SoundSoftware.pm:$$: In authentication handler at " . scalar localtime() . "\n";
212 220
213 my $dbh = connect_database($r); 221 my $dbh = connect_database($r);
214 unless ($dbh) { 222 unless ($dbh) {
215 print STDERR "SoundSoftware.pm: Database connection failed!: " . $DBI::errstr . "\n"; 223 print STDERR "SoundSoftware.pm:$$: Database connection failed!: " . $DBI::errstr . "\n";
216 return AUTH_REQUIRED; 224 return AUTH_REQUIRED;
217 } 225 }
218 226
219 my $project_id = get_project_identifier($dbh, $r); 227 my $project_id = get_project_identifier($dbh, $r);
220 my $realm = get_realm($dbh, $project_id, $r); 228 my $realm = get_realm($dbh, $project_id, $r);
225 $dbh->disconnect(); 233 $dbh->disconnect();
226 undef $dbh; 234 undef $dbh;
227 return $res; 235 return $res;
228 } 236 }
229 237
230 print STDERR "SoundSoftware.pm: User is " . $r->user . ", got password\n"; 238 print STDERR "SoundSoftware.pm:$$: User is " . $r->user . ", got password\n";
231 239
232 my $permitted = is_permitted($dbh, $project_id, $r->user, $redmine_pass, $r); 240 my $permitted = is_permitted($dbh, $project_id, $r->user, $redmine_pass, $r);
233 241
234 $dbh->disconnect(); 242 $dbh->disconnect();
235 undef $dbh; 243 undef $dbh;
236 244
237 if ($permitted) { 245 if ($permitted) {
238 return OK; 246 return OK;
239 } else { 247 } else {
240 print STDERR "SoundSoftware.pm: Not permitted\n"; 248 print STDERR "SoundSoftware.pm:$$: Not permitted\n";
241 $r->note_auth_failure(); 249 $r->note_auth_failure();
242 return AUTH_REQUIRED; 250 return AUTH_REQUIRED;
243 } 251 }
244 } 252 }
245 253
269 undef $sth; 277 undef $sth;
270 278
271 $ret; 279 $ret;
272 } 280 }
273 281
282 sub project_repo_is_readonly {
283 my $dbh = shift;
284 my $project_id = shift;
285 my $r = shift;
286
287 if (!defined $project_id or $project_id eq '') {
288 return 0; # nonexistent
289 }
290
291 my $sth = $dbh->prepare(
292 "SELECT repositories.is_external FROM repositories, projects WHERE projects.identifier = ? AND repositories.project_id = projects.id;"
293 );
294
295 $sth->execute($project_id);
296 my $ret = 0; # nonexistent
297 if (my @row = $sth->fetchrow_array) {
298 if (defined($row[0]) && ($row[0] eq "1" || $row[0] eq "t")) {
299 $ret = 1; # read-only (i.e. external)
300 } else {
301 $ret = 0; # read-write
302 }
303 }
304 $sth->finish();
305 undef $sth;
306
307 $ret;
308 }
309
274 sub is_permitted { 310 sub is_permitted {
275 my $dbh = shift; 311 my $dbh = shift;
276 my $project_id = shift; 312 my $project_id = shift;
277 my $redmine_user = shift; 313 my $redmine_user = shift;
278 my $redmine_pass = shift; 314 my $redmine_pass = shift;
286 my $query = $cfg->{SoundSoftwareQuery}; 322 my $query = $cfg->{SoundSoftwareQuery};
287 my $sth = $dbh->prepare($query); 323 my $sth = $dbh->prepare($query);
288 $sth->execute($redmine_user, $project_id); 324 $sth->execute($redmine_user, $project_id);
289 325
290 my $ret; 326 my $ret;
291 while (my ($hashed_password, $auth_source_id, $permissions) = $sth->fetchrow_array) { 327 while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) {
292 328
293 # Test permissions for this user before we verify credentials 329 # Test permissions for this user before we verify credentials
294 # -- if the user is not permitted this action anyway, there's 330 # -- if the user is not permitted this action anyway, there's
295 # not much point in e.g. contacting the LDAP 331 # not much point in e.g. contacting the LDAP
296 332
303 # credentials checked out -- test those now 339 # credentials checked out -- test those now
304 340
305 print STDERR "SoundSoftware.pm: User $redmine_user has required role, checking credentials\n"; 341 print STDERR "SoundSoftware.pm: User $redmine_user has required role, checking credentials\n";
306 342
307 unless ($auth_source_id) { 343 unless ($auth_source_id) {
308 if ($hashed_password eq $pass_digest) { 344 my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
345 if ($hashed_password eq $salted_password) {
309 print STDERR "SoundSoftware.pm: User $redmine_user authenticated via password\n"; 346 print STDERR "SoundSoftware.pm: User $redmine_user authenticated via password\n";
310 $ret = 1; 347 $ret = 1;
311 last; 348 last;
312 } 349 }
313 } else { 350 } else {
323 binddn => $rowldap[3] ? $rowldap[3] : "", 360 binddn => $rowldap[3] ? $rowldap[3] : "",
324 bindpw => $rowldap[4] ? $rowldap[4] : "", 361 bindpw => $rowldap[4] ? $rowldap[4] : "",
325 filter => "(".$rowldap[6]."=%s)" 362 filter => "(".$rowldap[6]."=%s)"
326 ); 363 );
327 if ($ldap->authenticate($redmine_user, $redmine_pass)) { 364 if ($ldap->authenticate($redmine_user, $redmine_pass)) {
328 print STDERR "SoundSoftware.pm: User $redmine_user authenticated via LDAP\n"; 365 print STDERR "SoundSoftware.pm:$$: User $redmine_user authenticated via LDAP\n";
329 $ret = 1; 366 $ret = 1;
330 } 367 }
331 } 368 }
332 $sthldap->finish(); 369 $sthldap->finish();
333 undef $sthldap; 370 undef $sthldap;
334 } 371 }
335 } else { 372 } else {
336 print STDERR "SoundSoftware.pm: User $redmine_user lacks required role for this project\n"; 373 print STDERR "SoundSoftware.pm:$$: User $redmine_user lacks required role for this project\n";
337 } 374 }
338 } 375 }
339 376
340 $sth->finish(); 377 $sth->finish();
341 undef $sth; 378 undef $sth;
382 $identifier = $row[0]; 419 $identifier = $row[0];
383 } 420 }
384 $sth->finish(); 421 $sth->finish();
385 undef $sth; 422 undef $sth;
386 423
387 print STDERR "SoundSoftware.pm: Repository '$repo' belongs to project '$identifier'\n"; 424 print STDERR "SoundSoftware.pm:$$: Repository '$repo' belongs to project '$identifier'\n";
388 425
389 $identifier; 426 $identifier;
390 } 427 }
391 428
392 sub get_realm { 429 sub get_realm {