Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions config/vufind/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1849,6 +1849,17 @@ skip_numeric = true
; - 'username' logs the currently logged-in username, if there is one.
;reference_id = false

; A comma-separated list of event types to enable logging of audit events to the
; database audit_event table. Disabled by default.
; The following built-in event types are available (local extensions could be used
; as well):
; ils - Actions involving the library catalog (renewal, requests)
; user - User actions such as logins
; You should run the "php $VUFIND_HOME/public/index.php util expire_audit_events"
; utility periodically to purge old data in the event table unless you want
; the data to accumulate indefinitely.
;log_audit_events = "ils,user"

; This section can be used to specify a "parent configuration" from which
; the current configuration file will inherit. You can chain multiple
; configurations together if you wish.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CREATE TABLE `audit_event` (
`id` int NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`type` varchar(50) NOT NULL,
`subtype` varchar(50) NOT NULL,
`user_id` int NULL,
`session_id` varchar(128) NULL,
`username` varchar(255) NULL,
`client_ip` varchar(255) NULL,
`server_ip` varchar(255) NULL,
`server_name` varchar(255) NULL,
`message` varchar(255) NULL,
`data` json DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `audit_event_user_id_idx` (`user_id`),
CONSTRAINT `audit_event_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
CREATE TABLE audit_event (
id SERIAL,
date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
type varchar(50) NOT NULL,
subtype varchar(50) NOT NULL,
user_id int,
session_id varchar(128),
username varchar(255),
client_ip varchar(255),
server_ip varchar(255),
server_name varchar(255),
message varchar(255),
data json,
PRIMARY KEY (id)
);
CREATE INDEX audit_event_user_id_idx ON audit_event (user_id);

ALTER TABLE audit_event
ADD CONSTRAINT audit_event_ibfk_1 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE SET NULL;
25 changes: 25 additions & 0 deletions module/VuFind/sql/mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -438,3 +438,28 @@ CREATE TABLE `login_token` (
CONSTRAINT `login_token_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `audit_event`
--

/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `audit_event` (
`id` int NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`type` varchar(50) NOT NULL,
`subtype` varchar(50) NOT NULL,
`user_id` int NULL,
`session_id` varchar(128) NULL,
`username` varchar(255) NULL,
`client_ip` varchar(255) NULL,
`server_ip` varchar(255) NULL,
`server_name` varchar(255) NULL,
`message` varchar(255) NULL,
`data` json DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `audit_event_user_id_idx` (`user_id`),
CONSTRAINT `audit_event_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
28 changes: 28 additions & 0 deletions module/VuFind/sql/pgsql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,27 @@ CREATE TABLE login_token (
CREATE INDEX login_token_user_id_idx ON login_token (user_id);
CREATE INDEX login_token_series_idx ON login_token (series);

--
-- Table structure for table `audit_event`
--

CREATE TABLE audit_event (
id SERIAL,
date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
type varchar(50) NOT NULL,
subtype varchar(50) NOT NULL,
user_id int,
session_id varchar(128),
username varchar(255),
client_ip varchar(255),
server_ip varchar(255),
server_name varchar(255),
message varchar(255),
data json,
PRIMARY KEY (id)
);
CREATE INDEX audit_event_user_id_idx ON audit_event (user_id);

-- --------------------------------------------------------

--
Expand Down Expand Up @@ -480,6 +501,7 @@ ADD CONSTRAINT feedback_ibfk_1 FOREIGN KEY (user_id) REFERENCES "user" (id) ON D
ADD CONSTRAINT feedback_ibfk_2 FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL;


--
-- Constraints for table access_token
--
ALTER TABLE access_token
Expand All @@ -491,4 +513,10 @@ ADD CONSTRAINT access_token_ibfk_1 FOREIGN KEY (user_id) REFERENCES "user" (id)
ALTER TABLE login_token
ADD CONSTRAINT login_token_ibfk_1 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE CASCADE;

--
-- Constraints for table audit_event
--
ALTER TABLE audit_event
ADD CONSTRAINT audit_event_ibfk_1 FOREIGN KEY (user_id) REFERENCES "user" (id) ON DELETE SET NULL;

-- --------------------------------------------------------
69 changes: 60 additions & 9 deletions module/VuFind/src/VuFind/Auth/ILSAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@
use Closure;
use VuFind\Config\Config;
use VuFind\Db\Entity\UserEntityInterface;
use VuFind\Db\Service\AuditEventServiceInterface;
use VuFind\Db\Service\DbServiceAwareInterface;
use VuFind\Db\Service\DbServiceAwareTrait;
use VuFind\Db\Service\UserCardServiceInterface;
use VuFind\Db\Service\UserServiceInterface;
use VuFind\Db\Type\AuditEventSubtype;
use VuFind\Db\Type\AuditEventType;
use VuFind\Exception\ILS as ILSException;
use VuFind\ILS\Connection as ILSConnection;

Expand Down Expand Up @@ -80,6 +83,13 @@ class ILSAuthenticator implements DbServiceAwareInterface
*/
protected $encryptionKey = null;

/**
* Audit event service (optional)
*
* @var ?AuditEventServiceInterface
*/
protected ?AuditEventServiceInterface $auditEventService = null;

/**
* Constructor
*
Expand Down Expand Up @@ -138,6 +148,18 @@ public function encrypt(?string $text)
return $this->encryptOrDecrypt($text, true);
}

/**
* Set audit event service.
*
* @param AuditEventServiceInterface $auditEventService Audit event service
*
* @return void
*/
public function setAuditEventService(AuditEventServiceInterface $auditEventService): void
{
$this->auditEventService = $auditEventService;
}

/**
* This is a central function for encrypting and decrypting so that
* logic is all in one location
Expand Down Expand Up @@ -337,17 +359,28 @@ public function storedCatalogLogin()
/**
* Attempt to log in the user to the ILS, and save credentials if it works.
*
* @param string $username Catalog username
* @param string $password Catalog password
* @param string $username Catalog username
* @param string $password Catalog password
* @param ?UserEntityInterface $loggedInUser Logged-in user (optional, for auditing purposes)
*
* Returns associative array of patron data on success, false on failure.
*
* @return array|bool
* @throws ILSException
*/
public function newCatalogLogin($username, $password)
public function newCatalogLogin(string $username, string $password, ?UserEntityInterface $loggedInUser = null)
{
$result = $this->catalog->patronLogin($username, $password);

if ($this->auditEventService) {
$this->auditEventService->addEvent(
AuditEventType::User,
$result ? AuditEventSubtype::ILSLogin : AuditEventSubtype::ILSLoginFailure,
$loggedInUser,
data: compact('username')
);
}

if ($result) {
$this->updateUser($username, $password, $result);
return $result;
Expand All @@ -358,15 +391,21 @@ public function newCatalogLogin($username, $password)
/**
* Send email authentication link
*
* @param string $email Email address
* @param string $route Route for the login link
* @param array $routeParams Route parameters
* @param array $urlParams URL parameters
* @param string $email Email address
* @param string $route Route for the login link
* @param array $routeParams Route parameters
* @param array $urlParams URL parameters
* @param ?UserEntityInterface $loggedInUser Logged-in user (optional, for auditing purposes)
*
* @return void
*/
public function sendEmailLoginLink($email, $route, $routeParams = [], $urlParams = [])
{
public function sendEmailLoginLink(
string $email,
string $route,
array $routeParams = [],
array $urlParams = [],
?UserEntityInterface $loggedInUser = null
): void {
if (null === $this->emailAuthenticator) {
throw new \Exception('Email authenticator not set');
}
Expand All @@ -380,6 +419,18 @@ public function sendEmailLoginLink($email, $route, $routeParams = [], $urlParams
$route,
$routeParams
);

if ($this->auditEventService) {
$this->auditEventService->addEvent(
AuditEventType::User,
AuditEventSubtype::SendEmailLoginLink,
$loggedInUser,
data: [
'username' => $email,
'email' => $userData['email'],
]
);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions module/VuFind/src/VuFind/Auth/ILSAuthenticatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
use Psr\Container\ContainerExceptionInterface as ContainerException;
use Psr\Container\ContainerInterface;
use VuFind\Crypt\BlockCipher;
use VuFind\Db\Service\AuditEventServiceInterface;
use VuFind\Db\Service\PluginManager as DatabaseServiceManager;

/**
* ILS Authenticator factory.
Expand Down Expand Up @@ -87,6 +89,8 @@ function (string $algo) use ($container) {
$container->get(\VuFind\Auth\EmailAuthenticator::class),
$container->get(\VuFind\Config\PluginManager::class)->get('config')
);
$dbServiceManager = $container->get(DatabaseServiceManager::class);
$service->setAuditEventService($dbServiceManager->get(AuditEventServiceInterface::class));
return $service;
}
}
Loading