Bugzilla – Attachment 141367 Details for
Bug 31378
Add a generic OAuth2/OIDC client implementation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 31378: Add Koha::Auth::Client* modules
Bug-31378-Add-KohaAuthClient-modules.patch (text/plain), 9.57 KB, created by
Tomás Cohen Arazi (tcohen)
on 2022-10-05 12:17:58 UTC
(
hide
)
Description:
Bug 31378: Add Koha::Auth::Client* modules
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2022-10-05 12:17:58 UTC
Size:
9.57 KB
patch
obsolete
>From 6afd6a689d97ddf26a71c59e5d082badc40b7f50 Mon Sep 17 00:00:00 2001 >From: Agustin Moyano <agustinmoyano@theke.io> >Date: Thu, 18 Aug 2022 16:29:19 -0300 >Subject: [PATCH] Bug 31378: Add Koha::Auth::Client* modules > >--- > Koha/Auth/Client.pm | 198 ++++++++++++++++++++++++++++++++++++++ > Koha/Auth/Client/OAuth.pm | 118 +++++++++++++++++++++++ > 2 files changed, 316 insertions(+) > create mode 100644 Koha/Auth/Client.pm > create mode 100644 Koha/Auth/Client/OAuth.pm > >diff --git a/Koha/Auth/Client.pm b/Koha/Auth/Client.pm >new file mode 100644 >index 0000000000..7fd6627197 >--- /dev/null >+++ b/Koha/Auth/Client.pm >@@ -0,0 +1,198 @@ >+package Koha::Auth::Client; >+ >+# Copyright Theke Solutions 2022 >+# >+# 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 Koha::Exceptions::Auth; >+use Koha::Auth::Providers; >+ >+=head1 NAME >+ >+Koha::Auth::Client - Base Koha auth client >+ >+=head1 API >+ >+=head2 Methods >+ >+=head3 new >+ >+ my $auth_client = Koha::Auth::Client->new(); >+ >+=cut >+ >+sub new { >+ my ($class) = @_; >+ my $self = {}; >+ >+ bless( $self, $class ); >+} >+ >+=head3 get_user >+ >+ $auth_client->get_user($provider, $data) >+ >+Get user data according to provider's mapping configuration >+ >+=cut >+ >+sub get_user { >+ my ( $self, $params ) = @_; >+ my $provider_code = $params->{provider}; >+ my $data = $params->{data}; >+ my $interface = $params->{interface}; >+ my $config = $params->{config}; >+ >+ my $provider = Koha::Auth::Providers->search({ code => $provider_code })->next; >+ >+ my ( $mapped_data, $patron ) = $self->_get_data_and_patron({ provider => $provider, data => $data, config => $config }); >+ >+ if ($mapped_data) { >+ my $domain = $self->has_valid_domain_config({ provider => $provider, email => $mapped_data->{email}, interface => $interface}); >+ >+ $mapped_data->{categorycode} = $domain->default_category_id; >+ $mapped_data->{branchcode} = $domain->default_library_id; >+ >+ return ( $patron, $mapped_data, $domain ); >+ } >+} >+ >+=head3 get_valid_domain_config >+ >+ my $domain = Koha::Auth::Client->get_valid_domain_config( >+ { provider => $provider, >+ email => $user_email, >+ interface => $interface >+ } >+ ); >+ >+Gets the best suited valid domain configuration for the given provider. >+ >+=cut >+ >+sub get_valid_domain_config { >+ # FIXME: Should be a hashref param >+ my ( $self, $params ) = @_; >+ my $provider = $params->{provider}; >+ my $user_email = $params->{email}; >+ my $interface = $params->{interface}; >+ >+ my $domains = $provider->domains; >+ my $pattern = '@'; >+ my $allow = "allow_$interface"; >+ my @subdomain_matches; >+ my $default_match; >+ >+ while ( my $domain = $domains->next ) { >+ next unless $domain->$allow; >+ >+ my $domain_text = $domain->domain; >+ unless ( defined $domain_text && $domain_text ne '') { >+ $default_match = $domain; >+ next; >+ } >+ my ( $asterisk, $domain_name ) = ( $domain_text =~ /^(\*)?(.+)$/ ); >+ if ( $asterisk eq '*' ) { >+ $pattern .= '.*'; >+ } >+ $domain_name =~ s/\./\\\./g; >+ $pattern .= $domain_name . '$'; >+ if ( $user_email =~ /$pattern/ ) { >+ if ( $asterisk eq '*' ) { >+ push @subdomain_matches, { domain => $domain, match_length => length $domain_name }; >+ } else { >+ >+ # Perfect match.. return this one. >+ return $domain; >+ } >+ } >+ } >+ >+ if ( @subdomain_matches ) { >+ @subdomain_matches = sort { $b->{match_length} <=> $a->{match_length} } @subdomain_matches >+ unless scalar @subdomain_matches == 1; >+ return $subdomain_matches[0]->{domain}; >+ } >+ >+ return $default_match || 0; >+} >+ >+=head3 has_valid_domain_config >+ >+ my $has_valid_domain = Koha::Auth::Client->has_valid_domain_config( >+ { provider => $provider, >+ email => $user_email, >+ interface => $interface >+ } >+ ); >+ >+Checks if provider has a valid domain for user email. If has, returns that domain. >+ >+=cut >+ >+sub has_valid_domain_config { >+ # FIXME: Should be a hashref param >+ my ( $self, $params ) = @_; >+ my $domain = $self->get_valid_domain_config( $params ); >+ >+ Koha::Exceptions::Auth::NoValidDomain->throw( code => 401 ) >+ unless $domain; >+ >+ return $domain; >+} >+ >+=head3 _get_data_and_patron >+ >+ my $mapping = $auth_client->_get_data_and_patron( >+ { provider => $provider, >+ data => $data, >+ config => $config >+ } >+ ); >+ >+Generic method that maps raw data to patron schema, and returns a patron if it can. >+ >+Note: this only returns an empty I<hashref>. Each class should have its >+own mapping returned. >+ >+=cut >+ >+sub _get_data_and_patron { >+ return {}; >+} >+ >+=head3 _tranverse_hash >+ >+ my $value = $auth_client->_tranverse_hash( { base => $base_hash, keys => $key_string } ); >+ >+Get deep nested value in a hash. >+ >+=cut >+ >+sub _tranverse_hash { >+ my ($self, $params) = @_; >+ my $base = $params->{base}; >+ my $keys = $params->{keys}; >+ my ($key, $rest) = ($keys =~ /^([^.]+)(?:\.(.*))?/); >+ return unless defined $key; >+ my $value = ref $base eq 'HASH' ? $base->{$key} : $base->[$key]; >+ return $value unless $rest; >+ return $self->_tranverse_hash({ base => $value, keys => $rest }); >+} >+ >+1; >diff --git a/Koha/Auth/Client/OAuth.pm b/Koha/Auth/Client/OAuth.pm >new file mode 100644 >index 0000000000..728fa4e3ec >--- /dev/null >+++ b/Koha/Auth/Client/OAuth.pm >@@ -0,0 +1,118 @@ >+package Koha::Auth::Client::OAuth; >+ >+# Copyright Theke Solutions 2022 >+# >+# 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 JSON qw( decode_json ); >+use MIME::Base64 qw{ decode_base64url }; >+use Koha::Patrons; >+use Mojo::UserAgent; >+use Mojo::Parameters; >+ >+use base qw( Koha::Auth::Client ); >+ >+=head1 NAME >+ >+Koha::Auth::Client::OAuth - Koha OAuth Client >+ >+=head1 API >+ >+=head2 Class methods >+ >+=head3 _get_data_and_patron >+ >+ my $mapping = $object->_get_data_and_patron( >+ { provider => $provider, >+ data => $data, >+ config => $config >+ } >+ ); >+ >+Maps OAuth raw data to a patron schema, and returns a patron if it can. >+ >+=cut >+ >+sub _get_data_and_patron { >+ my ( $self, $params ) = @_; >+ >+ my $provider = $params->{provider}; >+ my $data = $params->{data}; >+ my $config = $params->{config}; >+ >+ my $patron; >+ my $mapped_data; >+ >+ my $mapping = decode_json( $provider->mapping ); >+ my $matchpoint = $provider->matchpoint; >+ >+ if ( $data->{id_token} ) { >+ my ( $header_part, $claims_part, $footer_part ) = split( /\./, $data->{id_token} ); >+ >+ my $claim = decode_json( decode_base64url($claims_part) ); >+ foreach my $key ( keys %$mapping ) { >+ my $pkey = $mapping->{$key}; >+ $mapped_data->{$key} = $claim->{$pkey} >+ if defined $claim->{$pkey}; >+ } >+ >+ my $value = $mapped_data->{$matchpoint}; >+ >+ my $matchpoint_rs = Koha::Patrons->search( { $matchpoint => $value } ); >+ >+ if ( defined $value and $matchpoint_rs->count ) { >+ $patron = $matchpoint_rs->next; >+ } >+ >+ return ( $mapped_data, $patron ) >+ if $patron; >+ } >+ >+ if ( defined $config->{userinfo_url} ) { >+ my $access_token = $data->{access_token}; >+ my $ua = Mojo::UserAgent->new; >+ my $tx = $ua->get( $config->{userinfo_url} => { Authorization => "Bearer $access_token" } ); >+ my $code = $tx->res->code || 'No response'; >+ >+ return if $code ne '200'; >+ my $claim = >+ $tx->res->headers->content_type =~ m!^(application/json|text/javascript)(;\s*charset=\S+)?$! >+ ? $tx->res->json >+ : Mojo::Parameters->new( $tx->res->body )->to_hash; >+ >+ foreach my $key ( keys %$mapping ) { >+ my $pkey = $mapping->{$key}; >+ my $value = $self->_tranverse_hash( { base => $claim, keys => $pkey } ); >+ $mapped_data->{$key} = $value >+ if defined $value; >+ } >+ >+ my $value = $mapped_data->{$matchpoint}; >+ >+ my $matchpoint_rs = Koha::Patrons->search( { $matchpoint => $value } ); >+ >+ if ( defined $value and $matchpoint_rs->count ) { >+ $patron = $matchpoint_rs->next; >+ } >+ >+ return ( $mapped_data, $patron ) >+ if $patron; >+ } >+} >+ >+1; >-- >2.37.3
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 31378
:
141362
|
141363
|
141364
|
141365
|
141366
|
141367
|
141368
|
141369
|
141370
|
141371
|
141372
|
141373
|
141374
|
141375
|
141376
|
141377
|
141378
|
141514
|
141771
|
141772
|
141773
|
141774
|
141775
|
141776
|
141777
|
141778
|
141779
|
141780
|
141781
|
141782
|
141783
|
141784
|
141785
|
141786
|
141787
|
141788
|
141801
|
141802
|
141803
|
141804
|
141805
|
141806
|
141807
|
141808
|
141809
|
141810
|
141811
|
141812
|
141813
|
141814
|
141815
|
141816
|
141817
|
141818
|
141853
|
143056
|
143087
|
143088
|
143089
|
143090
|
143091
|
143092
|
143093
|
143094
|
143095
|
143096
|
143097
|
143098
|
143099
|
143100
|
143101
|
143102
|
143103
|
143104
|
143105
|
143106
|
143107
|
143186
|
143187
|
143188
|
143189
|
143190
|
143191
|
143192
|
143193
|
143194
|
143195
|
143196
|
143197
|
143198
|
143199
|
143200
|
143202
|
143204
|
143205
|
143206
|
143207
|
143208
|
143215
|
143216
|
143217
|
143218
|
143219
|
143220
|
143221
|
143222
|
143223
|
143224
|
143225
|
143226
|
143227
|
143228
|
143229
|
143230
|
143231
|
143232
|
143233
|
143234
|
143235
|
143236
|
143266
|
143267
|
143268
|
143269
|
143270
|
143271
|
143272
|
143273
|
143274
|
143275
|
143277
|
143278
|
143279
|
143280
|
143281
|
143282
|
143283
|
143284
|
143285
|
143286
|
143287
|
143288
|
143396
|
143397
|
143398
|
143399
|
143400
|
143401
|
143402
|
143403
|
143404
|
143405
|
143406
|
143407
|
143408
|
143409
|
143410
|
143411
|
143412
|
143413
|
143414
|
143415
|
143416
|
143417
|
143418
|
143420
|
143421
|
143422
|
143423
|
143424
|
143425
|
143426
|
143427
|
143428
|
143429
|
143430
|
143431
|
143432
|
143433
|
143434
|
143435
|
143436
|
143437
|
143438
|
143439
|
143440
|
143441
|
143442
|
143443
|
143450
|
144071
|
144175