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

(-)a/C4/Auth.pm (-49 / +78 lines)
Lines 32-58 use C4::Koha; Link Here
32
use C4::Branch; # GetBranches
32
use C4::Branch; # GetBranches
33
use C4::VirtualShelves;
33
use C4::VirtualShelves;
34
use POSIX qw/strftime/;
34
use POSIX qw/strftime/;
35
use List::MoreUtils qw/ any /;
35
36
36
# use utf8;
37
# use utf8;
37
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout $servers $memcached);
38
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug $ldap $cas $caslogout $servers $memcached);
38
39
39
BEGIN {
40
BEGIN {
40
    $VERSION = 3.02;        # set version for version checking
41
    sub psgi_env { any { /^psgi\./ } keys %ENV }
41
    $debug = $ENV{DEBUG};
42
    sub safe_exit {
42
    @ISA   = qw(Exporter);
43
	if ( psgi_env ) { die 'psgi:exit' }
43
    @EXPORT    = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions);
44
	else { exit }
44
    @EXPORT_OK = qw(&check_api_auth &get_session &check_cookie_auth &checkpw &get_all_subpermissions &get_user_subpermissions);
45
    }
45
    %EXPORT_TAGS = (EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)]);
46
46
    $ldap = C4::Context->config('useldapserver') || 0;
47
    $VERSION     = 3.02;                                                                                                            # set version for version checking
47
    $cas = C4::Context->preference('casAuthentication');
48
    $debug       = $ENV{DEBUG};
48
    $caslogout = C4::Context->preference('casLogout');
49
    @ISA         = qw(Exporter);
50
    @EXPORT      = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions);
51
    @EXPORT_OK   = qw(&check_api_auth &get_session &check_cookie_auth &checkpw &get_all_subpermissions &get_user_subpermissions);
52
    %EXPORT_TAGS = ( EditPermissions => [qw(get_all_subpermissions get_user_subpermissions)] );
53
    $ldap        = C4::Context->config('useldapserver') || 0;
54
    $cas         = C4::Context->preference('casAuthentication');
55
    $caslogout   = C4::Context->preference('casLogout');
56
    require C4::Auth_with_cas;             # no import
49
    if ($ldap) {
57
    if ($ldap) {
50
        require C4::Auth_with_ldap;             # no import
58
	require C4::Auth_with_ldap;
51
        import  C4::Auth_with_ldap qw(checkpw_ldap);
59
	# no import import C4::Auth_with_ldap qw(checkpw_ldap);
52
    }
60
    }
53
    if ($cas) {
61
    if ($cas) {
54
        require C4::Auth_with_cas;             # no import
62
        import  C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url);
55
        import  C4::Auth_with_cas qw(checkpw_cas login_cas logout_cas login_cas_url);
56
    }
63
    }
57
    $servers = C4::Context->config('memcached_servers');
64
    $servers = C4::Context->config('memcached_servers');
58
    if ($servers) {
65
    if ($servers) {
Lines 130-137 Output.pm module. Link Here
130
=cut
137
=cut
131
138
132
my $SEARCH_HISTORY_INSERT_SQL =<<EOQ;
139
my $SEARCH_HISTORY_INSERT_SQL =<<EOQ;
133
INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, total, time            )
140
INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, limit_desc, limit_cgi, total, time            )
134
VALUES                    (     ?,         ?,          ?,         ?,     ?, FROM_UNIXTIME(?))
141
VALUES                    (     ?,         ?,          ?,         ?,          ?,         ?,     ?, FROM_UNIXTIME(?))
135
EOQ
142
EOQ
136
sub get_template_and_user {
143
sub get_template_and_user {
137
    my $in       = shift;
144
    my $in       = shift;
Lines 264-276 sub get_template_and_user { Link Here
264
			        my @recentSearches = @{thaw($searchcookie) || []};
271
			        my @recentSearches = @{thaw($searchcookie) || []};
265
				if (@recentSearches) {
272
				if (@recentSearches) {
266
					my $sth = $dbh->prepare($SEARCH_HISTORY_INSERT_SQL);
273
					my $sth = $dbh->prepare($SEARCH_HISTORY_INSERT_SQL);
267
					$sth->execute( $borrowernumber,
274
                    
268
						       $in->{'query'}->cookie("CGISESSID"),
275
                    $sth->execute( $borrowernumber, $in->{'query'}->cookie("CGISESSID"), $_->{'query_desc'}, $_->{'query_cgi'}, $_->{'limit_desc'}, $_->{'limit_cgi'}, $_->{'total'}, $_->{'time'}, )
269
						       $_->{'query_desc'},
276
                                foreach @recentSearches;
270
						       $_->{'query_cgi'},
271
						       $_->{'total'},
272
						       $_->{'time'},
273
                                        ) foreach @recentSearches;
274
277
275
					# And then, delete the cookie's content
278
					# And then, delete the cookie's content
276
					my $newsearchcookie = $in->{'query'}->cookie(
279
					my $newsearchcookie = $in->{'query'}->cookie(
Lines 571-589 sub _version_check ($$) { Link Here
571
    # and so we must redirect to OPAC maintenance page or to the WebInstaller
574
    # and so we must redirect to OPAC maintenance page or to the WebInstaller
572
	# also, if OpacMaintenance is ON, OPAC should redirect to maintenance
575
	# also, if OpacMaintenance is ON, OPAC should redirect to maintenance
573
	if (C4::Context->preference('OpacMaintenance') && $type eq 'opac') {
576
	if (C4::Context->preference('OpacMaintenance') && $type eq 'opac') {
574
		warn "OPAC Install required, redirecting to maintenance";
575
		print $query->redirect("/cgi-bin/koha/maintenance.pl");
576
	}
577
    unless ($version = C4::Context->preference('Version')) {    # assignment, not comparison
578
      if ($type ne 'opac') {
579
        warn "Install required, redirecting to Installer";
580
        print $query->redirect("/cgi-bin/koha/installer/install.pl");
581
      }
582
      else {
583
        warn "OPAC Install required, redirecting to maintenance";
577
        warn "OPAC Install required, redirecting to maintenance";
584
        print $query->redirect("/cgi-bin/koha/maintenance.pl");
578
        print $query->redirect("/cgi-bin/koha/maintenance.pl");
585
      }
579
    }
586
      exit;
580
    unless ( $version = C4::Context->preference('Version') ) {    # assignment, not comparison
581
        if ( $type ne 'opac' ) {
582
            warn "Install required, redirecting to Installer";
583
            print $query->redirect("/cgi-bin/koha/installer/install.pl");
584
        } else {
585
            warn "OPAC Install required, redirecting to maintenance";
586
            print $query->redirect("/cgi-bin/koha/maintenance.pl");
587
        }
588
        safe_exit;
587
    }
589
    }
588
590
589
    # check that database and koha version are the same
591
    # check that database and koha version are the same
Lines 603-609 sub _version_check ($$) { Link Here
603
            warn sprintf("OPAC: " . $warning, 'maintenance');
605
            warn sprintf("OPAC: " . $warning, 'maintenance');
604
            print $query->redirect("/cgi-bin/koha/maintenance.pl");
606
            print $query->redirect("/cgi-bin/koha/maintenance.pl");
605
        }
607
        }
606
        exit;
608
        safe_exit;
607
    }
609
    }
608
}
610
}
609
611
Lines 638-643 sub checkauth { Link Here
638
    my ( $userid, $cookie, $sessionID, $flags, $barshelves, $pubshelves );
640
    my ( $userid, $cookie, $sessionID, $flags, $barshelves, $pubshelves );
639
    my $logout = $query->param('logout.x');
641
    my $logout = $query->param('logout.x');
640
642
643
    # This parameter is the name of the CAS server we want to authenticate against,
644
    # when using authentication against multiple CAS servers, as configured in Auth_cas_servers.yaml
645
    my $casparam = $query->param('cas');
646
641
    if ( $userid = $ENV{'REMOTE_USER'} ) {
647
    if ( $userid = $ENV{'REMOTE_USER'} ) {
642
        # Using Basic Authentication, no cookies required
648
        # Using Basic Authentication, no cookies required
643
        $cookie = $query->cookie(
649
        $cookie = $query->cookie(
Lines 985-995 sub checkauth { Link Here
985
    $template->param( OpacPublic => C4::Context->preference("OpacPublic"));
991
    $template->param( OpacPublic => C4::Context->preference("OpacPublic"));
986
    $template->param( loginprompt => 1 ) unless $info{'nopermission'};
992
    $template->param( loginprompt => 1 ) unless $info{'nopermission'};
987
993
988
    if ($cas) { 
994
    if ($cas) {
995
996
	# Is authentication against multiple CAS servers enabled?
997
        if (C4::Auth_with_cas::multipleAuth && !$casparam) {
998
	    my $casservers = C4::Auth_with_cas::getMultipleAuth();		    
999
	    my @tmplservers;
1000
	    foreach my $key (keys %$casservers) {
1001
		push @tmplservers, {name => $key, value => login_cas_url($query, $key) . "?cas=$key" };
1002
	    }
1003
	    #warn Data::Dumper::Dumper(\@tmplservers);
1004
	    $template->param(
1005
		casServersLoop => \@tmplservers
1006
	    );
1007
	} else {
1008
        $template->param(
1009
            casServerUrl    => login_cas_url($query),
1010
	    );
1011
	}
1012
989
	$template->param(
1013
	$template->param(
990
	    casServerUrl    => login_cas_url(),
1014
            invalidCasLogin => $info{'invalidCasLogin'}
991
	    invalidCasLogin => $info{'invalidCasLogin'}
1015
        );
992
	);
993
    }
1016
    }
994
1017
995
    my $self_url = $query->url( -absolute => 1 );
1018
    my $self_url = $query->url( -absolute => 1 );
Lines 1006-1012 sub checkauth { Link Here
1006
        -cookie => $cookie
1029
        -cookie => $cookie
1007
      ),
1030
      ),
1008
      $template->output;
1031
      $template->output;
1009
    exit;
1032
    safe_exit;
1010
}
1033
}
1011
1034
1012
=head2 check_api_auth
1035
=head2 check_api_auth
Lines 1079-1085 sub check_api_auth { Link Here
1079
    unless ($query->param('userid')) {
1102
    unless ($query->param('userid')) {
1080
        $sessionID = $query->cookie("CGISESSID");
1103
        $sessionID = $query->cookie("CGISESSID");
1081
    }
1104
    }
1082
    if ($sessionID) {
1105
    if ($sessionID && not $cas) {
1083
        my $session = get_session($sessionID);
1106
        my $session = get_session($sessionID);
1084
        C4::Context->_new_userenv($sessionID);
1107
        C4::Context->_new_userenv($sessionID);
1085
        if ($session) {
1108
        if ($session) {
Lines 1129-1146 sub check_api_auth { Link Here
1129
        # new login
1152
        # new login
1130
        my $userid = $query->param('userid');
1153
        my $userid = $query->param('userid');
1131
        my $password = $query->param('password');
1154
        my $password = $query->param('password');
1132
        unless ($userid and $password) {
1155
       	my ($return, $cardnumber);
1133
            # caller did something wrong, fail the authenticateion
1156
1134
            return ("failed", undef, undef);
1157
	# Proxy CAS auth
1135
        }
1158
	if ($cas && $query->param('PT')) {
1136
	my ($return, $cardnumber);
1137
	if ($cas && $query->param('ticket')) {
1138
	    my $retuserid;
1159
	    my $retuserid;
1139
	    ( $return, $cardnumber, $retuserid ) = checkpw( $dbh, $userid, $password, $query );
1160
	    $debug and print STDERR "## check_api_auth - checking CAS\n";
1140
	    $userid = $retuserid;
1161
	    # In case of a CAS authentication, we use the ticket instead of the password
1162
	    my $PT = $query->param('PT');
1163
	    ($return,$cardnumber,$userid) = check_api_auth_cas($dbh, $PT, $query);    # EXTERNAL AUTH
1141
	} else {
1164
	} else {
1165
	    # User / password auth
1166
	    unless ($userid and $password) {
1167
		# caller did something wrong, fail the authenticateion
1168
		return ("failed", undef, undef);
1169
	    }
1142
	    ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password, $query );
1170
	    ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password, $query );
1143
	}
1171
	}
1172
1144
        if ($return and haspermission(  $userid, $flagsrequired)) {
1173
        if ($return and haspermission(  $userid, $flagsrequired)) {
1145
            my $session = get_session("");
1174
            my $session = get_session("");
1146
            return ("failed", undef, undef) unless $session;
1175
            return ("failed", undef, undef) unless $session;
Lines 1397-1403 sub checkpw { Link Here
1397
        ($retval) and return ($retval,$retcard);
1426
        ($retval) and return ($retval,$retcard);
1398
    }
1427
    }
1399
1428
1400
    if ($cas && $query->param('ticket')) {
1429
    if ($cas && $query && $query->param('ticket')) {
1401
        $debug and print STDERR "## checkpw - checking CAS\n";
1430
        $debug and print STDERR "## checkpw - checking CAS\n";
1402
	# In case of a CAS authentication, we use the ticket instead of the password
1431
	# In case of a CAS authentication, we use the ticket instead of the password
1403
	my $ticket = $query->param('ticket');
1432
	my $ticket = $query->param('ticket');
(-)a/C4/Auth_cas_servers.yaml.orig (+12 lines)
Line 0 Link Here
1
# This file is used for authenticating against multiple CAS servers
2
# If the file Auth_cas_servers.yaml exists, then the casServerUrl syspref will be ignored
3
4
# If you have to authenticate against only one CAS server, which is usually the case,
5
# don't use this file, but the casServerUrl syspref instead
6
7
default: ServerName
8
---
9
  ServerName: "https://example.com/cas"
10
  OtherServerName: "https://example.org/cas"
11
  ThirdServerName: "https://example.edu/cas"
12
(-)a/C4/Auth_with_cas.pm (-42 / +139 lines)
Lines 25-30 use C4::Context; Link Here
25
use C4::Utils qw( :all );
25
use C4::Utils qw( :all );
26
use Authen::CAS::Client;
26
use Authen::CAS::Client;
27
use CGI;
27
use CGI;
28
use FindBin;
28
29
29
30
30
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug);
31
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $debug);
Lines 34-64 BEGIN { Link Here
34
	$VERSION = 3.03;	# set the version for version checking
35
	$VERSION = 3.03;	# set the version for version checking
35
	$debug = $ENV{DEBUG};
36
	$debug = $ENV{DEBUG};
36
	@ISA    = qw(Exporter);
37
	@ISA    = qw(Exporter);
37
	@EXPORT = qw(checkpw_cas login_cas logout_cas login_cas_url);
38
	@EXPORT = qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url);
39
}
40
my $context = C4::Context->new() or die 'C4::Context->new failed';
41
my $defaultcasserver;
42
my $casservers;
43
my $yamlauthfile = "../C4/Auth_cas_servers.yaml";
44
45
46
# If there's a configuration for multiple cas servers, then we get it
47
if (multipleAuth()) {
48
    ($defaultcasserver, $casservers) = YAML::LoadFile(qq($FindBin::Bin/$yamlauthfile));
49
    $defaultcasserver = $defaultcasserver->{'default'};
50
} else {
51
# Else, we fall back to casServerUrl syspref
52
    $defaultcasserver = 'default';
53
    $casservers = { 'default' => C4::Context->preference('casServerUrl') };
38
}
54
}
39
55
56
# Is there a configuration file for multiple cas servers?
57
sub multipleAuth {
58
    return (-e qq($FindBin::Bin/$yamlauthfile));
59
}
40
60
41
my $context = C4::Context->new() 	or die 'C4::Context->new failed';
61
# Returns configured CAS servers' list if multiple authentication is enabled
42
my $casserver = C4::Context->preference('casServerUrl');
62
sub getMultipleAuth {
63
   return $casservers; 
64
}
43
65
44
# Logout from CAS
66
# Logout from CAS
45
sub logout_cas {
67
sub logout_cas {
46
    my ($query) = @_;
68
    my ($query) = @_;
47
    my $cas = Authen::CAS::Client->new($casserver);
69
    my $uri = $ENV{'SCRIPT_URI'};
48
    print $query->redirect($cas->logout_url(url => $ENV{'SCRIPT_URI'}));
70
    my $casparam = $query->param('cas');
71
    # FIXME: This should be more generic and handle whatever parameters there might be
72
    $uri .= "?cas=" . $casparam if (defined $casparam);
73
    $casparam = $defaultcasserver if (not defined $casparam);
74
    my $cas = Authen::CAS::Client->new($casservers->{$casparam});
75
    print $query->redirect( $cas->logout_url($uri));
49
}
76
}
50
77
51
# Login to CAS
78
# Login to CAS
52
sub login_cas {
79
sub login_cas {
53
    my ($query) = @_;
80
    my ($query) = @_;
54
    my $cas = Authen::CAS::Client->new($casserver);
81
    my $uri = $ENV{'SCRIPT_URI'};
55
    print $query->redirect($cas->login_url($ENV{'SCRIPT_URI'})); 
82
    my $casparam = $query->param('cas');
83
    # FIXME: This should be more generic and handle whatever parameters there might be
84
    $uri .= "?cas=" . $casparam if (defined $casparam);
85
    $casparam = $defaultcasserver if (not defined $casparam);
86
    my $cas = Authen::CAS::Client->new($casservers->{$casparam});
87
    print $query->redirect( $cas->login_url($uri));
56
}
88
}
57
89
58
# Returns CAS login URL with callback to the requesting URL
90
# Returns CAS login URL with callback to the requesting URL
59
sub login_cas_url {
91
sub login_cas_url {
60
    my $cas = Authen::CAS::Client->new($casserver);
92
61
    return $cas->login_url($ENV{'SCRIPT_URI'});
93
    my ($query, $key) = @_;
94
    my $uri = $ENV{'SCRIPT_URI'};
95
    my $casparam = $query->param('cas');
96
    # FIXME: This should be more generic and handle whatever parameters there might be
97
    $uri .= "?cas=" . $casparam if (defined $casparam);
98
    $casparam = $defaultcasserver if (not defined $casparam);
99
    $casparam = $key if (defined $key);
100
    my $cas = Authen::CAS::Client->new($casservers->{$casparam});
101
    return $cas->login_url($uri);
62
}
102
}
63
103
64
# Checks for password correctness
104
# Checks for password correctness
Lines 67-112 sub checkpw_cas { Link Here
67
    $debug and warn "checkpw_cas";
107
    $debug and warn "checkpw_cas";
68
    my ($dbh, $ticket, $query) = @_;
108
    my ($dbh, $ticket, $query) = @_;
69
    my $retnumber;
109
    my $retnumber;
70
    my $cas = Authen::CAS::Client->new($casserver);
110
    my $uri = $ENV{'SCRIPT_URI'};
111
    my $casparam = $query->param('cas');
112
    # FIXME: This should be more generic and handle whatever parameters there might be
113
    $uri .= "?cas=" . $casparam if (defined $casparam);
114
    $casparam = $defaultcasserver if (not defined $casparam);
115
    my $cas = Authen::CAS::Client->new($casservers->{$casparam});
71
116
72
    # If we got a ticket
117
    # If we got a ticket
73
    if ($ticket) {
118
    if ($ticket) {
74
	$debug and warn "Got ticket : $ticket";
119
        $debug and warn "Got ticket : $ticket";
75
	
120
76
	# We try to validate it
121
        # We try to validate it
77
	my $val = $cas->service_validate($ENV{'SCRIPT_URI'}, $ticket);
122
        my $val = $cas->service_validate($uri, $ticket );
78
	
123
79
	# If it's valid
124
        # If it's valid
80
	if( $val->is_success() ) {
125
        if ( $val->is_success() ) {
81
126
82
	    my $userid = $val->user();
127
            my $userid = $val->user();
83
	    $debug and warn "User CAS authenticated as: $userid";
128
            $debug and warn "User CAS authenticated as: $userid";
84
129
85
	    # Does it match one of our users ?
130
            # Does it match one of our users ?
86
    	    my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
131
            my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
87
    	    $sth->execute($userid);
132
            $sth->execute($userid);
88
    	    if ( $sth->rows ) {
133
            if ( $sth->rows ) {
89
		$retnumber = $sth->fetchrow;
134
                $retnumber = $sth->fetchrow;
90
		return (1, $retnumber, $userid);
135
                return ( 1, $retnumber, $userid );
91
	    }
136
            }
92
	    $sth = $dbh->prepare("select userid from borrowers where cardnumber=?");
137
            $sth = $dbh->prepare("select userid from borrowers where cardnumber=?");
93
	    $sth->execute($userid);
138
            $sth->execute($userid);
94
	    if ( $sth->rows ) {
139
            if ( $sth->rows ) {
95
	    	$retnumber = $sth->fetchrow;
140
                $retnumber = $sth->fetchrow;
96
		return (1, $retnumber, $userid);
141
                return ( 1, $retnumber, $userid );
97
	    }
142
            }
98
	    
143
99
	    # If we reach this point, then the user is a valid CAS user, but not a Koha user
144
            # If we reach this point, then the user is a valid CAS user, but not a Koha user
100
	    $debug and warn "User $userid is not a valid Koha user";
145
            $debug and warn "User $userid is not a valid Koha user";
101
146
102
    	} else {
147
        } else {
103
    	    $debug and warn "Invalid session ticket : $ticket";
148
            $debug and warn "Invalid session ticket : $ticket";
104
    	    return 0;
149
            return 0;
105
	}
150
        }
151
    }
152
    return 0;
153
}
154
155
# Proxy CAS auth
156
sub check_api_auth_cas {
157
    $debug and warn "check_api_auth_cas";
158
    my ($dbh, $PT, $query) = @_;
159
    my $retnumber;
160
    my $url = $query->url();
161
162
    my $casparam = $query->param('cas');
163
    $casparam = $defaultcasserver if (not defined $casparam);
164
    my $cas = Authen::CAS::Client->new($casservers->{$casparam});
165
166
    # If we have a Proxy Ticket
167
    if ($PT) {
168
        my $r = $cas->proxy_validate( $url, $PT );
169
170
        # If the PT is valid
171
        if ( $r->is_success ) {
172
173
            # We've got a username !
174
            $debug and warn "User authenticated as: ", $r->user, "\n";
175
            $debug and warn "Proxied through:\n";
176
            $debug and warn "  $_\n" for $r->proxies;
177
178
            my $userid = $r->user;
179
180
            # Does it match one of our users ?
181
            my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?");
182
            $sth->execute($userid);
183
            if ( $sth->rows ) {
184
                $retnumber = $sth->fetchrow;
185
                return ( 1, $retnumber, $userid );
186
            }
187
            $sth = $dbh->prepare("select userid from borrowers where cardnumber=?");
188
            return $r->user;
189
            $sth->execute($userid);
190
            if ( $sth->rows ) {
191
                $retnumber = $sth->fetchrow;
192
                return ( 1, $retnumber, $userid );
193
            }
194
195
            # If we reach this point, then the user is a valid CAS user, but not a Koha user
196
            $debug and warn "User $userid is not a valid Koha user";
197
198
        } else {
199
            $debug and warn "Proxy Ticket authentication failed";
200
            return 0;
201
        }
106
    }
202
    }
107
    return 0;
203
    return 0;
108
}
204
}
109
205
206
110
1;
207
1;
111
__END__
208
__END__
112
209
(-)a/docs/CAS/CAS/README (+8 lines)
Line 0 Link Here
1
CAS authentication is available through CasAuthentication and casServerUrl sysprefs.
2
3
However, if you plan to use multi-CAS (ie: authentication against multiple CAS server,
4
you'll have to use C4/Auth_cas_servers.yaml.
5
6
Anyway, please keep in mind that if you want to authenticate through https against the
7
CAS serveur, you have to install Crypt::SSLeay package, or the authentication will 
8
silently fail.
(-)a/docs/CAS/CASProxy/README (+9 lines)
Line 0 Link Here
1
As CAS Proxying is not an obvious authentication to set up, here are
2
some documented examples showing how a foreign application can query
3
koha webservices, being CAS authenticated.
4
5
The starting point is proxy_cas.pl
6
7
To find more about how CAS Proxy works :
8
http://afs.berkeley.edu/~lr/presentations/cas-auth/
9
http://www.ja-sig.org/wiki/display/CAS/Proxy+CAS+Walkthrough
(-)a/docs/CAS/CASProxy/examples/koha_webservice.pl (+58 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2009 SARL 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 with
17
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18
# Suite 330, Boston, MA  02111-1307 USA
19
20
=head1 DESCRIPTION
21
22
# Here is an exemple of a simple phony webservice, returning "Hello World" if the user is authenticated
23
# The purpose is to show how CAS Proxy can work with koha
24
# In this configuration, this page acts as a CAS Client, instead of the user's browser.
25
# This page is meant to be called from a foreign application
26
27
=head1 CGI PARAMETERS
28
29
=item PT
30
The Proxy Ticket, needed for check_api_auth, that will try to make the CAS Server validate it.
31
32
=cut 
33
34
use utf8;
35
use strict;
36
use warnings;
37
binmode(STDOUT, ":utf8");
38
39
use C4::Auth qw(check_api_auth);
40
use C4::Output;
41
use C4::Context;
42
use CGI;
43
44
my $cgi = new CGI;
45
46
print CGI::header('-type'=>'text/plain', '-charset'=>'utf-8');
47
48
# The authentication : if $cgi contains a PT parameter, and CAS is enabled (casAuthentication syspref),
49
# a CAS Proxy authentication will take place
50
my ( $status, $cookie_, $sessionID ) = check_api_auth( $cgi, {circulate => 'override_renewals'});
51
52
if ($status ne 'ok') {
53
    print "Authentication failed : $status";
54
} else {
55
    print "Hello World!";
56
}
57
exit 0;
58
(-)a/docs/CAS/CASProxy/examples/proxy_cas.pl (+91 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2009 SARL 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 with
17
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18
# Suite 330, Boston, MA  02111-1307 USA
19
20
=head1 DESCRIPTION
21
22
# Here is an exemple of a CAS Proxy
23
# The proxy is a foreign application that will authenticate the user against CAS
24
# Once authenticated as a proxy, the foreign application will be able to call some
25
# Koha webservices, proving authentication only by giving a proxy ticket
26
27
# Note: please keep in mind that all url's must be https and their certificates must be trusted
28
29
=cut
30
31
use strict;
32
use warnings;
33
use CGI;
34
use Authen::CAS::Client;
35
36
# URL Of the CAS Server
37
my $casServerUrl = 'https://localhost:8443/cas/';
38
my $cas = Authen::CAS::Client->new($casServerUrl);
39
my $cgi = new CGI;
40
41
# URL of the service we're requesting a Service Ticket for (typically this very same page)
42
my $proxy_service = $cgi->url;
43
44
45
# Callback URL (this is an URL the CAS Server will query, providing the Proxy Ticket we'll need 
46
# to query the koha webservice). It can be this page or another. In this example, another page will be 
47
# called back
48
my $pgtUrl = "https://.../proxy_cas_callback.pl";
49
50
print $cgi->header({-type  =>  'text/html'});
51
print $cgi->start_html("proxy cas");
52
53
# If we already have a service ticket
54
if ($cgi->param('ticket')) {
55
56
    print "Got a ticket :" . $cgi->param('ticket') . "<br>\n";
57
  
58
    # We validate it against the CAS Server, providing the callback URL
59
    my $r = $cas->service_validate( $proxy_service, $cgi->param('ticket'), pgtUrl => $pgtUrl);
60
61
    # If it is sucessful, we are authenticated
62
    if( $r->is_success() ) {
63
	print "User authenticated as: ", $r->user(), "<br>\n";
64
    } else {
65
	print "User authentication failed<br />\n";
66
    }
67
68
    # If we have a PGTIou ticket, the proxy validation was sucessful 
69
    if (defined $r->iou) {
70
      print "Proxy granting ticket IOU: ", $r->iou, "<br />\n";
71
      my $pgtIou = $r->iou;
72
73
      print '<a href="proxy_cas_data.pl?PGTIOU=', $r->iou, '">Next</a>';
74
75
      
76
     	    
77
    } else {
78
      print "Service validation for proxying failed\n";
79
   }
80
81
# If we don't have a Service Ticket, we ask for one (ie : the user will be redirected to the CAS Server for authentication)
82
} else {
83
84
    my $url = $cas->login_url($proxy_service);
85
    print "<a href=\"$url\">Please log in</a>";
86
}
87
88
print $cgi->end_html;
89
90
91
(-)a/docs/CAS/CASProxy/examples/proxy_cas_callback.pl (+62 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2009 SARL 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 with
17
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18
# Suite 330, Boston, MA  02111-1307 USA
19
20
=head1 DESCRIPTION
21
22
# Here is an exemple of a callback page for a CAS Proxy
23
# This is the page the CAS server will call back with a Proxy Ticket, allowing us (the foreign application)
24
# to query koha webservices, being CAS authenticated 
25
26
=cut
27
28
use strict;
29
use warnings;
30
use CGI;
31
use Authen::CAS::Client;
32
use Storable qw(nstore_fd);
33
34
my $casServerUrl = 'https://localhost:8443/cas/';
35
my $cas = Authen::CAS::Client->new($casServerUrl);
36
37
my $cgi = new CGI;
38
39
my $proxy_service = $cgi->url;
40
41
print $cgi->header({-type  =>  'text/html'});
42
print $cgi->start_html("proxy cas callback");
43
44
# If we have a pgtId, it means the cas server called us back
45
if ($cgi->param('pgtId')) {
46
    warn "Got a pgtId :" . $cgi->param('pgtId');
47
    warn "Got a pgtIou :" . $cgi->param('pgtIou');
48
    my $pgtIou =  $cgi->param('pgtIou');
49
    my $pgtId =  $cgi->param('pgtId');
50
51
    # Now we store the pgtIou and the pgtId in the application vars (in our case a storable object in a file), 
52
    # so that the page requesting the webservice can retrieve the pgtId matching it's PgtIou 
53
    open FILE, ">", "casSession.tmp" or die "Unable to open file";
54
    nstore_fd({$pgtIou => $pgtId}, \*FILE);
55
    close FILE;
56
57
} else {
58
    warn "Failed to get a Proxy Ticket\n";
59
}
60
61
print $cgi->end_html;
62
(-)a/docs/CAS/CASProxy/examples/proxy_cas_data.pl (+80 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2009 SARL 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 with
17
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18
# Suite 330, Boston, MA  02111-1307 USA
19
20
=head1 DESCRIPTION
21
22
# This page will display the result of the call to the koha webservice
23
24
=head1 CGI PARAMETERS
25
26
=item PGTIOU
27
28
The Proxy Granting Ticket IOU the CAS Server returned to us when we gave him the Service Ticket
29
This PGTIOU will allow us to retrive the matching PGTID
30
31
=cut 
32
33
use strict;
34
use warnings;
35
use CGI;
36
use Authen::CAS::Client;
37
use Storable qw(fd_retrieve);
38
use LWP::Simple;
39
use URI::Escape;
40
41
my $casServerUrl = 'https://localhost:8443/cas/';
42
my $cas = Authen::CAS::Client->new($casServerUrl);
43
44
# URL of the service we'd like to be proxy for (typically the Koha webservice we want to query)
45
my $target_service = "https://.../koha_webservice.pl";
46
47
my $cgi = new CGI;
48
49
print $cgi->header({-type  =>  'text/html'});
50
print $cgi->start_html("proxy cas");
51
52
53
if ($cgi->param('PGTIOU')) {
54
55
      # At this point, we must retrieve the PgtId by matching the PgtIou we
56
      # just received and the PgtIou given by the CAS Server to the callback URL
57
      # The callback page stored it in the application vars (in our case a storable object in a file)
58
      open FILE, "casSession.tmp" or die "Unable to open file";
59
      my $hashref = fd_retrieve(\*FILE);
60
      my $pgtId = %$hashref->{$cgi->param('PGTIOU')};
61
      close FILE;
62
63
      # Now that we have a PgtId, we can ask the cas server for a proxy ticket...
64
      my $rp = $cas->proxy( $pgtId, $target_service );
65
      if( $rp->is_success ) {
66
        print "Proxy Ticket issued: ", $rp->proxy_ticket, "<br />\n";
67
68
	# ...which we will provide to the target service (the koha webservice) for authentication !
69
	my $data = get($target_service . "?PT=" . $rp->proxy_ticket);
70
	
71
	# And finally, we can display the data gathered from the koha webservice !
72
	print "This is the output of the koha webservice we just queried, CAS authenticated : <br/>";
73
	print "<code>$data</code>";
74
75
      } else {
76
	print "Cannot get Proxy Ticket";
77
      }
78
79
80
}
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-auth.tt (-2 / +13 lines)
Lines 53-59 Link Here
53
<p>Sorry, the CAS login failed.</p>
53
<p>Sorry, the CAS login failed.</p>
54
[% END %]
54
[% END %]
55
55
56
<p>If you have a <acronym title="Central Authentication Service">CAS</acronym> account, please <a href="[% casServerUrl %]">click here to login</a>.<p>
56
<p>If you have a <acronym title="Central Authentication Service">CAS</acronym> account, 
57
[% IF ( casServerUrl ) %]
58
    please <a href="[% casServerUrl %]">click here to login</a>.<p>
59
[% END %]
60
61
[% IF ( casServersLoop ) %]
62
please choose against which one you would like to authenticate: </p>
63
<ul>
64
    [% FOREACH casServer IN casServersLoop %]
65
	<li><a href="[% casServer.value %]">[% casServer.name %]</a></li>
66
    [% END %]
67
[% END %]
68
</ul>
57
69
58
<h4>Local Login</h4>
70
<h4>Local Login</h4>
59
<p>If you do not have a CAS account, but a local account, you can still log in : </p>
71
<p>If you do not have a CAS account, but a local account, you can still log in : </p>
60
- 

Return to bug 5630