Bug 29609: Centralized code to build the link to a biblio detail page
[srvgit] / C4 / Auth.pm
index 4133a6e..67158a0 100644 (file)
@@ -23,6 +23,9 @@ use Carp qw( croak );
 
 use Digest::MD5 qw( md5_base64 );
 use CGI::Session;
+use CGI::Session::ErrorHandler;
+use URI;
+use URI::QueryParam;
 
 use C4::Context;
 use C4::Templates;    # to get the template
@@ -72,14 +75,14 @@ BEGIN {
     $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);
     }
 
 }
@@ -196,14 +199,26 @@ sub get_template_and_user {
     }
 
     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;
@@ -287,12 +302,12 @@ sub get_template_and_user {
             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(
@@ -333,6 +348,7 @@ sub get_template_and_user {
             $template->param( CAN_user_stockrotation    => 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} } ) {
@@ -431,12 +447,15 @@ sub get_template_and_user {
             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};
         }
     }
 
@@ -479,7 +498,6 @@ sub get_template_and_user {
     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"),
@@ -501,7 +519,6 @@ sub get_template_and_user {
         $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"),
@@ -526,7 +543,7 @@ sub get_template_and_user {
             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 {
@@ -546,9 +563,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;
             }
         }
 
@@ -568,7 +586,7 @@ sub get_template_and_user {
             $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,
@@ -588,14 +606,11 @@ sub get_template_and_user {
             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'} : '',
@@ -866,8 +881,9 @@ 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} }
+            { remote_addr => $ENV{REMOTE_ADDR}, skip_version_check => 1 }
         );
 
         if ( $return eq 'ok' ) {
@@ -886,7 +902,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) {
 
@@ -895,7 +912,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);
@@ -914,14 +932,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 ) {
@@ -936,13 +951,14 @@ 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()";
+        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
@@ -1091,7 +1107,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,
@@ -1145,7 +1161,7 @@ sub checkauth {
                         $register_id   = $register->id   if ($register);
                         $register_name = $register->name if ($register);
                     }
-                    my $branches = { map { $_->branchcode => $_->unblessed } Koha::Libraries->search };
+                    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
@@ -1174,6 +1190,12 @@ sub checkauth {
                             $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 );
@@ -1191,6 +1213,7 @@ sub checkauth {
                     $session->param( 'shibboleth',   $shibSuccess );
                     $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(
@@ -1209,7 +1232,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() );
@@ -1227,6 +1250,7 @@ sub checkauth {
             $session->param( 'sessiontype', 'anon' );
             $session->param( 'interface', $type);
         }
+        $session->flush;
     }    # END unless ($userid)
 
     # finished authentification, now respond
@@ -1288,13 +1312,10 @@ sub checkauth {
         casAuthentication                     => C4::Context->preference("casAuthentication"),
         shibbolethAuthentication              => $shib,
         suggestion                            => C4::Context->preference("suggestion"),
-        SessionRestrictionByIP                => C4::Context->preference("SessionRestrictionByIP"),
         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"),
@@ -1330,7 +1351,7 @@ sub checkauth {
         require Koha::Virtualshelves;
         my $some_public_shelves = Koha::Virtualshelves->get_some_shelves(
             {
-                category       => 2,
+                public => 1,
             }
         );
         $template->param(
@@ -1341,8 +1362,9 @@ sub checkauth {
     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" };
@@ -1562,7 +1584,7 @@ sub check_api_auth {
                     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
@@ -1606,7 +1628,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>
@@ -1625,6 +1647,8 @@ Possible return values in C<$status> are:
 
 =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
@@ -1644,72 +1668,79 @@ sub check_cookie_auth {
 
     my $remote_addr = $params->{remote_addr} || $ENV{REMOTE_ADDR};
 
-    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 );
+        }
     }
 
     # 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 $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});
-        } else {
+
+        } 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;
-                C4::Context->_unset_userenv($sessionID);
                 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 );
@@ -1756,9 +1787,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} );
+        # no need to flush here
     }
     return $session;
 }