Bugzilla – Attachment 187217 Details for
Bug 34164
OAuth2/OIDC should redirect to page that initiated login
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 34164: Redirect to referring URL when doing OIDC/OAuth SSO
Bug-34164-Redirect-to-referring-URL-when-doing-OID.patch (text/plain), 14.16 KB, created by
Tomás Cohen Arazi (tcohen)
on 2025-10-01 15:47:42 UTC
(
hide
)
Description:
Bug 34164: Redirect to referring URL when doing OIDC/OAuth SSO
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2025-10-01 15:47:42 UTC
Size:
14.16 KB
patch
obsolete
>From 1a11f85c385ddbfbe11a3ef3a792feaefebba73f Mon Sep 17 00:00:00 2001 >From: David Cook <dcook@prosentient.com.au> >Date: Fri, 26 Sep 2025 07:10:41 +0000 >Subject: [PATCH] Bug 34164: Redirect to referring URL when doing OIDC/OAuth > SSO >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >This patch makes it so that a successful SSO will return you to >the place where you initiated the SSO. This is especially useful >when doing searches, placing holds, etc. > >Test plan: >0. Apply patch and koha-plack --restart kohadev >1. Set up OIDC SSO using >https://wiki.koha-community.org/wiki/Testing_SSO >2. Go to http://localhost:8081/cgi-bin/koha/circ/circulation-home.pl >3. Do a staff login using SSO >4. Note that you're redirected to >http://localhost:8081/cgi-bin/koha/circ/circulation-home.pl >after the successful login > >5. Go to http://localhost:8080/cgi-bin/koha/opac-search.pl?idx=&q=test&weight_search=1 >6. Do a OPAC SSO login >7. Note that you're returned to >http://localhost:8080/cgi-bin/koha/opac-search.pl?idx=&q=test&weight_search=1 >after the successful login > >8. Logout of the staff admin and OPAC >9. Note your URL ends in ?logout.x=1 >10. Try logging back into them using SSO >11a. Note that you're logged in and not automatically logged out >11b. Note that if you're on the OPAC, you should be redirected >to opac-user.pl instead of opac-main.pl or the root path > >12. If you change the domain for the SSO users to something >that your user does not match, try logging in again, and note >that the error message should display on mainpage.pl or opac-main.pl/opac-user.pl >for the OPAC. (This is because these are the pages that show SSO errors.) > >Signed-off-by: Lukas Koszyk <lukasz.koszyk@kit.edu> >Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io> >--- > Koha/Auth/Identity/Referer.pm | 121 +++++++++++++++++ > Koha/REST/V1/OAuth/Client.pm | 25 ++++ > t/Koha/Auth/Identity/Referer.t | 234 +++++++++++++++++++++++++++++++++ > 3 files changed, 380 insertions(+) > create mode 100644 Koha/Auth/Identity/Referer.pm > create mode 100755 t/Koha/Auth/Identity/Referer.t > >diff --git a/Koha/Auth/Identity/Referer.pm b/Koha/Auth/Identity/Referer.pm >new file mode 100644 >index 0000000000..166136c3a4 >--- /dev/null >+++ b/Koha/Auth/Identity/Referer.pm >@@ -0,0 +1,121 @@ >+package Koha::Auth::Identity::Referer; >+ >+# >+# 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 <https://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use C4::Context; >+ >+=head1 NAME >+ >+Koha::Auth::Identity::Referer >+ >+=head1 SYNOPSIS >+ >+ use Koha::Auth::Identity::Referer; >+ >+ Koha::Auth::Identity::Referer->store_referer({ >+ referer => $c->req->headers->referer, >+ interface => $interface, >+ session => $session, >+ }); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer({ >+ session => $session, >+ }); >+ >+=head1 DESCRIPTION >+ >+ Class for working with HTTP referrers specifically for >+ when doing SSO. >+ >+=head1 FUNCTIONS >+ >+=head2 store_referer >+ >+ Koha::Auth::Identity::Referer->store_referer({ >+ referer => $c->req->headers->referer, >+ interface => $interface, >+ session => $session, >+ }); >+ >+ If the referer is for a Koha URL, then it gets saved >+ in a session variable for use after a successful SSO login. >+ >+=cut >+ >+sub store_referer { >+ my ( $class, $args ) = @_; >+ my $referer = $args->{referer}; >+ my $interface = $args->{interface}; >+ my $session = $args->{session}; >+ my $valid_referer; >+ if ( $referer && $interface && $session ) { >+ my $base_url; >+ if ( $interface eq 'opac' ) { >+ $base_url = C4::Context->preference('OPACBaseURL'); >+ } else { >+ $base_url = C4::Context->preference('staffClientBaseURL'); >+ } >+ if ( $base_url && $referer && $referer =~ /^\Q$base_url\E/ ) { >+ my $referer_uri = URI->new($referer); >+ >+ #NOTE: Remove logout.x query param to prevent logout loops >+ $referer_uri->query_param_delete('logout.x') if $referer_uri->query_param('logout.x'); >+ my $referer_to_save = $referer_uri->path_query(); >+ if ($referer_to_save) { >+ >+ #NOTE: Don't bother saving a root referer >+ #NOTE: Don't save opac-main.pl because it should redirect to opac-user.pl >+ unless ( ( $referer_to_save eq '/' ) || ( $referer_to_save eq '/cgi-bin/koha/opac-main.pl' ) ) { >+ $session->param( 'idp_referer', $referer_to_save ); >+ $session->flush(); >+ } >+ } >+ } >+ } >+ return $valid_referer; >+} >+ >+=head2 get_referer >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer({ >+ session => $session, >+ }); >+ >+ If a referer was stored in a session variable, then we retrieve >+ it for use by SSO functionality. That is, after a successful SSO, we'll >+ redirect to this referer, so we wind up back where we started. >+ >+=cut >+ >+sub get_referer { >+ my ( $class, $args ) = @_; >+ my $referer; >+ my $session = $args->{session}; >+ if ($session) { >+ my $idp_referer = $session->param('idp_referer'); >+ if ($idp_referer) { >+ $referer = $idp_referer; >+ $session->clear('idp_referer'); >+ $session->flush(); >+ } >+ } >+ return $referer; >+} >+ >+1; >diff --git a/Koha/REST/V1/OAuth/Client.pm b/Koha/REST/V1/OAuth/Client.pm >index 9b84edc980..3b5ea677d3 100644 >--- a/Koha/REST/V1/OAuth/Client.pm >+++ b/Koha/REST/V1/OAuth/Client.pm >@@ -25,6 +25,8 @@ use Scalar::Util qw(blessed); > use Try::Tiny; > use Koha::Token; > use URI::Escape qw(uri_escape_utf8); >+use Koha::Session; >+use Koha::Auth::Identity::Referer; > > =head1 NAME > >@@ -63,6 +65,13 @@ sub login { > $uri = '/cgi-bin/koha/mainpage.pl'; > } > >+ my $current_session; >+ my $current_session_cookie = $c->req->cookie('CGISESSID'); >+ if ($current_session_cookie) { >+ my $current_session_id = $current_session_cookie->value; >+ $current_session = Koha::Session->get_session( { sessionID => $current_session_id } ); >+ } >+ > unless ( $provider_config && $provider_config->{authorize_url} ) { > my $error = "No configuration found for your provider"; > return $c->redirect_to( $uri . "?auth_error=$error" ); >@@ -98,6 +107,14 @@ sub login { > > # initial request, generate CSRF token > $state = Koha::Token->new->generate_csrf( { session_id => $c->req->cookie('CGISESSID')->value } ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => $c->req->headers->referer, >+ interface => $interface, >+ session => $current_session, >+ } >+ ); > } > > return $c->oauth2->get_token_p( >@@ -133,6 +150,14 @@ sub login { > > $c->cookie( CGISESSID => $session_id, { path => "/" } ); > >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $current_session, >+ } >+ ); >+ if ($target_uri) { >+ $uri = $target_uri; >+ } > $c->redirect_to($uri); > } catch { > my $error = $_; >diff --git a/t/Koha/Auth/Identity/Referer.t b/t/Koha/Auth/Identity/Referer.t >new file mode 100755 >index 0000000000..3fdc56e8bd >--- /dev/null >+++ b/t/Koha/Auth/Identity/Referer.t >@@ -0,0 +1,234 @@ >+#!/usr/bin/perl >+ >+# 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 <https://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Test::NoWarnings; >+use Test::More tests => 10; >+use t::lib::Mocks; >+ >+use C4::Auth qw(); >+ >+use_ok('Koha::Auth::Identity::Referer'); >+ >+subtest 'Typical staff success' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'staffClientBaseURL', 'http://mystaffadmin' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://mystaffadmin/cgi-bin/koha/catalogue/search.pl?q=test', >+ interface => 'staff', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, '/cgi-bin/koha/catalogue/search.pl?q=test', 'Correct staff referer processed' ); >+ >+ $session->delete; >+ $session->flush; >+}; >+ >+subtest 'External staff referrers do not get saved' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'staffClientBaseURL', 'http://mystaffadmin' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://externalreferer', >+ interface => 'staff', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, undef, 'Bad referrers do not get stored' ); >+ >+ $session->delete; >+ $session->flush; >+}; >+ >+subtest 'Staff logout referer does not lead to loop' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'staffClientBaseURL', 'http://mystaffadmin' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://mystaffadmin/cgi-bin/koha/mainpage.pl?logout.x=1', >+ interface => 'staff', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, '/cgi-bin/koha/mainpage.pl', 'Staff logout URL does not lead to loop' ); >+ >+ $session->delete; >+ $session->flush; >+}; >+ >+subtest 'Typical OPAC success' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'OPACBaseURL', 'http://myopac' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://myopac/cgi-bin/koha/opac-detail.pl?biblionumber=999', >+ interface => 'opac', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, '/cgi-bin/koha/opac-detail.pl?biblionumber=999', 'Correct OPAC referer processed' ); >+ >+ $session->delete; >+ $session->flush; >+}; >+ >+subtest 'OPAC logout referer does not lead to loop' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'OPACBaseURL', 'http://myopac' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://myopac/cgi-bin/koha/opac-main.pl?logout.x=1', >+ interface => 'opac', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, undef, 'OPAC logout URL does not lead to loop' ); >+ >+ $session->delete; >+ $session->flush; >+}; >+ >+subtest 'Do not save referer to OPAC root' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'OPACBaseURL', 'http://myopac' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://myopac', >+ interface => 'opac', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, undef, 'Do not save referer to OPAC root' ); >+ >+ $session->delete; >+ $session->flush; >+}; >+ >+subtest 'Do not save referer to OPAC root (ie opac-main.pl)' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'OPACBaseURL', 'http://myopac' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://myopac/cgi-bin/koha/opac-main.pl', >+ interface => 'opac', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, undef, 'Do not save referer to OPAC root (ie opac-main.pl)' ); >+ >+ $session->delete; >+ $session->flush; >+}; >+ >+subtest 'External OPAC referrers do not get saved' => sub { >+ plan tests => 1; >+ my $session = C4::Auth::get_session(""); >+ >+ t::lib::Mocks::mock_preference( 'OPACBaseURL', 'http://myopac' ); >+ >+ Koha::Auth::Identity::Referer->store_referer( >+ { >+ referer => 'http://externalreferer', >+ interface => 'opac', >+ session => $session, >+ } >+ ); >+ >+ my $target_uri = Koha::Auth::Identity::Referer->get_referer( >+ { >+ session => $session, >+ } >+ ); >+ >+ is( $target_uri, undef, 'Bad referrers do not get stored' ); >+ >+ $session->delete; >+ $session->flush; >+}; >-- >2.51.0
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 34164
:
163127
|
163128
|
163129
|
163493
|
163494
|
163495
|
163496
|
164979
|
164980
|
186959
|
187045
| 187217