Bug 14868: Swagger2-driven Permission checking
authorOlli-Antti Kivilahti <olli-antti.kivilahti@jns.fi>
Mon, 14 Sep 2015 12:20:20 +0000 (15:20 +0300)
committerKyle M Hall <kyle@bywatersolutions.com>
Fri, 2 Sep 2016 12:20:35 +0000 (12:20 +0000)
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 <benjamin.rokseth@kul.oslo.kommune.no>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Koha/REST/V1.pm
api/v1/swagger/swagger.json

index 33ee9cc..8b02a52 100644 (file)
@@ -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;
index 249e71b..75fe161 100644 (file)
@@ -13,6 +13,7 @@
     }
   },
   "basePath": "/api/v1",
+  "x-mojo-around-action": "Koha::REST::V1::authenticate_api_request",
   "paths": {
     "$ref": "paths.json"
   },