Bug 31378: Add Koha::Auth::Client* modules
[koha.git] / Koha / Auth / Client / OAuth.pm
1 package Koha::Auth::Client::OAuth;
2
3 # Copyright Theke Solutions 2022
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use JSON qw( decode_json );
23 use MIME::Base64 qw{ decode_base64url };
24 use Koha::Patrons;
25 use Mojo::UserAgent;
26 use Mojo::Parameters;
27
28 use base qw( Koha::Auth::Client );
29
30 =head1 NAME
31
32 Koha::Auth::Client::OAuth - Koha OAuth Client
33
34 =head1 API
35
36 =head2 Class methods
37
38 =head3 _get_data_and_patron
39
40     my $mapping = $object->_get_data_and_patron(
41         {   provider => $provider,
42             data     => $data,
43             config   => $config
44         }
45     );
46
47 Maps OAuth raw data to a patron schema, and returns a patron if it can.
48
49 =cut
50
51 sub _get_data_and_patron {
52     my ( $self, $params ) = @_;
53
54     my $provider = $params->{provider};
55     my $data     = $params->{data};
56     my $config   = $params->{config};
57
58     my $patron;
59     my $mapped_data;
60
61     my $mapping = decode_json( $provider->mapping );
62     my $matchpoint = $provider->matchpoint;
63
64     if ( $data->{id_token} ) {
65         my ( $header_part, $claims_part, $footer_part ) = split( /\./, $data->{id_token} );
66
67         my $claim = decode_json( decode_base64url($claims_part) );
68         foreach my $key ( keys %$mapping ) {
69             my $pkey = $mapping->{$key};
70             $mapped_data->{$key} = $claim->{$pkey}
71               if defined $claim->{$pkey};
72         }
73
74         my $value = $mapped_data->{$matchpoint};
75
76         my $matchpoint_rs = Koha::Patrons->search( { $matchpoint => $value } );
77
78         if ( defined $value and $matchpoint_rs->count ) {
79             $patron = $matchpoint_rs->next;
80         }
81
82         return ( $mapped_data, $patron )
83           if $patron;
84     }
85
86     if ( defined $config->{userinfo_url} ) {
87         my $access_token = $data->{access_token};
88         my $ua           = Mojo::UserAgent->new;
89         my $tx           = $ua->get( $config->{userinfo_url} => { Authorization => "Bearer $access_token" } );
90         my $code         = $tx->res->code || 'No response';
91
92         return if $code ne '200';
93         my $claim =
94             $tx->res->headers->content_type =~ m!^(application/json|text/javascript)(;\s*charset=\S+)?$!
95           ? $tx->res->json
96           : Mojo::Parameters->new( $tx->res->body )->to_hash;
97
98         foreach my $key ( keys %$mapping ) {
99             my $pkey  = $mapping->{$key};
100             my $value = $self->_tranverse_hash( { base => $claim, keys => $pkey } );
101             $mapped_data->{$key} = $value
102               if defined $value;
103         }
104
105         my $value = $mapped_data->{$matchpoint};
106
107         my $matchpoint_rs = Koha::Patrons->search( { $matchpoint => $value } );
108
109         if ( defined $value and $matchpoint_rs->count ) {
110             $patron = $matchpoint_rs->next;
111         }
112
113         return ( $mapped_data, $patron )
114           if $patron;
115     }
116 }
117
118 1;