aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Citharel <tcit@tcit.fr>2023-03-13 09:57:55 +0100
committerThomas Citharel <tcit@tcit.fr>2023-05-02 15:54:09 +0200
commit7f5ff6c19b3651ea79e188627dc82f4cd7e6b5ed (patch)
treef26e992f172f924d4200cd196e708de13b16fde3
parentac0c20112513cfa141da93fadabdb5d4e2039804 (diff)
downloadnextcloud-server-admin_audit/enh/move-to-event-listeners.tar.gz
nextcloud-server-admin_audit/enh/move-to-event-listeners.zip
Move admin_audit hooks to modern event listenersadmin_audit/enh/move-to-event-listeners
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
-rw-r--r--apps/admin_audit/composer/composer/autoload_classmap.php13
-rw-r--r--apps/admin_audit/composer/composer/autoload_static.php13
-rw-r--r--apps/admin_audit/lib/Actions/AppManagement.php61
-rw-r--r--apps/admin_audit/lib/Actions/Auth.php65
-rw-r--r--apps/admin_audit/lib/Actions/GroupManagement.php109
-rw-r--r--apps/admin_audit/lib/Actions/Security.php78
-rw-r--r--apps/admin_audit/lib/Actions/UserManagement.php80
-rw-r--r--apps/admin_audit/lib/AppInfo/Application.php204
-rw-r--r--apps/admin_audit/lib/AuditLogger.php25
-rw-r--r--apps/admin_audit/lib/Listener/AppManagementEventListener.php76
-rw-r--r--apps/admin_audit/lib/Listener/AuthEventListener.php83
-rw-r--r--apps/admin_audit/lib/Listener/ConsoleEventListener.php (renamed from apps/admin_audit/lib/Actions/Console.php)30
-rw-r--r--apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php3
-rw-r--r--apps/admin_audit/lib/Listener/FileEventListener.php65
-rw-r--r--apps/admin_audit/lib/Listener/GroupManagementEventListener.php97
-rw-r--r--apps/admin_audit/lib/Listener/SecurityEventListener.php77
-rw-r--r--apps/admin_audit/lib/Listener/SharingEventListener.php307
-rw-r--r--apps/admin_audit/lib/Listener/UserManagementEventListener.php142
-rw-r--r--apps/admin_audit/tests/Listener/SecurityEventListenerTest.php (renamed from apps/admin_audit/tests/Actions/SecurityTest.php)27
19 files changed, 994 insertions, 561 deletions
diff --git a/apps/admin_audit/composer/composer/autoload_classmap.php b/apps/admin_audit/composer/composer/autoload_classmap.php
index fc4be52ebbb..1f831dd430c 100644
--- a/apps/admin_audit/composer/composer/autoload_classmap.php
+++ b/apps/admin_audit/composer/composer/autoload_classmap.php
@@ -8,12 +8,7 @@ $baseDir = $vendorDir;
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'OCA\\AdminAudit\\Actions\\Action' => $baseDir . '/../lib/Actions/Action.php',
- 'OCA\\AdminAudit\\Actions\\AppManagement' => $baseDir . '/../lib/Actions/AppManagement.php',
- 'OCA\\AdminAudit\\Actions\\Auth' => $baseDir . '/../lib/Actions/Auth.php',
- 'OCA\\AdminAudit\\Actions\\Console' => $baseDir . '/../lib/Actions/Console.php',
'OCA\\AdminAudit\\Actions\\Files' => $baseDir . '/../lib/Actions/Files.php',
- 'OCA\\AdminAudit\\Actions\\GroupManagement' => $baseDir . '/../lib/Actions/GroupManagement.php',
- 'OCA\\AdminAudit\\Actions\\Security' => $baseDir . '/../lib/Actions/Security.php',
'OCA\\AdminAudit\\Actions\\Sharing' => $baseDir . '/../lib/Actions/Sharing.php',
'OCA\\AdminAudit\\Actions\\Trashbin' => $baseDir . '/../lib/Actions/Trashbin.php',
'OCA\\AdminAudit\\Actions\\UserManagement' => $baseDir . '/../lib/Actions/UserManagement.php',
@@ -22,5 +17,13 @@ return array(
'OCA\\AdminAudit\\AuditLogger' => $baseDir . '/../lib/AuditLogger.php',
'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => $baseDir . '/../lib/BackgroundJobs/Rotate.php',
'OCA\\AdminAudit\\IAuditLogger' => $baseDir . '/../lib/IAuditLogger.php',
+ 'OCA\\AdminAudit\\Listener\\AppManagementEventListener' => $baseDir . '/../lib/Listener/AppManagementEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\AuthEventListener' => $baseDir . '/../lib/Listener/AuthEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\ConsoleEventListener' => $baseDir . '/../lib/Listener/ConsoleEventListener.php',
'OCA\\AdminAudit\\Listener\\CriticalActionPerformedEventListener' => $baseDir . '/../lib/Listener/CriticalActionPerformedEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\FileEventListener' => $baseDir . '/../lib/Listener/FileEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\GroupManagementEventListener' => $baseDir . '/../lib/Listener/GroupManagementEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\SecurityEventListener' => $baseDir . '/../lib/Listener/SecurityEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\SharingEventListener' => $baseDir . '/../lib/Listener/SharingEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\UserManagementEventListener' => $baseDir . '/../lib/Listener/UserManagementEventListener.php',
);
diff --git a/apps/admin_audit/composer/composer/autoload_static.php b/apps/admin_audit/composer/composer/autoload_static.php
index 38518c8a9ba..24b3ae3de1e 100644
--- a/apps/admin_audit/composer/composer/autoload_static.php
+++ b/apps/admin_audit/composer/composer/autoload_static.php
@@ -23,12 +23,7 @@ class ComposerStaticInitAdminAudit
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'OCA\\AdminAudit\\Actions\\Action' => __DIR__ . '/..' . '/../lib/Actions/Action.php',
- 'OCA\\AdminAudit\\Actions\\AppManagement' => __DIR__ . '/..' . '/../lib/Actions/AppManagement.php',
- 'OCA\\AdminAudit\\Actions\\Auth' => __DIR__ . '/..' . '/../lib/Actions/Auth.php',
- 'OCA\\AdminAudit\\Actions\\Console' => __DIR__ . '/..' . '/../lib/Actions/Console.php',
'OCA\\AdminAudit\\Actions\\Files' => __DIR__ . '/..' . '/../lib/Actions/Files.php',
- 'OCA\\AdminAudit\\Actions\\GroupManagement' => __DIR__ . '/..' . '/../lib/Actions/GroupManagement.php',
- 'OCA\\AdminAudit\\Actions\\Security' => __DIR__ . '/..' . '/../lib/Actions/Security.php',
'OCA\\AdminAudit\\Actions\\Sharing' => __DIR__ . '/..' . '/../lib/Actions/Sharing.php',
'OCA\\AdminAudit\\Actions\\Trashbin' => __DIR__ . '/..' . '/../lib/Actions/Trashbin.php',
'OCA\\AdminAudit\\Actions\\UserManagement' => __DIR__ . '/..' . '/../lib/Actions/UserManagement.php',
@@ -37,7 +32,15 @@ class ComposerStaticInitAdminAudit
'OCA\\AdminAudit\\AuditLogger' => __DIR__ . '/..' . '/../lib/AuditLogger.php',
'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => __DIR__ . '/..' . '/../lib/BackgroundJobs/Rotate.php',
'OCA\\AdminAudit\\IAuditLogger' => __DIR__ . '/..' . '/../lib/IAuditLogger.php',
+ 'OCA\\AdminAudit\\Listener\\AppManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/AppManagementEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\AuthEventListener' => __DIR__ . '/..' . '/../lib/Listener/AuthEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\ConsoleEventListener' => __DIR__ . '/..' . '/../lib/Listener/ConsoleEventListener.php',
'OCA\\AdminAudit\\Listener\\CriticalActionPerformedEventListener' => __DIR__ . '/..' . '/../lib/Listener/CriticalActionPerformedEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\FileEventListener' => __DIR__ . '/..' . '/../lib/Listener/FileEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\GroupManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/GroupManagementEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\SecurityEventListener' => __DIR__ . '/..' . '/../lib/Listener/SecurityEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\SharingEventListener' => __DIR__ . '/..' . '/../lib/Listener/SharingEventListener.php',
+ 'OCA\\AdminAudit\\Listener\\UserManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/UserManagementEventListener.php',
);
public static function getInitializer(ClassLoader $loader)
diff --git a/apps/admin_audit/lib/Actions/AppManagement.php b/apps/admin_audit/lib/Actions/AppManagement.php
deleted file mode 100644
index d6bc7d2c61f..00000000000
--- a/apps/admin_audit/lib/Actions/AppManagement.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-namespace OCA\AdminAudit\Actions;
-
-class AppManagement extends Action {
-
- /**
- * @param string $appName
- */
- public function enableApp(string $appName): void {
- $this->log('App "%s" enabled',
- ['app' => $appName],
- ['app']
- );
- }
-
- /**
- * @param string $appName
- * @param string[] $groups
- */
- public function enableAppForGroups(string $appName, array $groups): void {
- $this->log('App "%1$s" enabled for groups: %2$s',
- ['app' => $appName, 'groups' => implode(', ', $groups)],
- ['app', 'groups']
- );
- }
-
- /**
- * @param string $appName
- */
- public function disableApp(string $appName): void {
- $this->log('App "%s" disabled',
- ['app' => $appName],
- ['app']
- );
- }
-}
diff --git a/apps/admin_audit/lib/Actions/Auth.php b/apps/admin_audit/lib/Actions/Auth.php
deleted file mode 100644
index 27722d4a41c..00000000000
--- a/apps/admin_audit/lib/Actions/Auth.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
- *
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-namespace OCA\AdminAudit\Actions;
-
-/**
- * Class Auth logs all auth related actions
- *
- * @package OCA\AdminAudit\Actions
- */
-class Auth extends Action {
- public function loginAttempt(array $params): void {
- $this->log(
- 'Login attempt: "%s"',
- $params,
- [
- 'uid',
- ],
- true
- );
- }
-
- public function loginSuccessful(array $params): void {
- $this->log(
- 'Login successful: "%s"',
- $params,
- [
- 'uid',
- ],
- true
- );
- }
-
- public function logout(array $params): void {
- $this->log(
- 'Logout occurred',
- [],
- []
- );
- }
-}
diff --git a/apps/admin_audit/lib/Actions/GroupManagement.php b/apps/admin_audit/lib/Actions/GroupManagement.php
deleted file mode 100644
index e79b86bb88b..00000000000
--- a/apps/admin_audit/lib/Actions/GroupManagement.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Roger Szabo <roger.szabo@web.de>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-namespace OCA\AdminAudit\Actions;
-
-use OCP\IGroup;
-use OCP\IUser;
-
-/**
- * Class GroupManagement logs all group manager related events
- *
- * @package OCA\AdminAudit\Actions
- */
-class GroupManagement extends Action {
-
- /**
- * log add user to group event
- *
- * @param IGroup $group
- * @param IUser $user
- */
- public function addUser(IGroup $group, IUser $user): void {
- $this->log('User "%s" added to group "%s"',
- [
- 'group' => $group->getGID(),
- 'user' => $user->getUID()
- ],
- [
- 'user', 'group'
- ]
- );
- }
-
- /**
- * log remove user from group event
- *
- * @param IGroup $group
- * @param IUser $user
- */
- public function removeUser(IGroup $group, IUser $user): void {
- $this->log('User "%s" removed from group "%s"',
- [
- 'group' => $group->getGID(),
- 'user' => $user->getUID()
- ],
- [
- 'user', 'group'
- ]
- );
- }
-
- /**
- * log create group to group event
- *
- * @param IGroup $group
- */
- public function createGroup(IGroup $group): void {
- $this->log('Group created: "%s"',
- [
- 'group' => $group->getGID()
- ],
- [
- 'group'
- ]
- );
- }
-
- /**
- * log delete group to group event
- *
- * @param IGroup $group
- */
- public function deleteGroup(IGroup $group): void {
- $this->log('Group deleted: "%s"',
- [
- 'group' => $group->getGID()
- ],
- [
- 'group'
- ]
- );
- }
-}
diff --git a/apps/admin_audit/lib/Actions/Security.php b/apps/admin_audit/lib/Actions/Security.php
deleted file mode 100644
index e4831ac6fc1..00000000000
--- a/apps/admin_audit/lib/Actions/Security.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-namespace OCA\AdminAudit\Actions;
-
-use OCP\IUser;
-
-/**
- * Class Sharing logs the sharing actions
- *
- * @package OCA\AdminAudit\Actions
- */
-class Security extends Action {
- /**
- * Log twofactor auth enabled
- *
- * @param IUser $user
- * @param array $params
- */
- public function twofactorFailed(IUser $user, array $params): void {
- $params['uid'] = $user->getUID();
- $params['displayName'] = $user->getDisplayName();
-
- $this->log(
- 'Failed two factor attempt by user %s (%s) with provider %s',
- $params,
- [
- 'displayName',
- 'uid',
- 'provider',
- ]
- );
- }
-
- /**
- * Logs unsharing of data
- *
- * @param IUser $user
- * @param array $params
- */
- public function twofactorSuccess(IUser $user, array $params): void {
- $params['uid'] = $user->getUID();
- $params['displayName'] = $user->getDisplayName();
-
- $this->log(
- 'Successful two factor attempt by user %s (%s) with provider %s',
- $params,
- [
- 'displayName',
- 'uid',
- 'provider',
- ]
- );
- }
-}
diff --git a/apps/admin_audit/lib/Actions/UserManagement.php b/apps/admin_audit/lib/Actions/UserManagement.php
index 02d5b60d2fa..a3a3afb23e3 100644
--- a/apps/admin_audit/lib/Actions/UserManagement.php
+++ b/apps/admin_audit/lib/Actions/UserManagement.php
@@ -31,28 +31,12 @@ declare(strict_types=1);
*/
namespace OCA\AdminAudit\Actions;
-use OCP\IUser;
-
/**
* Class UserManagement logs all user management related actions.
*
* @package OCA\AdminAudit\Actions
*/
class UserManagement extends Action {
- /**
- * Log creation of users
- *
- * @param array $params
- */
- public function create(array $params): void {
- $this->log(
- 'User created: "%s"',
- $params,
- [
- 'uid',
- ]
- );
- }
/**
* Log assignments of users (typically user backends)
@@ -68,21 +52,6 @@ class UserManagement extends Action {
}
/**
- * Log deletion of users
- *
- * @param array $params
- */
- public function delete(array $params): void {
- $this->log(
- 'User deleted: "%s"',
- $params,
- [
- 'uid',
- ]
- );
- }
-
- /**
* Log unassignments of users (typically user backends, no data removed)
*
* @param string $uid
@@ -94,53 +63,4 @@ class UserManagement extends Action {
[ 'uid' ]
);
}
-
- /**
- * Log enabling of users
- *
- * @param array $params
- */
- public function change(array $params): void {
- switch ($params['feature']) {
- case 'enabled':
- $this->log(
- $params['value'] === true
- ? 'User enabled: "%s"'
- : 'User disabled: "%s"',
- ['user' => $params['user']->getUID()],
- [
- 'user',
- ]
- );
- break;
- case 'eMailAddress':
- $this->log(
- 'Email address changed for user %s',
- ['user' => $params['user']->getUID()],
- [
- 'user',
- ]
- );
- break;
- }
- }
-
- /**
- * Logs changing of the user scope
- *
- * @param IUser $user
- */
- public function setPassword(IUser $user): void {
- if ($user->getBackendClassName() === 'Database') {
- $this->log(
- 'Password of user "%s" has been changed',
- [
- 'user' => $user->getUID(),
- ],
- [
- 'user',
- ]
- );
- }
- }
}
diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php
index 1160d151710..6f18990dc37 100644
--- a/apps/admin_audit/lib/AppInfo/Application.php
+++ b/apps/admin_audit/lib/AppInfo/Application.php
@@ -13,6 +13,7 @@ declare(strict_types=1);
* @author Joas Schilling <coding@schilljs.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Thomas Citharel <nextcloud@tcit.fr>
* @author Tiago Flores <tiago.flores@yahoo.com.br>
*
* @license GNU AGPL version 3 or any later version
@@ -33,50 +34,58 @@ declare(strict_types=1);
*/
namespace OCA\AdminAudit\AppInfo;
-use Closure;
use OC\Files\Filesystem;
-use OC\Files\Node\File;
-use OC\Group\Manager as GroupManager;
-use OC\User\Session as UserSession;
-use OCA\AdminAudit\Actions\AppManagement;
-use OCA\AdminAudit\Actions\Auth;
-use OCA\AdminAudit\Actions\Console;
use OCA\AdminAudit\Actions\Files;
-use OCA\AdminAudit\Actions\GroupManagement;
-use OCA\AdminAudit\Actions\Security;
use OCA\AdminAudit\Actions\Sharing;
use OCA\AdminAudit\Actions\Trashbin;
-use OCA\AdminAudit\Actions\UserManagement;
use OCA\AdminAudit\Actions\Versions;
use OCA\AdminAudit\AuditLogger;
use OCA\AdminAudit\IAuditLogger;
+use OCA\AdminAudit\Listener\AppManagementEventListener;
+use OCA\AdminAudit\Listener\AuthEventListener;
+use OCA\AdminAudit\Listener\ConsoleEventListener;
use OCA\AdminAudit\Listener\CriticalActionPerformedEventListener;
-use OCP\App\ManagerEvent;
+use OCA\AdminAudit\Listener\FileEventListener;
+use OCA\AdminAudit\Listener\GroupManagementEventListener;
+use OCA\AdminAudit\Listener\SecurityEventListener;
+use OCA\AdminAudit\Listener\SharingEventListener;
+use OCA\AdminAudit\Listener\UserManagementEventListener;
+use OCP\App\Events\AppDisableEvent;
+use OCP\App\Events\AppEnableEvent;
+use OCP\App\Events\AppUpdateEvent;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
-use OCP\Authentication\TwoFactorAuth\IProvider;
-use OCP\Console\ConsoleEvent;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserDisabled;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserEnabled;
+use OCP\Console\ConsoleEventV2;
+use OCP\Group\Events\GroupCreatedEvent;
+use OCP\Group\Events\GroupDeletedEvent;
+use OCP\Group\Events\UserAddedEvent;
+use OCP\Group\Events\UserRemovedEvent;
use OCP\IConfig;
-use OCP\IGroupManager;
-use OCP\IPreview;
-use OCP\IServerContainer;
-use OCP\IUserSession;
use OCP\Log\Audit\CriticalActionPerformedEvent;
use OCP\Log\ILogFactory;
+use OCP\Preview\BeforePreviewFetchedEvent;
use OCP\Share;
+use OCP\Share\Events\ShareCreatedEvent;
+use OCP\Share\Events\ShareDeletedEvent;
+use OCP\User\Events\BeforeUserLoggedInEvent;
+use OCP\User\Events\BeforeUserLoggedOutEvent;
+use OCP\User\Events\PasswordUpdatedEvent;
+use OCP\User\Events\UserChangedEvent;
+use OCP\User\Events\UserCreatedEvent;
+use OCP\User\Events\UserDeletedEvent;
+use OCP\User\Events\UserIdAssignedEvent;
+use OCP\User\Events\UserIdUnassignedEvent;
+use OCP\User\Events\UserLoggedInEvent;
+use OCP\User\Events\UserLoggedInWithCookieEvent;
use OCP\Util;
use Psr\Container\ContainerInterface;
-use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
class Application extends App implements IBootstrap {
- /** @var LoggerInterface */
- protected $logger;
-
public function __construct() {
parent::__construct('admin_audit');
}
@@ -87,6 +96,45 @@ class Application extends App implements IBootstrap {
});
$context->registerEventListener(CriticalActionPerformedEvent::class, CriticalActionPerformedEventListener::class);
+
+ // User management events
+ $context->registerEventListener(UserCreatedEvent::class, UserManagementEventListener::class);
+ $context->registerEventListener(UserDeletedEvent::class, UserManagementEventListener::class);
+ $context->registerEventListener(UserChangedEvent::class, UserManagementEventListener::class);
+ $context->registerEventListener(PasswordUpdatedEvent::class, UserManagementEventListener::class);
+ $context->registerEventListener(UserIdAssignedEvent::class, UserManagementEventListener::class);
+ $context->registerEventListener(UserIdUnassignedEvent::class, UserManagementEventListener::class);
+
+ // Group management events
+ $context->registerEventListener(UserAddedEvent::class, GroupManagementEventListener::class);
+ $context->registerEventListener(UserRemovedEvent::class, GroupManagementEventListener::class);
+ $context->registerEventListener(GroupCreatedEvent::class, GroupManagementEventListener::class);
+ $context->registerEventListener(GroupDeletedEvent::class, GroupManagementEventListener::class);
+
+ // Sharing events
+ $context->registerEventListener(ShareCreatedEvent::class, SharingEventListener::class);
+ $context->registerEventListener(ShareDeletedEvent::class, SharingEventListener::class);
+
+ // Auth events
+ $context->registerEventListener(BeforeUserLoggedInEvent::class, AuthEventListener::class);
+ $context->registerEventListener(UserLoggedInWithCookieEvent::class, AuthEventListener::class);
+ $context->registerEventListener(UserLoggedInEvent::class, AuthEventListener::class);
+ $context->registerEventListener(BeforeUserLoggedOutEvent::class, AuthEventListener::class);
+
+ // File events
+ $context->registerEventListener(BeforePreviewFetchedEvent::class, FileEventListener::class);
+
+ // Security events
+ $context->registerEventListener(TwoFactorProviderForUserEnabled::class, SecurityEventListener::class);
+ $context->registerEventListener(TwoFactorProviderForUserDisabled::class, SecurityEventListener::class);
+
+ // App management events
+ $context->registerEventListener(AppEnableEvent::class, AppManagementEventListener::class);
+ $context->registerEventListener(AppDisableEvent::class, AppManagementEventListener::class);
+ $context->registerEventListener(AppUpdateEvent::class, AppManagementEventListener::class);
+
+ // Console events
+ $context->registerEventListener(ConsoleEventV2::class, ConsoleEventListener::class);
}
public function boot(IBootContext $context): void {
@@ -97,118 +145,32 @@ class Application extends App implements IBootstrap {
* TODO: once the hooks are migrated to lazy events, this should be done
* in \OCA\AdminAudit\AppInfo\Application::register
*/
- $this->registerHooks($logger, $context->getServerContainer());
+ $this->registerLegacyHooks($logger);
}
/**
* Register hooks in order to log them
*/
- private function registerHooks(IAuditLogger $logger,
- IServerContainer $serverContainer): void {
- $this->userManagementHooks($logger, $serverContainer->get(IUserSession::class));
- $this->groupHooks($logger, $serverContainer->get(IGroupManager::class));
- $this->authHooks($logger);
+ private function registerLegacyHooks(IAuditLogger $logger): void {
- /** @var EventDispatcherInterface $eventDispatcher */
- $eventDispatcher = $serverContainer->get(EventDispatcherInterface::class);
- $this->consoleHooks($logger, $eventDispatcher);
- $this->appHooks($logger, $eventDispatcher);
+ $this->sharingLegacyHooks($logger);
- $this->sharingHooks($logger);
-
- $this->fileHooks($logger, $eventDispatcher);
+ $this->fileHooks($logger);
$this->trashbinHooks($logger);
$this->versionsHooks($logger);
-
- $this->securityHooks($logger, $eventDispatcher);
- }
-
- private function userManagementHooks(IAuditLogger $logger,
- IUserSession $userSession): void {
- $userActions = new UserManagement($logger);
-
- Util::connectHook('OC_User', 'post_createUser', $userActions, 'create');
- Util::connectHook('OC_User', 'post_deleteUser', $userActions, 'delete');
- Util::connectHook('OC_User', 'changeUser', $userActions, 'change');
-
- assert($userSession instanceof UserSession);
- $userSession->listen('\OC\User', 'postSetPassword', [$userActions, 'setPassword']);
- $userSession->listen('\OC\User', 'assignedUserId', [$userActions, 'assign']);
- $userSession->listen('\OC\User', 'postUnassignedUserId', [$userActions, 'unassign']);
- }
-
- private function groupHooks(IAuditLogger $logger,
- IGroupManager $groupManager): void {
- $groupActions = new GroupManagement($logger);
-
- assert($groupManager instanceof GroupManager);
- $groupManager->listen('\OC\Group', 'postRemoveUser', [$groupActions, 'removeUser']);
- $groupManager->listen('\OC\Group', 'postAddUser', [$groupActions, 'addUser']);
- $groupManager->listen('\OC\Group', 'postDelete', [$groupActions, 'deleteGroup']);
- $groupManager->listen('\OC\Group', 'postCreate', [$groupActions, 'createGroup']);
}
- private function sharingHooks(IAuditLogger $logger): void {
+ private function sharingLegacyHooks(IAuditLogger $logger): void {
$shareActions = new Sharing($logger);
- Util::connectHook(Share::class, 'post_shared', $shareActions, 'shared');
- Util::connectHook(Share::class, 'post_unshare', $shareActions, 'unshare');
- Util::connectHook(Share::class, 'post_unshareFromSelf', $shareActions, 'unshare');
Util::connectHook(Share::class, 'post_update_permissions', $shareActions, 'updatePermissions');
Util::connectHook(Share::class, 'post_update_password', $shareActions, 'updatePassword');
Util::connectHook(Share::class, 'post_set_expiration_date', $shareActions, 'updateExpirationDate');
Util::connectHook(Share::class, 'share_link_access', $shareActions, 'shareAccessed');
}
- private function authHooks(IAuditLogger $logger): void {
- $authActions = new Auth($logger);
-
- Util::connectHook('OC_User', 'pre_login', $authActions, 'loginAttempt');
- Util::connectHook('OC_User', 'post_login', $authActions, 'loginSuccessful');
- Util::connectHook('OC_User', 'logout', $authActions, 'logout');
- }
-
- private function appHooks(IAuditLogger $logger,
- EventDispatcherInterface $eventDispatcher): void {
- $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function (ManagerEvent $event) use ($logger) {
- $appActions = new AppManagement($logger);
- $appActions->enableApp($event->getAppID());
- });
- $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function (ManagerEvent $event) use ($logger) {
- $appActions = new AppManagement($logger);
- $appActions->enableAppForGroups($event->getAppID(), $event->getGroups());
- });
- $eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function (ManagerEvent $event) use ($logger) {
- $appActions = new AppManagement($logger);
- $appActions->disableApp($event->getAppID());
- });
- }
-
- private function consoleHooks(IAuditLogger $logger,
- EventDispatcherInterface $eventDispatcher): void {
- $eventDispatcher->addListener(ConsoleEvent::EVENT_RUN, function (ConsoleEvent $event) use ($logger) {
- $appActions = new Console($logger);
- $appActions->runCommand($event->getArguments());
- });
- }
-
- private function fileHooks(IAuditLogger $logger,
- EventDispatcherInterface $eventDispatcher): void {
+ private function fileHooks(IAuditLogger $logger): void {
$fileActions = new Files($logger);
- $eventDispatcher->addListener(
- IPreview::EVENT,
- function (GenericEvent $event) use ($fileActions) {
- /** @var File $file */
- $file = $event->getSubject();
- $fileActions->preview([
- 'path' => mb_substr($file->getInternalPath(), 5),
- 'width' => $event->getArguments()['width'],
- 'height' => $event->getArguments()['height'],
- 'crop' => $event->getArguments()['crop'],
- 'mode' => $event->getArguments()['mode']
- ]);
- }
- );
Util::connectHook(
Filesystem::CLASSNAME,
@@ -265,16 +227,4 @@ class Application extends App implements IBootstrap {
Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete');
Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore');
}
-
- private function securityHooks(IAuditLogger $logger,
- EventDispatcherInterface $eventDispatcher): void {
- $eventDispatcher->addListener(IProvider::EVENT_SUCCESS, function (GenericEvent $event) use ($logger) {
- $security = new Security($logger);
- $security->twofactorSuccess($event->getSubject(), $event->getArguments());
- });
- $eventDispatcher->addListener(IProvider::EVENT_FAILED, function (GenericEvent $event) use ($logger) {
- $security = new Security($logger);
- $security->twofactorFailed($event->getSubject(), $event->getArguments());
- });
- }
}
diff --git a/apps/admin_audit/lib/AuditLogger.php b/apps/admin_audit/lib/AuditLogger.php
index 0a7a330a743..c985d770f62 100644
--- a/apps/admin_audit/lib/AuditLogger.php
+++ b/apps/admin_audit/lib/AuditLogger.php
@@ -1,4 +1,7 @@
<?php
+
+declare(strict_types=1);
+
/**
* @copyright Copyright (c) 2022 Carl Schwan <carl@carlschwan.eu>
*
@@ -31,9 +34,7 @@ use Psr\Log\LoggerInterface;
* Logger that logs in the audit log file instead of the normal log file
*/
class AuditLogger implements IAuditLogger {
-
- /** @var LoggerInterface */
- private $parentLogger;
+ private LoggerInterface $parentLogger;
public function __construct(ILogFactory $logFactory, IConfig $config) {
$auditType = $config->getSystemValueString('log_type_audit', 'file');
@@ -50,39 +51,39 @@ class AuditLogger implements IAuditLogger {
$this->parentLogger = $logFactory->getCustomPsrLogger($logFile, $auditType, $auditTag);
}
- public function emergency($message, array $context = array()) {
+ public function emergency($message, array $context = array()): void {
$this->parentLogger->emergency($message, $context);
}
- public function alert($message, array $context = array()) {
+ public function alert($message, array $context = array()): void {
$this->parentLogger->alert($message, $context);
}
- public function critical($message, array $context = array()) {
+ public function critical($message, array $context = array()): void {
$this->parentLogger->critical($message, $context);
}
- public function error($message, array $context = array()) {
+ public function error($message, array $context = array()): void {
$this->parentLogger->error($message, $context);
}
- public function warning($message, array $context = array()) {
+ public function warning($message, array $context = array()): void {
$this->parentLogger->warning($message, $context);
}
- public function notice($message, array $context = array()) {
+ public function notice($message, array $context = array()): void {
$this->parentLogger->notice($message, $context);
}
- public function info($message, array $context = array()) {
+ public function info($message, array $context = array()): void {
$this->parentLogger->info($message, $context);
}
- public function debug($message, array $context = array()) {
+ public function debug($message, array $context = array()): void {
$this->parentLogger->debug($message, $context);
}
- public function log($level, $message, array $context = array()) {
+ public function log($level, $message, array $context = array()): void {
$this->parentLogger->log($level, $message, $context);
}
}
diff --git a/apps/admin_audit/lib/Listener/AppManagementEventListener.php b/apps/admin_audit/lib/Listener/AppManagementEventListener.php
new file mode 100644
index 00000000000..43f3359b8ea
--- /dev/null
+++ b/apps/admin_audit/lib/Listener/AppManagementEventListener.php
@@ -0,0 +1,76 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\AdminAudit\Listener;
+
+use OCA\AdminAudit\Actions\Action;
+use OCP\App\Events\AppDisableEvent;
+use OCP\App\Events\AppEnableEvent;
+use OCP\App\Events\AppUpdateEvent;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+/**
+ * @template-implements UserManagementEventListener<AppEnableEvent|AppDisableEvent|AppUpdateEvent>
+ */
+class AppManagementEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof AppEnableEvent) {
+ $this->appEnable($event);
+ } elseif ($event instanceof AppDisableEvent) {
+ $this->appDisable($event);
+ } elseif ($event instanceof AppUpdateEvent) {
+ $this->appUpdate($event);
+ }
+ }
+
+ private function appEnable(AppEnableEvent $event): void {
+ if (empty($event->getGroupIds())) {
+ $this->log('App "%s" enabled',
+ ['app' => $event->getAppId()],
+ ['app']
+ );
+ } else {
+ $this->log('App "%1$s" enabled for groups: %2$s',
+ ['app' => $event->getAppId(), 'groups' => implode(', ', $event->getGroupIds())],
+ ['app', 'groups']
+ );
+ }
+ }
+
+ private function appDisable(AppDisableEvent $event): void {
+ $this->log('App "%s" disabled',
+ ['app' => $event->getAppId()],
+ ['app']
+ );
+ }
+
+ private function appUpdate(AppUpdateEvent $event): void {
+ $this->log('App "%s" updated',
+ ['app' => $event->getAppId()],
+ ['app']
+ );
+ }
+}
diff --git a/apps/admin_audit/lib/Listener/AuthEventListener.php b/apps/admin_audit/lib/Listener/AuthEventListener.php
new file mode 100644
index 00000000000..a9a60313f6c
--- /dev/null
+++ b/apps/admin_audit/lib/Listener/AuthEventListener.php
@@ -0,0 +1,83 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\AdminAudit\Listener;
+
+use OCA\AdminAudit\Actions\Action;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\BeforeUserLoggedInEvent;
+use OCP\User\Events\BeforeUserLoggedOutEvent;
+use OCP\User\Events\UserLoggedInEvent;
+use OCP\User\Events\UserLoggedInWithCookieEvent;
+
+/**
+ * @template-implements UserManagementEventListener<BeforeUserLoggedInEvent|UserLoggedInWithCookieEvent|UserLoggedInEvent|BeforeUserLoggedOutEvent>
+ */
+class AuthEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof BeforeUserLoggedInEvent) {
+ $this->beforeUserLoggedIn($event);
+ } elseif ($event instanceof UserLoggedInWithCookieEvent || $event instanceof UserLoggedInEvent) {
+ $this->userLoggedIn($event);
+ } elseif ($event instanceof BeforeUserLoggedOutEvent) {
+ $this->beforeUserLogout($event);
+ }
+ }
+
+ private function beforeUserLoggedIn(BeforeUserLoggedInEvent $event): void {
+ $this->log(
+ 'Login attempt: "%s"',
+ [
+ 'uid' => $event->getUsername()
+ ],
+ [
+ 'uid',
+ ],
+ true
+ );
+ }
+
+ private function userLoggedIn(UserLoggedInWithCookieEvent|UserLoggedInEvent $event): void {
+ $this->log(
+ 'Login successful: "%s"',
+ [
+ 'uid' => $event->getUser()->getUID()
+ ],
+ [
+ 'uid',
+ ],
+ true
+ );
+ }
+
+ private function beforeUserLogout(BeforeUserLoggedOutEvent $event): void {
+ $this->log(
+ 'Logout occurred',
+ [],
+ []
+ );
+ }
+}
diff --git a/apps/admin_audit/lib/Actions/Console.php b/apps/admin_audit/lib/Listener/ConsoleEventListener.php
index a69d1f5ff82..2470fcb3166 100644
--- a/apps/admin_audit/lib/Actions/Console.php
+++ b/apps/admin_audit/lib/Listener/ConsoleEventListener.php
@@ -3,11 +3,9 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
*
- * @author Daniel Kesselberg <mail@danielkesselberg.de>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Thomas Citharel <nextcloud@tcit.fr>
*
* @license GNU AGPL version 3 or any later version
*
@@ -25,13 +23,25 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
-namespace OCA\AdminAudit\Actions;
+namespace OCA\AdminAudit\Listener;
-class Console extends Action {
- /**
- * @param $arguments
- */
- public function runCommand(array $arguments): void {
+use OCA\AdminAudit\Actions\Action;
+use OCP\Console\ConsoleEventV2;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+/**
+ * @template-implements UserManagementEventListener<ConsoleEventV2>
+ */
+class ConsoleEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof ConsoleEventV2) {
+ $this->runCommand($event);
+ }
+ }
+
+ private function runCommand(ConsoleEventV2 $event): void {
+ $arguments = $event->getArguments();
if (!isset($arguments[1]) || $arguments[1] === '_completion') {
// Don't log autocompletion
return;
diff --git a/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php b/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php
index 3f91c0c2731..8cfbc240755 100644
--- a/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php
+++ b/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php
@@ -30,6 +30,9 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Log\Audit\CriticalActionPerformedEvent;
+/**
+ * @template-implements UserManagementEventListener<CriticalActionPerformedEvent>
+ */
class CriticalActionPerformedEventListener extends Action implements IEventListener {
public function handle(Event $event): void {
if (!($event instanceof CriticalActionPerformedEvent)) {
diff --git a/apps/admin_audit/lib/Listener/FileEventListener.php b/apps/admin_audit/lib/Listener/FileEventListener.php
new file mode 100644
index 00000000000..9e9305f7896
--- /dev/null
+++ b/apps/admin_audit/lib/Listener/FileEventListener.php
@@ -0,0 +1,65 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\AdminAudit\Listener;
+
+use OCA\AdminAudit\Actions\Action;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Preview\BeforePreviewFetchedEvent;
+
+
+/**
+ * @template-implements UserManagementEventListener<BeforePreviewFetchedEvent>
+ */
+class FileEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof BeforePreviewFetchedEvent) {
+ $this->beforePreviewFetched($event);
+ }
+ }
+
+ private function beforePreviewFetched(BeforePreviewFetchedEvent $event): void {
+ $file = $event->getNode();
+
+ $this->log(
+ 'Preview accessed: "%s" (width: "%s", height: "%s" crop: "%s", mode: "%s")',
+ [
+ 'path' => mb_substr($file->getInternalPath(), 5),
+ 'width' => $event->getWidth(),
+ 'height' => $event->getHeight(),
+ 'crop' => $event->isCrop(),
+ 'mode' => $event->getMode(),
+ ],
+ [
+ 'path',
+ 'width',
+ 'height',
+ 'crop',
+ 'mode'
+ ]
+ );
+ }
+}
diff --git a/apps/admin_audit/lib/Listener/GroupManagementEventListener.php b/apps/admin_audit/lib/Listener/GroupManagementEventListener.php
new file mode 100644
index 00000000000..92a0ddb0837
--- /dev/null
+++ b/apps/admin_audit/lib/Listener/GroupManagementEventListener.php
@@ -0,0 +1,97 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\AdminAudit\Listener;
+
+use OCA\AdminAudit\Actions\Action;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Group\Events\GroupCreatedEvent;
+use OCP\Group\Events\GroupDeletedEvent;
+use OCP\Group\Events\UserAddedEvent;
+use OCP\Group\Events\UserRemovedEvent;
+
+/**
+ * @template-implements UserManagementEventListener<UserAddedEvent|UserRemovedEvent|GroupCreatedEvent|GroupDeletedEvent>
+ */
+class GroupManagementEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof UserAddedEvent) {
+ $this->userAdded($event);
+ } elseif ($event instanceof UserRemovedEvent) {
+ $this->userRemoved($event);
+ } elseif ($event instanceof GroupCreatedEvent) {
+ $this->groupCreated($event);
+ } elseif ($event instanceof GroupDeletedEvent) {
+ $this->groupDeleted($event);
+ }
+ }
+
+ private function userAdded(UserAddedEvent $event): void {
+ $this->log('User "%s" added to group "%s"',
+ [
+ 'group' => $event->getGroup()->getGID(),
+ 'user' => $event->getUser()->getUID()
+ ],
+ [
+ 'user', 'group'
+ ]
+ );
+ }
+
+ private function userRemoved(UserRemovedEvent $event): void {
+ $this->log('User "%s" removed from group "%s"',
+ [
+ 'group' => $event->getGroup()->getGID(),
+ 'user' => $event->getUser()->getUID()
+ ],
+ [
+ 'user', 'group'
+ ]
+ );
+ }
+
+ private function groupCreated(GroupCreatedEvent $event): void {
+ $this->log('Group created: "%s"',
+ [
+ 'group' => $event->getGroup()->getGID()
+ ],
+ [
+ 'group'
+ ]
+ );
+ }
+
+ private function groupDeleted(GroupDeletedEvent $event): void {
+ $this->log('Group deleted: "%s"',
+ [
+ 'group' => $event->getGroup()->getGID()
+ ],
+ [
+ 'group'
+ ]
+ );
+ }
+}
diff --git a/apps/admin_audit/lib/Listener/SecurityEventListener.php b/apps/admin_audit/lib/Listener/SecurityEventListener.php
new file mode 100644
index 00000000000..d7676cf8c4d
--- /dev/null
+++ b/apps/admin_audit/lib/Listener/SecurityEventListener.php
@@ -0,0 +1,77 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\AdminAudit\Listener;
+
+use OCA\AdminAudit\Actions\Action;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserDisabled;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserEnabled;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+/**
+ * @template-implements UserManagementEventListener<TwoFactorProviderForUserEnabled|TwoFactorProviderForUserDisabled>
+ */
+class SecurityEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof TwoFactorProviderForUserEnabled) {
+ $this->twoFactorProviderForUserEnabled($event);
+ } elseif ($event instanceof TwoFactorProviderForUserDisabled) {
+ $this->twoFactorProviderForUserDisabled($event);
+ }
+ }
+
+ private function twoFactorProviderForUserEnabled(TwoFactorProviderForUserEnabled $event): void {
+ $this->log(
+ 'Successful two factor attempt by user %s (%s) with provider %s',
+ [
+ 'uid' => $event->getUser()->getUID(),
+ 'displayName' => $event->getUser()->getDisplayName(),
+ 'provider' => $event->getProvider()->getDisplayName()
+ ],
+ [
+ 'displayName',
+ 'uid',
+ 'provider',
+ ]
+ );
+ }
+
+ private function twoFactorProviderForUserDisabled(TwoFactorProviderForUserDisabled $event): void {
+ $this->log(
+ 'Failed two factor attempt by user %s (%s) with provider %s',
+ [
+ 'uid' => $event->getUser()->getUID(),
+ 'displayName' => $event->getUser()->getDisplayName(),
+ 'provider' => $event->getProvider()->getDisplayName()
+ ],
+ [
+ 'displayName',
+ 'uid',
+ 'provider',
+ ]
+ );
+ }
+}
diff --git a/apps/admin_audit/lib/Listener/SharingEventListener.php b/apps/admin_audit/lib/Listener/SharingEventListener.php
new file mode 100644
index 00000000000..5fcaba64c2f
--- /dev/null
+++ b/apps/admin_audit/lib/Listener/SharingEventListener.php
@@ -0,0 +1,307 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\AdminAudit\Listener;
+
+use OCA\AdminAudit\Actions\Action;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Share\Events\ShareCreatedEvent;
+use OCP\Share\Events\ShareDeletedEvent;
+use OCP\Share\IShare;
+
+/**
+ * @template-implements UserManagementEventListener<ShareCreatedEvent|ShareDeletedEvent>
+ */
+class SharingEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof ShareCreatedEvent) {
+ $this->shareCreated($event);
+ } elseif ($event instanceof ShareDeletedEvent) {
+ $this->shareDeleted($event);
+ }
+ }
+
+ private function shareCreated(ShareCreatedEvent $event): void {
+ $share = $event->getShare();
+
+ $params = [
+ 'itemType' => $share->getNodeType(),
+ 'path' => $share->getNode()->getPath(),
+ 'itemSource' => $share->getNodeId(),
+ 'shareWith' => $share->getSharedWith(),
+ 'permissions' => $share->getPermissions(),
+ 'id' => $share->getId()
+ ];
+
+ match ($share->getShareType()) {
+ IShare::TYPE_LINK => $this->log(
+ 'The %s "%s" with ID "%s" has been shared via link with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_USER => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the user "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_GROUP => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the group "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_ROOM => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the room "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_EMAIL => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the email recipient "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_CIRCLE => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the circle "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_REMOTE => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the remote user "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_REMOTE_GROUP => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the remote group "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_DECK => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the deck card "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_SCIENCEMESH => $this->log(
+ 'The %s "%s" with ID "%s" has been shared to the sciencemesh user "%s" with permissions "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'path',
+ 'itemSource',
+ 'shareWith',
+ 'permissions',
+ 'id',
+ ]
+ ),
+ default => null
+ };
+ }
+
+ private function shareDeleted(ShareDeletedEvent $event): void {
+ $share = $event->getShare();
+
+ $params = [
+ 'itemType' => $share->getNodeType(),
+ 'fileTarget' => $share->getTarget(),
+ 'itemSource' => $share->getNodeId(),
+ 'shareWith' => $share->getSharedWith(),
+ 'id' => $share->getId()
+ ];
+
+ match ($share->getShareType()) {
+ IShare::TYPE_LINK => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_USER => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the user "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_GROUP => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the group "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_ROOM => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the room "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_EMAIL => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the email recipient "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_CIRCLE => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the circle "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_REMOTE => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the remote user "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_REMOTE_GROUP => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the remote group "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_DECK => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the deck card "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ IShare::TYPE_SCIENCEMESH => $this->log(
+ 'The %s "%s" with ID "%s" has been unshared from the sciencemesh user "%s" (Share ID: %s)',
+ $params,
+ [
+ 'itemType',
+ 'fileTarget',
+ 'itemSource',
+ 'shareWith',
+ 'id',
+ ]
+ ),
+ default => null
+ };
+ }
+}
diff --git a/apps/admin_audit/lib/Listener/UserManagementEventListener.php b/apps/admin_audit/lib/Listener/UserManagementEventListener.php
new file mode 100644
index 00000000000..40baf99cc55
--- /dev/null
+++ b/apps/admin_audit/lib/Listener/UserManagementEventListener.php
@@ -0,0 +1,142 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @author Thomas Citharel <nextcloud@tcit.fr>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\AdminAudit\Listener;
+
+use OCA\AdminAudit\Actions\Action;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\PasswordUpdatedEvent;
+use OCP\User\Events\UserChangedEvent;
+use OCP\User\Events\UserCreatedEvent;
+use OCP\User\Events\UserDeletedEvent;
+use OCP\User\Events\UserIdAssignedEvent;
+use OCP\User\Events\UserIdUnassignedEvent;
+
+/**
+ * @template-implements UserManagementEventListener<UserCreatedEvent|UserDeletedEvent|UserChangedEvent|PasswordUpdatedEvent|UserIdAssignedEvent|UserIdUnassignedEvent>
+ */
+class UserManagementEventListener extends Action implements IEventListener {
+ public function handle(Event $event): void {
+ if ($event instanceof UserCreatedEvent) {
+ $this->userCreated($event);
+ } elseif ($event instanceof UserDeletedEvent) {
+ $this->userDeleted($event);
+ } elseif ($event instanceof UserChangedEvent) {
+ $this->userChanged($event);
+ } elseif ($event instanceof PasswordUpdatedEvent) {
+ $this->passwordUpdated($event);
+ } elseif ($event instanceof UserIdAssignedEvent) {
+ $this->userIdAssigned($event);
+ } elseif ($event instanceof UserIdUnassignedEvent) {
+ $this->userIdUnassigned($event);
+ }
+ }
+
+ private function userCreated(UserCreatedEvent $event): void {
+ $this->log(
+ 'User created: "%s"',
+ [
+ 'uid' => $event->getUid()
+ ],
+ [
+ 'uid',
+ ]
+ );
+ }
+
+ private function userDeleted(UserDeletedEvent $event): void {
+ $this->log(
+ 'User deleted: "%s"',
+ [
+ 'uid' => $event->getUser()->getUID()
+ ],
+ [
+ 'uid',
+ ]
+ );
+ }
+
+ private function userChanged(UserChangedEvent $event): void {
+ switch ($event->getFeature()) {
+ case 'enabled':
+ $this->log(
+ $event->getValue() === true
+ ? 'User enabled: "%s"'
+ : 'User disabled: "%s"',
+ ['user' => $event->getUser()->getUID()],
+ [
+ 'user',
+ ]
+ );
+ break;
+ case 'eMailAddress':
+ $this->log(
+ 'Email address changed for user %s',
+ ['user' => $event->getUser()->getUID()],
+ [
+ 'user',
+ ]
+ );
+ break;
+ }
+ }
+
+ private function passwordUpdated(PasswordUpdatedEvent $event): void {
+ if ($event->getUser()->getBackendClassName() === 'Database') {
+ $this->log(
+ 'Password of user "%s" has been changed',
+ [
+ 'user' => $event->getUser()->getUID(),
+ ],
+ [
+ 'user',
+ ]
+ );
+ }
+ }
+
+ /**
+ * Log assignments of users (typically user backends)
+ */
+ private function userIdAssigned(UserIdAssignedEvent $event): void {
+ $this->log(
+ 'UserID assigned: "%s"',
+ [ 'uid' => $event->getUserId() ],
+ [ 'uid' ]
+ );
+ }
+
+ /**
+ * Log unassignments of users (typically user backends, no data removed)
+ */
+ private function userIdUnassigned(UserIdUnassignedEvent $event): void {
+ $this->log(
+ 'UserID unassigned: "%s"',
+ [ 'uid' => $event->getUserId() ],
+ [ 'uid' ]
+ );
+ }
+}
diff --git a/apps/admin_audit/tests/Actions/SecurityTest.php b/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php
index d45cbb75a64..f9f236c4998 100644
--- a/apps/admin_audit/tests/Actions/SecurityTest.php
+++ b/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php
@@ -7,6 +7,7 @@ declare(strict_types=1);
*
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Thomas Citharel <nextcloud@tcit.fr>
*
* @license GNU AGPL version 3 or any later version
*
@@ -26,30 +27,38 @@ declare(strict_types=1);
*/
namespace OCA\AdminAudit\Tests\Actions;
-use OCA\AdminAudit\Actions\Security;
+use OCA\AdminAudit\Listener\SecurityEventListener;
+use OCP\Authentication\TwoFactorAuth\IProvider;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserDisabled;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserEnabled;
use OCP\IUser;
use OCA\AdminAudit\AuditLogger;
+use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
-class SecurityTest extends TestCase {
- /** @var AuditLogger|\PHPUnit\Framework\MockObject\MockObject */
+class SecurityEventListenerTest extends TestCase {
+ /** @var AuditLogger|MockObject */
private $logger;
- /** @var Security */
- private $security;
+ private SecurityEventListener $security;
- /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
+ /** @var IUser|MockObject */
private $user;
+ /** @var IProvider|(IProvider&MockObject)|MockObject */
+ private $provider;
+
protected function setUp(): void {
parent::setUp();
$this->logger = $this->createMock(AuditLogger::class);
- $this->security = new Security($this->logger);
+ $this->security = new SecurityEventListener($this->logger);
$this->user = $this->createMock(IUser::class);
$this->user->method('getUID')->willReturn('myuid');
$this->user->method('getDisplayName')->willReturn('mydisplayname');
+ $this->provider = $this->createMock(IProvider::class);
+ $this->provider->method('getDisplayName')->willReturn('myprovider');
}
public function testTwofactorFailed() {
@@ -60,7 +69,7 @@ class SecurityTest extends TestCase {
['app' => 'admin_audit']
);
- $this->security->twofactorFailed($this->user, ['provider' => 'myprovider']);
+ $this->security->handle(new TwoFactorProviderForUserEnabled($this->user, $this->provider));
}
public function testTwofactorSuccess() {
@@ -71,6 +80,6 @@ class SecurityTest extends TestCase {
['app' => 'admin_audit']
);
- $this->security->twofactorSuccess($this->user, ['provider' => 'myprovider']);
+ $this->security->handle(new TwoFactorProviderForUserDisabled($this->user, $this->provider));
}
}