Skip to content
Open
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
1 change: 1 addition & 0 deletions apps/provisioning_api/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
['root' => '/cloud', 'name' => 'Users#editUser', 'url' => '/users/{userId}', 'verb' => 'PUT'],
['root' => '/cloud', 'name' => 'Users#editUserMultiValue', 'url' => '/users/{userId}/{collectionName}', 'verb' => 'PUT', 'requirements' => ['collectionName' => '^(?!enable$|disable$)[a-zA-Z0-9_]*$']],
['root' => '/cloud', 'name' => 'Users#wipeUserDevices', 'url' => '/users/{userId}/wipe', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#invalidateUserTokens', 'url' => '/users/{userId}/invalidate', 'verb' => 'POST'],
['root' => '/cloud', 'name' => 'Users#deleteUser', 'url' => '/users/{userId}', 'verb' => 'DELETE'],
['root' => '/cloud', 'name' => 'Users#enableUser', 'url' => '/users/{userId}/enable', 'verb' => 'PUT'],
['root' => '/cloud', 'name' => 'Users#disableUser', 'url' => '/users/{userId}/disable', 'verb' => 'PUT'],
Expand Down
47 changes: 47 additions & 0 deletions apps/provisioning_api/lib/Controller/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace OCA\Provisioning_API\Controller;

use InvalidArgumentException;
use OC\Authentication\Token\Invalidator;
use OC\Authentication\Token\RemoteWipe;
use OC\KnownUser\KnownUserService;
use OC\User\Backend;
Expand Down Expand Up @@ -71,6 +72,7 @@ public function __construct(
private NewUserMailHelper $newUserMailHelper,
private ISecureRandom $secureRandom,
private RemoteWipe $remoteWipe,
private Invalidator $invalidator,
private KnownUserService $knownUserService,
private IEventDispatcher $eventDispatcher,
private IPhoneNumberUtil $phoneNumberUtil,
Expand Down Expand Up @@ -1250,6 +1252,51 @@ public function wipeUserDevices(string $userId): DataResponse {
return new DataResponse();
}


/**
* Invalidate all tokens of a user
*
* @param string $userId ID of the user
*
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
*
* @throws OCSException
*
* 200: Invalidated all user tokens successfully
*/
#[NoAdminRequired]
public function invalidateUserTokens(string $userId): DataResponse {
/** @var IUser $currentLoggedInUser */
$currentLoggedInUser = $this->userSession->getUser();

$targetUser = $this->userManager->get($userId);

if ($targetUser === null) {
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}

if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
throw new OCSException('', 101);
}

// If not permitted
$subAdminManager = $this->groupManager->getSubAdmin();
$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
}

$this->logger->warning('Invalidating all tokens for user ' . $userId . ' by user ' . $currentLoggedInUser->getUID(), [
'app' => 'ocs_api',
'adminUserId' => $currentLoggedInUser->getUID(),
'accountId' => $userId,
]);

$this->invalidator->invalidateAllUserTokens($targetUser->getUID());

return new DataResponse();
}
/**
* Delete a user
*
Expand Down
68 changes: 68 additions & 0 deletions apps/provisioning_api/openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -3214,6 +3214,74 @@
}
}
},
"/ocs/v2.php/cloud/users/{userId}/invalidate": {
"post": {
"operationId": "users-invalidate-user-tokens",
"summary": "Invalidate all tokens of a user",
"tags": [
"users"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "userId",
"in": "path",
"description": "ID of the user",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "Invalidated all user tokens successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/cloud/users/{userId}/enable": {
"put": {
"operationId": "users-enable-user",
Expand Down
68 changes: 68 additions & 0 deletions apps/provisioning_api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2151,6 +2151,74 @@
}
}
},
"/ocs/v2.php/cloud/users/{userId}/invalidate": {
"post": {
"operationId": "users-invalidate-user-tokens",
"summary": "Invalidate all tokens of a user",
"tags": [
"users"
],
"security": [
{
"bearer_auth": []
},
{
"basic_auth": []
}
],
"parameters": [
{
"name": "userId",
"in": "path",
"description": "ID of the user",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "OCS-APIRequest",
"in": "header",
"description": "Required to be true for the API request to pass",
"required": true,
"schema": {
"type": "boolean",
"default": true
}
}
],
"responses": {
"200": {
"description": "Invalidated all user tokens successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
},
"/ocs/v2.php/cloud/users/{userId}/enable": {
"put": {
"operationId": "users-enable-user",
Expand Down
36 changes: 36 additions & 0 deletions apps/provisioning_api/tests/Controller/UsersControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace OCA\Provisioning_API\Tests\Controller;

use Exception;
use OC\Authentication\Token\Invalidator;
use OC\Authentication\Token\RemoteWipe;
use OC\Group\Manager;
use OC\KnownUser\KnownUserService;
Expand Down Expand Up @@ -73,6 +74,8 @@ class UsersControllerTest extends TestCase {
/** @var RemoteWipe|MockObject */
private $remoteWipe;
/** @var KnownUserService|MockObject */
private $invalidator;
/** @var KnownUserService|MockObject */
private $knownUserService;
/** @var IEventDispatcher|MockObject */
private $eventDispatcher;
Expand All @@ -95,6 +98,7 @@ protected function setUp(): void {
$this->newUserMailHelper = $this->createMock(NewUserMailHelper::class);
$this->secureRandom = $this->createMock(ISecureRandom::class);
$this->remoteWipe = $this->createMock(RemoteWipe::class);
$this->invalidator = $this->createMock(Invalidator::class);
$this->knownUserService = $this->createMock(KnownUserService::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
$this->phoneNumberUtil = new PhoneNumberUtil();
Expand All @@ -119,6 +123,7 @@ protected function setUp(): void {
$this->newUserMailHelper,
$this->secureRandom,
$this->remoteWipe,
$this->invalidator,
$this->knownUserService,
$this->eventDispatcher,
$this->phoneNumberUtil,
Expand Down Expand Up @@ -513,6 +518,7 @@ public function testAddUserSuccessfulWithDisplayName() {
$this->newUserMailHelper,
$this->secureRandom,
$this->remoteWipe,
$this->invalidator,
$this->knownUserService,
$this->eventDispatcher,
$this->phoneNumberUtil,
Expand Down Expand Up @@ -3133,6 +3139,34 @@ public function testRemoveFromGroupWithNoTargetGroup() {
$this->api->removeFromGroup('TargetUser', '');
}

public function testInvalidateUserTokensSuccess(): void {
$currentUser = $this->createMock(IUser::class);
$targetUser = $this->createMock(IUser::class);

$this->userSession->method('getUser')->willReturn($currentUser);
$currentUser->method('getUID')->willReturn('currentUserId');
$targetUser->method('getUID')->willReturn('targetUserId');

$this->userManager->method('get')->with('targetUserId')->willReturn($targetUser);

$this->groupManager->method('isAdmin')->with('currentUserId')->willReturn(true);

$this->invalidator->expects($this->once())->method('invalidateAllUserTokens')->with('targetUserId');

$this->logger
->expects($this->once())
->method('warning')
->with('Invalidating all tokens for user targetUserId by user currentUserId', [
'app' => 'ocs_api',
'adminUserId' => 'currentUserId',
'accountId' => 'targetUserId',
]);

$response = $this->api->invalidateUserTokens('targetUserId');

$this->assertInstanceOf(DataResponse::class, $response);
$this->assertEquals([], $response->getData());
}

public function testRemoveFromGroupWithEmptyTargetGroup() {
$this->expectException(\OCP\AppFramework\OCS\OCSException::class);
Expand Down Expand Up @@ -3785,6 +3819,7 @@ public function testGetCurrentUserLoggedIn() {
$this->newUserMailHelper,
$this->secureRandom,
$this->remoteWipe,
$this->invalidator,
$this->knownUserService,
$this->eventDispatcher,
$this->phoneNumberUtil,
Expand Down Expand Up @@ -3873,6 +3908,7 @@ public function testGetUser() {
$this->newUserMailHelper,
$this->secureRandom,
$this->remoteWipe,
$this->invalidator,
$this->knownUserService,
$this->eventDispatcher,
$this->phoneNumberUtil,
Expand Down
24 changes: 24 additions & 0 deletions lib/private/Authentication/Events/AUserTokensInvalidationEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OC\Authentication\Events;

use OCP\EventDispatcher\Event;

abstract class AUserTokensInvalidationEvent extends Event {
public function __construct(
protected string $uid
) {
parent::__construct();
}

public function getUserId(): string {
return $this->uid;
}
}
12 changes: 12 additions & 0 deletions lib/private/Authentication/Events/TokensInvalidationFinished.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Authentication\Events;

class TokensInvalidationFinished extends AUserTokensInvalidationEvent {
}
12 changes: 12 additions & 0 deletions lib/private/Authentication/Events/TokensInvalidationStarted.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Authentication\Events;

class TokensInvalidationStarted extends AUserTokensInvalidationEvent {
}
Loading
Loading