Bugzilla – Attachment 136397 Details for
Bug 30988
Add generic OpenIDConnect client implementation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 30988: Moving id token validation code into a module
Bug-30988-Moving-id-token-validation-code-into-a-m.patch (text/plain), 12.51 KB, created by
Shi Yao Wang
on 2022-06-21 15:16:55 UTC
(
hide
)
Description:
Bug 30988: Moving id token validation code into a module
Filename:
MIME Type:
Creator:
Shi Yao Wang
Created:
2022-06-21 15:16:55 UTC
Size:
12.51 KB
patch
obsolete
>From 31616894be015f5de2f597a80497c50b085a1ded Mon Sep 17 00:00:00 2001 >From: Shi Yao Wang <shi-yao.wang@inlibro.com> >Date: Tue, 21 Jun 2022 10:59:26 -0400 >Subject: [PATCH] Bug 30988: Moving id token validation code into a module > >--- > Koha/Auth/Client/OIDC.pm | 82 ++++++++++++++++++ > opac/svc/auth/openidconnect | 164 +++++++++++++----------------------- > 2 files changed, 140 insertions(+), 106 deletions(-) > create mode 100644 Koha/Auth/Client/OIDC.pm > >diff --git a/Koha/Auth/Client/OIDC.pm b/Koha/Auth/Client/OIDC.pm >new file mode 100644 >index 0000000000..2193bbd976 >--- /dev/null >+++ b/Koha/Auth/Client/OIDC.pm >@@ -0,0 +1,82 @@ >+package Koha::Auth::Client::OIDC; >+ >+# 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; >+use MIME::Base64 qw{ decode_base64url }; >+ >+ >+sub ValidateIdToken { >+ my ($json, $issuer, $clientid) = @_; >+ >+ if ( ! exists( $json->{'id_token'} ) ) { >+ return ( undef, 'Failed to get proper credentials.' ); >+ } >+ if ( lc( $json->{'token_type'} ) ne 'bearer' ) { >+ return ( undef, >+ 'Authentication failed. Incorrect token type.' ); >+ } >+ my $idtoken = $json->{'id_token'}; >+ >+ # need to validate the token here >+ >+ my @segments = split( '\.', $idtoken ); >+ unless ( scalar(@segments) == 3 ) { >+ return ( undef, >+ 'Login token broken: either too many or too few segments.' ); >+ } >+ my ( $header, $claims, $validation ) = @segments; >+ $claims = decode_base64url($claims); >+ my $claims_json = decode_json($claims); >+ if ( $issuer eq q{} ) { >+ return ( undef, 'Unable to discover issuer.' ); >+ } >+ if ( ( $claims_json->{'iss'} ne ( 'https://' . $issuer ) ) >+ && ( $claims_json->{'iss'} ne $issuer ) ) >+ { >+ return ( undef, >+ "Authentication failed. Issuer of authentication is different from what we expected." >+ ); >+ } >+ if ( ref( $claims_json->{'aud'} ) eq 'ARRAY' ) { >+ warn "Audience is an array of size: " >+ . scalar( @$claims_json->{'aud'} ); >+ if ( scalar( @$claims_json->{'aud'} ) > 1 ) >+ { # We don't want any other audiences >+ return ( undef, >+ "Authentication failed. Unexpected audience provided." ); >+ } >+ } >+ if ( ( $claims_json->{'aud'} ne $clientid ) ) { >+ return ( undef, >+ "Authentication failed. Unexpected audience." ); >+ } >+ if ( $claims_json->{'exp'} < time() ) { >+ return ( undef, 'Sorry, your authentication has timed out.' ); >+ } >+ >+ if ( ! exists( $claims_json->{'email'} ) ) { >+ return ( undef, >+'Unexpectedly, no email seems to be associated with that account.' >+ ); >+ } >+ >+ return ($claims_json, undef); >+} >+ >+1; >diff --git a/opac/svc/auth/openidconnect b/opac/svc/auth/openidconnect >index 2f3b1c731f..8f0a03c127 100755 >--- a/opac/svc/auth/openidconnect >+++ b/opac/svc/auth/openidconnect >@@ -34,6 +34,7 @@ use C4::Auth qw{ checkauth get_session get_template_and_user }; > use C4::Context; > use C4::Output; > use Koha::Patrons; >+use Koha::Auth::Client::OIDC qw ( ValidateIdToken ); > > use LWP::UserAgent; > use HTTP::Request::Common qw{ POST }; >@@ -127,124 +128,75 @@ elsif ( defined $query->param('code') ) { > ); > my $response = $ua->request($request)->decoded_content; > my $json = decode_json($response); >- if ( exists( $json->{'id_token'} ) ) { >- if ( lc( $json->{'token_type'} ) ne 'bearer' ) { >- loginfailed( $query, >- 'Authentication failed. Incorrect token type.' ); >- } >- my $idtoken = $json->{'id_token'}; >- >- # need to validate the token here >- >- my @segments = split( '\.', $idtoken ); >- unless ( scalar(@segments) == 3 ) { >- loginfailed( $query, >- 'Login token broken: either too many or too few segments.' ); >- } >- my ( $header, $claims, $validation ) = @segments; >- $claims = decode_base64url($claims); >- my $claims_json = decode_json($claims); >- if ( $issuer eq q{} ) { >- loginfailed( $query, 'Unable to discover issuer.' ); >- } >- if ( ( $claims_json->{'iss'} ne ( 'https://' . $issuer ) ) >- && ( $claims_json->{'iss'} ne $issuer ) ) >+ my ($claims_json, $message) = ValidateIdToken($json, $issuer, $clientid); >+ >+ if ($claims_json) { >+ my $email = $claims_json->{'email'}; >+ if ( ( $restricttodomain ne q{} ) >+ && ( index( $email, $restricttodomain ) < 0 ) ) > { > loginfailed( $query, >- "Authentication failed. Issuer of authentication is different from what we expected." >- ); >- } >- if ( ref( $claims_json->{'aud'} ) eq 'ARRAY' ) { >- warn "Audience is an array of size: " >- . scalar( @$claims_json->{'aud'} ); >- if ( scalar( @$claims_json->{'aud'} ) > 1 ) >- { # We don't want any other audiences >- loginfailed( $query, >- "Authentication failed. Unexpected audience provided." ); >- } >- } >- if ( ( $claims_json->{'aud'} ne $clientid ) ) >- { >- loginfailed( $query, >- "Authentication failed. Unexpected audience." ); >- } >- if ( $claims_json->{'exp'} < time() ) { >- loginfailed( $query, 'Sorry, your authentication has timed out.' ); >+ 'The email you have used is not valid for this library. Email addresses should conclude with ' >+ . $restricttodomain >+ . ' .' ); > } >- >- if ( exists( $claims_json->{'email'} ) ) { >- my $email = $claims_json->{'email'}; >- if ( ( $restricttodomain ne q{} ) >- && ( index( $email, $restricttodomain ) < 0 ) ) >- { >- loginfailed( $query, >-'The email you have used is not valid for this library. Email addresses should conclude with ' >- . $restricttodomain >- . ' .' ); >- } >- else { >- my $error_feedback = >-'The email address you are trying to use is not associated with a borrower at this library.'; >- my $auto_registration = C4::Context->preference('OIDCAutoRegister') // q{0}; >- my $borrower = Koha::Patrons->find( { email => $email } ); >- if (! $borrower && $auto_registration==1) { >- my $firstname = $claims_json->{'given_name'} // q{}; >- my $surname = $claims_json->{'family_name'} // q{}; >- if ($firstname && $surname) { >- my $delimiter = $firstname ? q{.} : q{}; >- my $userid = $firstname . $delimiter . $surname; >- my $categorycode = C4::Context->preference('OIDCDefaultCategory') // q{}; >- my $patron_category = Koha::Patron::Categories->find( $categorycode ); >- my $branchcode = C4::Context->preference('OIDCDefaultBranch') // q{}; >- my $library = Koha::Libraries->find( $branchcode ); >- if (defined $patron_category && defined $library) { >- my $password = undef; >- # TODO errors handling! >- my $borrower = Koha::Patron->new({ >- firstname => $firstname, >- surname => $surname, >- email => $email, >- categorycode => $categorycode, >- branchcode => $branchcode, >- userid => $userid, >- password => $password >- })->store; >- } else { >- $error_feedback = 'The OIDCDefaultBranch or OIDCDefaultCategory system preferences are not configured properly. Please contact the library with this error message.'; >- } >+ else { >+ my $error_feedback = >+ 'The email address you are trying to use is not associated with a borrower at this library.'; >+ my $auto_registration = C4::Context->preference('OIDCAutoRegister') // q{0}; >+ my $borrower = Koha::Patrons->find( { email => $email } ); >+ if (! $borrower && $auto_registration==1) { >+ my $firstname = $claims_json->{'given_name'} // q{}; >+ my $surname = $claims_json->{'family_name'} // q{}; >+ if ($firstname && $surname) { >+ my $delimiter = $firstname ? q{.} : q{}; >+ my $userid = $firstname . $delimiter . $surname; >+ my $categorycode = C4::Context->preference('OIDCDefaultCategory') // q{}; >+ my $patron_category = Koha::Patron::Categories->find( $categorycode ); >+ my $branchcode = C4::Context->preference('OIDCDefaultBranch') // q{}; >+ my $library = Koha::Libraries->find( $branchcode ); >+ if (defined $patron_category && defined $library) { >+ my $password = undef; >+ # TODO errors handling! >+ my $borrower = Koha::Patron->new({ >+ firstname => $firstname, >+ surname => $surname, >+ email => $email, >+ categorycode => $categorycode, >+ branchcode => $branchcode, >+ userid => $userid, >+ password => $password >+ })->store; > } else { >- $error_feedback = 'We could not find given name and/or family name.' >+ $error_feedback = 'The OIDCDefaultBranch or OIDCDefaultCategory system preferences are not configured properly. Please contact the library with this error message.'; > } >+ } else { >+ $error_feedback = 'We could not find given name and/or family name.' > } >- my ( $userid, $cookie, $session_id ) = >- checkauth( $query, 1, {}, 'opac', $email ); >- if ($userid) { # A user with this email is registered in koha >+ } >+ my ( $userid, $cookie, $session_id ) = >+ checkauth( $query, 1, {}, 'opac', $email ); >+ if ($userid) { # A user with this email is registered in koha > >- #handle redirect to main.pl, for private opac >- my $uri; >- if (C4::Context->preference('OpacPublic') ) { >- $uri = '/cgi-bin/koha/opac-user.pl'; >- } else { >- $uri = '/cgi-bin/koha/opac-main.pl'; >- } >- print $query->redirect( >- -uri => $uri, >- -cookie => $cookie >- ); >- } >- else { >- loginfailed( $query, $error_feedback ); >+ #handle redirect to main.pl, for private opac >+ my $uri; >+ if (C4::Context->preference('OpacPublic') ) { >+ $uri = '/cgi-bin/koha/opac-user.pl'; >+ } else { >+ $uri = '/cgi-bin/koha/opac-main.pl'; > } >+ print $query->redirect( >+ -uri => $uri, >+ -cookie => $cookie >+ ); >+ } >+ else { >+ loginfailed( $query, $error_feedback ); > } >- } >- else { >- loginfailed( $query, >-'Unexpectedly, no email seems to be associated with that acccount.' >- ); > } > } > else { >- loginfailed( $query, 'Failed to get proper credentials.' ); >+ loginfailed( $query, $message); > } > } > else { >-- >2.25.1
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 30988
:
136301
|
136302
|
136382
|
136396
|
136397
|
136403
|
136430
|
136431
|
136450
|
136451
|
136467
|
136468
|
136469
|
137230
|
137231
|
137232