From af5774cf6e200d2b468f32ca2a60115e7504a60f Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Tue, 15 Jan 2019 13:23:23 -0300 Subject: [PATCH] Bug 22132: Add Basic authentication to the API This patch implements Basic authentication for the API to aid testers and developers with tools like Postman. To test: - Apply this patches - Run: $ kshell k$ prove t/db_dependent/api/v1/auth_basic.t => SUCCESS: Tests pass! - Open Postman or your favourite tool - In Authorization, choose Basic auth. - Enter the username and password of a known privileged user. - Hit an endpoint with Postman, for example: ] GET http://kohadev-intra.myDNSname.org:8081/api/v1/patrons => SUCCESS: Basic authentication is great! - Sign off :-D --- Koha/REST/V1/Auth.pm | 49 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/Koha/REST/V1/Auth.pm b/Koha/REST/V1/Auth.pm index cf64a25828..1a6da441b3 100644 --- a/Koha/REST/V1/Auth.pm +++ b/Koha/REST/V1/Auth.pm @@ -21,7 +21,7 @@ use Modern::Perl; use Mojo::Base 'Mojolicious::Controller'; -use C4::Auth qw( check_cookie_auth get_session haspermission ); +use C4::Auth qw( check_cookie_auth checkpw_internal get_session haspermission ); use C4::Context; use Koha::ApiKeys; @@ -37,6 +37,7 @@ use Koha::Exceptions; use Koha::Exceptions::Authentication; use Koha::Exceptions::Authorization; +use MIME::Base64; use Module::Load::Conditional; use Scalar::Util qw( blessed ); use Try::Tiny; @@ -78,7 +79,7 @@ sub under { return $c->render(status => 401, json => { error => $_->error }); } elsif ($_->isa('Koha::Exceptions::Authentication')) { - return $c->render(status => 500, json => { error => $_->error }); + return $c->render(status => 401, json => { error => $_->error }); } elsif ($_->isa('Koha::Exceptions::BadParameter')) { return $c->render(status => 400, json => $_->error ); @@ -89,6 +90,9 @@ sub under { required_permissions => $_->required_permissions, }); } + elsif ($_->isa('Koha::Exceptions::Authorization')) { + return $c->render(status => 403, json => $_->error); + } elsif ($_->isa('Koha::Exceptions')) { return $c->render(status => 500, json => { error => $_->error }); } @@ -151,6 +155,21 @@ sub authenticate_api_request { ); } } + elsif ( $authorization_header and $authorization_header =~ /^Basic / ) { + unless ( C4::Context->preference('RESTBasicAuth') ) { + Koha::Exceptions::Authentication::Required->throw( + error => 'Basic authentication disabled' + ); + } + $user = $c->_basic_auth( $authorization_header ); + unless ( $user ) { + # If we have "Authorization: Basic" header and authentication + # failed, do not try other authentication means + Koha::Exceptions::Authentication::Required->throw( + error => 'Authentication failure.' + ); + } + } else { my $cookie = $c->cookie('CGISESSID'); @@ -390,4 +409,30 @@ sub _object_ownership_by_reserve_id { return $reserve && $user->borrowernumber == $reserve->borrowernumber; } +=head3 _basic_auth + +Internal method that performs Basic authentication. + +=cut + +sub _basic_auth { + my ( $c, $authorization_header ) = @_; + + my ( $type, $credentials ) = split / /, $authorization_header; + + unless ($credentials) { + Koha::Exceptions::Authentication::Required->throw( error => 'Authentication failure.' ); + } + + my $decoded_credentials = decode_base64( $credentials ); + my ( $user_id, $password ) = split( /:/, $decoded_credentials, 2 ); + + my $dbh = C4::Context->dbh; + unless ( checkpw_internal($dbh, $user_id, $password ) ) { + Koha::Exceptions::Authorization::Unauthorized->throw( error => 'Invalid password' ); + } + + return Koha::Patrons->find({ userid => $user_id }); +} + 1; -- 2.20.1