Bugzilla – Attachment 54766 Details for
Bug 14868
REST API: Swagger2-driven permission checking
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14868: Give users possibility to request their own object
Bug-14868-Give-users-possibility-to-request-their-.patch (text/plain), 7.82 KB, created by
Lari Taskula
on 2016-08-23 11:51:32 UTC
(
hide
)
Description:
Bug 14868: Give users possibility to request their own object
Filename:
MIME Type:
Creator:
Lari Taskula
Created:
2016-08-23 11:51:32 UTC
Size:
7.82 KB
patch
obsolete
>From 846eab0200417806ff8c2b6627ef5f9d81168de1 Mon Sep 17 00:00:00 2001 >From: Lari Taskula <larit@student.uef.fi> >Date: Fri, 17 Jun 2016 11:43:52 +0300 >Subject: [PATCH] Bug 14868: Give users possibility to request their own object > >Allow access to user's own objects even if they do not have required permissions. >This will be very useful in many cases where an user wants to request their own >object, for example renewing their checkouts or placing a hold for themselves. > >First, this patch renames "x-koha-permission" to "x-koha-authorization" in order >to describe the new functionality better. > >Second, we can now add two extra parameters under "x-koha-authorization": >- "allow-owner"; Allows the owner of object to access it (without permission) >- "allow-guarantor"; Allows guarantor of the owner of object to access it > (without permission) > >Third, since permission checking is outside of actual controller, we need a way >to find out ownership from different types of parameters, e.g. checkout_id from >/checkouts/{checkout_id}, borrowernumber from /patrons/{borrowernumber} etc. >A solution is to match the parameter with a subroutine that is designed to verify >the ownership for that object. See the new subroutines in Koha::REST::V1. > >To use this functionality you will simply define it in Swagger: >"/patrons/{borrowernumber}": { > "get": { > ..., > "x-koha-authorization": { > "allow-owner": true, > "permissions": { > "borrowers": "1" > } > } > } >} > >If a parameter that is not yet defined in Koha::REST::V1::check_object_ownership, >you also need to define it and implement a subroutine that determines ownership. > >Tests are provided in a following patch that adds this functionality for current >API operations. >--- > Koha/REST/V1.pm | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 165 insertions(+), 18 deletions(-) > >diff --git a/Koha/REST/V1.pm b/Koha/REST/V1.pm >index 8b02a52..4cb6236 100644 >--- a/Koha/REST/V1.pm >+++ b/Koha/REST/V1.pm >@@ -20,6 +20,10 @@ use Mojo::Base 'Mojolicious'; > > use C4::Auth qw( check_cookie_auth get_session haspermission ); > use C4::Context; >+use Koha::Account::Lines; >+use Koha::Issues; >+use Koha::Holds; >+use Koha::OldIssues; > use Koha::Patrons; > > sub startup { >@@ -68,30 +72,173 @@ sub authenticate_api_request { > { error => "Authentication failure." }, > {}, > 401 >- ) if $cookie and $action_spec->{'x-koha-permission'}; >+ ) if $cookie and $action_spec->{'x-koha-authorization'}; > } > >- if ($action_spec->{'x-koha-permission'}) { >- return $c->render_swagger( >- { error => "Authentication required." }, >- {}, >- 401 >- ) unless $user; >+ return $next->($c) unless $action_spec->{'x-koha-authorization'}; >+ unless ($user) { >+ return $c->render_swagger({ error => "Authentication required." },{},401); >+ } > >- if (C4::Auth::haspermission($user->userid, $action_spec->{'x-koha-permission'})) { >- return $next->($c); >- } >- else { >- return $c->render_swagger( >- { error => "Authorization failure. Missing required permission(s)." }, >- {}, >- 403 >- ); >+ my $authorization = $action_spec->{'x-koha-authorization'}; >+ return $next->($c) if allow_owner($c, $authorization, $user); >+ return $next->($c) if allow_guarantor($c, $authorization, $user); >+ >+ my $permissions = $authorization->{'permissions'}; >+ return $next->($c) if C4::Auth::haspermission($user->userid, $permissions); >+ return $c->render_swagger( >+ { error => "Authorization failure. Missing required permission(s)." }, >+ {}, >+ 403 >+ ); >+} >+ >+=head3 allow_owner >+ >+Allows access to object for its owner. >+ >+There are endpoints that should allow access for the object owner even if they >+do not have the required permission, e.g. access an own reserve. This can be >+achieved by defining the operation as follows: >+ >+"/holds/{reserve_id}": { >+ "get": { >+ ..., >+ "x-koha-authorization": { >+ "allow-owner": true, >+ "permissions": { >+ "borrowers": "1" >+ } > } > } >- else { >- return $next->($c); >+} >+ >+=cut >+ >+sub allow_owner { >+ my ($c, $authorization, $user) = @_; >+ >+ return unless $authorization->{'allow-owner'}; >+ >+ return check_object_ownership($c, $user) if $user and $c; >+} >+ >+=head3 allow_guarantor >+ >+Same as "allow_owner", but checks if the object is owned by one of C<$user>'s >+guarantees. >+ >+=cut >+ >+sub allow_guarantor { >+ my ($c, $authorization, $user) = @_; >+ >+ if (!$c || !$user || !$authorization || !$authorization->{'allow-guarantor'}){ >+ return; >+ } >+ >+ my $guarantees = $user->guarantees->as_list; >+ foreach my $guarantee (@{$guarantees}) { >+ return 1 if check_object_ownership($c, $guarantee); > } > } > >+=head3 check_object_ownership >+ >+Determines ownership of an object from request parameters. >+ >+As introducing an endpoint that allows access for object's owner; if the >+parameter that will be used to determine ownership is not already inside >+$parameters, add a new subroutine that checks the ownership and extend >+$parameters to contain a key with parameter_name and a value of a subref to >+the subroutine that you created. >+ >+=cut >+ >+sub check_object_ownership { >+ my ($c, $user) = @_; >+ >+ return if not $c or not $user; >+ >+ my $parameters = { >+ accountlines_id => \&_object_ownership_by_accountlines_id, >+ borrowernumber => \&_object_ownership_by_borrowernumber, >+ checkout_id => \&_object_ownership_by_checkout_id, >+ reserve_id => \&_object_ownership_by_reserve_id, >+ }; >+ >+ foreach my $param (keys $parameters) { >+ my $check_ownership = $parameters->{$param}; >+ if ($c->stash($param)) { >+ return &$check_ownership($c, $user, $c->stash($param)); >+ } >+ elsif ($c->param($param)) { >+ return &$check_ownership($c, $user, $c->param($param)); >+ } >+ elsif ($c->req->json && $c->req->json->{$param}) { >+ return 1 if &$check_ownership($c, $user, $c->req->json->{$param}); >+ } >+ } >+} >+ >+=head3 _object_ownership_by_accountlines_id >+ >+Finds a Koha::Account::Line-object by C<$accountlines_id> and checks if it >+belongs to C<$user>. >+ >+=cut >+ >+sub _object_ownership_by_accountlines_id { >+ my ($c, $user, $accountlines_id) = @_; >+ >+ my $accountline = Koha::Account::Lines->find($accountlines_id); >+ return $accountline && $user->borrowernumber == $accountline->borrowernumber; >+} >+ >+=head3 _object_ownership_by_borrowernumber >+ >+Compares C<$borrowernumber> to currently logged in C<$user>. >+ >+=cut >+ >+sub _object_ownership_by_borrowernumber { >+ my ($c, $user, $borrowernumber) = @_; >+ >+ return $user->borrowernumber == $borrowernumber; >+} >+ >+=head3 _object_ownership_by_checkout_id >+ >+First, attempts to find a Koha::Issue-object by C<$issue_id>. If we find one, >+compare its borrowernumber to currently logged in C<$user>. However, if an issue >+is not found, attempt to find a Koha::OldIssue-object instead and compare its >+borrowernumber to currently logged in C<$user>. >+ >+=cut >+ >+sub _object_ownership_by_checkout_id { >+ my ($c, $user, $issue_id) = @_; >+ >+ my $issue = Koha::Issues->find($issue_id); >+ $issue = Koha::OldIssues->find($issue_id) unless $issue; >+ return $issue && $issue->borrowernumber >+ && $user->borrowernumber == $issue->borrowernumber; >+} >+ >+=head3 _object_ownership_by_reserve_id >+ >+Finds a Koha::Hold-object by C<$reserve_id> and checks if it >+belongs to C<$user>. >+ >+TODO: Also compare against old_reserves >+ >+=cut >+ >+sub _object_ownership_by_reserve_id { >+ my ($c, $user, $reserve_id) = @_; >+ >+ my $reserve = Koha::Holds->find($reserve_id); >+ return $reserve && $user->borrowernumber == $reserve->borrowernumber; >+} >+ > 1; >-- >1.9.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 14868
:
42761
|
52577
|
52578
|
52579
|
52592
|
52593
|
52594
|
52602
|
52603
|
52604
|
52963
|
52964
|
52965
|
52966
|
52967
|
52981
|
52992
|
52993
|
52994
|
52995
|
52996
|
54457
|
54458
|
54459
|
54631
|
54632
|
54633
|
54765
|
54766
|
54767
|
54770
|
54771
|
54894
|
54895
|
54896
|
54897
|
55084
|
55085
|
55086
|
55087
|
55088
|
55089
|
55099
|
55100
|
55101
|
55102
|
55103
|
55104
|
55105