use strict;
use warnings;
-use Carp qw/croak/;
+use Carp qw( croak );
-use Digest::MD5 qw(md5_base64);
-use JSON qw/encode_json/;
-use URI::Escape;
+use Digest::MD5 qw( md5_base64 );
use CGI::Session;
+use CGI::Session::ErrorHandler;
+use URI;
+use URI::QueryParam;
-require Exporter;
use C4::Context;
use C4::Templates; # to get the template
use C4::Languages;
use C4::Search::History;
use Koha;
+use Koha::Logger;
use Koha::Caches;
-use Koha::AuthUtils qw(get_script_name hash_password);
+use Koha::AuthUtils qw( get_script_name hash_password );
+use Koha::Auth::TwoFactorAuth;
use Koha::Checkouts;
-use Koha::DateUtils qw(dt_from_string);
+use Koha::DateUtils qw( dt_from_string );
use Koha::Library::Groups;
use Koha::Libraries;
+use Koha::Cash::Registers;
use Koha::Desks;
use Koha::Patrons;
use Koha::Patron::Consents;
-use POSIX qw/strftime/;
-use List::MoreUtils qw/ any /;
-use Encode qw( encode is_utf8);
-use C4::Auth_with_shibboleth;
+use List::MoreUtils qw( any );
+use Encode;
+use C4::Auth_with_shibboleth qw( shib_ok get_login_shib login_shib_url logout_shib checkpw_shib );
use Net::CIDR;
-use C4::Log qw/logaction/;
+use C4::Log qw( logaction );
+use Koha::CookieManager;
# use utf8;
-use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout);
+use vars qw($ldap $cas $caslogout);
+our (@ISA, @EXPORT_OK);
BEGIN {
sub psgi_env { any { /^psgi\./ } keys %ENV }
C4::Context->set_remote_address;
- $debug = $ENV{DEBUG};
- @ISA = qw(Exporter);
- @EXPORT = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions);
- @EXPORT_OK = qw(&check_api_auth &get_session &check_cookie_auth &checkpw &checkpw_internal &checkpw_hash
- &get_all_subpermissions &get_user_subpermissions track_login_daily &in_iprange
+ require Exporter;
+ @ISA = qw(Exporter);
+
+ @EXPORT_OK = qw(
+ checkauth check_api_auth get_session check_cookie_auth checkpw checkpw_internal checkpw_hash
+ get_all_subpermissions get_user_subpermissions track_login_daily in_iprange
+ get_template_and_user haspermission
);
- %EXPORT_TAGS = ( EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)] );
+
$ldap = C4::Context->config('useldapserver') || 0;
$cas = C4::Context->preference('casAuthentication');
$caslogout = C4::Context->preference('casLogout');
- require C4::Auth_with_cas; # no import
if ($ldap) {
require C4::Auth_with_ldap;
import C4::Auth_with_ldap qw(checkpw_ldap);
}
if ($cas) {
- import C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url logout_if_required);
+ require C4::Auth_with_cas; # no import
+ import C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url logout_if_required multipleAuth getMultipleAuth);
}
}
use C4::Auth;
use C4::Output;
- my $query = new CGI;
+ my $query = CGI->new;
my ($template, $borrowernumber, $cookie)
= get_template_and_user(
my $in = shift;
my ( $user, $cookie, $sessionID, $flags );
+ $cookie = [];
+
+ my $cookie_mgr = Koha::CookieManager->new;
# Get shibboleth login attribute
my $shib = C4::Context->config('useshibboleth') && shib_ok();
}
if ( $in->{type} eq 'opac' && $user ) {
+ my $is_sco_user;
+ if ($sessionID){
+ my $session = get_session($sessionID);
+ if ($session){
+ $is_sco_user = $session->param('sco_user');
+ }
+ }
my $kick_out;
if (
# If the user logged in is the SCO user and they try to go out of the SCO module,
# log the user out removing the CGISESSID cookie
$in->{template_name} !~ m|sco/| && $in->{template_name} !~ m|errors/errorpage.tt|
- && C4::Context->preference('AutoSelfCheckID')
- && $user eq C4::Context->preference('AutoSelfCheckID')
+ && (
+ $is_sco_user ||
+ (
+ C4::Context->preference('AutoSelfCheckID')
+ && $user eq C4::Context->preference('AutoSelfCheckID')
+ )
+ )
)
{
$kick_out = 1;
if ($kick_out) {
$template = C4::Templates::gettemplate( 'opac-auth.tt', 'opac',
$in->{query} );
- $cookie = $in->{query}->cookie(
+ $cookie = $cookie_mgr->replace_in_list( $cookie, $in->{query}->cookie(
-name => 'CGISESSID',
-value => '',
- -expires => '',
-HttpOnly => 1,
-secure => ( C4::Context->https_enabled() ? 1 : 0 ),
- );
+ -sameSite => 'Lax',
+ ));
$template->param(
loginprompt => 1,
my $some_private_shelves = Koha::Virtualshelves->get_some_shelves(
{
borrowernumber => $borrowernumber,
- category => 1,
+ public => 0,
}
);
my $some_public_shelves = Koha::Virtualshelves->get_some_shelves(
{
- category => 2,
+ public => 1,
}
);
$template->param(
$template->param( CAN_user_editcatalogue => 1 );
$template->param( CAN_user_updatecharges => 1 );
$template->param( CAN_user_acquisition => 1 );
+ $template->param( CAN_user_suggestions => 1 );
$template->param( CAN_user_tools => 1 );
$template->param( CAN_user_editauthorities => 1 );
$template->param( CAN_user_serials => 1 );
$template->param( CAN_user_reports => 1 );
$template->param( CAN_user_staffaccess => 1 );
- $template->param( CAN_user_plugins => 1 );
$template->param( CAN_user_coursereserves => 1 );
+ $template->param( CAN_user_plugins => 1 );
+ $template->param( CAN_user_lists => 1 );
$template->param( CAN_user_clubs => 1 );
$template->param( CAN_user_ill => 1 );
$template->param( CAN_user_stockrotation => 1 );
- $template->param( CAN_user_problem_reports => 1 );
+ $template->param( CAN_user_cash_management => 1 );
+ $template->param( CAN_user_problem_reports => 1 );
+ $template->param( CAN_user_recalls => 1 );
foreach my $module ( keys %$all_perms ) {
foreach my $subperm ( keys %{ $all_perms->{$module} } ) {
require Koha::Virtualshelves;
my $some_public_shelves = Koha::Virtualshelves->get_some_shelves(
{
- category => 2,
+ public => 1,
}
);
$template->param(
some_public_shelves => $some_public_shelves,
);
+
+ # Set default branch if one has been passed by the environment.
+ $template->param( default_branch => $ENV{OPAC_BRANCH_DEFAULT} ) if $ENV{OPAC_BRANCH_DEFAULT};
}
}
+ # Sysprefs disabled via URL param
+ # Note that value must be defined in order to override via ENV
+ foreach my $syspref (
+ qw(
+ OPACUserCSS
+ OPACUserJS
+ IntranetUserCSS
+ IntranetUserJS
+ OpacAdditionalStylesheet
+ opaclayoutstylesheet
+ intranetcolorstylesheet
+ intranetstylesheet
+ )
+ )
+ {
+ $ENV{"OVERRIDE_SYSPREF_$syspref"} = q{}
+ if $in->{'query'}->param("DISABLE_SYSPREF_$syspref");
+ }
+
# Anonymous opac search history
# If opac search history is enabled and at least one search has already been performed
if ( C4::Context->preference('EnableOpacSearchHistory') ) {
my $minPasswordLength = C4::Context->preference('minPasswordLength');
$minPasswordLength = 3 if not $minPasswordLength or $minPasswordLength < 3;
$template->param(
- "BiblioDefaultView" . C4::Context->preference("BiblioDefaultView") => 1,
EnhancedMessagingPreferences => C4::Context->preference('EnhancedMessagingPreferences'),
GoogleJackets => C4::Context->preference("GoogleJackets"),
OpenLibraryCovers => C4::Context->preference("OpenLibraryCovers"),
item_level_itypes => C4::Context->preference('item-level_itypes'),
patronimages => C4::Context->preference("patronimages"),
singleBranchMode => ( Koha::Libraries->search->count == 1 ),
- XSLTDetailsDisplay => C4::Context->preference("XSLTDetailsDisplay"),
- XSLTResultsDisplay => C4::Context->preference("XSLTResultsDisplay"),
noItemTypeImages => C4::Context->preference("noItemTypeImages"),
marcflavour => C4::Context->preference("marcflavour"),
OPACBaseURL => C4::Context->preference('OPACBaseURL'),
$template->param(
AmazonCoverImages => C4::Context->preference("AmazonCoverImages"),
AutoLocation => C4::Context->preference("AutoLocation"),
- "BiblioDefaultView" . C4::Context->preference("IntranetBiblioDefaultView") => 1,
PatronAutoComplete => C4::Context->preference("PatronAutoComplete"),
FRBRizeEditions => C4::Context->preference("FRBRizeEditions"),
IndependentBranches => C4::Context->preference("IndependentBranches"),
intranetstylesheet => C4::Context->preference("intranetstylesheet"),
IntranetUserCSS => C4::Context->preference("IntranetUserCSS"),
IntranetUserJS => C4::Context->preference("IntranetUserJS"),
- intranetbookbag => C4::Context->preference("intranetbookbag"),
suggestion => C4::Context->preference("suggestion"),
virtualshelves => C4::Context->preference("virtualshelves"),
StaffSerialIssueDisplayCount => C4::Context->preference("StaffSerialIssueDisplayCount"),
EnableBorrowerFiles => C4::Context->preference('EnableBorrowerFiles'),
UseCourseReserves => C4::Context->preference("UseCourseReserves"),
useDischarge => C4::Context->preference('useDischarge'),
- pending_checkout_notes => scalar Koha::Checkouts->search({ noteseen => 0 }),
+ pending_checkout_notes => Koha::Checkouts->search({ noteseen => 0 }),
);
}
else {
&& $in->{'template_name'} =~ /opac-(.+)\.(?:tt|tmpl)$/ ) {
my $pagename = $1;
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;
}
}
if (
( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /branch:([\w-]+)/ ) ||
( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /branch:([\w-]+)/ ) ||
- ( $in->{'query'}->param('multibranchlimit') && $in->{'query'}->param('multibranchlimit') =~ /multibranchlimit-(\w+)/ )
+ ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /multibranchlimit:(\w+)/ )
) {
$opac_name = $1; # opac_search_limit is a branch, so we use it.
} elsif ( $in->{'query'}->param('multibranchlimit') ) {
$opac_name = C4::Context->userenv->{'branch'};
}
- my @search_groups = Koha::Library::Groups->get_search_groups({ interface => 'opac' });
+ my @search_groups = Koha::Library::Groups->get_search_groups({ interface => 'opac' })->as_list;
$template->param(
AnonSuggestions => "" . C4::Context->preference("AnonSuggestions"),
LibrarySearchGroups => \@search_groups,
OpacBrowser => C4::Context->preference("OpacBrowser"),
OpacCloud => C4::Context->preference("OpacCloud"),
OpacKohaUrl => C4::Context->preference("OpacKohaUrl"),
- OpacNav => "" . C4::Context->preference("OpacNav"),
- OpacNavBottom => "" . C4::Context->preference("OpacNavBottom"),
OpacPasswordChange => C4::Context->preference("OpacPasswordChange"),
OPACPatronDetails => C4::Context->preference("OPACPatronDetails"),
OPACPrivacy => C4::Context->preference("OPACPrivacy"),
OPACFinesTab => C4::Context->preference("OPACFinesTab"),
OpacTopissue => C4::Context->preference("OpacTopissue"),
- RequestOnOpac => C4::Context->preference("RequestOnOpac"),
'Version' => C4::Context->preference('Version'),
hidelostitems => C4::Context->preference("hidelostitems"),
mylibraryfirst => ( C4::Context->preference("SearchMyLibraryFirst") && C4::Context->userenv ) ? C4::Context->userenv->{'branch'} : '',
suggestion => "" . C4::Context->preference("suggestion"),
virtualshelves => "" . C4::Context->preference("virtualshelves"),
OPACSerialIssueDisplayCount => C4::Context->preference("OPACSerialIssueDisplayCount"),
- OPACXSLTDetailsDisplay => C4::Context->preference("OPACXSLTDetailsDisplay"),
- OPACXSLTResultsDisplay => C4::Context->preference("OPACXSLTResultsDisplay"),
SyndeticsClientCode => C4::Context->preference("SyndeticsClientCode"),
SyndeticsEnabled => C4::Context->preference("SyndeticsEnabled"),
SyndeticsCoverImages => C4::Context->preference("SyndeticsCoverImages"),
# what to do
my $language = C4::Languages::getlanguage( $in->{'query'} );
my $languagecookie = C4::Templates::getlanguagecookie( $in->{'query'}, $language );
- if ( ref $cookie eq 'ARRAY' ) {
- push @{$cookie}, $languagecookie;
- } else {
- $cookie = [ $cookie, $languagecookie ];
- }
+ $cookie = $cookie_mgr->replace_in_list( $cookie, $languagecookie );
}
return ( $template, $borrowernumber, $cookie, $flags );
# remove the 3 last . to have a Perl number
$kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
- $debug and print STDERR "kohaversion : $kohaversion\n";
+ Koha::Logger->get->debug("kohaversion : $kohaversion");
if ( $version < $kohaversion ) {
my $warning = "Database update needed, redirecting to %s. Database is $version and Koha is $kohaversion";
if ( $type ne 'opac' ) {
}
}
-sub _session_log {
- (@_) or return 0;
- open my $fh, '>>', "/tmp/sessionlog" or warn "ERROR: Cannot append to /tmp/sessionlog";
- printf $fh join( "\n", @_ );
- close $fh;
-}
-
sub _timeout_syspref {
- my $timeout = C4::Context->preference('timeout') || 600;
+ my $default_timeout = 600;
+ my $timeout = C4::Context->preference('timeout') || $default_timeout;
# value in days, convert in seconds
- if ( $timeout =~ /(\d+)[dD]/ ) {
+ if ( $timeout =~ /^(\d+)[dD]$/ ) {
$timeout = $1 * 86400;
}
+ # value in hours, convert in seconds
+ elsif ( $timeout =~ /^(\d+)[hH]$/ ) {
+ $timeout = $1 * 3600;
+ }
+ elsif ( $timeout !~ m/^\d+$/ ) {
+ warn "The value of the system preference 'timeout' is not correct, defaulting to $default_timeout";
+ $timeout = $default_timeout;
+ }
+
return $timeout;
}
sub checkauth {
my $query = shift;
- $debug and warn "Checking Auth";
# Get shibboleth login attribute
my $shib = C4::Context->config('useshibboleth') && shib_ok();
opac-registration-confirmation.tt
opac-memberentry-update-submitted.tt
opac-password-recovery.tt
+ opac-reset-password.tt
);
$authnotrequired = 0 unless grep { $_ eq $template_name }
@allowed_scripts_for_private_opac;
my $dbh = C4::Context->dbh;
my $timeout = _timeout_syspref();
+ my $cookie_mgr = Koha::CookieManager->new;
+
_version_check( $type, $query );
# state variables
my $loggedin = 0;
+ my $auth_state = 'failed';
my %info;
my ( $userid, $cookie, $sessionID, $flags );
+ $cookie = [];
my $logout = $query->param('logout.x');
my $anon_search_history;
my $q_userid = $query->param('userid') // '';
my $session;
+ my $invalid_otp_token;
+ my $require_2FA = ( C4::Context->preference('TwoFactorAuthentication') && $type ne "OPAC" ) ? 1 : 0;
# Basic authentication is incompatible with the use of Shibboleth,
# as Shibboleth may return REMOTE_USER as a Shibboleth attribute,
if ( !$shib and defined( $ENV{'REMOTE_USER'} ) and $ENV{'REMOTE_USER'} ne '' and $userid = $ENV{'REMOTE_USER'} ) {
# Using Basic Authentication, no cookies required
- $cookie = $query->cookie(
+ $cookie = $cookie_mgr->replace_in_list( $cookie, $query->cookie(
-name => 'CGISESSID',
-value => '',
- -expires => '',
-HttpOnly => 1,
-secure => ( C4::Context->https_enabled() ? 1 : 0 ),
- );
+ -sameSite => 'Lax',
+ ));
$loggedin = 1;
}
elsif ( $emailaddress) {
# the Google OpenID Connect passes an email address
}
- elsif ( $sessionID = $query->cookie("CGISESSID") )
- { # assignment, not comparison
- $session = get_session($sessionID);
- C4::Context->_new_userenv($sessionID);
- my ( $ip, $lasttime, $sessiontype );
- my $s_userid = '';
- if ($session) {
- $s_userid = $session->param('id') // '';
- C4::Context->set_userenv(
- $session->param('number'), $s_userid,
- $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')
- );
- C4::Context::set_shelves_userenv( 'bar', $session->param('barshelves') );
- C4::Context::set_shelves_userenv( 'pub', $session->param('pubshelves') );
- C4::Context::set_shelves_userenv( 'tot', $session->param('totshelves') );
- $debug and printf STDERR "AUTH_SESSION: (%s)\t%s %s - %s\n", map { $session->param($_) } qw(cardnumber firstname surname branch);
- $ip = $session->param('ip');
- $lasttime = $session->param('lasttime');
- $userid = $s_userid;
- $sessiontype = $session->param('sessiontype') || '';
- }
- if ( ( $query->param('koha_login_context') && ( $q_userid ne $s_userid ) )
- || ( $cas && $query->param('ticket') && !C4::Context->userenv->{'id'} )
- || ( $shib && $shib_login && !$logout && !C4::Context->userenv->{'id'} )
- ) {
-
- #if a user enters an id ne to the id in the current session, we need to log them in...
- #first we need to clear the anonymous session...
- $debug and warn "query id = $q_userid but session id = $s_userid";
- $anon_search_history = $session->param('search_history');
- $session->delete();
- $session->flush;
- C4::Context->_unset_userenv($sessionID);
- $sessionID = undef;
- $userid = undef;
- }
- elsif ($logout) {
+ 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 }
+ );
- # voluntary logout the user
- # check wether the user was using their shibboleth session or a local one
- my $shibSuccess = C4::Context->userenv->{'shibboleth'};
- $session->delete();
- $session->flush;
- C4::Context->_unset_userenv($sessionID);
+ if ( $return eq 'ok' || $return eq 'additional-auth-needed' ) {
+ $userid = $session->param('id');
+ }
- #_session_log(sprintf "%20s from %16s logged out at %30s (manually).\n", $userid,$ip,(strftime "%c",localtime));
- $sessionID = undef;
- $userid = undef;
+ $auth_state =
+ $return eq 'ok' ? 'completed'
+ : $return eq 'additional-auth-needed' ? 'additional-auth-needed'
+ : 'failed';
- if ($cas and $caslogout) {
- logout_cas($query, $type);
+ # We are at the second screen if the waiting-for-2FA is set in session
+ # and otp_token param has been passed
+ if ( $require_2FA
+ && $auth_state eq 'additional-auth-needed'
+ && ( my $otp_token = $query->param('otp_token') ) )
+ {
+ my $patron = Koha::Patrons->find( { userid => $userid } );
+ my $auth = Koha::Auth::TwoFactorAuth->new( { patron => $patron } );
+ my $verified = $auth->verify($otp_token, 1);
+ $auth->clear;
+ if ( $verified ) {
+ # The token is correct, the user is fully logged in!
+ $auth_state = 'completed';
+ $session->param( 'waiting-for-2FA', 0 );
+
+ # This is an ugly trick to pass the test
+ # $query->param('koha_login_context') && ( $q_userid ne $userid )
+ # few lines later
+ $q_userid = $userid;
}
-
- # If we are in a shibboleth session (shibboleth is enabled, a shibboleth match attribute is set and matches koha matchpoint)
- if ( $shib and $shib_login and $shibSuccess) {
- logout_shib($query);
+ else {
+ $invalid_otp_token = 1;
}
}
- elsif ( !$lasttime || ( $lasttime < time() - $timeout ) ) {
- # timed logout
- $info{'timed_out'} = 1;
- if ($session) {
+ if ( $auth_state eq 'completed' ) {
+ Koha::Logger->get->debug(sprintf "AUTH_SESSION: (%s)\t%s %s - %s", map { $session->param($_) || q{} } qw(cardnumber firstname surname branch));
+
+ if ( ( $query->param('koha_login_context') && ( $q_userid ne $userid ) )
+ || ( $cas && $query->param('ticket') && !C4::Context->userenv->{'id'} )
+ || ( $shib && $shib_login && !$logout && !C4::Context->userenv->{'id'} )
+ ) {
+
+ #if a user enters an id ne to the id in the current session, we need to log them in...
+ #first we need to clear the anonymous session...
+ $anon_search_history = $session->param('search_history');
$session->delete();
$session->flush;
- }
- C4::Context->_unset_userenv($sessionID);
+ $cookie = $cookie_mgr->clear_unless( $query->cookie, @$cookie );
+ C4::Context::_unset_userenv($sessionID);
+ $sessionID = undef;
+ } elsif (!$logout) {
- #_session_log(sprintf "%20s from %16s logged out at %30s (inactivity).\n", $userid,$ip,(strftime "%c",localtime));
- $userid = undef;
- $sessionID = undef;
+ $cookie = $cookie_mgr->replace_in_list( $cookie, $query->cookie(
+ -name => 'CGISESSID',
+ -value => $session->id,
+ -HttpOnly => 1,
+ -secure => ( C4::Context->https_enabled() ? 1 : 0 ),
+ -sameSite => 'Lax',
+ ));
+
+ $flags = haspermission( $userid, $flagsrequired );
+ unless ( $flags ) {
+ $auth_state = 'failed';
+ $info{'nopermission'} = 1;
+ }
+ }
+ } elsif ( !$logout ) {
+ if ( $return eq 'expired' ) {
+ $info{timed_out} = 1;
+ } elsif ( $return eq 'restricted' ) {
+ $info{oldip} = $more_info->{old_ip};
+ $info{newip} = $more_info->{new_ip};
+ $info{different_ip} = 1;
+ } elsif ( $return eq 'password_expired' ) {
+ $info{password_has_expired} = 1;
+ }
}
- elsif ( C4::Context->preference('SessionRestrictionByIP') && $ip ne $ENV{'REMOTE_ADDR'} ) {
+ }
+
+ if ( $auth_state eq 'failed' || $logout ) {
+ $sessionID = undef;
+ $userid = undef;
+ }
+
+ if ($logout) {
- # Different ip than originally logged in from
- $info{'oldip'} = $ip;
- $info{'newip'} = $ENV{'REMOTE_ADDR'};
- $info{'different_ip'} = 1;
+ # voluntary logout the user
+ # check wether the user was using their shibboleth session or a local one
+ my $shibSuccess = C4::Context->userenv->{'shibboleth'};
+ if ( $session ) {
$session->delete();
$session->flush;
- C4::Context->_unset_userenv($sessionID);
+ }
+ C4::Context::_unset_userenv($sessionID);
+ $cookie = $cookie_mgr->clear_unless( $query->cookie, @$cookie );
- #_session_log(sprintf "%20s from %16s logged out at %30s (ip changed to %16s).\n", $userid,$ip,(strftime "%c",localtime), $info{'newip'});
- $sessionID = undef;
- $userid = undef;
+ if ($cas and $caslogout) {
+ logout_cas($query, $type);
}
- else {
- $cookie = $query->cookie(
- -name => 'CGISESSID',
- -value => $session->id,
- -HttpOnly => 1,
- -secure => ( C4::Context->https_enabled() ? 1 : 0 ),
- );
- $session->param( 'lasttime', time() );
- 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;
- }
- }
+
+ # If we are in a shibboleth session (shibboleth is enabled, a shibboleth match attribute is set and matches koha matchpoint)
+ if ( $shib and $shib_login and $shibSuccess) {
+ logout_shib($query);
}
+
+ $session = undef;
+ $auth_state = 'logout';
}
- unless ( $userid || $sessionID ) {
+
+ 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()";
+ if( !$session or !$sessionID ) { # if we cleared sessionID, we need a new 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
$sessionID = $session->id;
C4::Context->_new_userenv($sessionID);
- $cookie = $query->cookie(
+ $cookie = $cookie_mgr->replace_in_list( $cookie, $query->cookie(
-name => 'CGISESSID',
- -value => $session->id,
+ -value => $sessionID,
-HttpOnly => 1,
-secure => ( C4::Context->https_enabled() ? 1 : 0 ),
- );
+ -sameSite => 'Lax',
+ ));
my $pki_field = C4::Context->preference('AllowPKIAuth');
if ( !defined($pki_field) ) {
print STDERR "ERROR: Missing system preference AllowPKIAuth.\n";
}
else {
my $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);
+ my $request_method = $query->request_method();
+
+ if (
+ $request_method eq 'POST'
+ || ( C4::Context->preference('AutoSelfCheckID')
+ && $q_userid eq C4::Context->preference('AutoSelfCheckID') )
+ )
+ {
+
+ ( $return, $cardnumber, $retuserid, $cas_ticket ) =
+ checkpw( $dbh, $q_userid, $password, $query, $type );
+ $userid = $retuserid if ($retuserid);
+ $info{'invalid_username_or_password'} = 1 unless ($return);
+ }
}
}
+ # If shib configured and shibOnly enabled, we should ignore anything other than a shibboleth type login.
+ if (
+ $shib
+ && !$shibSuccess
+ && (
+ (
+ ( $type eq 'opac' )
+ && C4::Context->preference('OPACShibOnly')
+ )
+ || ( ( $type ne 'opac' )
+ && C4::Context->preference('staffShibOnly') )
+ )
+ )
+ {
+ $return = 0;
+ }
+
# $return: 1 = valid user
- if ($return) {
+ if ($return > 0) {
- #_session_log(sprintf "%20s from %16s logged in at %30s.\n", $userid,$ENV{'REMOTE_ADDR'},(strftime '%c', localtime));
if ( $flags = haspermission( $userid, $flagsrequired ) ) {
- $loggedin = 1;
+ $auth_state = "logged_in";
}
else {
$info{'nopermission'} = 1;
- C4::Context->_unset_userenv($sessionID);
+ C4::Context::_unset_userenv($sessionID);
}
my ( $borrowernumber, $firstname, $surname, $userflags,
- $branchcode, $branchname, $emailaddress, $desk_id, $desk_name );
+ $branchcode, $branchname, $emailaddress, $desk_id,
+ $desk_name, $register_id, $register_name );
if ( $return == 1 ) {
my $select = "
my $sth = $dbh->prepare("$select where userid=?");
$sth->execute($userid);
unless ( $sth->rows ) {
- $debug and print STDERR "AUTH_1: no rows for userid='$userid'\n";
$sth = $dbh->prepare("$select where cardnumber=?");
$sth->execute($cardnumber);
unless ( $sth->rows ) {
- $debug and print STDERR "AUTH_2a: no rows for cardnumber='$cardnumber'\n";
$sth->execute($userid);
- unless ( $sth->rows ) {
- $debug and print STDERR "AUTH_2b: no rows for userid='$userid' AS cardnumber\n";
- }
}
}
if ( $sth->rows ) {
( $borrowernumber, $firstname, $surname, $userflags,
$branchcode, $branchname, $emailaddress ) = $sth->fetchrow;
- $debug and print STDERR "AUTH_3 results: " .
- "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress\n";
- } else {
- print STDERR "AUTH_3: no results for userid='$userid', cardnumber='$cardnumber'.\n";
}
# launch a sequence to check if we have a ip for the branch, i
my $desk = Koha::Desks->find($desk_id);
$desk_name = $desk ? $desk->desk_name : '';
}
- my $branches = { map { $_->branchcode => $_->unblessed } Koha::Libraries->search };
- if ( $type ne 'opac' and C4::Context->boolean_preference('AutoLocation') ) {
+ if ( C4::Context->preference('UseCashRegisters') ) {
+ my $register =
+ $query->param('register_id')
+ ? Koha::Cash::Registers->find($query->param('register_id'))
+ : Koha::Cash::Registers->search(
+ { branch => $branchcode, branch_default => 1 },
+ { rows => 1 } )->single;
+ $register_id = $register->id if ($register);
+ $register_name = $register->name if ($register);
+ }
+ my $branches = { map { $_->branchcode => $_->unblessed } Koha::Libraries->search->as_list };
+ if ( $type ne 'opac' and C4::Context->preference('AutoLocation') ) {
# we have to check they are coming from the right ip range
my $domain = $branches->{$branchcode}->{'branchip'};
$domain =~ s|\.\*||g;
if ( $ip !~ /^$domain/ ) {
$loggedin = 0;
- $cookie = $query->cookie(
+ $cookie = $cookie_mgr->replace_in_list( $cookie, $query->cookie(
-name => 'CGISESSID',
-value => '',
-HttpOnly => 1,
-secure => ( C4::Context->https_enabled() ? 1 : 0 ),
- );
+ -sameSite => 'Lax',
+ ));
$info{'wrongip'} = 1;
}
}
$branchname = $branches->{$br}->{'branchname'};
}
}
+
+ my $is_sco_user = 0;
+ if ( $query->param('sco_user_login') && ( $query->param('sco_user_login') eq '1' ) ){
+ $is_sco_user = 1;
+ }
+
$session->param( 'number', $borrowernumber );
$session->param( 'id', $userid );
$session->param( 'cardnumber', $cardnumber );
$session->param( 'lasttime', time() );
$session->param( 'interface', $type);
$session->param( 'shibboleth', $shibSuccess );
- $debug and printf STDERR "AUTH_4: (%s)\t%s %s - %s\n", map { $session->param($_) } qw(cardnumber firstname surname branch);
+ $session->param( 'register_id', $register_id );
+ $session->param( 'register_name', $register_name );
+ $session->param( 'sco_user', $is_sco_user );
}
$session->param('cas_ticket', $cas_ticket) if $cas_ticket;
C4::Context->set_userenv(
$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('desk_id'), $session->param('desk_name'),
+ $session->param('register_id'), $session->param('register_name')
);
}
# $return: 0 = invalid user
# reset to anonymous session
else {
- $debug and warn "Login failed, resetting anonymous session...";
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() );
} # END if ( $q_userid
elsif ( $type eq "opac" ) {
- # if we are here this is an anonymous session; add public lists to it and a few other items...
# anonymous sessions are created only for the OPAC
- $debug and warn "Initiating an anonymous session...";
# setting a couple of other session vars...
$session->param( 'ip', $session->remote_addr() );
$session->param( 'sessiontype', 'anon' );
$session->param( 'interface', $type);
}
+ $session->flush;
} # END unless ($userid)
+
+ if ( $auth_state eq 'logged_in' ) {
+ $auth_state = 'completed';
+
+ # Auth is completed unless an additional auth is needed
+ if ( $require_2FA ) {
+ my $patron = Koha::Patrons->find({userid => $userid});
+ if ( $patron->auth_method eq 'two-factor' ) {
+ # Ask for the OTP token
+ $auth_state = 'additional-auth-needed';
+ $session->param('waiting-for-2FA', 1);
+ %info = ();# We remove the warnings/errors we may have set incorrectly before
+ }
+ }
+ }
+
# finished authentification, now respond
- if ( $loggedin || $authnotrequired )
- {
+ if ( $auth_state eq 'completed' || $authnotrequired ) {
# successful login
- unless ($cookie) {
- $cookie = $query->cookie(
+ unless (@$cookie) {
+ $cookie = $cookie_mgr->replace_in_list( $cookie, $query->cookie(
-name => 'CGISESSID',
-value => '',
-HttpOnly => 1,
-secure => ( C4::Context->https_enabled() ? 1 : 0 ),
- );
+ -sameSite => 'Lax',
+ ));
}
+ track_login_daily( $userid );
+
# In case, that this request was a login attempt, we want to prevent that users can repost the opac login
# request. We therefore redirect the user to the requested page again without the login parameters.
# See Post/Redirect/Get (PRG) design pattern: https://en.wikipedia.org/wiki/Post/Redirect/Get
exit;
}
- track_login_daily( $userid );
-
return ( $userid, $cookie, $sessionID, $flags );
}
#
#
+ my $patron = Koha::Patrons->find({ userid => $q_userid }); # Not necessary logged in!
+
# get the inputs from the incoming query
my @inputs = ();
+ my @inputs_to_clean = qw( userid password ticket logout.x otp_token );
foreach my $name ( param $query) {
- (next) if ( $name eq 'userid' || $name eq 'password' || $name eq 'ticket' );
+ next if grep { $name eq $_ } @inputs_to_clean;
my @value = $query->multi_param($name);
push @inputs, { name => $name, value => $_ } for @value;
}
- my $patron = Koha::Patrons->find({ userid => $q_userid }); # Not necessary logged in!
-
my $LibraryNameTitle = C4::Context->preference("LibraryName");
$LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi;
$LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg;
script_name => get_script_name(),
casAuthentication => C4::Context->preference("casAuthentication"),
shibbolethAuthentication => $shib,
- SessionRestrictionByIP => C4::Context->preference("SessionRestrictionByIP"),
suggestion => C4::Context->preference("suggestion"),
virtualshelves => C4::Context->preference("virtualshelves"),
LibraryName => "" . C4::Context->preference("LibraryName"),
LibraryNameTitle => "" . $LibraryNameTitle,
opacuserlogin => C4::Context->preference("opacuserlogin"),
- OpacNav => C4::Context->preference("OpacNav"),
- OpacNavBottom => C4::Context->preference("OpacNavBottom"),
OpacFavicon => C4::Context->preference("OpacFavicon"),
opacreadinghistory => C4::Context->preference("opacreadinghistory"),
opaclanguagesdisplay => C4::Context->preference("opaclanguagesdisplay"),
OPACUserCSS => C4::Context->preference("OPACUserCSS"),
intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
intranetstylesheet => C4::Context->preference("intranetstylesheet"),
- intranetbookbag => C4::Context->preference("intranetbookbag"),
IntranetNav => C4::Context->preference("IntranetNav"),
IntranetFavicon => C4::Context->preference("IntranetFavicon"),
IntranetUserCSS => C4::Context->preference("IntranetUserCSS"),
PatronSelfRegistration => C4::Context->preference("PatronSelfRegistration"),
PatronSelfRegistrationDefaultCategory => C4::Context->preference("PatronSelfRegistrationDefaultCategory"),
opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'},
- too_many_login_attempts => ( $patron and $patron->account_locked )
+ too_many_login_attempts => ( $patron and $patron->account_locked ),
);
$template->param( SCO_login => 1 ) if ( $query->param('sco_user_login') );
$template->param( SCI_login => 1 ) if ( $query->param('sci_user_login') );
$template->param( OpacPublic => C4::Context->preference("OpacPublic") );
$template->param( loginprompt => 1 ) unless $info{'nopermission'};
+ if ( $auth_state eq 'additional-auth-needed' ) {
+ $template->param(
+ TwoFA_prompt => 1,
+ invalid_otp_token => $invalid_otp_token,
+ );
+ }
if ( $type eq 'opac' ) {
require Koha::Virtualshelves;
my $some_public_shelves = Koha::Virtualshelves->get_some_shelves(
{
- category => 2,
+ public => 1,
}
);
$template->param(
if ($cas) {
# Is authentication against multiple CAS servers enabled?
- if ( C4::Auth_with_cas::multipleAuth && !$casparam ) {
- my $casservers = C4::Auth_with_cas::getMultipleAuth();
+ require C4::Auth_with_cas;
+ if ( multipleAuth() && !$casparam ) {
+ my $casservers = getMultipleAuth();
my @tmplservers;
foreach my $key ( keys %$casservers ) {
push @tmplservers, { name => $key, value => login_cas_url( $query, $key, $type ) . "?cas=$key" };
}
if ($shib) {
+ #If shibOnly is enabled just go ahead and redirect directly
+ if ( (($type eq 'opac') && C4::Context->preference('OPACShibOnly')) || (($type ne 'opac') && C4::Context->preference('staffShibOnly')) ) {
+ my $redirect_url = login_shib_url( $query );
+ print $query->redirect( -uri => "$redirect_url", -status => 303 );
+ safe_exit;
+ }
+
$template->param(
shibbolethAuthentication => $shib,
shibbolethLoginUrl => login_shib_url($query),
{ type => 'text/html',
charset => 'utf-8',
cookie => $cookie,
- 'X-Frame-Options' => 'SAMEORIGIN'
+ 'X-Frame-Options' => 'SAMEORIGIN',
+ -sameSite => 'Lax'
}
),
$template->output;
=item "expired -- session cookie has expired; API user should resubmit userid and password
+=item "restricted" -- The IP has changed (if SessionRestrictionByIP)
+
+=item "additional-auth-needed -- User is in an authentication process that is not finished
+
=back
=cut
return ( "maintenance", undef, undef );
}
- # FIXME -- most of what follows is a copy-and-paste
- # of code from checkauth. There is an obvious need
- # for refactoring to separate the various parts of
- # the authentication code, but as of 2007-11-19 this
- # is deferred so as to not introduce bugs into the
- # regular authentication code for Koha 3.0.
-
- # see if we have a valid session cookie already
- # however, if a userid parameter is present (i.e., from
- # a form submission, assume that any current cookie
- # is to be ignored
- my $sessionID = undef;
+ my ( $sessionID, $session );
unless ( $query->param('userid') ) {
$sessionID = $query->cookie("CGISESSID");
}
if ( $sessionID && not( $cas && $query->param('PT') ) ) {
- 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')
- );
- my $ip = $session->param('ip');
- my $lasttime = $session->param('lasttime');
- my $userid = $session->param('id');
- if ( $lasttime < time() - $timeout ) {
+ my $return;
+ ( $return, $session, undef ) = check_cookie_auth(
+ $sessionID, $flagsrequired, { remote_addr => $ENV{REMOTE_ADDR} } );
- # time out
- $session->delete();
- $session->flush;
- C4::Context->_unset_userenv($sessionID);
- $userid = undef;
- $sessionID = undef;
- return ( "expired", undef, undef );
- } elsif ( C4::Context->preference('SessionRestrictionByIP') && $ip ne $ENV{'REMOTE_ADDR'} ) {
+ return ( $return, undef, undef ) # Cookie auth failed
+ if $return ne "ok";
+
+ my $cookie = $query->cookie(
+ -name => 'CGISESSID',
+ -value => $session->id,
+ -HttpOnly => 1,
+ -secure => ( C4::Context->https_enabled() ? 1 : 0 ),
+ -sameSite => 'Lax'
+ );
+ return ( $return, $cookie, $session ); # return == 'ok' here
- # IP address changed
- $session->delete();
- $session->flush;
- C4::Context->_unset_userenv($sessionID);
- $userid = undef;
- $sessionID = undef;
- return ( "expired", undef, undef );
- } else {
- my $cookie = $query->cookie(
- -name => 'CGISESSID',
- -value => $session->id,
- -HttpOnly => 1,
- -secure => ( C4::Context->https_enabled() ? 1 : 0 ),
- );
- $session->param( 'lasttime', time() );
- my $flags = haspermission( $userid, $flagsrequired );
- if ($flags) {
- return ( "ok", $cookie, $sessionID );
- } else {
- $session->delete();
- $session->flush;
- C4::Context->_unset_userenv($sessionID);
- $userid = undef;
- $sessionID = undef;
- return ( "failed", undef, undef );
- }
- }
- } else {
- return ( "expired", undef, undef );
- }
} else {
# new login
# Proxy CAS auth
if ( $cas && $query->param('PT') ) {
my $retuserid;
- $debug and print STDERR "## check_api_auth - checking CAS\n";
# In case of a CAS authentication, we use the ticket instead of the password
my $PT = $query->param('PT');
-value => $sessionID,
-HttpOnly => 1,
-secure => ( C4::Context->https_enabled() ? 1 : 0 ),
+ -sameSite => 'Lax'
);
if ( $return == 1 ) {
my (
my $library = Koha::Libraries->find($branchcode);
$branchname = $library? $library->branchname: '';
}
- my $branches = { map { $_->branchcode => $_->unblessed } Koha::Libraries->search };
+ my $branches = { map { $_->branchcode => $_->unblessed } Koha::Libraries->search->as_list };
foreach my $br ( keys %$branches ) {
# now we work with the treatment of ip
$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('desk_id'), $session->param('desk_name'),
+ $session->param('register_id'), $session->param('register_name')
);
return ( "ok", $cookie, $sessionID );
} else {
=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>
=item "ok" -- user authenticated; C<$sessionID> have valid values.
+=item "anon" -- user not authenticated but valid for anonymous session.
+
=item "failed" -- credentials are not correct; C<$sessionid> are undef
=item "maintenance" -- DB is in maintenance mode; no login possible at the moment
=item "expired -- session cookie has expired; API user should resubmit userid and password
+=item "restricted" -- The IP has changed (if SessionRestrictionByIP)
+
=back
=cut
sub check_cookie_auth {
- my $cookie = shift;
+ my $sessionID = shift;
my $flagsrequired = shift;
my $params = shift;
my $remote_addr = $params->{remote_addr} || $ENV{REMOTE_ADDR};
- my $dbh = C4::Context->dbh;
- my $timeout = _timeout_syspref();
- unless ( C4::Context->preference('Version') ) {
+ my $skip_version_check = $params->{skip_version_check}; # Only for checkauth
- # database has not been installed yet
- return ( "maintenance", undef );
- }
- my $kohaversion = Koha::version();
- $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
- if ( C4::Context->preference('Version') < $kohaversion ) {
+ unless ( $skip_version_check ) {
+ unless ( C4::Context->preference('Version') ) {
- # database in need of version update; assume that
- # no API should be called while databsae is in
- # this condition.
- return ( "maintenance", undef );
+ # database has not been installed yet
+ return ( "maintenance", undef );
+ }
+ my $kohaversion = Koha::version();
+ $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
+ if ( C4::Context->preference('Version') < $kohaversion ) {
+
+ # database in need of version update; assume that
+ # no API should be called while databsae is in
+ # this condition.
+ return ( "maintenance", undef );
+ }
}
- # FIXME -- most of what follows is a copy-and-paste
- # of code from checkauth. There is an obvious need
- # for refactoring to separate the various parts of
- # the authentication code, but as of 2007-11-23 this
- # is deferred so as to not introduce bugs into the
- # regular authentication code for Koha 3.0.
-
# see if we have a valid session cookie already
# however, if a userid parameter is present (i.e., from
# a form submission, assume that any current cookie
# is to be ignored
- unless ( defined $cookie and $cookie ) {
+ unless ( $sessionID ) {
return ( "failed", undef );
}
- my $sessionID = $cookie;
+ 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')
- );
-
+ my $userid = $session->param('id');
my $ip = $session->param('ip');
my $lasttime = $session->param('lasttime');
- my $userid = $session->param('id');
- if ( $lasttime < time() - $timeout ) {
+ my $timeout = _timeout_syspref();
+ if ( !$lasttime || ( $lasttime < time() - $timeout ) ) {
# time out
$session->delete();
$session->flush;
- C4::Context->_unset_userenv($sessionID);
- $userid = undef;
- $sessionID = undef;
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);
- $userid = undef;
- $sessionID = undef;
- return ( "expired", undef );
- } else {
+ return ( "restricted", undef, { old_ip => $ip, new_ip => $remote_addr});
+
+ } elsif ( $userid ) {
$session->param( 'lasttime', time() );
+ my $patron = Koha::Patrons->find({ userid => $userid });
+ $patron = Koha::Patron->find({ cardnumber => $userid }) unless $patron;
+ return ("password_expired", undef ) if $patron->password_expired;
my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1;
if ($flags) {
- return ( "ok", $sessionID );
+ 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 ( "additional-auth-needed", $session )
+ if $session->param('waiting-for-2FA');
+
+ return ( "ok", $session );
} else {
$session->delete();
$session->flush;
- C4::Context->_unset_userenv($sessionID);
- $userid = undef;
- $sessionID = undef;
return ( "failed", undef );
}
+
+ } else {
+ C4::Context->_new_userenv($sessionID);
+ C4::Context->interface($session->param('interface'));
+ C4::Context->set_userenv( undef, q{} );
+ return ( "anon", $session );
}
} else {
return ( "expired", undef );
my $storage_method = C4::Context->preference('SessionStorage');
if ( $storage_method eq 'mysql' ) {
my $dbh = C4::Context->dbh;
- return { dsn => "driver:MySQL;serializer:yaml;id:md5", dsn_args => { Handle => $dbh } };
+ return { dsn => "serializer:yamlxs;driver:MySQL;id:md5", dsn_args => { Handle => $dbh } };
}
elsif ( $storage_method eq 'Pg' ) {
my $dbh = C4::Context->dbh;
- return { dsn => "driver:PostgreSQL;serializer:yaml;id:md5", dsn_args => { Handle => $dbh } };
+ return { dsn => "serializer:yamlxs;driver:PostgreSQL;id:md5", dsn_args => { Handle => $dbh } };
}
elsif ( $storage_method eq 'memcached' && Koha::Caches->get_instance->memcached_cache ) {
my $memcached = Koha::Caches->get_instance()->memcached_cache;
- return { dsn => "driver:memcached;serializer:yaml;id:md5", dsn_args => { Memcached => $memcached } };
+ return { dsn => "serializer:yamlxs;driver:memcached;id:md5", dsn_args => { Memcached => $memcached } };
}
else {
# catch all defaults to tmp should work on all systems
my $dir = C4::Context::temporary_directory;
my $instance = C4::Context->config( 'database' ); #actually for packages not exactly the instance name, but generally safer to leave it as it is
- return { dsn => "driver:File;serializer:yaml;id:md5", dsn_args => { Directory => "$dir/cgisess_$instance" } };
+ return { dsn => "serializer:yamlxs;driver:File;id:md5", dsn_args => { Directory => "$dir/cgisess_$instance" } };
}
}
sub get_session {
my $sessionID = shift;
my $params = _get_session_params();
- return new CGI::Session( $params->{dsn}, $sessionID, $params->{dsn_args} );
+ 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} );
+ # no need to flush here
+ }
+ return $session;
}
# 0 if auth is nok
# -1 if user bind failed (LDAP only)
- if ( $patron and $patron->account_locked ) {
+ if ( $patron and ( $patron->account_locked ) ) {
# Nothing to check, account is locked
} elsif ($ldap && defined($password)) {
- $debug and print STDERR "## checkpw - checking LDAP\n";
my ( $retval, $retcard, $retuserid ) = checkpw_ldap(@_); # EXTERNAL AUTH
if ( $retval == 1 ) {
@return = ( $retval, $retcard, $retuserid );
$check_internal_as_fallback = 1 if $retval == 0;
} elsif ( $cas && $query && $query->param('ticket') ) {
- $debug and print STDERR "## checkpw - checking CAS\n";
# In case of a CAS authentication, we use the ticket instead of the password
my $ticket = $query->param('ticket');
# time around.
elsif ( $shib && $shib_login && !$password ) {
- $debug and print STDERR "## checkpw - checking Shibboleth\n";
-
# In case of a Shibboleth authentication, we expect a shibboleth user attribute
# (defined under shibboleth mapping in koha-conf.xml) to contain the login of the
# shibboleth-authenticated user
if( $patron ) {
if ( $passwd_ok ) {
$patron->update({ login_attempts => 0 });
+ if( $patron->password_expired ){
+ @return = (-2);
+ }
} elsif( !$patron->account_locked ) {
$patron->update({ login_attempts => $patron->login_attempts + 1 });
}
if (scalar @allowedipranges > 0) {
my @rangelist;
eval { @rangelist = Net::CIDR::range2cidr(@allowedipranges); }; return 0 if $@;
- eval { $result = Net::CIDR::cidrlookup($ENV{'REMOTE_ADDR'}, @rangelist) } || ( $ENV{DEBUG} && warn 'cidrlookup failed for ' . join(' ',@rangelist) );
+ eval { $result = Net::CIDR::cidrlookup($ENV{'REMOTE_ADDR'}, @rangelist) } || Koha::Logger->get->warn('cidrlookup failed for ' . join(' ',@rangelist) );
}
return $result ? 1 : 0;
}