View | Details | Raw Unified | Return to bug 28907
Collapse All | Expand All

(-)a/Koha/REST/V1/Auth.pm (-156 / +1 lines)
Lines 319-327 sub authenticate_api_request { Link Here
319
319
320
    my $permissions = $authorization->{'permissions'};
320
    my $permissions = $authorization->{'permissions'};
321
    # Check if the user is authorized
321
    # Check if the user is authorized
322
    if ( ( defined($permissions) and haspermission($user->userid, $permissions) )
322
    if ( ( defined($permissions) and haspermission($user->userid, $permissions) ) ) {
323
        or allow_owner($c, $authorization, $user)
324
        or allow_guarantor($c, $authorization, $user) ) {
325
323
326
        validate_query_parameters( $c, $spec );
324
        validate_query_parameters( $c, $spec );
327
325
Lines 360-517 sub validate_query_parameters { Link Here
360
    ) if @errors;
358
    ) if @errors;
361
}
359
}
362
360
363
=head3 allow_owner
364
365
Allows access to object for its owner.
366
367
There are endpoints that should allow access for the object owner even if they
368
do not have the required permission, e.g. access an own reserve. This can be
369
achieved by defining the operation as follows:
370
371
"/holds/{reserve_id}": {
372
    "get": {
373
        ...,
374
        "x-koha-authorization": {
375
            "allow-owner": true,
376
            "permissions": {
377
                "borrowers": "1"
378
            }
379
        }
380
    }
381
}
382
383
=cut
384
385
sub allow_owner {
386
    my ($c, $authorization, $user) = @_;
387
388
    return unless $authorization->{'allow-owner'};
389
390
    return check_object_ownership($c, $user) if $user and $c;
391
}
392
393
=head3 allow_guarantor
394
395
Same as "allow_owner", but checks if the object is owned by one of C<$user>'s
396
guarantees.
397
398
=cut
399
400
sub allow_guarantor {
401
    my ($c, $authorization, $user) = @_;
402
403
    if (!$c || !$user || !$authorization || !$authorization->{'allow-guarantor'}){
404
        return;
405
    }
406
407
    my $guarantees = $user->guarantee_relationships->guarantees->as_list;
408
    foreach my $guarantee (@{$guarantees}) {
409
        return 1 if check_object_ownership($c, $guarantee);
410
    }
411
}
412
413
=head3 check_object_ownership
414
415
Determines ownership of an object from request parameters.
416
417
As introducing an endpoint that allows access for object's owner; if the
418
parameter that will be used to determine ownership is not already inside
419
$parameters, add a new subroutine that checks the ownership and extend
420
$parameters to contain a key with parameter_name and a value of a subref to
421
the subroutine that you created.
422
423
=cut
424
425
sub check_object_ownership {
426
    my ($c, $user) = @_;
427
428
    return if not $c or not $user;
429
430
    my $parameters = {
431
        accountlines_id => \&_object_ownership_by_accountlines_id,
432
        borrowernumber  => \&_object_ownership_by_patron_id,
433
        patron_id       => \&_object_ownership_by_patron_id,
434
        checkout_id     => \&_object_ownership_by_checkout_id,
435
        reserve_id      => \&_object_ownership_by_reserve_id,
436
    };
437
438
    foreach my $param ( keys %{ $parameters } ) {
439
        my $check_ownership = $parameters->{$param};
440
        if ($c->stash($param)) {
441
            return &$check_ownership($c, $user, $c->stash($param));
442
        }
443
        elsif ($c->param($param)) {
444
            return &$check_ownership($c, $user, $c->param($param));
445
        }
446
        elsif ($c->match->stack->[-1]->{$param}) {
447
            return &$check_ownership($c, $user, $c->match->stack->[-1]->{$param});
448
        }
449
        elsif ($c->req->json && $c->req->json->{$param}) {
450
            return 1 if &$check_ownership($c, $user, $c->req->json->{$param});
451
        }
452
    }
453
}
454
455
=head3 _object_ownership_by_accountlines_id
456
457
Finds a Koha::Account::Line-object by C<$accountlines_id> and checks if it
458
belongs to C<$user>.
459
460
=cut
461
462
sub _object_ownership_by_accountlines_id {
463
    my ($c, $user, $accountlines_id) = @_;
464
465
    my $accountline = Koha::Account::Lines->find($accountlines_id);
466
    return $accountline && $user->borrowernumber == $accountline->borrowernumber;
467
}
468
469
=head3 _object_ownership_by_borrowernumber
470
471
Compares C<$borrowernumber> to currently logged in C<$user>.
472
473
=cut
474
475
sub _object_ownership_by_patron_id {
476
    my ($c, $user, $patron_id) = @_;
477
478
    return $user->borrowernumber == $patron_id;
479
}
480
481
=head3 _object_ownership_by_checkout_id
482
483
First, attempts to find a Koha::Checkout-object by C<$issue_id>. If we find one,
484
compare its borrowernumber to currently logged in C<$user>. However, if an issue
485
is not found, attempt to find a Koha::Old::Checkout-object instead and compare its
486
borrowernumber to currently logged in C<$user>.
487
488
=cut
489
490
sub _object_ownership_by_checkout_id {
491
    my ($c, $user, $issue_id) = @_;
492
493
    my $issue = Koha::Checkouts->find($issue_id);
494
    $issue = Koha::Old::Checkouts->find($issue_id) unless $issue;
495
    return $issue && $issue->borrowernumber
496
            && $user->borrowernumber == $issue->borrowernumber;
497
}
498
499
=head3 _object_ownership_by_reserve_id
500
501
Finds a Koha::Hold-object by C<$reserve_id> and checks if it
502
belongs to C<$user>.
503
504
TODO: Also compare against old_reserves
505
506
=cut
507
508
sub _object_ownership_by_reserve_id {
509
    my ($c, $user, $reserve_id) = @_;
510
511
    my $reserve = Koha::Holds->find($reserve_id);
512
    return $reserve && $user->borrowernumber == $reserve->borrowernumber;
513
}
514
515
=head3 _basic_auth
361
=head3 _basic_auth
516
362
517
Internal method that performs Basic authentication.
363
Internal method that performs Basic authentication.
518
- 

Return to bug 28907