Bug 30962: REST API: Add endpoint /auth/password/validation
authorDavid Cook <dcook@prosentient.com.au>
Fri, 17 Jun 2022 04:43:44 +0000 (04:43 +0000)
committerTomas Cohen Arazi <tomascohen@theke.io>
Fri, 3 Feb 2023 13:30:11 +0000 (10:30 -0300)
This patch adds an endpoint for /auth/password/validation

This allows a third-party, using an authenticated and authorized Koha
API user, to check if the username and password given by a user is
correct in Koha.

For example, a Keycloak extension can be created using its
User Storage SPI to use Koha as the user database for Keycloak. This
API allows us to authenticate the user as a particular Koha user - without
creating a Koha user session for them.

Test plan:
0. Apply patch and koha-plack --restart kohadev
1. Go to http://localhost:8081/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=RESTBasicAuth
2. Enable "RESTBasicAuth"
3. Run the following commands while substituting correct values for <koha_user> and <koha_password>
3. curl -XPOST -H "Content-Type: application/json" -u <koha_user>:<koha_password> http://localhost:8081/api/v1/auth/password/validation -d '{ "username": "<koha_username">, "password": "<koha_password>" }' -v
4. Note "204 No Content" response
5. curl -XPOST -H "Content-Type: application/json" -u <koha_user>:<koha_password> http://localhost:8081/api/v1/auth/password/validation -d '{ "username": "<koha_username">, "password": "this is definitely not the password" }' -v
6. Note "400 Bad Request" response and error message {"error":"Validation failed"}

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Koha/REST/V1/Auth/Password.pm [new file with mode: 0644]
api/v1/swagger/paths/auth.yaml
api/v1/swagger/swagger.yaml

diff --git a/Koha/REST/V1/Auth/Password.pm b/Koha/REST/V1/Auth/Password.pm
new file mode 100644 (file)
index 0000000..8cc9304
--- /dev/null
@@ -0,0 +1,76 @@
+package Koha::REST::V1::Auth::Password;
+
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use Mojo::Base 'Mojolicious::Controller';
+
+use C4::Auth qw/checkpw/;
+use Koha::Patrons;
+
+=head1 NAME
+
+Koha::REST::V1::Auth::Password - Controller library for handling
+validation of username and password.
+
+Intended use case is authenticating Koha patrons in external
+applications via Koha's REST API.
+
+=head2 Operations
+
+=head3 validate
+
+Controller method that checks a patron's password
+
+=cut
+
+sub validate {
+    my $c = shift->openapi->valid_input or return;
+    my $body   = $c->validation->param('body');
+    my $username = $body->{username} // '';
+    my $patron = Koha::Patrons->find({ userid => $username });
+
+    unless ($patron) {
+        return $c->render( status => 400, openapi => { error => "Validation failed" } );
+    }
+
+    my $password   = $body->{password}   // "";
+
+    return try {
+        my ($status, $cardnumber, $userid) = C4::Auth::checkpw($patron->userid, $password );
+        unless ( $status ) {
+            return $c->render(
+                status  => 400,
+                openapi => { error => "Validation failed" }
+            );
+        }
+
+        return $c->render( status => 204, openapi => '' );
+    }
+    catch {
+        if ( blessed $_ and $_->isa('Koha::Exceptions::Password') ) {
+            return $c->render(
+                status  => 400,
+                openapi => { error => "$_" }
+            );
+        }
+
+        $c->unhandled_exception($_);
+    };
+}
+
+1;
index d7be7e8..7130860 100644 (file)
           $ref: ../swagger.yaml#/definitions/error
     x-koha-authorization:
       permissions:
-        parameters: manage_identity_providers
\ No newline at end of file
+        parameters: manage_identity_providers
+"/auth/password/validation":
+  post:
+    x-mojo-to: Auth::Password#validate
+    operationId: validateUserAndPassword
+    tags:
+      - patrons
+    summary: Check validity of username and password
+    parameters:
+      - name: body
+        in: body
+        description: A JSON object containing username and password information
+        schema:
+          type: object
+          properties:
+            username:
+              description: Username
+              type: string
+            password:
+              description: Password (plain text)
+              type: string
+          required:
+            - username
+            - password
+          additionalProperties: false
+    produces:
+      - application/json
+    responses:
+      "204":
+        description: Validation successful
+      "400":
+        description: Bad request
+        schema:
+          $ref: ../swagger.yaml#/definitions/error
+      "401":
+        description: Authentication required
+        schema:
+          $ref: ../swagger.yaml#/definitions/error
+      "403":
+        description: Access forbidden
+        schema:
+          $ref: ../swagger.yaml#/definitions/error
+      "500":
+        description: |
+          Internal server error. Possible `error_code` attribute values:
+
+          * `internal_server_error`
+        schema:
+          $ref: ../swagger.yaml#/definitions/error
+      "503":
+        description: Under maintenance
+        schema:
+          $ref: ../swagger.yaml#/definitions/error
+    x-koha-authorization:
+      permissions:
+        borrowers: "1"
index 696a73b..479c4d7 100644 (file)
@@ -125,6 +125,8 @@ paths:
     $ref: "./paths/article_requests.yaml#/~1article_requests~1{article_request_id}"
   /auth/otp/token_delivery:
     $ref: paths/auth.yaml#/~1auth~1otp~1token_delivery
+  "/auth/password/validation":
+    $ref: "./paths/auth.yaml#/~1auth~1password~1validation"
   /auth/two-factor/registration:
     $ref: paths/auth.yaml#/~1auth~1two-factor~1registration
   /auth/two-factor/registration/verification: