diff --git a/C4/Auth.pm b/C4/Auth.pm
index 650618bacd..94a8d750fc 100644
--- a/C4/Auth.pm
+++ b/C4/Auth.pm
@@ -23,6 +23,7 @@ use Carp qw( croak );
use Digest::MD5 qw( md5_base64 );
use CGI::Session;
+use CGI::Session::ErrorHandler;
use URI;
use URI::QueryParam;
@@ -560,9 +561,10 @@ sub get_template_and_user {
unless ( $pagename =~ /^(?:MARC|ISBD)?detail$/
or $pagename =~ /^showmarc$/
or $pagename =~ /^addbybiblionumber$/
- or $pagename =~ /^review$/ ) {
- my $sessionSearch = get_session( $sessionID || $in->{'query'}->cookie("CGISESSID") );
- $sessionSearch->clear( ["busc"] ) if ( $sessionSearch->param("busc") );
+ or $pagename =~ /^review$/ )
+ {
+ my $sessionSearch = get_session( $sessionID );
+ $sessionSearch->clear( ["busc"] ) if $sessionSearch;
}
}
@@ -877,6 +879,7 @@ sub checkauth {
}
elsif ( $sessionID = $query->cookie("CGISESSID") ) { # assignment, not comparison
my ( $return, $more_info );
+ # NOTE: $flags in the following call is still undefined !
( $return, $session, $more_info ) = check_cookie_auth( $sessionID, $flags,
{ remote_addr => $ENV{REMOTE_ADDR}, skip_version_check => 1 }
);
@@ -897,7 +900,8 @@ sub checkauth {
$anon_search_history = $session->param('search_history');
$session->delete();
$session->flush;
- C4::Context->_unset_userenv($sessionID);
+ C4::Context::_unset_userenv($sessionID);
+ $sessionID = undef;
}
elsif ($logout) {
@@ -906,7 +910,8 @@ sub checkauth {
my $shibSuccess = C4::Context->userenv->{'shibboleth'};
$session->delete();
$session->flush;
- C4::Context->_unset_userenv($sessionID);
+ C4::Context::_unset_userenv($sessionID);
+ $sessionID = undef;
if ($cas and $caslogout) {
logout_cas($query, $type);
@@ -925,14 +930,11 @@ sub checkauth {
-secure => ( C4::Context->https_enabled() ? 1 : 0 ),
);
- my $sessiontype = $session->param('sessiontype') || '';
- unless ( $sessiontype && $sessiontype eq 'anon' ) { #if this is an anonymous session, we want to update the session, but not behave as if they are logged in...
- $flags = haspermission( $userid, $flagsrequired );
- if ($flags) {
- $loggedin = 1;
- } else {
- $info{'nopermission'} = 1;
- }
+ $flags = haspermission( $userid, $flagsrequired );
+ if ($flags) {
+ $loggedin = 1;
+ } else {
+ $info{'nopermission'} = 1;
}
}
} elsif ( !$logout ) {
@@ -947,13 +949,12 @@ sub checkauth {
}
unless ( $loggedin ) {
- $sessionID = undef;
$userid = undef;
}
unless ( $userid ) {
#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()";
+ $session ||= get_session("") or die "Auth ERROR: Cannot get_session()";
# Save anonymous search history in new session so it can be retrieved
# by get_template_and_user to store it in user's search history after
@@ -1102,7 +1103,7 @@ sub checkauth {
}
else {
$info{'nopermission'} = 1;
- C4::Context->_unset_userenv($sessionID);
+ C4::Context::_unset_userenv($sessionID);
}
my ( $borrowernumber, $firstname, $surname, $userflags,
$branchcode, $branchname, $emailaddress, $desk_id,
@@ -1227,7 +1228,7 @@ sub checkauth {
else {
if ($userid) {
$info{'invalid_username_or_password'} = 1;
- C4::Context->_unset_userenv($sessionID);
+ C4::Context::_unset_userenv($sessionID);
}
$session->param( 'lasttime', time() );
$session->param( 'ip', $session->remote_addr() );
@@ -1245,6 +1246,7 @@ sub checkauth {
$session->param( 'sessiontype', 'anon' );
$session->param( 'interface', $type);
}
+ $session->flush;
} # END unless ($userid)
# finished authentification, now respond
@@ -1622,7 +1624,7 @@ sub check_api_auth {
=head2 check_cookie_auth
- ($status, $sessionId) = check_api_auth($cookie, $userflags);
+ ($status, $sessionId) = check_cookie_auth($cookie, $userflags);
Given a CGISESSID cookie set during a previous login to Koha, determine
if the user has the privileges specified by C<$userflags>. C<$userflags>
@@ -1685,57 +1687,57 @@ sub check_cookie_auth {
# however, if a userid parameter is present (i.e., from
# a form submission, assume that any current cookie
# is to be ignored
- unless ( defined $sessionID and $sessionID ) {
+ unless ( $sessionID ) {
return ( "failed", undef );
}
+ C4::Context::_unset_userenv($sessionID); # remove old userenv first
my $session = get_session($sessionID);
- C4::Context->_new_userenv($sessionID);
if ($session) {
- C4::Context->interface($session->param('interface'));
- C4::Context->set_userenv(
- $session->param('number'), $session->param('id') // '',
- $session->param('cardnumber'), $session->param('firstname'),
- $session->param('surname'), $session->param('branch'),
- $session->param('branchname'), $session->param('flags'),
- $session->param('emailaddress'), $session->param('shibboleth'),
- $session->param('desk_id'), $session->param('desk_name'),
- $session->param('register_id'), $session->param('register_name')
- );
-
my $userid = $session->param('id');
my $ip = $session->param('ip');
my $lasttime = $session->param('lasttime');
my $timeout = _timeout_syspref();
if ( !$lasttime || ( $lasttime < time() - $timeout ) ) {
-
# time out
$session->delete();
$session->flush;
- C4::Context->_unset_userenv($sessionID);
return ("expired", undef);
- } elsif ( C4::Context->preference('SessionRestrictionByIP') && $ip ne $remote_addr ) {
+ } elsif ( C4::Context->preference('SessionRestrictionByIP') && $ip ne $remote_addr ) {
# IP address changed
$session->delete();
$session->flush;
- C4::Context->_unset_userenv($sessionID);
return ( "restricted", undef, { old_ip => $ip, new_ip => $remote_addr});
+
} elsif ( $userid ) {
$session->param( 'lasttime', time() );
my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1;
if ($flags) {
+ C4::Context->_new_userenv($sessionID);
+ C4::Context->interface($session->param('interface'));
+ C4::Context->set_userenv(
+ $session->param('number'), $session->param('id') // '',
+ $session->param('cardnumber'), $session->param('firstname'),
+ $session->param('surname'), $session->param('branch'),
+ $session->param('branchname'), $session->param('flags'),
+ $session->param('emailaddress'), $session->param('shibboleth'),
+ $session->param('desk_id'), $session->param('desk_name'),
+ $session->param('register_id'), $session->param('register_name')
+ );
return ( "ok", $session );
+ } else {
+ $session->delete();
+ $session->flush;
+ return ( "failed", undef );
}
+
} else {
+ C4::Context->_new_userenv($sessionID);
+ C4::Context->interface($session->param('interface'));
+ C4::Context->set_userenv( undef, q{} );
return ( "anon", $session );
}
- # If here user was logged in, but doesn't have correct permissions
- # could be an 'else' at `if($flags) return "ok"` , but left here to catch any errors
- $session->delete();
- $session->flush;
- C4::Context->_unset_userenv($sessionID);
- return ( "failed", undef );
} else {
return ( "expired", undef );
}
@@ -1781,9 +1783,13 @@ sub _get_session_params {
sub get_session {
my $sessionID = shift;
my $params = _get_session_params();
- my $session = CGI::Session->new( $params->{dsn}, $sessionID, $params->{dsn_args} );
- if ( ! $session ){
- die CGI::Session->errstr();
+ my $session;
+ if( $sessionID ) { # find existing
+ CGI::Session::ErrorHandler->set_error( q{} ); # clear error, cpan issue #111463
+ $session = CGI::Session->load( $params->{dsn}, $sessionID, $params->{dsn_args} );
+ } else {
+ $session = CGI::Session->new( $params->{dsn}, $sessionID, $params->{dsn_args} );
+ # $session->flush;
}
return $session;
}
diff --git a/C4/Search/History.pm b/C4/Search/History.pm
index df36cb0fbc..fec4f004fd 100644
--- a/C4/Search/History.pm
+++ b/C4/Search/History.pm
@@ -218,6 +218,7 @@ sub set_to_session {
return () unless $session;
$session->param( 'search_history',
uri_escape( encode_json($search_history) ) );
+ $session->flush;
}
1;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt
index 73b3761764..499c5bdbd3 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt
@@ -138,8 +138,8 @@
[% END %]
[% IF ( nopermission ) %]
-
[Previous page]
- [Main page]
+ [Previous page]
+ [Main page]
[% END %]
diff --git a/t/db_dependent/Auth.t b/t/db_dependent/Auth.t
index f053bd115d..5228254ab8 100755
--- a/t/db_dependent/Auth.t
+++ b/t/db_dependent/Auth.t
@@ -10,11 +10,12 @@ use CGI qw ( -utf8 );
use Test::MockObject;
use Test::MockModule;
use List::MoreUtils qw/all any none/;
-use Test::More tests => 24;
+use Test::More tests => 15;
use Test::Warn;
use t::lib::Mocks;
use t::lib::TestBuilder;
+use C4::Auth;
use C4::Members;
use Koha::AuthUtils qw/hash_password/;
use Koha::Database;
@@ -201,7 +202,7 @@ subtest 'checkpw lockout tests' => sub {
# get_template_and_user tests
-{ # Tests for the language URL parameter
+subtest 'get_template_and_user' => sub { # Tests for the language URL parameter
sub MockedCheckauth {
my ($query,$authnotrequired,$flagsrequired,$type) = @_;
@@ -342,7 +343,9 @@ subtest 'checkpw lockout tests' => sub {
);
is($template->{VARS}->{'opac_name'}, "multibranch-19", "Opac name was set correctly");
is($template->{VARS}->{'opac_search_limit'}, "branch:multibranch-19", "Search limit was set correctly");
-}
+
+ delete $ENV{"HTTP_COOKIE"};
+};
# Check that there is always an OPACBaseURL set.
my $input = CGI->new();
@@ -479,4 +482,176 @@ subtest 'check_cookie_auth' => sub {
#FIXME We should have a test to cover 'failed' status when a user has logged in, but doesn't have permission
};
+subtest 'checkauth & check_cookie_auth' => sub {
+ plan tests => 31;
+
+ # flags = 4 => { catalogue => 1 }
+ my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { flags => 4 } });
+ my $password = 'password';
+ t::lib::Mocks::mock_preference( 'RequireStrongPassword', 0 );
+ $patron->set_password( { password => $password } );
+
+ my $cgi_mock = Test::MockModule->new('CGI');
+ $cgi_mock->mock( 'request_method', sub { return 'POST' } );
+
+ my $cgi = CGI->new;
+
+ my $auth = Test::MockModule->new( 'C4::Auth' );
+ # Tests will fail if we hit safe_exit
+ $auth->mock( 'safe_exit', sub { return } );
+
+ my ( $userid, $cookie, $sessionID, $flags );
+ {
+ # checkauth will redirect and safe_exit if not authenticated and not authorized
+ local *STDOUT;
+ my $stdout;
+ open STDOUT, '>', \$stdout;
+ C4::Auth::checkauth($cgi, 0, {catalogue => 1});
+ like( $stdout, qr{\s*Log in to your account} );
+ $sessionID = ( $stdout =~ m{Set-Cookie: CGISESSID=((\d|\w)+);} ) ? $1 : undef;
+ ok($sessionID);
+ close STDOUT;
+ };
+
+ my $first_sessionID = $sessionID;
+
+ $ENV{"HTTP_COOKIE"} = "CGISESSID=$sessionID";
+ # Not authenticated yet, checkauth didn't return the session
+ {
+ local *STDOUT;
+ my $stdout;
+ open STDOUT, '>', \$stdout;
+ ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 0, {catalogue => 1} );
+ close STDOUT;
+ }
+ is( $sessionID, undef);
+ is( $userid, undef);
+
+ # Sending undefined fails obviously
+ my ( $auth_status, $session ) = C4::Auth::check_cookie_auth($sessionID, {catalogue => 1} );
+ is( $auth_status, 'failed' );
+ is( $session, undef );
+
+ # Simulating the login form submission
+ $cgi->param('userid', $patron->userid);
+ $cgi->param('password', $password);
+
+ # Logged in!
+ ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 0, {catalogue => 1});
+ is( $sessionID, $first_sessionID );
+ is( $userid, $patron->userid );
+
+ ( $auth_status, $session ) = C4::Auth::check_cookie_auth($sessionID, {catalogue => 1});
+ is( $auth_status, 'ok' );
+ is( $session->id, $first_sessionID );
+
+ # Logging out!
+ $cgi->param('logout.x', 1);
+ ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 0, {catalogue => 1});
+ is( $sessionID, undef );
+ is( $ENV{"HTTP_COOKIE"}, "CGISESSID=$first_sessionID", 'HTTP_COOKIE not unset' );
+ ( $auth_status, $session) = C4::Auth::check_cookie_auth( $first_sessionID, {catalogue => 1} );
+ is( $auth_status, "expired");
+ is( $session, undef );
+
+ {
+ # Trying to access without sessionID
+ $cgi = CGI->new;
+ ( $auth_status, $session) = C4::Auth::check_cookie_auth(undef, {catalogue => 1});
+ is( $auth_status, 'failed' );
+ is( $session, undef );
+
+ # This will fail on permissions
+ undef $ENV{"HTTP_COOKIE"};
+ {
+ local *STDOUT;
+ my $stdout;
+ open STDOUT, '>', \$stdout;
+ ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 0, {catalogue => 1} );
+ close STDOUT;
+ }
+ is( $userid, undef );
+ is( $sessionID, undef );
+ }
+
+ {
+ # First logging in
+ $cgi = CGI->new;
+ $cgi->param('userid', $patron->userid);
+ $cgi->param('password', $password);
+ ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 0, {catalogue => 1});
+ is( $userid, $patron->userid );
+ $first_sessionID = $sessionID;
+
+ # Patron does not have the borrowers permission
+ # $ENV{"HTTP_COOKIE"} = "CGISESSID=$sessionID"; # not needed, we use $cgi here
+ {
+ local *STDOUT;
+ my $stdout;
+ open STDOUT, '>', \$stdout;
+ ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 0, {borrowers => 1} );
+ close STDOUT;
+ }
+ is( $userid, undef );
+ is( $sessionID, undef );
+
+ # When calling check_cookie_auth, the session will be deleted
+ ( $auth_status, $session) = C4::Auth::check_cookie_auth( $first_sessionID, { borrowers => 1 } );
+ is( $auth_status, "failed" );
+ is( $session, undef );
+ ( $auth_status, $session) = C4::Auth::check_cookie_auth( $first_sessionID, { borrowers => 1 } );
+ is( $auth_status, 'expired', 'Session no longer exists' );
+
+ # NOTE: It is not what the UI is doing.
+ # From the UI we are allowed to hit an unauthorized page then reuse the session to hit back authorized area.
+ # It is because check_cookie_auth is ALWAYS called from checkauth WITHOUT $flagsrequired
+ # It then return "ok", when the previous called got "failed"
+
+ # Try reusing the deleted session: since it does not exist, we should get a new one now when passing correct permissions
+ $cgi->cookie( -name => 'CGISESSID', value => $first_sessionID );
+ ( $userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 0, {catalogue => 1});
+ is( $userid, $patron->userid );
+ isnt( $sessionID, undef, 'Check if we have a sessionID' );
+ isnt( $sessionID, $first_sessionID, 'New value expected' );
+ ( $auth_status, $session) = C4::Auth::check_cookie_auth( $sessionID, {catalogue => 1} );
+ is( $auth_status, "ok" );
+ is( $session->id, $sessionID, 'Same session' );
+ # Two additional tests on userenv
+ is( $C4::Context::context->{activeuser}, $session->id, 'Check if environment has been setup for session' );
+ is( C4::Context->userenv->{id}, $userid, 'Check userid in userenv' );
+ }
+};
+
+subtest 'Userenv clearing in check_cookie_auth' => sub {
+ # Note: We did already test userenv for a logged-in user in previous subtest
+ plan tests => 9;
+
+ t::lib::Mocks::mock_preference( 'timeout', 600 );
+ my $cgi = CGI->new;
+
+ # Create a new anonymous session by passing a fake session ID
+ $cgi->cookie( -name => 'CGISESSID', -value => 'fake_sessionID' );
+ my ($userid, $cookie, $sessionID, $flags ) = C4::Auth::checkauth($cgi, 1);
+ my ( $auth_status, $session) = C4::Auth::check_cookie_auth( $sessionID );
+ is( $auth_status, 'anon', 'Should be anonymous' );
+ is( $C4::Context::context->{activeuser}, $session->id, 'Check activeuser' );
+ is( defined C4::Context->userenv, 1, 'There should be a userenv' );
+ is( C4::Context->userenv->{id}, q{}, 'userid should be empty string' );
+
+ # Make the session expire now, check_cookie_auth will delete it
+ $session->param('lasttime', time() - 1200 );
+ $session->flush;
+ ( $auth_status, $session) = C4::Auth::check_cookie_auth( $sessionID );
+ is( $auth_status, 'expired', 'Should be expired' );
+ is( C4::Context->userenv, undef, 'Environment should be cleared too' );
+
+ # Show that we clear the userenv again: set up env and check deleted session
+ C4::Context->_new_userenv( $sessionID );
+ C4::Context->set_userenv; # empty
+ is( defined C4::Context->userenv, 1, 'There should be an empty userenv again' );
+ ( $auth_status, $session) = C4::Auth::check_cookie_auth( $sessionID );
+ is( $auth_status, 'expired', 'Should be expired already' );
+ is( C4::Context->userenv, undef, 'Environment should be cleared again' );
+};
+
$schema->storage->txn_rollback;
diff --git a/t/db_dependent/selenium/authentication.t b/t/db_dependent/selenium/authentication.t
index 591fb09d07..25dc8ed324 100755
--- a/t/db_dependent/selenium/authentication.t
+++ b/t/db_dependent/selenium/authentication.t
@@ -3,7 +3,7 @@
# This file is part of Koha.
#
# Copyright (C) 2017 Catalyst IT
-# Copyright 2018 Koha Development team
+# Copyright 2021 Koha Development team
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ SKIP: {
my $driver = $s->driver;
subtest 'Staff interface authentication' => sub {
- plan tests => 5;
+ plan tests => 6;
my $mainpage = $s->base_url . q|mainpage.pl|;
$driver->get($mainpage);
like( $driver->get_title, qr(Log in to Koha), 'Hitting the main page should redirect to the login form');
@@ -68,11 +68,74 @@ SKIP: {
$s->auth( $patron->userid, $password );
like( $driver->get_title, qr(Koha staff interface), 'Patron with flags superlibrarian should be able to login' );
+ subtest 'not authorized' => sub {
+ plan tests => 17;
+
+ # First, logout!
+ $driver->get($mainpage . q|?logout.x=1|);
+ $patron->flags(4)->store; # Patron has only catalogue permission
+ like( $driver->get_title, qr(Log in to Koha), 'Patron should hit the login form after logout' );
+ # Login!
+ $s->fill_form({ userid => $patron->userid, password => $password });
+ $s->driver->find_element('//input[@id="submit-button"]')->click;
+
+ my $cookie = $driver->get_cookie_named('CGISESSID');
+ my $first_sessionID = $cookie->{value};
+
+ # Patron is logged in and got a CGISESSID cookie, miam
+ like( $driver->get_title, qr(Koha staff interface), 'Patron is logged in' );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, 'no new session after login, the session has been upgraded' );
+
+ # Authorized page can be accessed, cookie does not change
+ $driver->get( $s->base_url . q|catalogue/search.pl| );
+ like( $driver->get_title, qr(Advanced search), 'Patron can access advanced search' );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, 'no new session after hit' );
+
+ # Unauthorized page redirect to the login form
+ $driver->get( $s->base_url . q|circ/circulation.pl| );
+ like( $driver->get_title, qr(Access denied), 'Patron cannot access the circulation module' );
+ # But the patron does not lose the CGISESSID cookie!
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, 'no new session if unauthorized page is hit' );
+
+ # Luckily mainpage can still be accessed
+ $s->click( { id => 'mainpage', main_class => 'main container-fluid' } );
+ like( $driver->get_title, qr(Koha staff interface), 'Patron can come back to the mainpage' );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, 'no new session if back to the mainpage' );
+
+ # As well as the search
+ $driver->get( $s->base_url . q|catalogue/search.pl| );
+ like( $driver->get_title, qr(Advanced search), 'Patron can access advanced search' );
+ # But circulation module is prohibided!
+ $driver->get( $s->base_url . q|circ/circulation.pl| );
+ like( $driver->get_title, qr(Access denied), 'Patron cannot access the circulation module' );
+ # Still can reuse the same cookie
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, 'no new session if unauthorized page is hit' );
+
+ # This is the "previous page" using the back() JS
+ $s->click( { id => 'previous_page', main_class => 'main container-fluid' } );
+ like( $driver->get_title, qr(Advanced search), 'Patron can come back to the previous page' );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, 'no new session if back to the previous page' );
+
+ # Check with a script that is using check_cookie_auth, session must not be deleted!
+ $driver->get( $s->base_url . q|svc/checkouts| );
+ #FIXME - 500 is the current behaviour, but it's not nice. It could be improved.
+ like( $driver->get_title, qr(Error 500), 'Patron cannot access svc script where circulate permissions are required');
+ $driver->get( $s->base_url . q|catalogue/search.pl| );
+ like( $driver->get_title, qr(Advanced search), 'Patron can reuse the cookie after a script that used check_cookie_auth' );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, 'no new session if unauthorized page is hit' );
+ };
push @data_to_cleanup, $patron, $patron->category, $patron->library;
};
subtest 'OPAC interface authentication' => sub {
- plan tests => 6;
+ plan tests => 7;
my $mainpage = $s->opac_base_url . q|opac-main.pl|;
@@ -149,6 +212,67 @@ SKIP: {
$driver->find_element('//a[@id="logout"]')->click;
$driver->find_element('//div[@id="login"]'); # logged out
+ subtest 'not authorized' => sub {
+ plan tests => 13;
+
+ $driver->get($mainpage . q|?logout.x=1|);
+ $driver->get($mainpage);
+ my $cookie = $driver->get_cookie_named('CGISESSID');
+ my $first_sessionID = $cookie->{value};
+
+ # User is not logged in, navigation does not generate a new cookie
+ $driver->get( $s->opac_base_url . q|opac-search.pl| );
+ like( $driver->get_title, qr(Advanced search) );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, );
+
+ # Login
+ $driver->get($mainpage);
+ $s->fill_form( { userid => $patron->userid, password => $password } );
+ $s->submit_form;
+
+ # After logged in, the same cookie is reused
+ like( $driver->get_title, qr(Your library home) );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, );
+ $driver->get( $s->opac_base_url . q|opac-search.pl| );
+ like( $driver->get_title, qr(Advanced search) );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, );
+
+ # Logged in user can place holds
+ $driver->get( $s->opac_base_url . q|opac-reserve.pl| ); # We may need to pass a biblionumber here in the future
+ like( $driver->get_title, qr(Placing a hold) );
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, );
+
+ $driver->get($mainpage . q|?logout.x=1|);
+
+ # FIXME This new get should not be needed, but the cookie is not modified right after logout
+ # However it's not the behaviour when testing the UI
+ $driver->get($mainpage);
+
+ # After logout a new cookie is generated, the previous session has been deleted
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ isnt( $cookie->{value}, $first_sessionID, );
+ $first_sessionID = $cookie->{value};
+
+ $driver->get( $s->opac_base_url . q|svc/checkout_notes| );
+ #FIXME - 500 is the current behaviour, but it's not nice. It could be improved.
+ like( $driver->get_title, qr(An error has occurred), 'Patron cannot access svc');
+ # No new cookie generated
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, );
+
+ $driver->get( $s->opac_base_url . q|opac-reserve.pl| );
+ like( $driver->get_title, qr(Log in to your account) );
+
+ # Still no new cookie generated
+ $driver->get($mainpage);
+ $cookie = $driver->get_cookie_named('CGISESSID');
+ is( $cookie->{value}, $first_sessionID, );
+ };
+
push @data_to_cleanup, $patron, $patron->category, $patron->library;
};