From ac1286dacdf92239ee91bf7932356adca7c486d2 Mon Sep 17 00:00:00 2001 From: Olli-Antti Kivilahti Date: Mon, 14 Sep 2015 15:20:20 +0300 Subject: [PATCH] Bug 14868: Swagger2-driven Permission checking Define 'x-koha-permission' for the Swagger2 Operation Object, to automatically authorize against the required permissions. This way we immediately tell the API consumer in the Swagger2-definition, which permissions are needed to access defined resources. Also we don't need to maintain permissions in multiple locations and we can build a smart testing framework to help a lot in creating tests for the new REST API. Signed-off-by: Benjamin Rokseth Signed-off-by: Tomas Cohen Arazi Signed-off-by: Kyle M Hall --- Koha/REST/V1.pm | 79 ++++++++++++++++++++++++++----------- api/v1/swagger/swagger.json | 1 + 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/Koha/REST/V1.pm b/Koha/REST/V1.pm index 33ee9ccc24..8b02a5260f 100644 --- a/Koha/REST/V1.pm +++ b/Koha/REST/V1.pm @@ -18,33 +18,13 @@ package Koha::REST::V1; use Modern::Perl; use Mojo::Base 'Mojolicious'; -use C4::Auth qw( check_cookie_auth get_session ); +use C4::Auth qw( check_cookie_auth get_session haspermission ); use C4::Context; use Koha::Patrons; sub startup { my $self = shift; - my $route = $self->routes->under->to( - cb => sub { - my $c = shift; - # Mojo doesn't use %ENV the way CGI apps do - # Manually pass the remote_address to check_auth_cookie - my $remote_addr = $c->tx->remote_address; - my ($status, $sessionID) = check_cookie_auth( - $c->cookie('CGISESSID'), undef, - { remote_addr => $remote_addr }); - - if ($status eq "ok") { - my $session = get_session($sessionID); - my $user = Koha::Patrons->find($session->param('number')); - $c->stash('koha.user' => $user); - } - - return 1; - } - ); - # Force charset=utf8 in Content-Type header for JSON responses $self->types->type(json => 'application/json; charset=utf8'); @@ -54,9 +34,64 @@ sub startup { } $self->plugin(Swagger2 => { - route => $route, url => $self->home->rel_file("api/v1/swagger/swagger.min.json"), }); } +=head3 authenticate_api_request + +Validates authentication and allows access if authorization is not required or +if authorization is required and user has required permissions to access. + +This subroutine is called before every request to API. + +=cut + +sub authenticate_api_request { + my ($next, $c, $action_spec) = @_; + + my ($session, $user); + my $cookie = $c->cookie('CGISESSID'); + # Mojo doesn't use %ENV the way CGI apps do + # Manually pass the remote_address to check_auth_cookie + my $remote_addr = $c->tx->remote_address; + my ($status, $sessionID) = check_cookie_auth( + $cookie, undef, + { remote_addr => $remote_addr }); + if ($status eq "ok") { + $session = get_session($sessionID); + $user = Koha::Patrons->find($session->param('number')); + $c->stash('koha.user' => $user); + } + else { + return $c->render_swagger( + { error => "Authentication failure." }, + {}, + 401 + ) if $cookie and $action_spec->{'x-koha-permission'}; + } + + if ($action_spec->{'x-koha-permission'}) { + return $c->render_swagger( + { error => "Authentication required." }, + {}, + 401 + ) unless $user; + + 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 + ); + } + } + else { + return $next->($c); + } +} + 1; diff --git a/api/v1/swagger/swagger.json b/api/v1/swagger/swagger.json index 249e71ba7e..75fe1619bf 100644 --- a/api/v1/swagger/swagger.json +++ b/api/v1/swagger/swagger.json @@ -13,6 +13,7 @@ } }, "basePath": "/api/v1", + "x-mojo-around-action": "Koha::REST::V1::authenticate_api_request", "paths": { "$ref": "paths.json" },