X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=C4%2FAuth.pm;h=c3ba5baad25204060488fabf353e80ce28c5dbe2;hb=refs%2Fheads%2Fkoha_ffzg;hp=60c8c87911faeaf4459c5f1dc6154f726cbab710;hpb=3d68ab447eda3eb5a25444b1ceaeea96b446c64b;p=koha.git diff --git a/C4/Auth.pm b/C4/Auth.pm index 60c8c87911..c3ba5baad2 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -19,8 +19,9 @@ package C4::Auth; use strict; use warnings; +use Carp qw/croak/; + use Digest::MD5 qw(md5_base64); -use File::Spec; use JSON qw/encode_json/; use URI::Escape; use CGI::Session; @@ -33,16 +34,19 @@ use C4::Search::History; use Koha; use Koha::Caches; use Koha::AuthUtils qw(get_script_name hash_password); +use Koha::Checkouts; use Koha::DateUtils qw(dt_from_string); use Koha::Library::Groups; use Koha::Libraries; 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 utf8; -use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout $shib $shib_login); +use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout); BEGIN { sub psgi_env { any { /^psgi\./ } keys %ENV } @@ -61,7 +65,6 @@ BEGIN { %EXPORT_TAGS = ( EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)] ); $ldap = C4::Context->config('useldapserver') || 0; $cas = C4::Context->preference('casAuthentication'); - $shib = C4::Context->config('useshibboleth') || 0; $caslogout = C4::Context->preference('casLogout'); require C4::Auth_with_cas; # no import @@ -69,23 +72,6 @@ BEGIN { require C4::Auth_with_ldap; import C4::Auth_with_ldap qw(checkpw_ldap); } - if ($shib) { - require C4::Auth_with_shibboleth; - import C4::Auth_with_shibboleth - qw(shib_ok checkpw_shib logout_shib login_shib_url get_login_shib); - - # Check for good config - if ( shib_ok() ) { - - # Get shibboleth login attribute - $shib_login = get_login_shib(); - } - - # Bad config, disable shibboleth - else { - $shib = 0; - } - } if ($cas) { import C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url logout_if_required); } @@ -145,7 +131,7 @@ See C<&checkauth> for an explanation of these parameters. The C is then used to find the correct template for the page. The authenticated users details are loaded onto the -template in the HTML::Template LOOP variable C. Also the +template in the logged_in_user variable (which is a Koha::Patron object). Also the C is passed to the template. This can be used in templates if cookies are disabled. It needs to be put as and input to every authenticated page. @@ -160,6 +146,10 @@ sub get_template_and_user { my $in = shift; my ( $user, $cookie, $sessionID, $flags ); + # Get shibboleth login attribute + my $shib = C4::Context->config('useshibboleth') && shib_ok(); + my $shib_login = $shib ? get_login_shib() : undef; + C4::Context->interface( $in->{type} ); $in->{'authnotrequired'} ||= 0; @@ -180,6 +170,22 @@ sub get_template_and_user { ); } + # If we enforce GDPR and the user did not consent, redirect + if( $in->{type} eq 'opac' && $user && + $in->{'template_name'} !~ /opac-patron-consent/ && + C4::Context->preference('GDPR_Policy') eq 'Enforced' ) + { + my $consent = Koha::Patron::Consents->search({ + borrowernumber => getborrowernumber($user), + type => 'GDPR_PROCESSING', + given_on => { '!=', undef }, + })->next; + if( !$consent ) { + print $in->{query}->redirect(-uri => '/cgi-bin/koha/opac-patron-consent.pl', -cookie => $cookie); + safe_exit; + } + } + if ( $in->{type} eq 'opac' && $user ) { my $kick_out; @@ -261,7 +267,7 @@ sub get_template_and_user { } # user info - $template->param( loggedinusername => $user ); # FIXME Should be replaced with something like patron-title.inc + $template->param( loggedinusername => $user ); # OBSOLETE - Do not reuse this in template, use logged_in_user.userid instead $template->param( loggedinusernumber => $borrowernumber ); # FIXME Should be replaced with logged_in_user.borrowernumber $template->param( logged_in_user => $patron ); $template->param( sessionID => $sessionID ); @@ -285,12 +291,10 @@ sub get_template_and_user { ); } - $template->param( "USER_INFO" => $patron->unblessed ) if $borrowernumber != 0; - my $all_perms = get_all_subpermissions(); my @flagroots = qw(circulate catalogue parameters borrowers permissions reserveforothers borrow - editcatalogue updatecharges management tools editauthorities serials reports acquisition clubs); + editcatalogue updatecharges tools editauthorities serials reports acquisition clubs); # We are going to use the $flags returned by checkauth # to create the template's parameters that will indicate @@ -305,7 +309,6 @@ sub get_template_and_user { $template->param( CAN_user_editcatalogue => 1 ); $template->param( CAN_user_updatecharges => 1 ); $template->param( CAN_user_acquisition => 1 ); - $template->param( CAN_user_management => 1 ); $template->param( CAN_user_tools => 1 ); $template->param( CAN_user_editauthorities => 1 ); $template->param( CAN_user_serials => 1 ); @@ -315,6 +318,7 @@ sub get_template_and_user { $template->param( CAN_user_coursereserves => 1 ); $template->param( CAN_user_clubs => 1 ); $template->param( CAN_user_ill => 1 ); + $template->param( CAN_user_stockrotation => 1 ); foreach my $module ( keys %$all_perms ) { foreach my $subperm ( keys %{ $all_perms->{$module} } ) { @@ -341,9 +345,6 @@ sub get_template_and_user { foreach my $module ( keys %$flags ) { if ( $flags->{$module} == 1 or ref( $flags->{$module} ) ) { $template->param( "CAN_user_$module" => 1 ); - if ( $module eq "parameters" ) { - $template->param( CAN_user_management => 1 ); - } } } } @@ -503,7 +504,8 @@ sub get_template_and_user { EnableBorrowerFiles => C4::Context->preference('EnableBorrowerFiles'), UseKohaPlugins => C4::Context->preference('UseKohaPlugins'), UseCourseReserves => C4::Context->preference("UseCourseReserves"), - useDischarge => C4::Context->preference('useDischarge') + useDischarge => C4::Context->preference('useDischarge'), + pending_checkout_notes => scalar Koha::Checkouts->search({ noteseen => 0 }), ); } else { @@ -533,8 +535,8 @@ sub get_template_and_user { my $opac_limit_override = $ENV{'OPAC_LIMIT_OVERRIDE'}; my $opac_name = ''; if ( - ( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /branch:(\w+)/ ) || - ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /branch:(\w+)/ ) || + ( $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+)/ ) ) { $opac_name = $1; # opac_search_limit is a branch, so we use it. @@ -778,6 +780,11 @@ sub _timeout_syspref { sub checkauth { my $query = shift; $debug and warn "Checking Auth"; + + # Get shibboleth login attribute + my $shib = C4::Context->config('useshibboleth') && shib_ok(); + my $shib_login = $shib ? get_login_shib() : undef; + # $authnotrequired will be set for scripts which will run without authentication my $authnotrequired = shift; my $flagsrequired = shift; @@ -886,9 +893,7 @@ sub checkauth { } # 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 and $type eq 'opac' ) { - - # (Note: $type eq 'opac' condition should be removed when shibboleth authentication for intranet will be implemented) + if ( $shib and $shib_login and $shibSuccess) { logout_shib($query); } } @@ -948,7 +953,7 @@ sub checkauth { $session->param( 'search_history', $anon_search_history ); } - my $sessionID = $session->id; + $sessionID = $session->id; C4::Context->_new_userenv($sessionID); $cookie = $query->cookie( -name => 'CGISESSID', @@ -971,7 +976,7 @@ sub checkauth { my ( $return, $cardnumber ); # If shib is enabled and we have a shib login, does the login match a valid koha user - if ( $shib && $shib_login && $type eq 'opac' ) { + if ( $shib && $shib_login ) { my $retuserid; # Do not pass password here, else shib will not be checked in checkpw. @@ -1217,8 +1222,8 @@ sub checkauth { my @inputs = (); foreach my $name ( param $query) { (next) if ( $name eq 'userid' || $name eq 'password' || $name eq 'ticket' ); - my $value = $query->param($name); - push @inputs, { name => $name, value => $value }; + 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! @@ -1601,7 +1606,11 @@ sub check_api_auth { ($status, $sessionId) = check_api_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>. +if the user has the privileges specified by C<$userflags>. C<$userflags> +is passed unaltered into C and as such accepts all options +avaiable to that routine with the one caveat that C will +also allow 'undef' to be passed and in such a case the permissions check +will be skipped altogether. C is meant for authenticating special services such as tools/upload-file.pl that are invoked by other pages that @@ -1696,7 +1705,7 @@ sub check_cookie_auth { return ( "expired", undef ); } else { $session->param( 'lasttime', time() ); - my $flags = haspermission( $userid, $flagsrequired ); + my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1; if ($flags) { return ( "ok", $sessionID ); } else { @@ -1744,7 +1753,7 @@ sub _get_session_params { } else { # catch all defaults to tmp should work on all systems - my $dir = File::Spec->tmpdir; + 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" } }; } @@ -1765,6 +1774,10 @@ sub checkpw { my ( $dbh, $userid, $password, $query, $type, $no_set_userenv ) = @_; $type = 'opac' unless $type; + # Get shibboleth login attribute + my $shib = C4::Context->config('useshibboleth') && shib_ok(); + my $shib_login = $shib ? get_login_shib() : undef; + my @return; my $patron = Koha::Patrons->find({ userid => $userid }); my $check_internal_as_fallback = 0; @@ -1776,7 +1789,7 @@ sub checkpw { if ( $patron and $patron->account_locked ) { # Nothing to check, account is locked - } elsif ($ldap) { + } elsif ($ldap && defined($password)) { $debug and print STDERR "## checkpw - checking LDAP\n"; my ( $retval, $retcard, $retuserid ) = checkpw_ldap(@_); # EXTERNAL AUTH if ( $retval == 1 ) { @@ -2015,45 +2028,74 @@ sub get_all_subpermissions { =head2 haspermission + $flagsrequired = '*'; # Any permission at all + $flagsrequired = 'a_flag'; # a_flag must be satisfied (all subpermissions) + $flagsrequired = [ 'a_flag', 'b_flag' ]; # a_flag OR b_flag must be satisfied + $flagsrequired = { 'a_flag => 1, 'b_flag' => 1 }; # a_flag AND b_flag must be satisfied + $flagsrequired = { 'a_flag' => 'sub_a' }; # sub_a of a_flag must be satisfied + $flagsrequired = { 'a_flag' => [ 'sub_a, 'sub_b' ] }; # sub_a OR sub_b of a_flag must be satisfied + $flags = ($userid, $flagsrequired); C<$userid> the userid of the member -C<$flags> is a hashref of required flags like C<$borrower-<{authflags}> +C<$flags> is a query structure similar to that used by SQL::Abstract that +denotes the combination of flags required. It is a required parameter. + +The main logic of this method is that things in arrays are OR'ed, and things +in hashes are AND'ed. The `*` character can be used, at any depth, to denote `ANY` Returns member's flags or 0 if a permission is not met. =cut +sub _dispatch { + my ($required, $flags) = @_; + + my $ref = ref($required); + if ($ref eq '') { + if ($required eq '*') { + return 0 unless ( $flags or ref( $flags ) ); + } else { + return 0 unless ( $flags and (!ref( $flags ) || $flags->{$required} )); + } + } elsif ($ref eq 'HASH') { + foreach my $key (keys %{$required}) { + my $require = $required->{$key}; + my $rflags = $flags->{$key}; + return 0 unless _dispatch($require, $rflags); + } + } elsif ($ref eq 'ARRAY') { + my $satisfied = 0; + foreach my $require ( @{$required} ) { + my $rflags = + ( ref($flags) && !ref($require) && ( $require ne '*' ) ) + ? $flags->{$require} + : $flags; + $satisfied++ if _dispatch( $require, $rflags ); + } + return 0 unless $satisfied; + } else { + croak "Unexpected structure found: $ref"; + } + + return $flags; +}; + sub haspermission { my ( $userid, $flagsrequired ) = @_; + + + #Koha::Exceptions::WrongParameter->throw('$flagsrequired should not be undef') + # unless defined($flagsrequired); + my $sth = C4::Context->dbh->prepare("SELECT flags FROM borrowers WHERE userid=?"); $sth->execute($userid); my $row = $sth->fetchrow(); my $flags = getuserflags( $row, $userid ); - if ( $userid eq C4::Context->config('user') ) { - - # Super User Account from /etc/koha.conf - $flags->{'superlibrarian'} = 1; - } + return $flags unless defined($flagsrequired); return $flags if $flags->{superlibrarian}; - - foreach my $module ( keys %$flagsrequired ) { - my $subperm = $flagsrequired->{$module}; - if ( $subperm eq '*' ) { - return 0 unless ( $flags->{$module} == 1 or ref( $flags->{$module} ) ); - } else { - return 0 unless ( - ( defined $flags->{$module} and - $flags->{$module} == 1 ) - or - ( ref( $flags->{$module} ) and - exists $flags->{$module}->{$subperm} and - $flags->{$module}->{$subperm} == 1 ) - ); - } - } - return $flags; + return _dispatch($flagsrequired, $flags); #FIXME - This fcn should return the failed permission so a suitable error msg can be delivered. }