feat (2fa): Add IStatelessProvider interface

Signed-off-by: michal.roszak@put.poznan.pl <michal.roszak@put.poznan.pl>
pull/57216/head
michal.roszak@put.poznan.pl 4 months ago committed by Anna
parent f2ea807be2
commit c42bc0cf09
  1. 1
      AUTHORS
  2. 1
      lib/composer/composer/autoload_classmap.php
  3. 1
      lib/composer/composer/autoload_static.php
  4. 9
      lib/private/Authentication/TwoFactorAuth/ProviderManager.php
  5. 9
      lib/private/Authentication/TwoFactorAuth/Registry.php
  6. 22
      lib/public/Authentication/TwoFactorAuth/IStatelessProvider.php
  7. 25
      tests/lib/Authentication/TwoFactorAuth/RegistryTest.php

@ -629,6 +629,7 @@
- zorn-v <zorn7@yandex.ru>
- zulan <git@zulan.net>
- Łukasz Buśko <busko.lukasz@pm.me>
- Michał Roszak <m.roszakos@gmail.com>
- Nextcloud GmbH
- ownCloud GmbH
- ownCloud, Inc.

@ -183,6 +183,7 @@ return array(
'OCP\\Authentication\\TwoFactorAuth\\IProvidesIcons' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IProvidesIcons.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesPersonalSettings' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php',
'OCP\\Authentication\\TwoFactorAuth\\IRegistry' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IRegistry.php',
'OCP\\Authentication\\TwoFactorAuth\\IStatelessProvider' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IStatelessProvider.php',
'OCP\\Authentication\\TwoFactorAuth\\RegistryEvent' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderChallengeFailed' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php',

@ -224,6 +224,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Authentication\\TwoFactorAuth\\IProvidesIcons' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IProvidesIcons.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesPersonalSettings' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php',
'OCP\\Authentication\\TwoFactorAuth\\IRegistry' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IRegistry.php',
'OCP\\Authentication\\TwoFactorAuth\\IStatelessProvider' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IStatelessProvider.php',
'OCP\\Authentication\\TwoFactorAuth\\RegistryEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorProviderChallengeFailed' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorProviderChallengeFailed.php',

@ -13,6 +13,7 @@ use OCP\Authentication\TwoFactorAuth\IActivatableByAdmin;
use OCP\Authentication\TwoFactorAuth\IDeactivatableByAdmin;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IRegistry;
use OCP\Authentication\TwoFactorAuth\IStatelessProvider;
use OCP\IUser;
class ProviderManager {
@ -42,7 +43,9 @@ class ProviderManager {
public function tryEnableProviderFor(string $providerId, IUser $user): bool {
$provider = $this->getProvider($providerId, $user);
if ($provider instanceof IActivatableByAdmin) {
if ($provider instanceof IActivatableByAdmin
&& !($provider instanceof IStatelessProvider)
) {
$provider->enableFor($user);
$this->providerRegistry->enableProviderFor($provider, $user);
return true;
@ -61,7 +64,9 @@ class ProviderManager {
public function tryDisableProviderFor(string $providerId, IUser $user): bool {
$provider = $this->getProvider($providerId, $user);
if ($provider instanceof IDeactivatableByAdmin) {
if ($provider instanceof IDeactivatableByAdmin
&& !($provider instanceof IStatelessProvider)
) {
$provider->disableFor($user);
$this->providerRegistry->disableProviderFor($provider, $user);
return true;

@ -11,6 +11,7 @@ namespace OC\Authentication\TwoFactorAuth;
use OC\Authentication\TwoFactorAuth\Db\ProviderUserAssignmentDao;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IRegistry;
use OCP\Authentication\TwoFactorAuth\IStatelessProvider;
use OCP\Authentication\TwoFactorAuth\RegistryEvent;
use OCP\Authentication\TwoFactorAuth\TwoFactorProviderDisabled;
use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered;
@ -33,6 +34,10 @@ class Registry implements IRegistry {
#[\Override]
public function enableProviderFor(IProvider $provider, IUser $user) {
if ($provider instanceof IStatelessProvider) {
return;
}
$this->assignmentDao->persist($provider->getId(), $user->getUID(), 1);
$event = new RegistryEvent($provider, $user);
@ -42,6 +47,10 @@ class Registry implements IRegistry {
#[\Override]
public function disableProviderFor(IProvider $provider, IUser $user) {
if ($provider instanceof IStatelessProvider) {
return;
}
$this->assignmentDao->persist($provider->getId(), $user->getUID(), 0);
$event = new RegistryEvent($provider, $user);

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCP\Authentication\TwoFactorAuth;
use OCP\AppFramework\Attribute\Implementable;
/**
* Marks the 2FA provider stateless. That means the state of 2FA activation
* for user will be checked dynamically and not stored in the database.
*
* @since 34.0.0
*/
#[Implementable(since: '34.0.0')]
interface IStatelessProvider extends IProvider {
}

@ -13,6 +13,7 @@ use OC\Authentication\TwoFactorAuth\Db\ProviderUserAssignmentDao;
use OC\Authentication\TwoFactorAuth\Registry;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IRegistry;
use OCP\Authentication\TwoFactorAuth\IStatelessProvider;
use OCP\Authentication\TwoFactorAuth\RegistryEvent;
use OCP\Authentication\TwoFactorAuth\TwoFactorProviderDisabled;
use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered;
@ -77,6 +78,18 @@ class RegistryTest extends TestCase {
$this->registry->enableProviderFor($provider, $user);
}
public function testEnableStatelessProvider(): void {
$user = $this->createMock(IUser::class);
$provider = $this->createMock(IStatelessProvider::class);
$this->dao->expects($this->never())->method('persist');
$this->dispatcher->expects($this->never())->method('dispatch');
$this->dispatcher->expects($this->never())->method('dispatchTyped');
$this->registry->enableProviderFor($provider, $user);
}
public function testDisableProvider(): void {
$user = $this->createMock(IUser::class);
$provider = $this->createMock(IProvider::class);
@ -104,6 +117,18 @@ class RegistryTest extends TestCase {
$this->registry->disableProviderFor($provider, $user);
}
public function testDisableStatelessProvider(): void {
$user = $this->createMock(IUser::class);
$provider = $this->createMock(IStatelessProvider::class);
$this->dao->expects($this->never())->method('persist');
$this->dispatcher->expects($this->never())->method('dispatch');
$this->dispatcher->expects($this->never())->method('dispatchTyped');
$this->registry->disableProviderFor($provider, $user);
}
public function testDeleteUserData(): void {
$user = $this->createMock(IUser::class);
$user->expects($this->once())->method('getUID')->willReturn('user123');

Loading…
Cancel
Save