From 4a72d2dc4968bf8895620bae591752daf0e84559 Mon Sep 17 00:00:00 2001 From: Jos Poortvliet Date: Mon, 19 Jan 2026 08:36:56 +0000 Subject: [PATCH 1/3] Listen to 2FA register/unregister events and log them in the audit app. --- apps/admin_audit/lib/AppInfo/Application.php | 4 ++ .../lib/Listener/SecurityEventListener.php | 40 ++++++++++++++++++- .../Listener/SecurityEventListenerTest.php | 24 +++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php index 077cc4c47adc0..78299fbcba65a 100644 --- a/apps/admin_audit/lib/AppInfo/Application.php +++ b/apps/admin_audit/lib/AppInfo/Application.php @@ -39,6 +39,8 @@ use OCP\Authentication\Events\AnyLoginFailedEvent; use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengeFailed; use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengePassed; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserUnregistered; use OCP\Console\ConsoleEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Cache\CacheEntryInsertedEvent; @@ -118,6 +120,8 @@ public function register(IRegistrationContext $context): void { // Security events $context->registerEventListener(TwoFactorProviderChallengePassed::class, SecurityEventListener::class); $context->registerEventListener(TwoFactorProviderChallengeFailed::class, SecurityEventListener::class); + $context->registerEventListener(TwoFactorProviderForUserRegistered::class, SecurityEventListener::class); + $context->registerEventListener(TwoFactorProviderForUserUnregistered::class, SecurityEventListener::class); // App management events $context->registerEventListener(AppEnableEvent::class, AppManagementEventListener::class); diff --git a/apps/admin_audit/lib/Listener/SecurityEventListener.php b/apps/admin_audit/lib/Listener/SecurityEventListener.php index 17253aa384c9f..e4b2f35eabbff 100644 --- a/apps/admin_audit/lib/Listener/SecurityEventListener.php +++ b/apps/admin_audit/lib/Listener/SecurityEventListener.php @@ -12,11 +12,13 @@ use OCA\AdminAudit\Actions\Action; use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengeFailed; use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengePassed; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserUnregistered; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; /** - * @template-implements IEventListener + * @template-implements IEventListener */ class SecurityEventListener extends Action implements IEventListener { public function handle(Event $event): void { @@ -24,6 +26,10 @@ public function handle(Event $event): void { $this->twoFactorProviderChallengePassed($event); } elseif ($event instanceof TwoFactorProviderChallengeFailed) { $this->twoFactorProviderChallengeFailed($event); + } elseif ($event instanceof TwoFactorProviderForUserRegistered) { + $this->twoFactorProviderForUserRegistered($event); + } elseif ($event instanceof TwoFactorProviderForUserUnregistered) { + $this->twoFactorProviderForUserUnregistered($event); } } @@ -58,4 +64,36 @@ private function twoFactorProviderChallengeFailed(TwoFactorProviderChallengeFail ] ); } + + private function twoFactorProviderForUserRegistered(TwoFactorProviderForUserRegistered $event): void { + $this->log( + 'Two factor provider %s enabled for user %s (%s)', + [ + 'provider' => $event->getProvider()->getDisplayName(), + 'uid' => $event->getUser()->getUID(), + 'displayName' => $event->getUser()->getDisplayName() + ], + [ + 'provider', + 'uid', + 'displayName', + ] + ); + } + + private function twoFactorProviderForUserUnregistered(TwoFactorProviderForUserUnregistered $event): void { + $this->log( + 'Two factor provider %s disabled for user %s (%s)', + [ + 'provider' => $event->getProvider()->getDisplayName(), + 'uid' => $event->getUser()->getUID(), + 'displayName' => $event->getUser()->getDisplayName() + ], + [ + 'provider', + 'uid', + 'displayName', + ] + ); + } } diff --git a/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php b/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php index 482301085308d..803d29abd056c 100644 --- a/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php +++ b/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php @@ -14,6 +14,8 @@ use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengeFailed; use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengePassed; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserUnregistered; use OCP\IUser; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; @@ -62,4 +64,26 @@ public function testTwofactorSuccess(): void { $this->security->handle(new TwoFactorProviderChallengePassed($this->user, $this->provider)); } + + public function testTwofactorRegistered(): void { + $this->logger->expects($this->once()) + ->method('info') + ->with( + $this->equalTo('Two factor provider myprovider enabled for user mydisplayname (myuid)'), + ['app' => 'admin_audit'] + ); + + $this->security->handle(new TwoFactorProviderForUserRegistered($this->user, $this->provider)); + } + + public function testTwofactorUnregistered(): void { + $this->logger->expects($this->once()) + ->method('info') + ->with( + $this->equalTo('Two factor provider myprovider disabled for user mydisplayname (myuid)'), + ['app' => 'admin_audit'] + ); + + $this->security->handle(new TwoFactorProviderForUserUnregistered($this->user, $this->provider)); + } } From 3e0d50085431e343f81d242f3d556c0a396f665c Mon Sep 17 00:00:00 2001 From: Jos Poortvliet Date: Thu, 12 Mar 2026 18:36:44 +0100 Subject: [PATCH 2/3] Update apps/admin_audit/lib/Listener/SecurityEventListener.php Co-authored-by: Carl Schwan Signed-off-by: Jos Poortvliet --- apps/admin_audit/lib/Listener/SecurityEventListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/admin_audit/lib/Listener/SecurityEventListener.php b/apps/admin_audit/lib/Listener/SecurityEventListener.php index e4b2f35eabbff..21a642cf40c2b 100644 --- a/apps/admin_audit/lib/Listener/SecurityEventListener.php +++ b/apps/admin_audit/lib/Listener/SecurityEventListener.php @@ -91,8 +91,8 @@ private function twoFactorProviderForUserUnregistered(TwoFactorProviderForUserUn ], [ 'provider', - 'uid', 'displayName', + 'uid', ] ); } From 2262e73102ce127c3fc8c0132a11bf0f9d885676 Mon Sep 17 00:00:00 2001 From: Jos Poortvliet Date: Thu, 12 Mar 2026 18:37:29 +0100 Subject: [PATCH 3/3] Update apps/admin_audit/lib/Listener/SecurityEventListener.php Co-authored-by: Carl Schwan Signed-off-by: Jos Poortvliet --- apps/admin_audit/lib/Listener/SecurityEventListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/admin_audit/lib/Listener/SecurityEventListener.php b/apps/admin_audit/lib/Listener/SecurityEventListener.php index 21a642cf40c2b..62d05438ba586 100644 --- a/apps/admin_audit/lib/Listener/SecurityEventListener.php +++ b/apps/admin_audit/lib/Listener/SecurityEventListener.php @@ -75,8 +75,8 @@ private function twoFactorProviderForUserRegistered(TwoFactorProviderForUserRegi ], [ 'provider', - 'uid', 'displayName', + 'uid', ] ); }