From e406ceeb523fd8610959c5563eff3a87e3aa2de6 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Wed, 19 Jan 2011 21:24:33 +0100 Subject: [PATCH] Bug 6012 : MT 2270: CAS proxy CAS Proxy Examples included are now really usable Signed-off-by: Chris Cormack Signed-off-by: Paul Poulain --- C4/Auth.pm | 26 ++++--- C4/Auth_with_cas.pm | 52 ++++++++++++- docs/CAS/CASProxy/README | 9 ++ docs/CAS/CASProxy/examples/casSession.tmp | Bin 0 -> 134 bytes docs/CAS/CASProxy/examples/koha_webservice.pl | 58 ++++++++++++++ docs/CAS/CASProxy/examples/proxy_cas.pl | 91 ++++++++++++++++++++++ docs/CAS/CASProxy/examples/proxy_cas_callback.pl | 62 +++++++++++++++ docs/CAS/CASProxy/examples/proxy_cas_data.pl | 80 +++++++++++++++++++ 8 files changed, 367 insertions(+), 11 deletions(-) create mode 100644 docs/CAS/CASProxy/README create mode 100644 docs/CAS/CASProxy/examples/casSession.tmp create mode 100755 docs/CAS/CASProxy/examples/koha_webservice.pl create mode 100755 docs/CAS/CASProxy/examples/proxy_cas.pl create mode 100755 docs/CAS/CASProxy/examples/proxy_cas_callback.pl create mode 100755 docs/CAS/CASProxy/examples/proxy_cas_data.pl diff --git a/C4/Auth.pm b/C4/Auth.pm index f580e53..e52ffe8 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -52,7 +52,7 @@ BEGIN { } if ($cas) { require C4::Auth_with_cas; # no import - import C4::Auth_with_cas qw(checkpw_cas login_cas logout_cas login_cas_url); + import C4::Auth_with_cas qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url); } $servers = C4::Context->config('memcached_servers'); if ($servers) { @@ -1079,7 +1079,7 @@ sub check_api_auth { unless ($query->param('userid')) { $sessionID = $query->cookie("CGISESSID"); } - if ($sessionID) { + if ($sessionID && not $cas) { my $session = get_session($sessionID); C4::Context->_new_userenv($sessionID); if ($session) { @@ -1129,18 +1129,24 @@ sub check_api_auth { # 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); - if ($cas && $query->param('ticket')) { + my ($return, $cardnumber); + + # Proxy CAS auth + if ($cas && $query->param('PT')) { my $retuserid; - ( $return, $cardnumber, $retuserid ) = checkpw( $dbh, $userid, $password, $query ); - $userid = $retuserid; + $debug and print STDERR "## check_api_auth - checking CAS\n"; + # In case of a CAS authentication, we use the ticket instead of the password + my $PT = $query->param('PT'); + ($return,$cardnumber,$userid) = check_api_auth_cas($dbh, $PT, $query); # EXTERNAL AUTH } else { + # User / password auth + unless ($userid and $password) { + # caller did something wrong, fail the authenticateion + return ("failed", undef, undef); + } ( $return, $cardnumber ) = checkpw( $dbh, $userid, $password, $query ); } + if ($return and haspermission( $userid, $flagsrequired)) { my $session = get_session(""); return ("failed", undef, undef) unless $session; diff --git a/C4/Auth_with_cas.pm b/C4/Auth_with_cas.pm index f9a03a3..0b66f5d 100644 --- a/C4/Auth_with_cas.pm +++ b/C4/Auth_with_cas.pm @@ -34,7 +34,7 @@ BEGIN { $VERSION = 3.03; # set the version for version checking $debug = $ENV{DEBUG}; @ISA = qw(Exporter); - @EXPORT = qw(checkpw_cas login_cas logout_cas login_cas_url); + @EXPORT = qw(check_api_auth_cas checkpw_cas login_cas logout_cas login_cas_url); } @@ -107,6 +107,56 @@ sub checkpw_cas { return 0; } +# Proxy CAS auth +sub check_api_auth_cas { + $debug and warn "check_api_auth_cas"; + my ($dbh, $PT, $query) = @_; + my $retnumber; + my $url = $query->url(); + my $cas = Authen::CAS::Client->new($casserver); + + # If we have a Proxy Ticket + if ($PT) { + my $r = $cas->proxy_validate( $url, $PT ); + + # If the PT is valid + if( $r->is_success ) { + + # We've got a username ! + $debug and warn "User authenticated as: ", $r->user, "\n"; + $debug and warn "Proxied through:\n"; + $debug and warn " $_\n" + for $r->proxies; + + my $userid = $r->user; + + # Does it match one of our users ? + my $sth = $dbh->prepare("select cardnumber from borrowers where userid=?"); + $sth->execute($userid); + if ( $sth->rows ) { + $retnumber = $sth->fetchrow; + return (1, $retnumber, $userid); + } + my $sth = $dbh->prepare("select userid from borrowers where cardnumber=?"); + return $r->user; + $sth->execute($userid); + if ( $sth->rows ) { + $retnumber = $sth->fetchrow; + return (1, $retnumber, $userid); + } + + # If we reach this point, then the user is a valid CAS user, but not a Koha user + $debug and warn "User $userid is not a valid Koha user"; + + } else { + $debug and warn "Proxy Ticket authentication failed"; + return 0; + } + } + return 0; +} + + 1; __END__ diff --git a/docs/CAS/CASProxy/README b/docs/CAS/CASProxy/README new file mode 100644 index 0000000..b1c882c --- /dev/null +++ b/docs/CAS/CASProxy/README @@ -0,0 +1,9 @@ +As CAS Proxying is not an obvious authentication to set up, here are +some documented examples showing how a foreign application can query +koha webservices, being CAS authenticated. + +The starting point is proxy_cas.pl + +To find more about how CAS Proxy works : +http://afs.berkeley.edu/~lr/presentations/cas-auth/ +http://www.ja-sig.org/wiki/display/CAS/Proxy+CAS+Walkthrough diff --git a/docs/CAS/CASProxy/examples/casSession.tmp b/docs/CAS/CASProxy/examples/casSession.tmp new file mode 100644 index 0000000000000000000000000000000000000000..ca78c338972f592560a68146fc7c534e3ebca685 GIT binary patch literal 134 zcmXRYE-_$bXJ%kvVC1q4a1YTnwA78Ts7!To^a=9!DoZId3JUY_NzO6IG&L^>H#V&Z zb1@0^H8ApwvIz1|E;KevODZ!p0BW}ZYWDOG)it!xO{($^NzODch|0@z^Y#c2u?TPv jjVgCbO06i2NX<*JOiCVF_e=Av3dsWinw}@# literal 0 HcmV?d00001 diff --git a/docs/CAS/CASProxy/examples/koha_webservice.pl b/docs/CAS/CASProxy/examples/koha_webservice.pl new file mode 100755 index 0000000..cb161f7 --- /dev/null +++ b/docs/CAS/CASProxy/examples/koha_webservice.pl @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +# Copyright 2009 SARL BibLibre +# +# 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 + +=head1 DESCRIPTION + +# Here is an exemple of a simple phony webservice, returning "Hello World" if the user is authenticated +# The purpose is to show how CAS Proxy can work with koha +# In this configuration, this page acts as a CAS Client, instead of the user's browser. +# This page is meant to be called from a foreign application + +=head1 CGI PARAMETERS + +=item PT +The Proxy Ticket, needed for check_api_auth, that will try to make the CAS Server validate it. + +=cut + +use utf8; +use strict; +use warnings; +binmode(STDOUT, ":utf8"); + +use C4::Auth qw(check_api_auth); +use C4::Output; +use C4::Context; +use CGI; + +my $cgi = new CGI; + +print CGI::header('-type'=>'text/plain', '-charset'=>'utf-8'); + +# The authentication : if $cgi contains a PT parameter, and CAS is enabled (casAuthentication syspref), +# a CAS Proxy authentication will take place +my ( $status, $cookie_, $sessionID ) = check_api_auth( $cgi, {circulate => 'override_renewals'}); + +if ($status ne 'ok') { + print "Authentication failed : $status"; +} else { + print "Hello World!"; +} +exit 0; + diff --git a/docs/CAS/CASProxy/examples/proxy_cas.pl b/docs/CAS/CASProxy/examples/proxy_cas.pl new file mode 100755 index 0000000..85085d7 --- /dev/null +++ b/docs/CAS/CASProxy/examples/proxy_cas.pl @@ -0,0 +1,91 @@ +#!/usr/bin/perl + +# Copyright 2009 SARL BibLibre +# +# 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 + +=head1 DESCRIPTION + +# Here is an exemple of a CAS Proxy +# The proxy is a foreign application that will authenticate the user against CAS +# Once authenticated as a proxy, the foreign application will be able to call some +# Koha webservices, proving authentication only by giving a proxy ticket + +# Note: please keep in mind that all url's must be https and their certificates must be trusted + +=cut + +use strict; +use warnings; +use CGI; +use Authen::CAS::Client; + +# URL Of the CAS Server +my $casServerUrl = 'https://localhost:8443/cas/'; +my $cas = Authen::CAS::Client->new($casServerUrl); +my $cgi = new CGI; + +# URL of the service we're requesting a Service Ticket for (typically this very same page) +my $proxy_service = $cgi->url; + + +# Callback URL (this is an URL the CAS Server will query, providing the Proxy Ticket we'll need +# to query the koha webservice). It can be this page or another. In this example, another page will be +# called back +my $pgtUrl = "https://.../proxy_cas_callback.pl"; + +print $cgi->header({-type => 'text/html'}); +print $cgi->start_html("proxy cas"); + +# If we already have a service ticket +if ($cgi->param('ticket')) { + + print "Got a ticket :" . $cgi->param('ticket') . "
\n"; + + # We validate it against the CAS Server, providing the callback URL + my $r = $cas->service_validate( $proxy_service, $cgi->param('ticket'), pgtUrl => $pgtUrl); + + # If it is sucessful, we are authenticated + if( $r->is_success() ) { + print "User authenticated as: ", $r->user(), "
\n"; + } else { + print "User authentication failed
\n"; + } + + # If we have a PGTIou ticket, the proxy validation was sucessful + if (defined $r->iou) { + print "Proxy granting ticket IOU: ", $r->iou, "
\n"; + my $pgtIou = $r->iou; + + print 'Next'; + + + + } else { + print "Service validation for proxying failed\n"; + } + +# If we don't have a Service Ticket, we ask for one (ie : the user will be redirected to the CAS Server for authentication) +} else { + + my $url = $cas->login_url($proxy_service); + print "Please log in"; +} + +print $cgi->end_html; + + + diff --git a/docs/CAS/CASProxy/examples/proxy_cas_callback.pl b/docs/CAS/CASProxy/examples/proxy_cas_callback.pl new file mode 100755 index 0000000..3c2c9ef --- /dev/null +++ b/docs/CAS/CASProxy/examples/proxy_cas_callback.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl + +# Copyright 2009 SARL BibLibre +# +# 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 + +=head1 DESCRIPTION + +# Here is an exemple of a callback page for a CAS Proxy +# This is the page the CAS server will call back with a Proxy Ticket, allowing us (the foreign application) +# to query koha webservices, being CAS authenticated + +=cut + +use strict; +use warnings; +use CGI; +use Authen::CAS::Client; +use Storable qw(nstore_fd); + +my $casServerUrl = 'https://localhost:8443/cas/'; +my $cas = Authen::CAS::Client->new($casServerUrl); + +my $cgi = new CGI; + +my $proxy_service = $cgi->url; + +print $cgi->header({-type => 'text/html'}); +print $cgi->start_html("proxy cas callback"); + +# If we have a pgtId, it means the cas server called us back +if ($cgi->param('pgtId')) { + warn "Got a pgtId :" . $cgi->param('pgtId'); + warn "Got a pgtIou :" . $cgi->param('pgtIou'); + my $pgtIou = $cgi->param('pgtIou'); + my $pgtId = $cgi->param('pgtId'); + + # Now we store the pgtIou and the pgtId in the application vars (in our case a storable object in a file), + # so that the page requesting the webservice can retrieve the pgtId matching it's PgtIou + open FILE, ">", "casSession.tmp" or die "Unable to open file"; + nstore_fd({$pgtIou => $pgtId}, \*FILE); + close FILE; + +} else { + warn "Failed to get a Proxy Ticket\n"; +} + +print $cgi->end_html; + diff --git a/docs/CAS/CASProxy/examples/proxy_cas_data.pl b/docs/CAS/CASProxy/examples/proxy_cas_data.pl new file mode 100755 index 0000000..92c61a5 --- /dev/null +++ b/docs/CAS/CASProxy/examples/proxy_cas_data.pl @@ -0,0 +1,80 @@ +#!/usr/bin/perl + +# Copyright 2009 SARL BibLibre +# +# 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 + +=head1 DESCRIPTION + +# This page will display the result of the call to the koha webservice + +=head1 CGI PARAMETERS + +=item PGTIOU + +The Proxy Granting Ticket IOU the CAS Server returned to us when we gave him the Service Ticket +This PGTIOU will allow us to retrive the matching PGTID + +=cut + +use strict; +use warnings; +use CGI; +use Authen::CAS::Client; +use Storable qw(fd_retrieve); +use LWP::Simple; +use URI::Escape; + +my $casServerUrl = 'https://localhost:8443/cas/'; +my $cas = Authen::CAS::Client->new($casServerUrl); + +# URL of the service we'd like to be proxy for (typically the Koha webservice we want to query) +my $target_service = "https://.../koha_webservice.pl"; + +my $cgi = new CGI; + +print $cgi->header({-type => 'text/html'}); +print $cgi->start_html("proxy cas"); + + +if ($cgi->param('PGTIOU')) { + + # At this point, we must retrieve the PgtId by matching the PgtIou we + # just received and the PgtIou given by the CAS Server to the callback URL + # The callback page stored it in the application vars (in our case a storable object in a file) + open FILE, "casSession.tmp" or die "Unable to open file"; + my $hashref = fd_retrieve(\*FILE); + my $pgtId = %$hashref->{$cgi->param('PGTIOU')}; + close FILE; + + # Now that we have a PgtId, we can ask the cas server for a proxy ticket... + my $rp = $cas->proxy( $pgtId, $target_service ); + if( $rp->is_success ) { + print "Proxy Ticket issued: ", $rp->proxy_ticket, "
\n"; + + # ...which we will provide to the target service (the koha webservice) for authentication ! + my $data = get($target_service . "?PT=" . $rp->proxy_ticket); + + # And finally, we can display the data gathered from the koha webservice ! + print "This is the output of the koha webservice we just queried, CAS authenticated :
"; + print "$data"; + + } else { + print "Cannot get Proxy Ticket"; + } + + +} -- 1.7.4.1