Lines 34-39
use Koha;
Link Here
|
34 |
use Koha::Logger; |
34 |
use Koha::Logger; |
35 |
use Koha::Caches; |
35 |
use Koha::Caches; |
36 |
use Koha::AuthUtils qw( get_script_name hash_password ); |
36 |
use Koha::AuthUtils qw( get_script_name hash_password ); |
|
|
37 |
use Koha::Auth::TwoFactorAuth; |
37 |
use Koha::Checkouts; |
38 |
use Koha::Checkouts; |
38 |
use Koha::DateUtils qw( dt_from_string ); |
39 |
use Koha::DateUtils qw( dt_from_string ); |
39 |
use Koha::Library::Groups; |
40 |
use Koha::Library::Groups; |
Lines 838-843
sub checkauth {
Link Here
|
838 |
my $q_userid = $query->param('userid') // ''; |
839 |
my $q_userid = $query->param('userid') // ''; |
839 |
|
840 |
|
840 |
my $session; |
841 |
my $session; |
|
|
842 |
my $invalid_otp_token; |
843 |
my $require_2FA = ( C4::Context->preference('TwoFactorAuthentication') && $type ne "OPAC" ) ? 1 : 0; |
844 |
my $auth_challenge_complete; |
841 |
|
845 |
|
842 |
# Basic authentication is incompatible with the use of Shibboleth, |
846 |
# Basic authentication is incompatible with the use of Shibboleth, |
843 |
# as Shibboleth may return REMOTE_USER as a Shibboleth attribute, |
847 |
# as Shibboleth may return REMOTE_USER as a Shibboleth attribute, |
Lines 869-881
sub checkauth {
Link Here
|
869 |
{ remote_addr => $ENV{REMOTE_ADDR}, skip_version_check => 1 } |
873 |
{ remote_addr => $ENV{REMOTE_ADDR}, skip_version_check => 1 } |
870 |
); |
874 |
); |
871 |
|
875 |
|
|
|
876 |
if ( $return eq 'ok' || $return eq 'additional-auth-needed' ) { |
877 |
$userid = $session->param('id'); |
878 |
} |
879 |
|
880 |
$additional_auth_needed = ( $return eq 'additional-auth-needed' ) ? 1 : 0; |
881 |
|
882 |
# We are at the second screen if the waiting-for-2FA is set in session |
883 |
# and otp_token param has been passed |
884 |
if ( $require_2FA |
885 |
&& $additional_auth_needed |
886 |
&& ( my $otp_token = $query->param('otp_token') ) ) |
887 |
{ |
888 |
my $patron = Koha::Patrons->find( { userid => $userid } ); |
889 |
my $auth = Koha::Auth::TwoFactorAuth::get_auth( { patron => $patron } ); |
890 |
my $verified = $auth->verify($otp_token); |
891 |
$auth->clear; |
892 |
if ( $verified ) { |
893 |
# The token is correct, the user is fully logged in! |
894 |
$additional_auth_needed = 0; |
895 |
$session->param( 'waiting-for-2FA', 0 ); |
896 |
$return = "ok"; |
897 |
$auth_challenge_complete = 1; |
898 |
|
899 |
# This is an ugly trick to pass the test |
900 |
# $query->param('koha_login_context') && ( $q_userid ne $userid ) |
901 |
# few lines later |
902 |
$q_userid = $userid; |
903 |
} |
904 |
else { |
905 |
$invalid_otp_token = 1; |
906 |
} |
907 |
} |
908 |
|
872 |
if ( $return eq 'ok' ) { |
909 |
if ( $return eq 'ok' ) { |
873 |
Koha::Logger->get->debug(sprintf "AUTH_SESSION: (%s)\t%s %s - %s", map { $session->param($_) || q{} } qw(cardnumber firstname surname branch)); |
910 |
Koha::Logger->get->debug(sprintf "AUTH_SESSION: (%s)\t%s %s - %s", map { $session->param($_) || q{} } qw(cardnumber firstname surname branch)); |
874 |
|
911 |
|
875 |
my $s_userid = $session->param('id'); |
912 |
if ( ( $query->param('koha_login_context') && ( $q_userid ne $userid ) ) |
876 |
$userid = $s_userid; |
|
|
877 |
|
878 |
if ( ( $query->param('koha_login_context') && ( $q_userid ne $s_userid ) ) |
879 |
|| ( $cas && $query->param('ticket') && !C4::Context->userenv->{'id'} ) |
913 |
|| ( $cas && $query->param('ticket') && !C4::Context->userenv->{'id'} ) |
880 |
|| ( $shib && $shib_login && !$logout && !C4::Context->userenv->{'id'} ) |
914 |
|| ( $shib && $shib_login && !$logout && !C4::Context->userenv->{'id'} ) |
881 |
) { |
915 |
) { |
Lines 886-910
sub checkauth {
Link Here
|
886 |
$session->delete(); |
920 |
$session->delete(); |
887 |
$session->flush; |
921 |
$session->flush; |
888 |
C4::Context->_unset_userenv($sessionID); |
922 |
C4::Context->_unset_userenv($sessionID); |
889 |
} |
923 |
} elsif (!$logout) { |
890 |
elsif ($logout) { |
|
|
891 |
|
892 |
# voluntary logout the user |
893 |
# check wether the user was using their shibboleth session or a local one |
894 |
my $shibSuccess = C4::Context->userenv->{'shibboleth'}; |
895 |
$session->delete(); |
896 |
$session->flush; |
897 |
C4::Context->_unset_userenv($sessionID); |
898 |
|
899 |
if ($cas and $caslogout) { |
900 |
logout_cas($query, $type); |
901 |
} |
902 |
|
903 |
# If we are in a shibboleth session (shibboleth is enabled, a shibboleth match attribute is set and matches koha matchpoint) |
904 |
if ( $shib and $shib_login and $shibSuccess) { |
905 |
logout_shib($query); |
906 |
} |
907 |
} else { |
908 |
|
924 |
|
909 |
$cookie = $query->cookie( |
925 |
$cookie = $query->cookie( |
910 |
-name => 'CGISESSID', |
926 |
-name => 'CGISESSID', |
Lines 931-944
sub checkauth {
Link Here
|
931 |
} |
947 |
} |
932 |
} |
948 |
} |
933 |
|
949 |
|
934 |
unless ( $loggedin ) { |
950 |
if ( ( !$loggedin && !$additional_auth_needed ) || $logout ) { |
935 |
$sessionID = undef; |
951 |
$sessionID = undef; |
|
|
952 |
$session = undef; |
936 |
$userid = undef; |
953 |
$userid = undef; |
937 |
} |
954 |
} |
938 |
|
955 |
|
|
|
956 |
if ($logout) { |
957 |
|
958 |
# voluntary logout the user |
959 |
# check wether the user was using their shibboleth session or a local one |
960 |
my $shibSuccess = C4::Context->userenv->{'shibboleth'}; |
961 |
if ( $session ) { |
962 |
$session->delete(); |
963 |
$session->flush; |
964 |
} |
965 |
C4::Context->_unset_userenv($sessionID); |
966 |
|
967 |
if ($cas and $caslogout) { |
968 |
logout_cas($query, $type); |
969 |
} |
970 |
|
971 |
# If we are in a shibboleth session (shibboleth is enabled, a shibboleth match attribute is set and matches koha matchpoint) |
972 |
if ( $shib and $shib_login and $shibSuccess) { |
973 |
logout_shib($query); |
974 |
} |
975 |
|
976 |
$sessionID = undef; |
977 |
$session = undef; |
978 |
$userid = undef; |
979 |
$additional_auth_needed = 0; |
980 |
} |
981 |
|
939 |
unless ( $userid ) { |
982 |
unless ( $userid ) { |
940 |
#we initiate a session prior to checking for a username to allow for anonymous sessions... |
983 |
#we initiate a session prior to checking for a username to allow for anonymous sessions... |
941 |
$session ||= get_session("") or die "Auth ERROR: Cannot get_session()"; |
984 |
$session = get_session("") or die "Auth ERROR: Cannot get_session()"; |
942 |
|
985 |
|
943 |
# Save anonymous search history in new session so it can be retrieved |
986 |
# Save anonymous search history in new session so it can be retrieved |
944 |
# by get_template_and_user to store it in user's search history after |
987 |
# by get_template_and_user to store it in user's search history after |
Lines 1225-1233
sub checkauth {
Link Here
|
1225 |
} |
1268 |
} |
1226 |
} # END unless ($userid) |
1269 |
} # END unless ($userid) |
1227 |
|
1270 |
|
|
|
1271 |
if ( $require_2FA && ( $loggedin && !$auth_challenge_complete)) { |
1272 |
my $patron = Koha::Patrons->find({userid => $userid}); |
1273 |
if ( $patron->auth_method eq 'two-factor' ) { |
1274 |
# Ask for the OTP token |
1275 |
$additional_auth_needed = 1; |
1276 |
$session->param('waiting-for-2FA', 1); |
1277 |
%info = ();# We remove the warnings/errors we may have set incorrectly before |
1278 |
} |
1279 |
} |
1280 |
|
1228 |
# finished authentification, now respond |
1281 |
# finished authentification, now respond |
1229 |
if ( $loggedin || $authnotrequired ) |
1282 |
if ( ( $loggedin || $authnotrequired ) && !$additional_auth_needed ) { |
1230 |
{ |
|
|
1231 |
# successful login |
1283 |
# successful login |
1232 |
unless ($cookie) { |
1284 |
unless ($cookie) { |
1233 |
$cookie = $query->cookie( |
1285 |
$cookie = $query->cookie( |
Lines 1261-1276
sub checkauth {
Link Here
|
1261 |
# |
1313 |
# |
1262 |
# |
1314 |
# |
1263 |
|
1315 |
|
|
|
1316 |
my $patron = Koha::Patrons->find({ userid => $q_userid }); # Not necessary logged in! |
1317 |
|
1264 |
# get the inputs from the incoming query |
1318 |
# get the inputs from the incoming query |
1265 |
my @inputs = (); |
1319 |
my @inputs = (); |
|
|
1320 |
my @inputs_to_clean = qw( userid password ticket logout.x otp_token ); |
1266 |
foreach my $name ( param $query) { |
1321 |
foreach my $name ( param $query) { |
1267 |
(next) if ( $name eq 'userid' || $name eq 'password' || $name eq 'ticket' ); |
1322 |
next if grep { $name eq $_ } @inputs_to_clean; |
1268 |
my @value = $query->multi_param($name); |
1323 |
my @value = $query->multi_param($name); |
1269 |
push @inputs, { name => $name, value => $_ } for @value; |
1324 |
push @inputs, { name => $name, value => $_ } for @value; |
1270 |
} |
1325 |
} |
1271 |
|
1326 |
|
1272 |
my $patron = Koha::Patrons->find({ userid => $q_userid }); # Not necessary logged in! |
|
|
1273 |
|
1274 |
my $LibraryNameTitle = C4::Context->preference("LibraryName"); |
1327 |
my $LibraryNameTitle = C4::Context->preference("LibraryName"); |
1275 |
$LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi; |
1328 |
$LibraryNameTitle =~ s/<(?:\/?)(?:br|p)\s*(?:\/?)>/ /sgi; |
1276 |
$LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg; |
1329 |
$LibraryNameTitle =~ s/<(?:[^<>'"]|'(?:[^']*)'|"(?:[^"]*)")*>//sg; |
Lines 1318-1323
sub checkauth {
Link Here
|
1318 |
$template->param( SCI_login => 1 ) if ( $query->param('sci_user_login') ); |
1371 |
$template->param( SCI_login => 1 ) if ( $query->param('sci_user_login') ); |
1319 |
$template->param( OpacPublic => C4::Context->preference("OpacPublic") ); |
1372 |
$template->param( OpacPublic => C4::Context->preference("OpacPublic") ); |
1320 |
$template->param( loginprompt => 1 ) unless $info{'nopermission'}; |
1373 |
$template->param( loginprompt => 1 ) unless $info{'nopermission'}; |
|
|
1374 |
if ( $additional_auth_needed ) { |
1375 |
$template->param( |
1376 |
TwoFA_prompt => 1, |
1377 |
invalid_otp_token => $invalid_otp_token, |
1378 |
); |
1379 |
} |
1321 |
|
1380 |
|
1322 |
if ( $type eq 'opac' ) { |
1381 |
if ( $type eq 'opac' ) { |
1323 |
require Koha::Virtualshelves; |
1382 |
require Koha::Virtualshelves; |
Lines 1426-1431
Possible return values in C<$status> are:
Link Here
|
1426 |
|
1485 |
|
1427 |
=item "restricted" -- The IP has changed (if SessionRestrictionByIP) |
1486 |
=item "restricted" -- The IP has changed (if SessionRestrictionByIP) |
1428 |
|
1487 |
|
|
|
1488 |
=item "additional-auth-needed -- User is in an authentication process that is not finished |
1489 |
|
1429 |
=back |
1490 |
=back |
1430 |
|
1491 |
|
1431 |
=cut |
1492 |
=cut |
Lines 1703-1708
sub check_cookie_auth {
Link Here
|
1703 |
$session->param( 'lasttime', time() ); |
1764 |
$session->param( 'lasttime', time() ); |
1704 |
my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1; |
1765 |
my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1; |
1705 |
if ($flags) { |
1766 |
if ($flags) { |
|
|
1767 |
|
1768 |
return ( "additional-auth-needed", $session ) |
1769 |
if $session->param('waiting-for-2FA'); |
1770 |
|
1706 |
return ( "ok", $session ); |
1771 |
return ( "ok", $session ); |
1707 |
} |
1772 |
} |
1708 |
} else { |
1773 |
} else { |