View | Details | Raw Unified | Return to bug 8446
Collapse All | Expand All

(-)a/C4/Auth.pm (-8 / +68 lines)
Lines 34-40 use POSIX qw/strftime/; Link Here
34
use List::MoreUtils qw/ any /;
34
use List::MoreUtils qw/ any /;
35
35
36
# use utf8;
36
# use utf8;
37
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout);
37
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout $shib $shib_login);
38
38
39
BEGIN {
39
BEGIN {
40
    sub psgi_env { any { /^psgi\./ } keys %ENV }
40
    sub psgi_env { any { /^psgi\./ } keys %ENV }
Lines 54-65 BEGIN { Link Here
54
    %EXPORT_TAGS = ( EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)] );
54
    %EXPORT_TAGS = ( EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)] );
55
    $ldap        = C4::Context->config('useldapserver') || 0;
55
    $ldap        = C4::Context->config('useldapserver') || 0;
56
    $cas         = C4::Context->preference('casAuthentication');
56
    $cas         = C4::Context->preference('casAuthentication');
57
    $shib        = C4::Context->preference('shibbolethAuthentication');
57
    $caslogout   = C4::Context->preference('casLogout');
58
    $caslogout   = C4::Context->preference('casLogout');
58
    require C4::Auth_with_cas;             # no import
59
    require C4::Auth_with_cas;             # no import
60
    require C4::Auth_with_Shibboleth;
59
    if ($ldap) {
61
    if ($ldap) {
60
    require C4::Auth_with_ldap;
62
    require C4::Auth_with_ldap;
61
    import C4::Auth_with_ldap qw(checkpw_ldap);
63
    import C4::Auth_with_ldap qw(checkpw_ldap);
62
    }
64
    }
65
    if ($shib) {
66
        import C4::Auth_with_Shibboleth qw(checkpw_shib logout_shib login_shib_url get_login_shib);
67
        # Getting user login
68
        $shib_login = get_login_shib();
69
    }
63
    if ($cas) {
70
    if ($cas) {
64
        import  C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url);
71
        import  C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url);
65
    }
72
    }
Lines 646-653 sub checkauth { Link Here
646
    # when using authentication against multiple CAS servers, as configured in Auth_cas_servers.yaml
653
    # when using authentication against multiple CAS servers, as configured in Auth_cas_servers.yaml
647
    my $casparam = $query->param('cas');
654
    my $casparam = $query->param('cas');
648
655
649
    if ( $userid = $ENV{'REMOTE_USER'} ) {
656
    # Basic authentication is incompatible with the use of Shibboleth, 
650
            # Using Basic Authentication, no cookies required
657
    # as Shibboleth may return REMOTE_USER as a Shibboleth attribute, 
658
    # and it may not be the attribute we want to use to match the koha login.
659
    # 
660
    # Also, do not consider an empty REMOTE_USER.
661
    #
662
    # Finally, after those tests, we can assume (although if it would be better with
663
    # a syspref) that if we get a REMOTE_USER, that's from basic authentication,
664
    # and we can affect it to $userid. 
665
    if ( !$shib and $ENV{'REMOTE_USER'} ne '' and $userid = $ENV{'REMOTE_USER'} ) {
666
667
        # Using Basic Authentication, no cookies required
651
        $cookie = $query->cookie(
668
        $cookie = $query->cookie(
652
            -name     => 'CGISESSID',
669
            -name     => 'CGISESSID',
653
            -value    => '',
670
            -value    => '',
Lines 702-712 sub checkauth { Link Here
702
            $sessionID = undef;
719
            $sessionID = undef;
703
            $userid    = undef;
720
            $userid    = undef;
704
721
705
        if ($cas and $caslogout) {
722
            if ($cas and $caslogout) {
706
        logout_cas($query);
723
                logout_cas($query);
707
        }
724
            }
725
726
            # If we are in a shibboleth session (shibboleth is enabled, and a shibboleth username is set)
727
            if ( $shib and $shib_login and $type eq 'opac') {
728
            # (Note: $type eq 'opac' condition should be removed when shibboleth authentication for intranet will be implemented)
729
                logout_shib($query);
730
            }
708
        }
731
        }
709
        elsif ( $lasttime < time() - $timeout ) {
732
        elsif ( $lasttime < time() - $timeout ) {
733
710
            # timed logout
734
            # timed logout
711
            $info{'timed_out'} = 1;
735
            $info{'timed_out'} = 1;
712
            $session->delete() if $session;
736
            $session->delete() if $session;
Lines 754-769 sub checkauth { Link Here
754
            -value    => $session->id,
778
            -value    => $session->id,
755
            -HttpOnly => 1
779
            -HttpOnly => 1
756
        );
780
        );
757
    $userid = $query->param('userid');
781
        $userid = $query->param('userid');
758
        if (   ( $cas && $query->param('ticket') )
782
        if (   ( $cas && $query->param('ticket') )
759
            || $userid
783
            || $userid
784
            || $shib
760
            || ( my $pki_field = C4::Context->preference('AllowPKIAuth') ) ne
785
            || ( my $pki_field = C4::Context->preference('AllowPKIAuth') ) ne
761
            'None' || $persona )
786
            'None' || $persona )
762
        {
787
        {
763
            my $password = $query->param('password');
788
            my $password = $query->param('password');
764
789
765
            my ( $return, $cardnumber );
790
            my ( $return, $cardnumber );
766
            if ( $cas && $query->param('ticket') ) {
791
            if ($shib && $shib_login && $type eq 'opac' && !$password) {
792
                my $retuserid;
793
                ( $return, $cardnumber, $retuserid ) = checkpw( $dbh, $userid, $password, $query );
794
                $userid = $retuserid;
795
                $info{'invalidShibLogin'} = 1 unless ($return);
796
797
            } elsif ( $cas && $query->param('ticket') ) {
767
                my $retuserid;
798
                my $retuserid;
768
                ( $return, $cardnumber, $retuserid ) =
799
                ( $return, $cardnumber, $retuserid ) =
769
                  checkpw( $dbh, $userid, $password, $query );
800
                  checkpw( $dbh, $userid, $password, $query );
Lines 1008-1013 sub checkauth { Link Here
1008
        login                => 1,
1039
        login                => 1,
1009
        INPUTS               => \@inputs,
1040
        INPUTS               => \@inputs,
1010
        casAuthentication    => C4::Context->preference("casAuthentication"),
1041
        casAuthentication    => C4::Context->preference("casAuthentication"),
1042
        shibbolethAuthentication => C4::Context->preference("shibbolethAuthentication"),
1011
        suggestion           => C4::Context->preference("suggestion"),
1043
        suggestion           => C4::Context->preference("suggestion"),
1012
        virtualshelves       => C4::Context->preference("virtualshelves"),
1044
        virtualshelves       => C4::Context->preference("virtualshelves"),
1013
        LibraryName          => "" . C4::Context->preference("LibraryName"),
1045
        LibraryName          => "" . C4::Context->preference("LibraryName"),
Lines 1079-1084 sub checkauth { Link Here
1079
        );
1111
        );
1080
    }
1112
    }
1081
1113
1114
    if ($shib) {
1115
            $template->param(
1116
                shibbolethLoginUrl    => login_shib_url($query),
1117
            );
1118
    }
1119
1082
    my $self_url = $query->url( -absolute => 1 );
1120
    my $self_url = $query->url( -absolute => 1 );
1083
    $template->param(
1121
    $template->param(
1084
        url         => $self_url,
1122
        url         => $self_url,
Lines 1505-1510 sub checkpw { Link Here
1505
        return 0;
1543
        return 0;
1506
    }
1544
    }
1507
1545
1546
    # If we are in a shibboleth session (shibboleth is enabled and no password has been provided)
1547
    if ($shib && !$password) {
1548
 
1549
        $debug and print STDERR "## checkpw - checking Shibboleth\n";
1550
        # In case of a Shibboleth authentication, we expect a shibboleth user attribute 
1551
        # (defined in the shibbolethLoginAttribute) tto contain the login of the 
1552
        # shibboleth-authenticated user
1553
 
1554
        # Shibboleth attributes are mapped into http environmement variables,
1555
        # so we're getting the login of the user this way
1556
        my $attributename = C4::Context->preference('shibbolethLoginAttribute');
1557
        my $attributevalue = $ENV{$attributename};
1558
 
1559
        # Then, we check if it matches a valid koha user
1560
        if ($shib_login) {
1561
            my ( $retval, $retcard, $retuserid ) = C4::Auth_with_Shibboleth::checkpw_shib( $dbh, $shib_login );    # EXTERNAL AUTH
1562
            ($retval) and return ( $retval, $retcard, $retuserid );
1563
            return 0;
1564
        }
1565
    }
1566
 
1567
    # INTERNAL AUTH
1508
    return checkpw_internal(@_)
1568
    return checkpw_internal(@_)
1509
}
1569
}
1510
1570
(-)a/C4/Auth_with_Shibboleth.pm (+100 lines)
Line 0 Link Here
1
package C4::Auth_with_Shibboleth;
2
3
# Copyright 2011 BibLibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use strict;
21
use warnings;
22
23
use C4::Debug;
24
use C4::Context;
25
use C4::Utils qw( :all );
26
use CGI;
27
28
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug);
29
30
BEGIN {
31
    require Exporter;
32
    $VERSION = 3.03;                                                                    # set the version for version checking
33
    $debug   = $ENV{DEBUG};
34
    @ISA     = qw(Exporter);
35
    @EXPORT  = qw(logout_shib login_shib_url checkpw_shib get_login_shib);
36
}
37
my $context = C4::Context->new() or die 'C4::Context->new failed';
38
my $protocol = "https://";
39
40
# Logout from Shibboleth
41
sub logout_shib {
42
    my ($query) = @_;
43
    my $uri = $protocol . $ENV{'SERVER_NAME'};
44
    print $query->redirect( $uri . "/Shibboleth.sso/Logout?return=$uri" );
45
}
46
47
# Returns Shibboleth login URL with callback to the requesting URL
48
sub login_shib_url {
49
50
    my ($query) = @_;
51
    my $param = $protocol . $ENV{'SERVER_NAME'} . $query->script_name();
52
    my $uri = $protocol . $ENV{'SERVER_NAME'} . "/Shibboleth.sso/Login?target=$param";
53
    return $uri;
54
}
55
56
# Returns shibboleth user login
57
sub get_login_shib {
58
59
    # In case of a Shibboleth authentication, we expect a shibboleth user attribute (defined in the shibbolethLoginAttribute)
60
    # to contain the login of the shibboleth-authenticated user
61
62
    # Shibboleth attributes are mapped into http environmement variables,
63
    # so we're getting the login of the user this way
64
65
    my $shibbolethLoginAttribute = C4::Context->preference('shibbolethLoginAttribute');
66
    $debug and warn "shibbolethLoginAttribute value: $shibbolethLoginAttribute";
67
    $debug and warn "$shibbolethLoginAttribute value: " . $ENV{$shibbolethLoginAttribute};
68
69
    return $ENV{$shibbolethLoginAttribute};
70
}
71
72
# Checks for password correctness
73
# In our case : does the given username matches one of our users ?
74
sub checkpw_shib {
75
    $debug and warn "checkpw_shib";
76
77
    my ( $dbh, $userid ) = @_;
78
    my $retnumber;
79
    $debug and warn "User Shibboleth-authenticated as: $userid";
80
81
    # Does it match one of our users ?
82
    my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
83
    $sth->execute($userid);
84
    if ( $sth->rows ) {
85
        $retnumber = $sth->fetchrow;
86
        return ( 1, $retnumber, $userid );
87
    }
88
    $sth = $dbh->prepare("select userid from borrowers where cardnumber=?");
89
    $sth->execute($userid);
90
    if ( $sth->rows ) {
91
        $retnumber = $sth->fetchrow;
92
        return ( 1, $retnumber, $userid );
93
    }
94
95
    # If we reach this point, the user is not a valid koha user
96
    $debug and warn "User $userid is not a valid Koha user";
97
    return 0;
98
}
99
100
1;
(-)a/installer/data/mysql/updatedatabase.pl (+8 lines)
Lines 7306-7311 if ( CheckVersion($DBversion) ) { Link Here
7306
    SetVersion($DBversion);
7306
    SetVersion($DBversion);
7307
}
7307
}
7308
7308
7309
$DBversion = "XXX";
7310
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
7311
    $dbh->do("INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('shibbolethAuthentication','','','Enable or disable Shibboleth authentication','YesNo')");
7312
    $dbh->do("INSERT INTO `systempreferences` (variable,value,options,explanation,type) VALUES('shibbolethLoginAttribute','','','Which shibboleth user attribute should be used to match koha user login?','')");
7313
    print "Upgrade to $DBversion done (Adds shibbolethAuthentication and shibbolethLoginAttribute preferences)\n";
7314
    SetVersion ($DBversion);
7315
}
7316
7309
=head1 FUNCTIONS
7317
=head1 FUNCTIONS
7310
7318
7311
=head2 TableExists($table)
7319
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref (+11 lines)
Lines 105-110 Administration: Link Here
105
                  yes: Allow
105
                  yes: Allow
106
                  no: "Don't Allow"
106
                  no: "Don't Allow"
107
            - Mozilla persona for login
107
            - Mozilla persona for login
108
    Shibboleth Authentication:
109
        -
110
            - pref: shibbolethAuthentication
111
              default: 0
112
              choices:
113
                  yes: Use
114
                  no: "Don't use"
115
            - Shibboleth for login authentication.
116
        -
117
            - Which shibboleth user attribute should be used to match koha user login?
118
            - pref: shibbolethLoginAttribute
108
    Search Engine:
119
    Search Engine:
109
        -
120
        -
110
            - pref: SearchEngine
121
            - pref: SearchEngine
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt (+16 lines)
Lines 46-51 Link Here
46
<p>You entered an incorrect username or password. Please try again! And remember, usernames and passwords are case sensitive.</p>
46
<p>You entered an incorrect username or password. Please try again! And remember, usernames and passwords are case sensitive.</p>
47
[% END %]
47
[% END %]
48
48
49
[% IF ( shibbolethAuthentication ) %]
50
<h4>Shibboleth Login</h4>
51
52
[% IF ( invalidShibLogin ) %]
53
<!-- This is what is displated if shibboleth login has failed -->
54
<p>Sorry, the shibboleth login failed.</p>
55
[% END %]
56
57
<p>If you have a shibboleth account, 
58
please <a href="[% shibbolethLoginUrl %]">click here to login</a>.</p>
59
60
<h4>Local Login</h4>
61
<p>If you do not have a shibboleth account, but a local account, you can still log in : </p>
62
63
[% END %]
64
49
[% IF ( casAuthentication ) %]
65
[% IF ( casAuthentication ) %]
50
<h4>Cas login</h4>
66
<h4>Cas login</h4>
51
67
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt (+1 lines)
Lines 47-52 Link Here
47
    [% IF ( opacuserlogin ) %]
47
    [% IF ( opacuserlogin ) %]
48
    [% UNLESS ( loggedinusername ) %]
48
    [% UNLESS ( loggedinusername ) %]
49
    [% UNLESS ( casAuthentication ) %]
49
    [% UNLESS ( casAuthentication ) %]
50
    [% UNLESS ( shibbolethAuthentication ) %]
50
    <div id="login" class="container clearfix">
51
    <div id="login" class="container clearfix">
51
	<form action="/cgi-bin/koha/opac-user.pl" method="post" name="auth" id="auth">
52
	<form action="/cgi-bin/koha/opac-user.pl" method="post" name="auth" id="auth">
52
    <input type="hidden" name="koha_login_context" value="opac" />
53
    <input type="hidden" name="koha_login_context" value="opac" />
(-)a/kohaversion.pl (-1 / +1 lines)
Lines 16-22 the kohaversion is divided in 4 parts : Link Here
16
use strict;
16
use strict;
17
17
18
sub kohaversion {
18
sub kohaversion {
19
    our $VERSION = '3.13.00.031';
19
    our $VERSION = 'XXX';
20
    # version needs to be set this way
20
    # version needs to be set this way
21
    # so that it can be picked up by Makefile.PL
21
    # so that it can be picked up by Makefile.PL
22
    # during install
22
    # during install
(-)a/opac/opac-main.pl (+2 lines)
Lines 43-48 $template->param( Link Here
43
    casAuthentication   => $casAuthentication,
43
    casAuthentication   => $casAuthentication,
44
);
44
);
45
45
46
my $shibbolethAuthentication = C4::Context->preference('shibbolethAuthentication');
47
$template->param( shibbolethAuthentication => $shibbolethAuthentication);
46
48
47
# display news
49
# display news
48
# use cookie setting for language, bug default to syspref if it's not set
50
# use cookie setting for language, bug default to syspref if it's not set
(-)a/opac/opac-user.pl (-1 / +3 lines)
Lines 72-77 for ( C4::Context->preference("OPACShowHoldQueueDetails") ) { Link Here
72
my $patronupdate = $query->param('patronupdate');
72
my $patronupdate = $query->param('patronupdate');
73
my $canrenew = 1;
73
my $canrenew = 1;
74
74
75
my $shibbolethAuthentication = C4::Context->preference('shibbolethAuthentication');
76
$template->param( shibbolethAuthentication => $shibbolethAuthentication );
77
75
# get borrower information ....
78
# get borrower information ....
76
my ( $borr ) = GetMemberDetails( $borrowernumber );
79
my ( $borr ) = GetMemberDetails( $borrowernumber );
77
80
78
- 

Return to bug 8446