bibllios integration: added authentication
Signed-off-by: Chris Cormack <crc@liblime.com> Signed-off-by: Joshua Ferraro <jmf@liblime.com>
This commit is contained in:
parent
16cc7e1626
commit
6eaf0d6a6e
2 changed files with 301 additions and 0 deletions
250
C4/Auth.pm
250
C4/Auth.pm
|
@ -87,6 +87,9 @@ C4::Auth - Authenticates Koha users
|
|||
&checkauth
|
||||
&get_template_and_user
|
||||
);
|
||||
@EXPORT_OK = qw(
|
||||
&check_api_auth
|
||||
);
|
||||
|
||||
=item get_template_and_user
|
||||
|
||||
|
@ -752,6 +755,253 @@ sub checkauth {
|
|||
exit;
|
||||
}
|
||||
|
||||
=item check_api_auth
|
||||
|
||||
($status, $cookie, $sessionId) = check_api_auth($query, $userflags);
|
||||
|
||||
Given a CGI query containing the parameters 'userid' and 'password' and/or a session
|
||||
cookie, determine if the user has the privileges specified by C<$userflags>.
|
||||
|
||||
C<check_api_auth> is is meant for authenticating users of web services, and
|
||||
consequently will always return and will not attempt to redirect the user
|
||||
agent.
|
||||
|
||||
If a valid session cookie is already present, check_api_auth will return a status
|
||||
of "ok", the cookie, and the Koha session ID.
|
||||
|
||||
If no session cookie is present, check_api_auth will check the 'userid' and 'password
|
||||
parameters and create a session cookie and Koha session if the supplied credentials
|
||||
are OK.
|
||||
|
||||
Possible return values in C<$status> are:
|
||||
|
||||
=over 4
|
||||
|
||||
=item "ok" -- user authenticated; C<$cookie> and C<$sessionid> have valid values.
|
||||
|
||||
=item "failed" -- credentials are not correct; C<$cookie> and C<$sessionid> are undef
|
||||
|
||||
=item "maintenance" -- DB is in maintenance mode; no login possible at the moment
|
||||
|
||||
=item "expired -- session cookie has expired; API user should resubmit userid and password
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub check_api_auth {
|
||||
my $query = shift;
|
||||
my $flagsrequired = shift;
|
||||
|
||||
my $dbh = C4::Context->dbh;
|
||||
my $timeout = C4::Context->preference('timeout');
|
||||
$timeout = 600 unless $timeout;
|
||||
|
||||
unless (C4::Context->preference('Version')) {
|
||||
# database has not been installed yet
|
||||
return ("maintenance", undef, undef);
|
||||
}
|
||||
my $kohaversion=C4::Context::KOHAVERSION;
|
||||
$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, undef);
|
||||
}
|
||||
|
||||
# FIXME -- most of what follows is a copy-and-paste
|
||||
# of code from checkauth. There is an obvious need
|
||||
# for refactoring to separate the various parts of
|
||||
# the authentication code, but as of 2007-11-19 this
|
||||
# is deferred so as to not introduce bugs into the
|
||||
# regular authentication code for Koha 3.0.
|
||||
|
||||
# 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
|
||||
my $sessionID = undef;
|
||||
unless ($query->param('userid')) {
|
||||
$sessionID = $query->cookie("CGISESSID");
|
||||
}
|
||||
if ($sessionID) {
|
||||
my $storage_method = C4::Context->preference('SessionStorage');
|
||||
my $session;
|
||||
if ($storage_method eq 'mysql'){
|
||||
$session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
|
||||
}
|
||||
elsif ($storage_method eq 'Pg') {
|
||||
$session = new CGI::Session("driver:PostgreSQL", $sessionID, {Handle=>$dbh});
|
||||
}
|
||||
else {
|
||||
# catch all defaults to tmp should work on all systems
|
||||
$session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
|
||||
}
|
||||
C4::Context->_new_userenv($sessionID);
|
||||
if ($session) {
|
||||
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('branchprinter')
|
||||
);
|
||||
|
||||
my $ip = $session->param('ip');
|
||||
my $lasttime = $session->param('lasttime');
|
||||
my $userid = $session->param('id');
|
||||
if ( $lasttime < time() - $timeout ) {
|
||||
# time out
|
||||
$session->delete();
|
||||
C4::Context->_unset_userenv($sessionID);
|
||||
$userid = undef;
|
||||
$sessionID = undef;
|
||||
return ("expired", undef, undef);
|
||||
} elsif ( $ip ne $ENV{'REMOTE_ADDR'} ) {
|
||||
# IP address changed
|
||||
$session->delete();
|
||||
C4::Context->_unset_userenv($sessionID);
|
||||
$userid = undef;
|
||||
$sessionID = undef;
|
||||
return ("expired", undef, undef);
|
||||
} else {
|
||||
my $cookie = $query->cookie( CGISESSID => $session->id );
|
||||
$session->param('lasttime',time());
|
||||
my $flags = haspermission( $dbh, $userid, $flagsrequired );
|
||||
if ($flags) {
|
||||
return ("ok", $cookie, $sessionID);
|
||||
} else {
|
||||
$session->delete();
|
||||
C4::Context->_unset_userenv($sessionID);
|
||||
$userid = undef;
|
||||
$sessionID = undef;
|
||||
return ("failed", undef, undef);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ("expired", undef, undef);
|
||||
}
|
||||
} else {
|
||||
# new login
|
||||
my $userid = $query->param('userid');
|
||||
my $password = $query->param('password');
|
||||
unless ($userid and $password) {
|
||||
# caller did something wrong, fail the authenticateion
|
||||
return ("failed", undef, undef);
|
||||
}
|
||||
my ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password );
|
||||
if ($return and haspermission( $dbh, $userid, $flagsrequired)) {
|
||||
my $storage_method = C4::Context->preference('SessionStorage');
|
||||
my $session;
|
||||
if ($storage_method eq 'mysql'){
|
||||
$session = new CGI::Session("driver:MySQL", $sessionID, {Handle=>$dbh});
|
||||
} elsif ($storage_method eq 'Pg') {
|
||||
$session = new CGI::Session("driver:PostgreSQL", $sessionID, {Handle=>$dbh});
|
||||
} else {
|
||||
# catch all defaults to tmp should work on all systems
|
||||
$session = new CGI::Session("driver:File", $sessionID, {Directory=>'/tmp'});
|
||||
}
|
||||
return ("failed", undef, undef) unless $session;
|
||||
|
||||
my $sessionID = $session->id;
|
||||
C4::Context->_new_userenv($sessionID);
|
||||
my $cookie = $query->cookie(CGISESSID => $sessionID);
|
||||
if ( $return == 1 ) {
|
||||
my (
|
||||
$borrowernumber, $firstname, $surname,
|
||||
$userflags, $branchcode, $branchname,
|
||||
$branchprinter, $emailaddress
|
||||
);
|
||||
my $sth =
|
||||
$dbh->prepare(
|
||||
"select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname,branches.branchprinter as branchprinter, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where userid=?"
|
||||
);
|
||||
$sth->execute($userid);
|
||||
(
|
||||
$borrowernumber, $firstname, $surname,
|
||||
$userflags, $branchcode, $branchname,
|
||||
$branchprinter, $emailaddress
|
||||
) = $sth->fetchrow if ( $sth->rows );
|
||||
|
||||
unless ($sth->rows ) {
|
||||
my $sth = $dbh->prepare(
|
||||
"select borrowernumber, firstname, surname, flags, borrowers.branchcode, branches.branchname as branchname, branches.branchprinter as branchprinter, email from borrowers left join branches on borrowers.branchcode=branches.branchcode where cardnumber=?"
|
||||
);
|
||||
$sth->execute($cardnumber);
|
||||
(
|
||||
$borrowernumber, $firstname, $surname,
|
||||
$userflags, $branchcode, $branchname,
|
||||
$branchprinter, $emailaddress
|
||||
) = $sth->fetchrow if ( $sth->rows );
|
||||
|
||||
unless ( $sth->rows ) {
|
||||
$sth->execute($userid);
|
||||
(
|
||||
$borrowernumber, $firstname, $surname, $userflags,
|
||||
$branchcode, $branchname, $branchprinter, $emailaddress
|
||||
) = $sth->fetchrow if ( $sth->rows );
|
||||
}
|
||||
}
|
||||
|
||||
my $ip = $ENV{'REMOTE_ADDR'};
|
||||
# if they specify at login, use that
|
||||
if ($query->param('branch')) {
|
||||
$branchcode = $query->param('branch');
|
||||
$branchname = GetBranchName($branchcode);
|
||||
}
|
||||
my $branches = GetBranches();
|
||||
my @branchesloop;
|
||||
foreach my $br ( keys %$branches ) {
|
||||
# now we work with the treatment of ip
|
||||
my $domain = $branches->{$br}->{'branchip'};
|
||||
if ( $domain && $ip =~ /^$domain/ ) {
|
||||
$branchcode = $branches->{$br}->{'branchcode'};
|
||||
|
||||
# new op dev : add the branchprinter and branchname in the cookie
|
||||
$branchprinter = $branches->{$br}->{'branchprinter'};
|
||||
$branchname = $branches->{$br}->{'branchname'};
|
||||
}
|
||||
}
|
||||
$session->param('number',$borrowernumber);
|
||||
$session->param('id',$userid);
|
||||
$session->param('cardnumber',$cardnumber);
|
||||
$session->param('firstname',$firstname);
|
||||
$session->param('surname',$surname);
|
||||
$session->param('branch',$branchcode);
|
||||
$session->param('branchname',$branchname);
|
||||
$session->param('flags',$userflags);
|
||||
$session->param('emailaddress',$emailaddress);
|
||||
$session->param('ip',$session->remote_addr());
|
||||
$session->param('lasttime',time());
|
||||
} elsif ( $return == 2 ) {
|
||||
#We suppose the user is the superlibrarian
|
||||
$session->param('number',0);
|
||||
$session->param('id',C4::Context->config('user'));
|
||||
$session->param('cardnumber',C4::Context->config('user'));
|
||||
$session->param('firstname',C4::Context->config('user'));
|
||||
$session->param('surname',C4::Context->config('user'));
|
||||
$session->param('branch','NO_LIBRARY_SET');
|
||||
$session->param('branchname','NO_LIBRARY_SET');
|
||||
$session->param('flags',1);
|
||||
$session->param('emailaddress', C4::Context->preference('KohaAdminEmailAddress'));
|
||||
$session->param('ip',$session->remote_addr());
|
||||
$session->param('lasttime',time());
|
||||
}
|
||||
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('branchprinter')
|
||||
);
|
||||
return ("ok", $cookie, $sessionID);
|
||||
} else {
|
||||
return ("failed", undef, undef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub checkpw {
|
||||
|
||||
my ( $dbh, $userid, $password ) = @_;
|
||||
|
|
51
biblios/authentication
Executable file
51
biblios/authentication
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Copyright 2007 LibLime
|
||||
#
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
# Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
use strict;
|
||||
use CGI;
|
||||
use C4::Auth qw/check_api_auth/;
|
||||
use XML::Simple;
|
||||
|
||||
my $query = new CGI;
|
||||
|
||||
# The authentication strategy for the biblios web
|
||||
# services is as follows.
|
||||
#
|
||||
# 1. biblios POSTs to the authenticate API with URL-encoded
|
||||
# form parameters 'userid' and 'password'. If the credentials
|
||||
# belong to a valid user with the 'editcatalogue' privilege,
|
||||
# a session cookie is returned and a Koha session created. Otherwise, an
|
||||
# appropriate error is returned.
|
||||
# 2. For subsequent calls to the biblios APIs, the user agent
|
||||
# should submit the same session cookie. If the cookie is
|
||||
# not supplied or does not correspond to a valid session, the API
|
||||
# will redirect to this authentication API.
|
||||
# 3. The session cookie should not be (directly) sent back to the user's
|
||||
# web browser, but instead should be stored and submitted by biblios.
|
||||
|
||||
|
||||
my ($status, $cookie, $sessionID) = check_api_auth($query, { editcatalogue => 1} );
|
||||
|
||||
if ($status eq "ok") {
|
||||
print $query->header(-type => 'text/xml', cookie => $cookie);
|
||||
} else {
|
||||
print $query->header(-type => 'text/xml');
|
||||
}
|
||||
print XMLout({ status => $status }, NoAttr => 1, RootName => 'response', XMLDecl => 1);
|
Loading…
Reference in a new issue