From df991072e89d1462149e26adf53129e1b4451983 Mon Sep 17 00:00:00 2001 From: Ere Maijala <ere.maijala@helsinki.fi> Date: Thu, 29 Sep 2016 08:50:46 -0400 Subject: [PATCH] Add support for Shibboleth single log-out (#791) - Adds new database table for correlating external sessions to internal ones - Includes command-line tool for maintenance --- config/vufind/config.ini | 7 + config/vufind/permissions.ini | 8 + module/VuFind/config/module.config.php | 57 ++++-- .../4.0/001-add-external-session-table.sql | 13 ++ module/VuFind/sql/mysql.sql | 17 ++ module/VuFind/sql/pgsql.sql | 16 ++ module/VuFind/src/VuFind/Auth/Factory.php | 14 ++ module/VuFind/src/VuFind/Auth/Shibboleth.php | 45 +++++ ...ShibbolethLogoutNotificationController.php | 180 ++++++++++++++++++ .../src/VuFind/Db/Row/ExternalSession.php | 53 ++++++ .../src/VuFind/Db/Table/ExternalSession.php | 118 ++++++++++++ .../src/VuFind/Session/AbstractBase.php | 6 +- module/VuFindConsole/Module.php | 2 + .../Controller/UtilController.php | 27 +++ 14 files changed, 549 insertions(+), 14 deletions(-) create mode 100644 module/VuFind/sql/migrations/pgsql/4.0/001-add-external-session-table.sql create mode 100644 module/VuFind/src/VuFind/Controller/ShibbolethLogoutNotificationController.php create mode 100644 module/VuFind/src/VuFind/Db/Row/ExternalSession.php create mode 100644 module/VuFind/src/VuFind/Db/Table/ExternalSession.php diff --git a/config/vufind/config.ini b/config/vufind/config.ini index f5fe32f6965..91923724fb6 100644 --- a/config/vufind/config.ini +++ b/config/vufind/config.ini @@ -522,6 +522,13 @@ database = mysql://root@localhost/vufind ; Server param with the identity provider entityID if a Shibboleth session exists. ; If omitted, Shib-Identity-Provider is used. ;idpserverparam = Shib-Identity-Provider +; Optional: Session ID parameter for SAML2 single logout support. If omitted, single +; logout support is disabled. Note that if SLO support is enabled, Shibboleth session +; ID's are tracked in external_session table which may need to be cleaned up with the +; expire_session_mappings command line utility. See +; https://vufind.org/wiki/configuration:shibboleth for more information on how +; to configure the single logout support. +;session_id = Shib-Session-ID ; Optional: you may set attribute names and values to be used as a filter; ; users will only be logged into VuFind if they match these filters. ;userattribute_1 = entitlement diff --git a/config/vufind/permissions.ini b/config/vufind/permissions.ini index e480e9d1e45..2395196637a 100644 --- a/config/vufind/permissions.ini +++ b/config/vufind/permissions.ini @@ -131,3 +131,11 @@ permission = access.StaffViewTab ;ipRange[] = 1.2.3.1-1.2.3.254 ; for the IP-range of your university's network ;role = loggedin ; if you want to allow authenticated users to use Primo module ;permission = primoOnCampus.MYINSTITUTION + +; Example Shibboleth logout API access permission. +; See https://vufind.org/wiki/configuration:shibboleth for more information. +;[api.ShibbolethLogoutNotification] +;permission = access.api.ShibbolethLogoutNotification +;require = ANY +;ipRange[] = '127.0.0.1' +;ipRange[] = '::1' diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php index 9a698d5a6fc..10ee1fafd90 100644 --- a/module/VuFind/config/module.config.php +++ b/module/VuFind/config/module.config.php @@ -57,6 +57,36 @@ $config = [ 'action' => 'Home', ] ] + ], + 'soap-shibboleth-logout-notification-handler' => [ + 'type' => 'Zend\Mvc\Router\Http\Literal', + 'options' => [ + 'route' => '/soap/shiblogout', + 'defaults' => [ + 'controller' => 'ShibbolethLogoutNotification', + 'action' => 'index' + ] + ], + 'child_routes' => [ + 'get' => [ + 'type' => 'method', + 'options' => [ + 'verb' => 'get', + 'defaults' => [ + 'action' => 'get' + ], + ], + ], + 'post' => [ + 'type' => 'method', + 'options' => [ + 'verb' => 'post', + 'defaults' => [ + 'action' => 'post' + ] + ] + ] + ] ] ], ], @@ -98,6 +128,7 @@ $config = [ 'qrcode' => 'VuFind\Controller\QRCodeController', 'records' => 'VuFind\Controller\RecordsController', 'search' => 'VuFind\Controller\SearchController', + 'shibbolethlogoutnotification' => 'VuFind\Controller\ShibbolethLogoutNotificationController', 'summon' => 'VuFind\Controller\SummonController', 'summonrecord' => 'VuFind\Controller\SummonrecordController', 'tag' => 'VuFind\Controller\TagController', @@ -225,17 +256,18 @@ $config = [ ], // PostgreSQL sequence mapping 'pgsql_seq_mapping' => [ - 'comments' => ['id', 'comments_id_seq'], - 'oai_resumption' => ['id', 'oai_resumption_id_seq'], - 'record' => ['id', 'record_id_seq'], - 'resource' => ['id', 'resource_id_seq'], - 'resource_tags' => ['id', 'resource_tags_id_seq'], - 'search' => ['id', 'search_id_seq'], - 'session' => ['id', 'session_id_seq'], - 'tags' => ['id', 'tags_id_seq'], - 'user' => ['id', 'user_id_seq'], - 'user_list' => ['id', 'user_list_id_seq'], - 'user_resource' => ['id', 'user_resource_id_seq'], + 'comments' => ['id', 'comments_id_seq'], + 'external_session' => ['id', 'external_session_id_seq'], + 'oai_resumption' => ['id', 'oai_resumption_id_seq'], + 'record' => ['id', 'record_id_seq'], + 'resource' => ['id', 'resource_id_seq'], + 'resource_tags' => ['id', 'resource_tags_id_seq'], + 'search' => ['id', 'search_id_seq'], + 'session' => ['id', 'session_id_seq'], + 'tags' => ['id', 'tags_id_seq'], + 'user' => ['id', 'user_id_seq'], + 'user_list' => ['id', 'user_list_id_seq'], + 'user_resource' => ['id', 'user_resource_id_seq'], ], // This section contains service manager configurations for all VuFind // pluggable components: @@ -247,13 +279,13 @@ $config = [ 'facebook' => 'VuFind\Auth\Factory::getFacebook', 'ils' => 'VuFind\Auth\Factory::getILS', 'multiils' => 'VuFind\Auth\Factory::getMultiILS', + 'shibboleth' => 'VuFind\Auth\Factory::getShibboleth' ], 'invokables' => [ 'cas' => 'VuFind\Auth\CAS', 'database' => 'VuFind\Auth\Database', 'ldap' => 'VuFind\Auth\LDAP', 'multiauth' => 'VuFind\Auth\MultiAuth', - 'shibboleth' => 'VuFind\Auth\Shibboleth', 'sip2' => 'VuFind\Auth\SIP2', ], 'aliases' => [ @@ -344,6 +376,7 @@ $config = [ 'invokables' => [ 'changetracker' => 'VuFind\Db\Table\ChangeTracker', 'comments' => 'VuFind\Db\Table\Comments', + 'externalsession' => 'VuFind\Db\Table\ExternalSession', 'oairesumption' => 'VuFind\Db\Table\OaiResumption', 'record' => 'VuFind\Db\Table\Record', 'search' => 'VuFind\Db\Table\Search', diff --git a/module/VuFind/sql/migrations/pgsql/4.0/001-add-external-session-table.sql b/module/VuFind/sql/migrations/pgsql/4.0/001-add-external-session-table.sql new file mode 100644 index 00000000000..4ebcb8f70d6 --- /dev/null +++ b/module/VuFind/sql/migrations/pgsql/4.0/001-add-external-session-table.sql @@ -0,0 +1,13 @@ +-- +-- Table structure for table external_session +-- + +CREATE TABLE external_session ( +id SERIAL, +session_id varchar(128) NOT NULL, +external_session_id varchar(255) NOT NULL, +created timestamp NOT NULL default '1970-01-01 00:00:00', +PRIMARY KEY (id), +UNIQUE (session_id) +); +CREATE INDEX external_session_id on external_session(external_session_id); diff --git a/module/VuFind/sql/mysql.sql b/module/VuFind/sql/mysql.sql index 9029d54fa5f..5fe37443422 100644 --- a/module/VuFind/sql/mysql.sql +++ b/module/VuFind/sql/mysql.sql @@ -145,6 +145,23 @@ CREATE TABLE `session` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `external_session` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `external_session` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `session_id` varchar(128) NOT NULL, + `external_session_id` varchar(255) NOT NULL, + `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00', + PRIMARY KEY (`id`), + UNIQUE KEY `session_id` (`session_id`), + KEY `external_session_id` (`external_session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `tags` -- diff --git a/module/VuFind/sql/pgsql.sql b/module/VuFind/sql/pgsql.sql index 94b949066dd..a63e2bb0425 100644 --- a/module/VuFind/sql/pgsql.sql +++ b/module/VuFind/sql/pgsql.sql @@ -188,6 +188,22 @@ UNIQUE (session_id) ); CREATE INDEX last_used_idx on session(last_used); +-- +-- Table structure for table external_session +-- + +DROP TABLE IF EXISTS "external_session"; + +CREATE TABLE external_session ( +id SERIAL, +session_id varchar(128) NOT NULL, +external_session_id varchar(255) NOT NULL, +created timestamp NOT NULL default '1970-01-01 00:00:00', +PRIMARY KEY (id), +UNIQUE (session_id) +); +CREATE INDEX external_session_id on external_session(external_session_id); + -- -- Table structure for table change_tracker -- diff --git a/module/VuFind/src/VuFind/Auth/Factory.php b/module/VuFind/src/VuFind/Auth/Factory.php index bf6740eed94..28acc1ceb60 100644 --- a/module/VuFind/src/VuFind/Auth/Factory.php +++ b/module/VuFind/src/VuFind/Auth/Factory.php @@ -167,4 +167,18 @@ class Factory $sm->getServiceLocator()->get('VuFind\ILSAuthenticator') ); } + + /** + * Construct the Shibboleth plugin. + * + * @param ServiceManager $sm Service manager. + * + * @return Shibboleth + */ + public static function getShibboleth(ServiceManager $sm) + { + return new Shibboleth( + $sm->getServiceLocator()->get('VuFind\SessionManager') + ); + } } diff --git a/module/VuFind/src/VuFind/Auth/Shibboleth.php b/module/VuFind/src/VuFind/Auth/Shibboleth.php index f872f781786..51bbc5c1e20 100644 --- a/module/VuFind/src/VuFind/Auth/Shibboleth.php +++ b/module/VuFind/src/VuFind/Auth/Shibboleth.php @@ -5,6 +5,7 @@ * PHP version 5 * * Copyright (C) Villanova University 2014. + * 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, @@ -25,6 +26,7 @@ * @author Jochen Lienhard <lienhard@ub.uni-freiburg.de> * @author Bernd Oberknapp <bo@ub.uni-freiburg.de> * @author Demian Katz <demian.katz@villanova.edu> + * @author Ere Maijala <ere.maijala@helsinki.fi> * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org Main Page */ @@ -40,6 +42,7 @@ use VuFind\Exception\Auth as AuthException; * @author Jochen Lienhard <lienhard@ub.uni-freiburg.de> * @author Bernd Oberknapp <bo@ub.uni-freiburg.de> * @author Demian Katz <demian.katz@villanova.edu> + * @author Ere Maijala <ere.maijala@helsinki.fi> * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org Main Page */ @@ -47,6 +50,23 @@ class Shibboleth extends AbstractBase { const DEFAULT_IDPSERVERPARAM = 'Shib-Identity-Provider'; + /** + * Session manager + * + * @var \Zend\Session\ManagerInterface + */ + protected $sessionManager; + + /** + * Constructor + * + * @param \Zend\Session\ManagerInterface $sessionManager Session manager + */ + public function __construct(\Zend\Session\ManagerInterface $sessionManager) + { + $this->sessionManager = $sessionManager; + } + /** * Validate configuration parameters. This is a support method for getConfig(), * so the configuration MUST be accessed using $this->config; do not call @@ -88,12 +108,20 @@ class Shibboleth extends AbstractBase $shib = $this->getConfig()->Shibboleth; $username = $request->getServer()->get($shib->username); if (empty($username)) { + $this->debug( + "No username attribute ({$shib->username}) present in request: " + . print_r($request->getServer()->toArray(), true) + ); throw new AuthException('authentication_error_admin'); } // Check if required attributes match up: foreach ($this->getRequiredAttributes() as $key => $value) { if (!preg_match('/' . $value . '/', $request->getServer()->get($key))) { + $this->debug( + "Attribute '$key' does not match required value '$value' in" + . ' request: ' . print_r($request->getServer()->toArray(), true) + ); throw new AuthException('authentication_error_denied'); } } @@ -136,6 +164,23 @@ class Shibboleth extends AbstractBase ); } + // Add session id mapping to external_session table for single logout support + if (isset($shib->session_id)) { + $shibSessionId = $request->getServer()->get($shib->session_id); + if (null !== $shibSessionId) { + $localSessionId = $this->sessionManager->getId(); + $externalSession = $this->getDbTableManager() + ->get('ExternalSession'); + $externalSession->addSessionMapping( + $localSessionId, $shibSessionId + ); + $this->debug( + "Cached Shibboleth session id '$shibSessionId' for local session" + . " '$localSessionId'" + ); + } + } + // Save and return the user object: $user->save(); return $user; diff --git a/module/VuFind/src/VuFind/Controller/ShibbolethLogoutNotificationController.php b/module/VuFind/src/VuFind/Controller/ShibbolethLogoutNotificationController.php new file mode 100644 index 00000000000..ddd874843c3 --- /dev/null +++ b/module/VuFind/src/VuFind/Controller/ShibbolethLogoutNotificationController.php @@ -0,0 +1,180 @@ +<?php +/** + * Shibboleth Logout Notification API 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Main Site + */ +namespace VuFind\Controller; + +use Zend\Stdlib\ResponseInterface as Response; + +/** + * Handles Shibboleth back-channel logout notifications. + * + * @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 Main Site + */ +class ShibbolethLogoutNotificationController extends AbstractBase +{ + /** + * Constructor + */ + public function __construct() + { + $this->accessPermission = 'access.api.ShibbolethLogoutNotification'; + $this->accessDeniedBehavior = 'exception'; + } + + /** + * GET method handler for the logout handler + * + * @return Response + */ + public function getAction() + { + $this->disableSessionWrites(); + $response = $this->getResponse(); + $response->getHeaders()->addHeaderLine( + 'Content-Type', 'application/wsdl+xml' + ); + $response->setContent($this->getWsdl()); + return $response; + } + + /** + * POST method handler for the logout handler + * + * @return Response + */ + public function postAction() + { + $this->disableSessionWrites(); + list($uri) = explode('?', $this->getRequest()->getUriString()); + $soapServer = new \Zend\Soap\Server( + 'data://text/plain;base64,' . base64_encode($this->getWsdl()) + ); + $soapServer->setReturnResponse(true); + $soapServer->setObject($this); + $soapResponse = $soapServer->handle(); + if ($soapResponse instanceof \SoapFault) { + $soapResponse = (string)$soapResponse; + } + $response = $this->getResponse(); + $response->getHeaders()->addHeaderLine('Content-Type', 'text/xml'); + $response->setContent($soapResponse); + return $response; + } + + /** + * Logout notification handler + * + * @param string $sessionId External session id + * + * @return void + */ + public function logoutNotification($sessionId) + { + $table = $this->getTable('ExternalSession'); + $row = $table->getByExternalSessionId(trim($sessionId)); + if (empty($row)) { + return; + } + $sessionManager = $this->getServiceLocator()->get('VuFind\SessionManager'); + $handler = $sessionManager->getSaveHandler(); + $handler->destroy($row['session_id']); + return; + } + + /** + * Get WSDL for the service + * + * @return string + */ + protected function getWsdl() + { + list($uri) = explode('?', $this->getRequest()->getUriString()); + return <<<EOT +<?xml version ="1.0" encoding ="UTF-8" ?> +<definitions name="LogoutNotification" + targetNamespace="urn:mace:shibboleth:2.0:sp:notify" + xmlns:notify="urn:mace:shibboleth:2.0:sp:notify" + xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" + xmlns="http://schemas.xmlsoap.org/wsdl/"> + + <types> + <schema targetNamespace="urn:mace:shibboleth:2.0:sp:notify" + xmlns="http://www.w3.org/2000/10/XMLSchema" + xmlns:notify="urn:mace:shibboleth:2.0:sp:notify"> + + <simpleType name="string"> + <restriction base="string"> + <minLength value="1"/> + </restriction> + </simpleType> + + <element name="OK" type="notify:OKType"/> + <complexType name="OKType"> + <sequence/> + </complexType> + + </schema> + </types> + + <message name="getLogoutNotificationRequest"> + <part name="SessionID" type="notify:string"/> + </message> + + <message name="getLogoutNotificationResponse" > + <part name="OK"/> + </message> + + <portType name="LogoutNotificationPortType"> + <operation name="LogoutNotification"> + <input message="getLogoutNotificationRequest"/> + <output message="getLogoutNotificationResponse"/> + </operation> + </portType> + + <binding name="LogoutNotificationBinding" + type="notify:LogoutNotificationPortType"> + <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> + <operation name="LogoutNotification"> + <soap:operation + soapAction="urn:xmethods-logout-notification#LogoutNotification"/> + </operation> + </binding> + + <service name="LogoutNotificationService"> + <port name="LogoutNotificationPort" + binding="notify:LogoutNotificationBinding"> + <soap:address location="$uri"/> + </port> + </service> +</definitions> +EOT; + } +} diff --git a/module/VuFind/src/VuFind/Db/Row/ExternalSession.php b/module/VuFind/src/VuFind/Db/Row/ExternalSession.php new file mode 100644 index 00000000000..07452cfbe24 --- /dev/null +++ b/module/VuFind/src/VuFind/Db/Row/ExternalSession.php @@ -0,0 +1,53 @@ +<?php +/** + * Row Definition for external_session + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * Copyrught (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Db_Row + * @author Demian Katz <demian.katz@villanova.edu> + * @author Ere Maijala <ere.maijala@helsinki.fi> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +namespace VuFind\Db\Row; + +/** + * Row Definition for external_session + * + * @category VuFind + * @package Db_Row + * @author Demian Katz <demian.katz@villanova.edu> + * @author Ere Maijala <ere.maijala@helsinki.fi> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +class ExternalSession extends RowGateway +{ + /** + * Constructor + * + * @param \Zend\Db\Adapter\Adapter $adapter Database adapter + */ + public function __construct($adapter) + { + parent::__construct('id', 'external_session', $adapter); + } +} diff --git a/module/VuFind/src/VuFind/Db/Table/ExternalSession.php b/module/VuFind/src/VuFind/Db/Table/ExternalSession.php new file mode 100644 index 00000000000..3e2763ff15a --- /dev/null +++ b/module/VuFind/src/VuFind/Db/Table/ExternalSession.php @@ -0,0 +1,118 @@ +<?php +/** + * Table Definition for external_session + * + * PHP version 5 + * + * Copyright (C) Villanova University 2010. + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Db_Table + * @author Demian Katz <demian.katz@villanova.edu> + * @author Ere Maijala <ere.maijala@helsinki.fi> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Page + */ +namespace VuFind\Db\Table; + +/** + * Table Definition for external_session + * + * @category VuFind + * @package Db_Table + * @author Demian Katz <demian.katz@villanova.edu> + * @author Ere Maijala <ere.maijala@helsinki.fi> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org Main Site + */ +class ExternalSession extends Gateway +{ + use ExpirationTrait; + + /** + * Constructor + */ + public function __construct() + { + parent::__construct('external_session', 'VuFind\Db\Row\ExternalSession'); + } + + /** + * Add a mapping between local and external session id's + * + * @param string $localSessionId Local (VuFind) session id + * @param string $externalSessionId External session id + * + * @return void + */ + public function addSessionMapping($localSessionId, $externalSessionId) + { + $this->destroySession($localSessionId); + $row = $this->createRow(); + $row->session_id = $localSessionId; + $row->external_session_id = $externalSessionId; + $row->created = date('Y-m-d H:i:s'); + $row->save(); + } + + /** + * Retrieve an object from the database based on an external session ID + * + * @param string $sid External session ID to retrieve + * + * @return \VuFind\Db\Row\ExternalSession + */ + public function getByExternalSessionId($sid) + { + return $this->select(['external_session_id' => $sid])->current(); + } + + /** + * Destroy data for the given session ID. + * + * @param string $sid Session ID to erase + * + * @return void + */ + public function destroySession($sid) + { + $this->delete(['session_id' => $sid]); + } + + /** + * Update the select statement to find records to delete. + * + * @param Select $select Select clause + * @param int $daysOld Age in days of an "expired" record. + * @param int $idFrom Lowest id of rows to delete. + * @param int $idTo Highest id of rows to delete. + * + * @return void + */ + protected function expirationCallback($select, $daysOld, $idFrom = null, + $idTo = null + ) { + $expireDate = date('Y-m-d', time() - $daysOld * 24 * 60 * 60); + $where = $select->where->lessThan('created', $expireDate); + if (null !== $idFrom) { + $where->and->greaterThanOrEqualTo('id', $idFrom); + } + if (null !== $idTo) { + $where->and->lessThanOrEqualTo('id', $idTo); + } + } +} diff --git a/module/VuFind/src/VuFind/Session/AbstractBase.php b/module/VuFind/src/VuFind/Session/AbstractBase.php index d8231664bab..26b545dab8c 100644 --- a/module/VuFind/src/VuFind/Session/AbstractBase.php +++ b/module/VuFind/src/VuFind/Session/AbstractBase.php @@ -133,8 +133,10 @@ abstract class AbstractBase implements SaveHandlerInterface, */ public function destroy($sess_id) { - $table = $this->getTable('Search'); - $table->destroySession($sess_id); + $searchTable = $this->getTable('Search'); + $searchTable->destroySession($sess_id); + $sessionTable = $this->getTable('ExternalSession'); + $sessionTable->destroySession($sess_id); return true; } diff --git a/module/VuFindConsole/Module.php b/module/VuFindConsole/Module.php index 016f39db18a..822f6c2b32b 100644 --- a/module/VuFindConsole/Module.php +++ b/module/VuFindConsole/Module.php @@ -98,6 +98,8 @@ class Module implements \Zend\ModuleManager\Feature\ConsoleUsageProviderInterfac 'util deletes' => 'Tool for deleting Solr records', 'util expire_searches' => 'Database search table cleanup', 'util expire_sessions' => 'Database session table cleanup', + 'util expire_external_sessions' + => 'Database external_session table cleanup', 'util index_reserves' => 'Solr reserves indexer', 'util optimize' => 'Solr optimize tool', 'util sitemap' => 'XML sitemap generator', diff --git a/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php b/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php index c6f4ecdb024..532f0f8ce3f 100644 --- a/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php +++ b/module/VuFindConsole/src/VuFindConsole/Controller/UtilController.php @@ -540,6 +540,33 @@ class UtilController extends AbstractBase ); } + /** + * Command-line tool to clear unwanted entries + * from external_session database table. + * + * @return \Zend\Console\Response + */ + public function expireExternalSessionsAction() + { + $this->consoleOpts->addRules( + [ + 'h|help' => 'Get help', + 'batch=i' => 'Batch size', + 'sleep=i' => 'Sleep interval between batches' + ] + ); + + if ($this->consoleOpts->getOption('h')) { + return $this->expirationHelp('external sessions'); + } + + return $this->expire( + 'ExternalSession', + '%%count%% expired external sessions deleted.', + 'No expired external sessions to delete.' + ); + } + /** * Command-line tool to delete suppressed records from the index. * -- GitLab