Bugzilla – Attachment 72358 Details for
Bug 19160
CAS Single Logout
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 19160: CAS Single logout
Bug-19160-CAS-Single-logout.patch (text/plain), 12.01 KB, created by
Kyle M Hall (khall)
on 2018-03-02 13:44:16 UTC
(
hide
)
Description:
Bug 19160: CAS Single logout
Filename:
MIME Type:
Creator:
Kyle M Hall (khall)
Created:
2018-03-02 13:44:16 UTC
Size:
12.01 KB
patch
obsolete
>From 1d5247a3e7877f1fa643afaf8fe977a5aa266efb Mon Sep 17 00:00:00 2001 >From: Chris Cormack <chrisc@catalyst.net.nz> >Date: Thu, 8 Jun 2017 09:38:30 +1200 >Subject: [PATCH] Bug 19160: CAS Single logout > >CAS supports single logout, where if you logout of one application it >logs you out of all of them. > >This bug implements this > >You will need a CAS server (with single logout configure), >and at least 2 applications (one being Koha) > >1/ In Koha login via CAS >2/ Login to the other application via CAS >3/ Logout of the other application >4/ Notice you are still logged into Koha >5/ Log out of Koha >6/ Apply patch >7/ Login to Koha via CAS, login to other app via CAS >8/ Log out of other app >9/ Notice you are logged out of Koha > >If you dont have CAS, this patch should be a no op, you could test that >1/ Login and logout normally >2/ Apply patch >3/ Login and logout still work fine > >Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de> >Patch works as described, local login still works correctly. > >Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> > >Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de> > >Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> >--- > C4/Auth.pm | 64 +++++++++++++++++++++++++++++++++++++++++++---------- > C4/Auth_with_cas.pm | 12 ++++++---- > opac/opac-user.pl | 22 ++++++++++++++++++ > 3 files changed, 82 insertions(+), 16 deletions(-) > >diff --git a/C4/Auth.pm b/C4/Auth.pm >index c3ad351..5df6f2e 100644 >--- a/C4/Auth.pm >+++ b/C4/Auth.pm >@@ -748,7 +748,6 @@ sub _timeout_syspref { > sub checkauth { > my $query = shift; > $debug and warn "Checking Auth"; >- > # $authnotrequired will be set for scripts which will run without authentication > my $authnotrequired = shift; > my $flagsrequired = shift; >@@ -768,7 +767,7 @@ sub checkauth { > my $logout = $query->param('logout.x'); > > my $anon_search_history; >- >+ my $cas_ticket = ''; > # This parameter is the name of the CAS server we want to authenticate against, > # when using authentication against multiple CAS servers, as configured in Auth_cas_servers.yaml > my $casparam = $query->param('cas'); >@@ -906,8 +905,45 @@ sub checkauth { > } > } > } >+ elsif ($logout && $cas) { >+ # We got a cas single logout request from a cas server; >+ my $ticket = $query->param('cas_ticket'); >+ # We've been called as part of the single logout destroy the session associated with the cas ticket >+ my $storage_method = C4::Context->preference('SessionStorage'); >+ my $dsn; >+ my $dsn_options; >+ # shift this to a function make get_session use the function too >+ my $dbh = C4::Context->dbh; >+ if ( $storage_method eq 'mysql' ) { >+ $dsn = "driver:MySQL;serializer:yaml;id:md5"; >+ $dsn_options = { Handle => $dbh }; >+ } >+ elsif ( $storage_method eq 'Pg' ) { >+ $dsn = "driver:PostgreSQL;serializer:yaml;id:md5"; >+ $dsn_options = { Handle => $dbh }; >+ } >+ elsif ( $storage_method eq 'memcached' && Koha::Caches->get_instance->memcached_cache ) { >+ $dsn = "driver:memcached;serializer:yaml;id:md5"; >+ my $memcached = Koha::Caches->get_instance()->memcached_cache; >+ $dsn_options = { Memcached => $memcached }; >+ } >+ else { >+ $dsn = "driver:File;serializer:yaml;id:md5"; >+ my $dir = File::Spec->tmpdir; >+ my $instance = C4::Context->config( 'database' ); #actually for packages not exactly the instance name, but generally safer to leave it as it is >+ $dsn_options = { Directory => "$dir/cgisess_$instance" }; >+ } >+ my $success = CGI::Session->find( $dsn, sub {delete_cas_session(@_, $ticket)}, $dsn_options ); >+ sub delete_cas_session { >+ my $session = shift; >+ my $ticket = shift; >+ if ($session->param('cas_ticket') && $session->param('cas_ticket') eq $ticket ) { >+ $session->delete; >+ $session->flush; >+ } >+ } >+ } > unless ( $userid || $sessionID ) { >- > #we initiate a session prior to checking for a username to allow for anonymous sessions... > my $session = get_session("") or die "Auth ERROR: Cannot get_session()"; > >@@ -938,7 +974,6 @@ sub checkauth { > { > my $password = $query->param('password'); > my $shibSuccess = 0; >- > my ( $return, $cardnumber ); > > # If shib is enabled and we have a shib login, does the login match a valid koha user >@@ -956,7 +991,7 @@ sub checkauth { > unless ($shibSuccess) { > if ( $cas && $query->param('ticket') ) { > my $retuserid; >- ( $return, $cardnumber, $retuserid ) = >+ ( $return, $cardnumber, $retuserid, $cas_ticket ) = > checkpw( $dbh, $userid, $password, $query, $type ); > $userid = $retuserid; > $info{'invalidCasLogin'} = 1 unless ($return); >@@ -1016,7 +1051,7 @@ sub checkauth { > } > else { > my $retuserid; >- ( $return, $cardnumber, $retuserid ) = >+ ( $return, $cardnumber, $retuserid, $cas_ticket ) = > checkpw( $dbh, $q_userid, $password, $query, $type ); > $userid = $retuserid if ($retuserid); > $info{'invalid_username_or_password'} = 1 unless ($return); >@@ -1142,6 +1177,7 @@ sub checkauth { > $session->param( 'ip', $session->remote_addr() ); > $session->param( 'lasttime', time() ); > } >+ $session->param('cas_ticket', $cas_ticket) if $cas_ticket; > C4::Context->set_userenv( > $session->param('number'), $session->param('id'), > $session->param('cardnumber'), $session->param('firstname'), >@@ -1374,9 +1410,9 @@ Possible return values in C<$status> are: > =cut > > sub check_api_auth { >+ > my $query = shift; > my $flagsrequired = shift; >- > my $dbh = C4::Context->dbh; > my $timeout = _timeout_syspref(); > >@@ -1470,7 +1506,7 @@ sub check_api_auth { > # new login > my $userid = $query->param('userid'); > my $password = $query->param('password'); >- my ( $return, $cardnumber ); >+ my ( $return, $cardnumber, $cas_ticket ); > > # Proxy CAS auth > if ( $cas && $query->param('PT') ) { >@@ -1479,7 +1515,7 @@ sub check_api_auth { > > # In case of a CAS authentication, we use the ticket instead of the password > my $PT = $query->param('PT'); >- ( $return, $cardnumber, $userid ) = check_api_auth_cas( $dbh, $PT, $query ); # EXTERNAL AUTH >+ ( $return, $cardnumber, $userid, $cas_ticket ) = check_api_auth_cas( $dbh, $PT, $query ); # EXTERNAL AUTH > } else { > > # User / password auth >@@ -1488,7 +1524,8 @@ sub check_api_auth { > # caller did something wrong, fail the authenticateion > return ( "failed", undef, undef ); > } >- ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password, $query ); >+ my $newuserid; >+ ( $return, $cardnumber, $newuserid, $cas_ticket ) = checkpw( $dbh, $userid, $password, $query ); > } > > if ( $return and haspermission( $userid, $flagsrequired ) ) { >@@ -1586,6 +1623,7 @@ sub check_api_auth { > $session->param( 'ip', $session->remote_addr() ); > $session->param( 'lasttime', time() ); > } >+ $session->param( 'cas_ticket', $cas_ticket); > C4::Context->set_userenv( > $session->param('number'), $session->param('id'), > $session->param('cardnumber'), $session->param('firstname'), >@@ -1792,9 +1830,11 @@ sub checkpw { > # In case of a CAS authentication, we use the ticket instead of the password > my $ticket = $query->param('ticket'); > $query->delete('ticket'); # remove ticket to come back to original URL >- my ( $retval, $retcard, $retuserid ) = checkpw_cas( $dbh, $ticket, $query, $type ); # EXTERNAL AUTH >+ my ( $retval, $retcard, $retuserid, $cas_ticket ) = checkpw_cas( $dbh, $ticket, $query, $type ); # EXTERNAL AUTH > if ( $retval ) { >- @return = ( $retval, $retcard, $retuserid ); >+ @return = ( $retval, $retcard, $retuserid, $cas_ticket ); >+ } else { >+ @return = (0); > } > $passwd_ok = $retval; > } >diff --git a/C4/Auth_with_cas.pm b/C4/Auth_with_cas.pm >index 6e7bb93..ba683cd 100644 >--- a/C4/Auth_with_cas.pm >+++ b/C4/Auth_with_cas.pm >@@ -105,18 +105,20 @@ sub checkpw_cas { > my $userid = $val->user(); > $debug and warn "User CAS authenticated as: $userid"; > >+ # we should store the CAS ticekt too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout >+ > # Does it match one of our users ? > my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?"); > $sth->execute($userid); > if ( $sth->rows ) { > $retnumber = $sth->fetchrow; >- return ( 1, $retnumber, $userid ); >+ return ( 1, $retnumber, $userid, $ticket ); > } > $sth = $dbh->prepare("select userid from borrowers where cardnumber=?"); > $sth->execute($userid); > if ( $sth->rows ) { > $retnumber = $sth->fetchrow; >- return ( 1, $retnumber, $userid ); >+ return ( 1, $retnumber, $userid, $ticket ); > } > > # If we reach this point, then the user is a valid CAS user, but not a Koha user >@@ -154,19 +156,21 @@ sub check_api_auth_cas { > > my $userid = $r->user; > >+ # we should store the CAS ticket too, we need this for single logout https://apereo.github.io/cas/4.2.x/protocol/CAS-Protocol-Specification.html#233-single-logout >+ > # Does it match one of our users ? > my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?"); > $sth->execute($userid); > if ( $sth->rows ) { > $retnumber = $sth->fetchrow; >- return ( 1, $retnumber, $userid ); >+ return ( 1, $retnumber, $userid, $PT ); > } > $sth = $dbh->prepare("select userid from borrowers where cardnumber=?"); > return $r->user; > $sth->execute($userid); > if ( $sth->rows ) { > $retnumber = $sth->fetchrow; >- return ( 1, $retnumber, $userid ); >+ return ( 1, $retnumber, $userid, $PT ); > } > > # If we reach this point, then the user is a valid CAS user, but not a Koha user >diff --git a/opac/opac-user.pl b/opac/opac-user.pl >index ac91d4f..c5d6ab7 100755 >--- a/opac/opac-user.pl >+++ b/opac/opac-user.pl >@@ -61,6 +61,22 @@ BEGIN { > import C4::External::BakerTaylor qw(&image_url &link_url); > } > } >+my $logout=''; >+# CAS Single Sign Out >+if (C4::Context->preference('casAuthentication')){ >+ # Check we havent been hit by a logout call >+ my $xml = $query->param('logoutRequest'); >+ if ($xml) { >+ my $dom = XML::LibXML->load_xml(string => $xml); >+ my $ticket; >+ foreach my $node ($dom->findnodes('/samlp:LogoutRequest')){ >+ $ticket = $node->findvalue('./samlp:SessionIndex'); >+ } >+ $query->param(-name =>'logout.x', -value => 1); >+ $query->param(-name =>'cas_ticket', -value => $ticket); >+ $logout=1; >+ } >+} > > my ( $template, $borrowernumber, $cookie ) = get_template_and_user( > { >@@ -72,6 +88,12 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( > } > ); > >+if ($logout){ >+ print $query->header; >+ exit; >+} >+ >+ > my %renewed = map { $_ => 1 } split( ':', $query->param('renewed') ); > > my $show_priority; >-- >2.10.2
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 19160
:
66285
|
66306
|
70408
|
70440
|
70441
|
70442
|
71829
|
71830
|
71831
|
71832
|
71833
|
71834
|
71835
| 72358 |
72359
|
72360
|
72361
|
72362
|
72363
|
72364