From 7552ef1baba78c71a9281e7e06a6b90a9cb6faed Mon Sep 17 00:00:00 2001 From: Ere Maijala <ere.maijala@helsinki.fi> Date: Tue, 4 Oct 2016 16:15:01 +0300 Subject: [PATCH] EZproxy ticket authentication handler. (#818) - This allows a user to be authorized into EZproxy via VuFind login. --- config/vufind/config.ini | 18 +++ config/vufind/permissions.ini | 6 + languages/en-gb.ini | 1 + languages/en.ini | 4 + languages/fi.ini | 4 + languages/sv.ini | 4 + module/VuFind/config/module.config.php | 1 + .../Controller/ExternalAuthController.php | 119 ++++++++++++++++++ .../templates/externalauth/ezproxylogin.phtml | 18 +++ .../templates/externalauth/ezproxylogin.phtml | 19 +++ 10 files changed, 194 insertions(+) create mode 100644 module/VuFind/src/VuFind/Controller/ExternalAuthController.php create mode 100644 themes/bootstrap3/templates/externalauth/ezproxylogin.phtml create mode 100644 themes/jquerymobile/templates/externalauth/ezproxylogin.phtml diff --git a/config/vufind/config.ini b/config/vufind/config.ini index 91923724fb6..414f72574b5 100644 --- a/config/vufind/config.ini +++ b/config/vufind/config.ini @@ -994,6 +994,24 @@ replace_other_urls = true ; are using EZProxy to provide off-site access to online materials. ;[EZproxy] ;host = http://proxy.myuniversity.edu +; Uncomment the following line and change the password to something secret to enable +; EZproxy ticket authentication. +;secret = "verysecretpassword" +; +; To enable ticket authentication in EZproxy, you will also need the following in +; EZproxy's user.txt or ezproxy.usr for older versions (without the leading +; semicolons and spaces): +; +; ::CGI=https://vufind-server/ExternalAuth/EzproxyLogin?url=^R +; ::Ticket +; TimeValid 10 +; SHA512 verysecretpassword +; +; Uncomment and modify the following line to use another hashing algorithm with the +; EZproxy authentication if necessary. SHA512 is the default, but it requires at +; least EZproxy version 6.1. Use "SHA1" for older EZproxy versions, and remember to +; replace SHA512 with SHA1 also in EZproxy's configuration file. +;secret_hash_method = "SHA512" ; These settings affect RefWorks record exports. They rarely need to be changed. [RefWorks] diff --git a/config/vufind/permissions.ini b/config/vufind/permissions.ini index 2395196637a..d61244aa0fd 100644 --- a/config/vufind/permissions.ini +++ b/config/vufind/permissions.ini @@ -139,3 +139,9 @@ permission = access.StaffViewTab ;require = ANY ;ipRange[] = '127.0.0.1' ;ipRange[] = '::1' + +; Example EZproxy authorization permission. +; See https://vufind.org/wiki/configuration:ezproxy for more information. +[ezproxy.authorized] +permission = ezproxy.authorized +role = loggedin diff --git a/languages/en-gb.ini b/languages/en-gb.ini index a6287be7592..8902ab2bf53 100644 --- a/languages/en-gb.ini +++ b/languages/en-gb.ini @@ -18,6 +18,7 @@ delete_selected_favorites = "Delete Selected Favourites" email_selected_favorites = "Email Selected Favourites" Export Favorites = "Export Favourites" export_selected_favorites = "Export Selected Favourites" +external_auth_unauthorized = "You are not authorised to access licensed material" fav_delete = "Delete Selected Favourites" fav_delete_deleting = "Your favourite(s) are being deleted." fav_delete_fail = "Sorry, an error has occurred. Your favourite(s) were not deleted." diff --git a/languages/en.ini b/languages/en.ini index d2940ce5040..829b42c7c1f 100644 --- a/languages/en.ini +++ b/languages/en.ini @@ -346,6 +346,10 @@ export_selected = "Export Selected" export_selected_favorites = "Export Selected Favorites" export_success = "Export Complete" export_unsupported_format = "Unsupported Export Format" +external_auth_heading = "Access to licensed material" +external_auth_login_message = "Login to access licensed material" +external_auth_unauthorized = "You are not authorized to access licensed material" +external_auth_unauthorized_desc = "Your login method does not provide access to licensed material. Please log out and then log in using another method." FAQs = "FAQs" fav_delete = "Delete Selected Favorites" fav_delete_deleting = "Your favorite(s) are being deleted." diff --git a/languages/fi.ini b/languages/fi.ini index ff74fc95490..42c03d555f1 100644 --- a/languages/fi.ini +++ b/languages/fi.ini @@ -350,6 +350,10 @@ export_selected = "Vie valitut" export_selected_favorites = "Vie valitut suosikit" export_success = "Vienti valmis" export_unsupported_format = "Vienti valitussa muodossa ei onnistu" +external_auth_heading = "Pääsy lisensioituun aineistoon" +external_auth_login_message = "Kirjaudu sisään päästäksesi lisensioituun aineistoon" +external_auth_unauthorized = "Sinulla ei ole käyttöoikeutta lisensioituun aineistoon" +external_auth_unauthorized_desc = "Käyttämälläsi kirjautumistavalla ei ole pääsyä lisensioituun aineistoon. Kirjaudu ensin ulos ja käytä sitten toista kirjautumistapaa." FAQs = "UKK:t" fav_delete = "Poista valitut suosikit" fav_delete_deleting = "Suosikkejasi poistetaan" diff --git a/languages/sv.ini b/languages/sv.ini index 412a9cadda0..9642a6e99ae 100644 --- a/languages/sv.ini +++ b/languages/sv.ini @@ -345,6 +345,10 @@ export_selected = "Exportera valda" export_selected_favorites = "Exportera valda favoriter" export_success = "Exporten färdig" export_unsupported_format = "Export i det valda formatet är inte möjlig" +external_auth_heading = "Behörighet att komma åt licensierat material" +external_auth_login_message = "Logga in för att komma åt licensierat material" +external_auth_unauthorized = "Du har inte behörighet att komma åt licensierat material" +external_auth_unauthorized_desc = "Du kan inte komma åt licensierat material med inloggningsmetoden du har använt. Logga ut först och sedan logga in med en annan metod." FAQs = "Vanliga frågor" fav_delete = "Radera valda favoriter" fav_delete_deleting = "Dina favoriter raderas" diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index 10ee1fafd90..554018c4786 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -112,6 +112,7 @@ $config = [ 'eit' => 'VuFind\Controller\EITController', 'eitrecord' => '\VuFind\Controller\EITrecordController', 'error' => 'VuFind\Controller\ErrorController', + 'externalauth' => 'VuFind\Controller\ExternalAuthController', 'feedback' => 'VuFind\Controller\FeedbackController', 'help' => 'VuFind\Controller\HelpController', 'hierarchy' => 'VuFind\Controller\HierarchyController', diff --git a/module/VuFind/src/VuFind/Controller/ExternalAuthController.php b/module/VuFind/src/VuFind/Controller/ExternalAuthController.php new file mode 100644 index 00000000000..76f03f03466 --- /dev/null +++ b/module/VuFind/src/VuFind/Controller/ExternalAuthController.php @@ -0,0 +1,119 @@ +<?php +/** + * External Authentication/Authorization Controller + * + * PHP Version 5 + * + * Copyright (C) The National Library of Finland 2016. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @category VuFind + * @package Controller + * @author Ere Maijala <ere.maijala@helsinki.fi> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:controllers Wiki + */ +namespace VuFind\Controller; + +/** + * External Authentication/Authorization Controller + * + * Provides authorization support for external systems, e.g. EZproxy + * + * @category VuFind + * @package Controller + * @author Ere Maijala <ere.maijala@helsinki.fi> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development:plugins:controllers Wiki + */ +class ExternalAuthController extends AbstractBase +{ + /** + * Permission from permissions.ini required for EZProxy authorization. + * + * @var string + */ + protected $ezproxyRequiredPermission = 'ezproxy.authorized'; + + /** + * Provides an EZproxy session to an authorized user + * + * @return mixed + * + * @throws \Exception + */ + public function ezproxyLoginAction() + { + $config = $this->getConfig(); + if (empty($config->EZproxy->host)) { + throw new \Exception('EZproxy host not defined in configuration'); + } + + $user = $this->getUser(); + if ($user) { + // Logged in, check for authorization + $authService = $this->getServiceLocator() + ->get('ZfcRbac\Service\AuthorizationService'); + if (!$authService->isGranted($this->ezproxyRequiredPermission)) { + $view = $this->createViewModel(); + $view->unauthorized = true; + $this->flashMessenger()->addErrorMessage( + 'external_auth_unauthorized' + ); + return $view; + } + $username = end(explode(':', $user->username, 2)); + $url = $this->params()->fromPost( + 'url', $this->params()->fromQuery('url') + ); + return $this->redirect()->toUrl( + $this->createEzproxyTicketUrl($username, $url) + ); + } + return $this->forceLogin('external_auth_login_message'); + } + + /** + * Create a ticket login URL for EZproxy + * + * @param string $user User name to pass on to EZproxy + * @param string $url The original URL + * + * @return string EZproxy URL + * + * @throws \Exception + * @see https://www.oclc.org/support/services/ezproxy/documentation/usr + * /ticket/php.en.html + */ + protected function createEzproxyTicketUrl($user, $url) + { + $config = $this->getConfig(); + if (empty($config->EZproxy->secret)) { + throw new \Exception('EZproxy secret not defined in configuration'); + } + + $packet = '$u' . time() . '$e'; + $hash = new \Zend\Crypt\Hash(); + $algorithm = !empty($config->EZproxy->secret_hash_method) + ? $config->EZproxy->secret_hash_method : 'SHA512'; + $ticket = $config->EZproxy->secret . $user . $packet; + $ticket = $hash->compute($algorithm, $ticket); + $ticket .= $packet; + $params = http_build_query( + ['user' => $user, 'ticket' => $ticket, 'url' => $url] + ); + return $config->EZproxy->host . "/login?$params"; + } +} diff --git a/themes/bootstrap3/templates/externalauth/ezproxylogin.phtml b/themes/bootstrap3/templates/externalauth/ezproxylogin.phtml new file mode 100644 index 00000000000..3d3b404fcec --- /dev/null +++ b/themes/bootstrap3/templates/externalauth/ezproxylogin.phtml @@ -0,0 +1,18 @@ +<? + // Set page title + $this->headTitle($this->translate('external_auth_heading')); +?> + +<div class="row external-content-access"> + <div class="col-sm-12"> + <?=$this->flashmessages()?> + <? if ($this->unauthorized): ?> + <div class="unauthorized-description"> + <p><?=$this->transEsc('external_auth_unauthorized_desc'); ?></p> + </div> + <div> + <a href="<?=$this->url('myresearch-logout')?>" class="logout btn btn-primary" title="<?=$this->transEsc("Log Out")?>"><strong><?=$this->transEsc("Log Out")?></strong></a> + </div> + <? endif; ?> + </div> +</div> diff --git a/themes/jquerymobile/templates/externalauth/ezproxylogin.phtml b/themes/jquerymobile/templates/externalauth/ezproxylogin.phtml new file mode 100644 index 00000000000..15ad9488cc7 --- /dev/null +++ b/themes/jquerymobile/templates/externalauth/ezproxylogin.phtml @@ -0,0 +1,19 @@ +<? + // Set up page title: + $this->headTitle($this->translate('external_auth_heading')); +?> +<div data-role="page" id="EzProxy-login"> + <?=$this->mobileMenu()->header()?> + <div data-role="content"> + <?=$this->flashmessages()?> + <? if ($this->unauthorized): ?> + <div class="unauthorized-description"> + <p><?=$this->transEsc('external_auth_unauthorized_desc'); ?></p> + </div> + <div> + <a href="<?=$this->url('myresearch-logout')?>" data-role="button" title="<?=$this->transEsc("Log Out")?>"><strong><?=$this->transEsc("Log Out")?></strong></a> + </div> + <? endif; ?> + </div> + <?=$this->mobileMenu()->footer()?> +</div> \ No newline at end of file -- GitLab