Auth.pm 11.3 KB
Newer Older
Benjamin Rokseth's avatar
Benjamin Rokseth committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
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) = @_;
    my $session = $self->{session};
    my $req     = $self->{req};

    $session or Deichman::Exception::Auth::InvalidSession->throw();
    $req     or Deichman::Exception::Auth::InvalidQuery->throw();

52 53
    C4::Context->_new_userenv( $session->id );

Benjamin Rokseth's avatar
Benjamin Rokseth committed
54
    if ($req->param("logout.x") ) {
55
        $self->LogOut();
Benjamin Rokseth's avatar
Benjamin Rokseth committed
56 57 58 59
    }
    # validate session
    my $auth = $session->get("auth");
    if ($auth) {
60
        $self->{logger}->debug("Got authenticated session: " . $auth->{user}->{userid});
Benjamin Rokseth's avatar
Benjamin Rokseth committed
61 62
        return;
    } else {
63
        $self->{logger}->debug("Session not authenticated, creating new");
Benjamin Rokseth's avatar
Benjamin Rokseth committed
64
        # Run all auth methods
65
        $auth = $self->checkAuthMethods();
66
        $auth or Deichman::Exception::Auth::InvalidSession->throw();
Benjamin Rokseth's avatar
Benjamin Rokseth committed
67 68 69
        $session->put(auth => $auth);
    }
    # decorate session with library, etc.
70 71
    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};
Benjamin Rokseth's avatar
Benjamin Rokseth committed
72 73
        try {
            my $lib = Deichman::Library->new()->Get($branchcode)->{library};
74 75
            $session->put(branch     => $lib->{branchcode});
            $session->put(branchname => $lib->{branchname});
Benjamin Rokseth's avatar
Benjamin Rokseth committed
76
        } catch {
77
            $self->{logger}->warn("Failed setting session branch");
78
            $self->{logger}->warn($_->description);
79 80
            $session->put(branch => "NO_LIBRARY_SET");
            $session->put(branchname => "NO_LIBRARY_SET");
Benjamin Rokseth's avatar
Benjamin Rokseth committed
81 82 83 84
        };

        # Set C4::Context user env
        C4::Context->set_userenv(
85
            $session->get("number"),
Benjamin Rokseth's avatar
Benjamin Rokseth committed
86
            $userid,
87
            map { $session->get($_); } qw/
Benjamin Rokseth's avatar
Benjamin Rokseth committed
88 89 90 91
                cardnumber firstname surname branch branchname
                flags emailaddress branchprinter shibbolet/,
        );
        # No idea what this is? Virtualshelves?
92 93 94
        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") );
Benjamin Rokseth's avatar
Benjamin Rokseth committed
95
    }
96
    # Should Auth return something?
Benjamin Rokseth's avatar
Benjamin Rokseth committed
97 98 99
    return;
}

100 101
sub LogOut {
    my ($self) = @_;
102
    $self->{logger}->debug("Deichman::Auth->LogOut Logging out of session");
103 104 105 106
    $self->{session}->clear();
    return $self;
}

Benjamin Rokseth's avatar
Benjamin Rokseth committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
# 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 {
            $auth = $class->new()->DoAuth($session, $req);
        } catch {
122
            $self->{logger}->debug("Session auth failed: ". $_->description);
Benjamin Rokseth's avatar
Benjamin Rokseth committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        };
        $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) = @_;
    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");
166 167
    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
168
    my $flags = $in->{flagsrequired}; # TODO this is unused
Benjamin Rokseth's avatar
Benjamin Rokseth committed
169

170
    #use Data::Dumper; warn Dumper($auth);
Benjamin Rokseth's avatar
Benjamin Rokseth committed
171 172
    my $info = {};

173 174 175 176
    # 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") );
Benjamin Rokseth's avatar
Benjamin Rokseth committed
177 178 179
        return $template;
    }

Benjamin Rokseth's avatar
Benjamin Rokseth committed
180
    my $template = C4::Templates::gettemplate( $name, $in->{type}, $self, $in->{is_plugin} ); # this is weird...
Benjamin Rokseth's avatar
Benjamin Rokseth committed
181 182 183 184 185 186 187 188 189 190

    #if ( $in->{'template_name'} !~ m/maintenance/ ) {
    #    ( $user, $cookie, $sessionID, $flags ) = checkauth(
    #            $in->{'query'},
    #            $in->{'authnotrequired'},
    #            $in->{'flagsrequired'},
    #            $in->{'type'}
    #    );
    #}

191
    $self->setTemplatePermissions( $template, $auth, $branch, $auth->{user}->{branchcode} );
192
    $self->setCustomTemplateParams( $template ); # Various overrides from previous C4::Auth::get_template_and_user
Benjamin Rokseth's avatar
Benjamin Rokseth committed
193 194 195 196 197
    return $template;
}

# set template permissions from auth object
sub setTemplatePermissions {
198
    my ($self, $template, $auth, $branchname, $branchcode) = @_;
Benjamin Rokseth's avatar
Benjamin Rokseth committed
199

200 201
    $template->param( LoginBranchname => $branchname );
    $template->param( LoginBranchcode => $branchcode );
202 203
    my $id = $self->{session}->get("id");
    if ($self->{session}->get("admin")) {
Benjamin Rokseth's avatar
Benjamin Rokseth committed
204
        # Admin user login should be removed!
205
        $self->{logger}->info("Template called with adminuser - better remove this");
Benjamin Rokseth's avatar
Benjamin Rokseth committed
206 207
        $auth->{permissions} = { superlibrarian => 1 };
        $template->param(loggedinusername => $id);
208
        $template->param(adminWarning => 1);
Benjamin Rokseth's avatar
Benjamin Rokseth committed
209 210 211 212 213
    } else {
        $template->param("USER_INFO" => $auth->{user});
        $template->param(loggedinusername => $auth->{user}->{userid});
        $template->param(loggedinusernumber => $auth->{user}->{borrowernumber}); # for legacy?
    }
Benjamin Rokseth's avatar
Benjamin Rokseth committed
214 215 216 217 218 219 220 221 222 223 224 225

    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 );
Benjamin Rokseth's avatar
Benjamin Rokseth committed
226
        # subpermissions
Benjamin Rokseth's avatar
Benjamin Rokseth committed
227 228 229
        for my $subname ( keys %$value ) {
            $template->param( "CAN_user_${name}_${subname}" => 1 );
        }
Benjamin Rokseth's avatar
Benjamin Rokseth committed
230 231 232
        # deviations
        $template->param( "CAN_user_management" => 1 ) if $name eq "parameters";
        $template->param( "CAN_user_catalogue" => 1 ) if $name eq "editcatalogue";
Benjamin Rokseth's avatar
Benjamin Rokseth committed
233 234 235
    }
    return $template;
}
236 237 238 239 240 241 242

# 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
243 244
        minPasswordLength => 0,
        EnhancedMessagingPreferences => 1,
245
        KohaAdminEmailAddress => 'noreply@deichman.no',
246 247
        UseKohaPlugins => 1,
        CircAutocompl => 1,
248
        IntranetCatalogSearchPulldown => 1,
249
        item_level_itypes => 1,
250 251 252
        IntranetUserCSS => "
.deichman-hidden { display: none !important; }
#aai_history_consent { display: none !important; }",
253
        canreservefromotherbranches => 1,
254 255
        intranetbookbag                 => 0,
        virtualshelves                  => 0,
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
        # 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"),
        # 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"),
        # 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"),
        # suggestion                      => C4::Context->preference("suggestion"),
        # 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'),
    );
}


Benjamin Rokseth's avatar
Benjamin Rokseth committed
298
1;