Skip to content

Commit 4249bdf

Browse files
Merge pull request #65952 from nextcloud/backport/65948/stable34
[stable34] fix: Remove avatar and credentials only after user removal
2 parents 4b66a1b + edfdb05 commit 4249bdf

6 files changed

Lines changed: 59 additions & 58 deletions

File tree

‎lib/composer/composer/autoload_classmap.php‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2328,7 +2328,6 @@
23282328
'OC\\User\\DisplayNameCache' => $baseDir . '/lib/private/User/DisplayNameCache.php',
23292329
'OC\\User\\LastInteractiveLogin' => $baseDir . '/lib/private/User/LastInteractiveLogin.php',
23302330
'OC\\User\\LazyUser' => $baseDir . '/lib/private/User/LazyUser.php',
2331-
'OC\\User\\Listeners\\BeforeUserDeletedListener' => $baseDir . '/lib/private/User/Listeners/BeforeUserDeletedListener.php',
23322331
'OC\\User\\Listeners\\UserChangedListener' => $baseDir . '/lib/private/User/Listeners/UserChangedListener.php',
23332332
'OC\\User\\Listeners\\UserLoggedInWithCookieListener' => $baseDir . '/lib/private/User/Listeners/UserLoggedInWithCookieListener.php',
23342333
'OC\\User\\LoginException' => $baseDir . '/lib/private/User/LoginException.php',

‎lib/composer/composer/autoload_static.php‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2369,7 +2369,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
23692369
'OC\\User\\DisplayNameCache' => __DIR__ . '/../../..' . '/lib/private/User/DisplayNameCache.php',
23702370
'OC\\User\\LastInteractiveLogin' => __DIR__ . '/../../..' . '/lib/private/User/LastInteractiveLogin.php',
23712371
'OC\\User\\LazyUser' => __DIR__ . '/../../..' . '/lib/private/User/LazyUser.php',
2372-
'OC\\User\\Listeners\\BeforeUserDeletedListener' => __DIR__ . '/../../..' . '/lib/private/User/Listeners/BeforeUserDeletedListener.php',
23732372
'OC\\User\\Listeners\\UserChangedListener' => __DIR__ . '/../../..' . '/lib/private/User/Listeners/UserChangedListener.php',
23742373
'OC\\User\\Listeners\\UserLoggedInWithCookieListener' => __DIR__ . '/../../..' . '/lib/private/User/Listeners/UserLoggedInWithCookieListener.php',
23752374
'OC\\User\\LoginException' => __DIR__ . '/../../..' . '/lib/private/User/LoginException.php',

‎lib/private/Server.php‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@
155155
use OC\Translation\TranslationManager;
156156
use OC\User\AvailabilityCoordinator;
157157
use OC\User\DisplayNameCache;
158-
use OC\User\Listeners\BeforeUserDeletedListener;
159158
use OC\User\Listeners\UserChangedListener;
160159
use OC\User\Listeners\UserLoggedInWithCookieListener;
161160
use OC\User\Session;
@@ -290,7 +289,6 @@
290289
use OCP\Talk\IBroker;
291290
use OCP\Teams\ITeamManager;
292291
use OCP\Translation\ITranslationManager;
293-
use OCP\User\Events\BeforeUserDeletedEvent;
294292
use OCP\User\Events\BeforeUserLoggedInEvent;
295293
use OCP\User\Events\BeforeUserLoggedInWithCookieEvent;
296294
use OCP\User\Events\BeforeUserLoggedOutEvent;
@@ -1358,7 +1356,6 @@ private function connectDispatcher(): void {
13581356
$eventDispatcher->addServiceListener(LoginFailed::class, LoginFailedListener::class);
13591357
$eventDispatcher->addServiceListener(PostLoginEvent::class, UserLoggedInListener::class);
13601358
$eventDispatcher->addServiceListener(UserChangedEvent::class, UserChangedListener::class);
1361-
$eventDispatcher->addServiceListener(BeforeUserDeletedEvent::class, BeforeUserDeletedListener::class);
13621359
$eventDispatcher->addServiceListener(UserLoggedInWithCookieEvent::class, UserLoggedInWithCookieListener::class);
13631360

13641361
FilesMetadataManager::loadListeners($eventDispatcher);

‎lib/private/User/Listeners/BeforeUserDeletedListener.php‎

Lines changed: 0 additions & 53 deletions
This file was deleted.

‎lib/private/User/User.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use OCP\IUser;
2727
use OCP\IUserBackend;
2828
use OCP\Notification\IManager as INotificationManager;
29+
use OCP\Security\ICredentialsManager;
2930
use OCP\Server;
3031
use OCP\Support\Subscription\IAssertion;
3132
use OCP\User\Backend\IGetHomeBackend;
@@ -293,6 +294,9 @@ public function delete(): bool {
293294
$avatarManager = Server::get(AvatarManager::class);
294295
$avatarManager->deleteUserAvatar($this->uid);
295296

297+
$credentialsManager = Server::get(ICredentialsManager::class);
298+
$credentialsManager->erase($this->uid);
299+
296300
$notificationManager = Server::get(INotificationManager::class);
297301
$notification = $notificationManager->createNotification();
298302
$notification->setUser($this->uid);

‎tests/lib/User/UserTest.php‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,29 @@
99
namespace Test\User;
1010

1111
use OC\AllConfig;
12+
use OC\Avatar\AvatarManager;
1213
use OC\Files\Mount\ObjectHomeMountProvider;
1314
use OC\Hooks\PublicEmitter;
1415
use OC\User\Database;
1516
use OC\User\User;
1617
use OCP\Comments\ICommentsManager;
18+
use OCP\Config\IUserConfig;
1719
use OCP\EventDispatcher\IEventDispatcher;
1820
use OCP\Files\FileInfo;
1921
use OCP\Files\Storage\IStorageFactory;
2022
use OCP\IConfig;
2123
use OCP\IURLGenerator;
2224
use OCP\IUser;
25+
use OCP\IUserManager;
2326
use OCP\Notification\IManager as INotificationManager;
2427
use OCP\Notification\INotification;
28+
use OCP\Security\ICredentialsManager;
2529
use OCP\Server;
2630
use PHPUnit\Framework\Attributes\DataProvider;
2731
use PHPUnit\Framework\Attributes\Group;
2832
use PHPUnit\Framework\MockObject\MockObject;
2933
use Test\TestCase;
34+
use Test\Util\User\Dummy;
3035

3136
#[Group('DB')]
3237
class UserTest extends TestCase {
@@ -429,6 +434,8 @@ public function testDeleteHooks(bool $result, int $expectedHooks): void {
429434

430435
$commentsManager = $this->createMock(ICommentsManager::class);
431436
$notificationManager = $this->createMock(INotificationManager::class);
437+
$avatarManager = $this->createMock(AvatarManager::class);
438+
$credentialsManager = $this->createMock(ICredentialsManager::class);
432439

433440
if ($result) {
434441
$config->expects($this->atLeastOnce())
@@ -453,6 +460,13 @@ public function testDeleteHooks(bool $result, int $expectedHooks): void {
453460
$notificationManager->expects($this->once())
454461
->method('markProcessed')
455462
->with($notification);
463+
464+
$avatarManager->expects($this->once())
465+
->method('deleteUserAvatar')
466+
->with('foo');
467+
$credentialsManager->expects($this->once())
468+
->method('erase')
469+
->with('foo');
456470
} else {
457471
$config->expects($this->never())
458472
->method('deleteAllUserValues');
@@ -466,20 +480,61 @@ public function testDeleteHooks(bool $result, int $expectedHooks): void {
466480
->method('createNotification');
467481
$notificationManager->expects($this->never())
468482
->method('markProcessed');
483+
484+
$avatarManager->expects($this->never())
485+
->method('deleteUserAvatar');
486+
$credentialsManager->expects($this->never())
487+
->method('erase');
469488
}
470489

471490
$this->overwriteService(INotificationManager::class, $notificationManager);
491+
$this->overwriteService(AvatarManager::class, $avatarManager);
492+
$this->overwriteService(ICredentialsManager::class, $credentialsManager);
472493
$this->overwriteService(ICommentsManager::class, $commentsManager);
473494

474495
$this->assertSame($result, $user->delete());
475496

476497
$this->restoreService(AllConfig::class);
477498
$this->restoreService(ICommentsManager::class);
478499
$this->restoreService(INotificationManager::class);
500+
$this->restoreService(AvatarManager::class);
501+
$this->restoreService(ICredentialsManager::class);
479502

480503
$this->assertEquals($expectedHooks, $hooksCalled);
481504
}
482505

506+
public function testDeleteRefusedByBackendKeepsAvatarAndCredentials(): void {
507+
$backend = new class extends Dummy {
508+
#[\Override]
509+
public function deleteUser($uid): bool {
510+
return false;
511+
}
512+
};
513+
$uid = $this->getUniqueID('user');
514+
$backend->createUser($uid, 'password');
515+
516+
$userManager = Server::get(IUserManager::class);
517+
$userManager->registerBackend($backend);
518+
$avatarManager = Server::get(AvatarManager::class);
519+
$credentialsManager = Server::get(ICredentialsManager::class);
520+
521+
try {
522+
$user = $userManager->get($uid);
523+
$avatarManager->getAvatar($uid)->set(file_get_contents(\OC::$SERVERROOT . '/tests/data/testavatar.png'));
524+
$credentialsManager->store($uid, 'test', ['password' => 'secret']);
525+
526+
$this->assertFalse($user->delete());
527+
528+
$this->assertTrue($avatarManager->getAvatar($uid)->exists());
529+
$this->assertSame(['password' => 'secret'], $credentialsManager->retrieve($uid, 'test'));
530+
} finally {
531+
$avatarManager->deleteUserAvatar($uid);
532+
$credentialsManager->erase($uid);
533+
Server::get(IUserConfig::class)->deleteAllUserConfig($uid);
534+
$userManager->removeBackend($backend);
535+
}
536+
}
537+
483538
public function testDeleteRecoverState() {
484539
$backend = $this->createMock(\Test\Util\User\Dummy::class);
485540
$backend->method('getBackendName')->willReturn('foo');

0 commit comments

Comments
 (0)