package Deichman::Auth; use strict; use warnings; use Data::Dumper; use parent "Deichman::Main"; use Try::Tiny; use C4::Context; use Deichman::Auth::Simple; use Deichman::Auth::LDAP; use Deichman::Auth::CAS; use Deichman::Exception; use Deichman::Patron; use Deichman::Library; =head Top level auth class to delegate authentication (and permissions) session object stored in DB or memory with auth object to handle permissions: { auth => { user => { userid => "x", username => "xx"}, permissions => { superlibrarian => 1, borrowers => 1 ...}, } } =cut sub new { my ( $class, $session, $req ) = @_; my $self = $class->SUPER::new(); $self = { %$self, session => $session, req => $req, }; bless $self, $class; return $self; } # Top level Auth method sub Auth { my ($self) = @_; warn "AUTH CALLED"; my $session = $self->{session}; my $req = $self->{req}; $session or Deichman::Exception::Auth::InvalidSession->throw(); $req or Deichman::Exception::Auth::InvalidQuery->throw(); C4::Context->_new_userenv( $session->id ); if ($req->param("logout.x") ) { $self->LogOut(); } # validate session my $auth = $session->get("auth"); if ($auth) { warn "GOT AUTHENTICATED SESSION"; return; } else { warn "NO AUTH SESSION - TRYING TO CREATE ONE"; # Run all auth methods $auth = $self->checkAuthMethods(); $auth or Deichman::Exception::Auth::InvalidSession->throw(); $session->put(auth => $auth); } # decorate session with library, etc. if ( my $userid = $req->param("userid") // $auth->{user}->{userid} ) { # 'id' will be set for admin user as well my $branchcode = $req->param("branch") || $auth->{user}->{branchcode}; try { my $lib = Deichman::Library->new()->Get($branchcode)->{library}; $session->put(branch => $lib->{branchcode}); $session->put(branchname => $lib->{branchname}); } catch { warn $_->description; $session->put(branch => "NO_LIBRARY_SET"); $session->put(branchname => "NO_LIBRARY_SET"); }; # Set C4::Context user env C4::Context->set_userenv( $session->get("number"), $userid, map { $session->get($_); } qw/ cardnumber firstname surname branch branchname flags emailaddress branchprinter shibbolet/, ); # No idea what this is? Virtualshelves? C4::Context::set_shelves_userenv( "bar", $session->get("barshelves") ); C4::Context::set_shelves_userenv( "pub", $session->get("pubshelves") ); C4::Context::set_shelves_userenv( "tot", $session->get("totshelves") ); } # Should Auth return something? return; } sub LogOut { my ($self) = @_; warn "LOGOUT CALLED"; $self->{session}->clear(); return $self; } # Try various Auth methods in given sequence sub checkAuthMethods { my ($self) = @_; my $session = $self->{session}; my $req = $self->{req}; my $auth; for my $class (qw/ Deichman::Auth::Simple Deichman::Auth::LDAP Deichman::Auth::CAS /) { try { warn $class; $auth = $class->new()->DoAuth($session, $req); } catch { warn $_->description; }; $auth->{auth} and return $auth->{auth}; } } # used by C4 modules, like Language sub param { my ($self, $key, @val) = @_; $self->{session}->param($key, @val); } # used by C4 modules, like Language sub cookie { my ($self, $name, @value) = @_; #print STDERR Dumper($self, "cookie($name)", @value); $self->{req}->cookies->{$name}; } # Differ from C4/Auth, it returns empty hashes for modules without submodules sub getAllPermissions { my ($self) = @_; my $dbh = $self->dbh; my $sth = $dbh->prepare( "SELECT flag, code FROM userflags LEFT JOIN permissions ON (module_bit = bit)" ); $sth->execute(); my $all_perms = {}; while ( my $row = $sth->fetchrow_hashref ) { my $flag = $row->{flag}; my $code = $row->{code}; my $module = $all_perms->{$flag} //= {}; $module->{$code} = 1 if $code; } return $all_perms; } # this is where CGI scripts ask for permissions sub templateAndPermissions { my ($self, $in) = @_; warn "TEMPLATE_AND_PERMISSIONS"; my $name = $in->{template_name} or Deichman::Exception::Auth::MissingTemplate->throw(); $name =~ m{^[a-zA-Z0-9_\-\/]+.tt$} or Deichman::Exception::Auth::InvalidTemplate->throw($name); # Use new auth object my $auth = $self->{session}->get("auth"); my $branch = $self->{session}->get("branchname") || $auth->{user}->{branchcode}; # session param overrides stored branch my $userid = $self->{session}->get("userid") || $auth->{user}->{userid}; # session param overrides stored userid my $flags = $in->{flagsrequired}; #use Data::Dumper; warn Dumper($auth); my $info = {}; # no session - present login page if (not $userid) { my $template = C4::Templates::gettemplate( "auth.tt", $in->{type}, $self); $template->param( loginprompt => 1, error => $self->{session}->get("error") ); return $template; } my $template = C4::Templates::gettemplate( $name, $in->{type}, $self, $in->{is_plugin} ); # this is weird... #if ( $in->{'template_name'} !~ m/maintenance/ ) { # ( $user, $cookie, $sessionID, $flags ) = checkauth( # $in->{'query'}, # $in->{'authnotrequired'}, # $in->{'flagsrequired'}, # $in->{'type'} # ); #} $self->setTemplatePermissions( $template, $auth, $branch ); $self->setCustomTemplateParams( $template ); # Various overrides from previous C4::Auth::get_template_and_user return $template; } # set template permissions from auth object sub setTemplatePermissions { my ($self, $template, $auth, $branch) = @_; $template->param( LoginBranchname => $branch ); my $id = $self->{session}->get("id"); if ($self->{session}->get("admin")) { # Admin user login should be removed! warn "TEMPLATE CALLED WITH ADMINUSER - BETTER REMOVE THIS"; $auth->{permissions} = { superlibrarian => 1 }; $template->param(loggedinusername => $id); $template->param(adminWarning => 1); } else { $template->param("USER_INFO" => $auth->{user}); $template->param(loggedinusername => $auth->{user}->{userid}); $template->param(loggedinusernumber => $auth->{user}->{borrowernumber}); # for legacy? } my $all_perms = $self->getAllPermissions(); for my $name (keys %$all_perms ) { my $value = $auth->{permissions}->{superlibrarian} ? 1 : $auth->{permissions}->{$name}; $value //= 0; #warn "$name => $value"; next unless $value; # expand a true value to a list of submodules; $value = $all_perms->{$name} unless ref $value; $template->param( "CAN_user_${name}" => 1 ); # subpermissions for my $subname ( keys %$value ) { $template->param( "CAN_user_${name}_${subname}" => 1 ); } # deviations $template->param( "CAN_user_management" => 1 ) if $name eq "parameters"; $template->param( "CAN_user_catalogue" => 1 ) if $name eq "editcatalogue"; } return $template; } # TODO: this should be handled by core prefs module # Various overrides from previous C4::Auth::get_template_and_user sub setCustomTemplateParams { my ($self, $template) = @_; $template->param( dateformat => "dmydot", # dd.mm.yyyy minPasswordLength => 0, EnhancedMessagingPreferences => 1, KohaAdminEmailAddress => 'noreply@deichman.no', UseKohaPlugins => 1, CircAutocompl => 1, IntranetCatalogSearchPulldown => 1, item_level_itypes => 1, # from Auth # LoginBranchcode => C4::Context->userenv->{"branch"}, # LoginFirstname => C4::Context->userenv->{"firstname"}, # LoginSurname => C4::Context->userenv->{"surname"}, # emailaddress => C4::Context->userenv->{"emailaddress"}, # unused # TagsEnabled => C4::Context->preference("TagsEnabled"), # hide_marc => C4::Context->preference("hide_marc"), # item_level_itypes => C4::Context->preference('item-level_itypes'), # XSLTDetailsDisplay => C4::Context->preference("XSLTDetailsDisplay"), # XSLTResultsDisplay => C4::Context->preference("XSLTResultsDisplay"), # using_https => 0, # noItemTypeImages => C4::Context->preference("noItemTypeImages"), # marcflavour => C4::Context->preference("marcflavour"), # AmazonCoverImages => C4::Context->preference("AmazonCoverImages"), # AutoLocation => C4::Context->preference("AutoLocation"), # FRBRizeEditions => C4::Context->preference("FRBRizeEditions"), # IndependentBranches => C4::Context->preference("IndependentBranches"), # IntranetNav => C4::Context->preference("IntranetNav"), # IntranetmainUserblock => C4::Context->preference("IntranetmainUserblock"), # LibraryName => C4::Context->preference("LibraryName"), # LoginBranchname => ( C4::Context->userenv ? C4::Context->userenv->{"branchname"} : undef ), # advancedMARCEditor => C4::Context->preference("advancedMARCEditor"), # canreservefromotherbranches => C4::Context->preference('canreservefromotherbranches'), # intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"), # IntranetFavicon => C4::Context->preference("IntranetFavicon"), # intranetreadinghistory => C4::Context->preference("intranetreadinghistory"), # 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"), # EasyAnalyticalRecords => C4::Context->preference('EasyAnalyticalRecords'), # LocalCoverImages => C4::Context->preference('LocalCoverImages'), # OPACLocalCoverImages => C4::Context->preference('OPACLocalCoverImages'), # AllowMultipleCovers => C4::Context->preference('AllowMultipleCovers'), # EnableBorrowerFiles => C4::Context->preference('EnableBorrowerFiles'), # UseCourseReserves => C4::Context->preference("UseCourseReserves"), # useDischarge => C4::Context->preference('useDischarge'), ); } 1;