Skip to content

Commit

Permalink
Merge pull request #3605 from nextcloud/backport/3590/stable29
Browse files Browse the repository at this point in the history
[stable29] include circles to acl
  • Loading branch information
icewind1991 authored Feb 12, 2025
2 parents fcff76a + 200399e commit 1d897a9
Show file tree
Hide file tree
Showing 16 changed files with 930 additions and 88 deletions.
1 change: 1 addition & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
->getFinder()
->ignoreVCSIgnored(true)
->notPath('build')
->notPath('tests/stubs')
->notPath('l10n')
->notPath('src')
->notPath('vendor')
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"php-parallel-lint/php-parallel-lint": "^1.2"
},
"scripts": {
"lint": "find . -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l",
"lint": "find . -name \\*.php -not -path './vendor/*' -not -path './vendor-bin/*' -not -path './tests/stubs/*' -print0 | xargs -0 -n1 php -l",
"cs:check": "php-cs-fixer fix --dry-run --diff",
"cs:fix": "php-cs-fixer fix",
"psalm": "psalm.phar --threads=1",
Expand Down
4 changes: 3 additions & 1 deletion lib/ACL/UserMapping/IUserMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
namespace OCA\GroupFolders\ACL\UserMapping;

interface IUserMapping {
/** @return 'user'|'group' */
/** @return 'user'|'group'|'dummy'|'circle' */
public function getType(): string;

public function getId(): string;

public function getDisplayName(): string;

public function getKey(): string;
}
9 changes: 9 additions & 0 deletions lib/ACL/UserMapping/IUserMappingManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,13 @@ public function getMappingsForUser(IUser $user, bool $userAssignable = true): ar
* @return IUserMapping|null
*/
public function mappingFromId(string $type, string $id): ?IUserMapping;

/**
* Check if a user is a member of one of the provided user mappings
*
* @param IUser $user
* @param IUserMapping[] $mappings
* @return bool
*/
public function userInMappings(IUser $user, array $mappings): bool;
}
20 changes: 13 additions & 7 deletions lib/ACL/UserMapping/UserMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@
namespace OCA\GroupFolders\ACL\UserMapping;

class UserMapping implements IUserMapping {
/** @var 'user'|'group' * */
private string $type;
private string $id;
private string $displayName;

public function __construct(string $type, string $id, ?string $displayName = null) {
$this->type = $type;
$this->id = $id;
/**
* @param 'user'|'group'|'dummy'|'circle' $type
*/
public function __construct(
private string $type,
private string $id,
?string $displayName = null,
) {
$this->displayName = $displayName ?? $id;
}

/** @return 'user'|'group' */
/** @return 'user'|'group'|'dummy'|'circle' */
public function getType(): string {
return $this->type;
}
Expand All @@ -47,4 +49,8 @@ public function getId(): string {
public function getDisplayName(): string {
return $this->displayName;
}

public function getKey(): string {
return $this->getType() . ':' . $this->getId();
}
}
117 changes: 105 additions & 12 deletions lib/ACL/UserMapping/UserMappingManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,37 +23,130 @@

namespace OCA\GroupFolders\ACL\UserMapping;

use OCA\Circles\CirclesManager;
use OCA\Circles\Exceptions\CircleNotFoundException;
use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Probes\CircleProbe;
use OCP\AutoloadNotAllowedException;
use OCP\IGroup;
use OCP\IGroupManager;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;

class UserMappingManager implements IUserMappingManager {
private $groupManager;
private $userManager;

public function __construct(IGroupManager $groupManager, IUserManager $userManager) {
$this->groupManager = $groupManager;
$this->userManager = $userManager;
public function __construct(
private IGroupManager $groupManager,
private IUserManager $userManager,
private LoggerInterface $logger,
) {
}

public function getMappingsForUser(IUser $user, bool $userAssignable = true): array {
$groupMappings = array_values(array_map(function (IGroup $group) {
return new UserMapping('group', $group->getGID(), $group->getDisplayName());
}, $this->groupManager->getUserGroups($user)));
$circleMappings = array_values(array_map(fn (Circle $circle): UserMapping => new UserMapping('circle', $circle->getSingleId(), $circle->getDisplayName()), $this->getUserCircles($user->getUID())));

return array_merge([
new UserMapping('user', $user->getUID(), $user->getDisplayName()),
], $groupMappings);
], $groupMappings, $circleMappings);
}

public function mappingFromId(string $type, string $id): ?IUserMapping {
$mappingObject = ($type === 'group' ? $this->groupManager : $this->userManager)->get($id);
if ($mappingObject) {
$displayName = $mappingObject->getDisplayName();
return new UserMapping($type, $id, $displayName);
} else {
switch ($type) {
case 'group':
$displayName = $this->groupManager->get($id)?->getDisplayName();
break;
case 'user':
$displayName = $this->userManager->get($id)?->getDisplayName();
break;
case 'circle':
$displayName = $this->getCircle($id)?->getDisplayName();
break;
default:
return null;
}
if ($displayName === null) {
return null;
}

return new UserMapping($type, $id, $displayName);
}



/**
* returns the Circle from its single Id, or NULL if not available
*/
private function getCircle(string $groupId): ?Circle {
$circlesManager = $this->getCirclesManager();
if ($circlesManager === null) {
return null;
}

$circlesManager->startSuperSession();
$probe = new CircleProbe();
$probe->includeSystemCircles();
$probe->includeSingleCircles();
try {
return $circlesManager->getCircle($groupId, $probe);
} catch (CircleNotFoundException) {
} catch (\Exception $e) {
$this->logger->warning('', ['exception' => $e]);
} finally {
$circlesManager->stopSession();
}

return null;
}

/**
* returns list of circles a user is member of
*/
private function getUserCircles(string $userId): array {
$circlesManager = $this->getCirclesManager();
if ($circlesManager === null) {
return [];
}

$circlesManager->startSession($circlesManager->getLocalFederatedUser($userId));
try {
return $circlesManager->probeCircles();
} catch (\Exception $e) {
$this->logger->warning('', ['exception' => $e]);
} finally {
$circlesManager->stopSession();
}

return [];
}

public function getCirclesManager(): ?CirclesManager {
try {
return Server::get(CirclesManager::class);
} catch (ContainerExceptionInterface|AutoloadNotAllowedException) {
return null;
}
}

public function userInMappings(IUser $user, array $mappings): bool {
foreach ($mappings as $mapping) {
if ($mapping->getType() === 'user' && $mapping->getId() === $user->getUID()) {
return true;
}
}

$mappingKeys = array_map(fn (IUserMapping $mapping) => $mapping->getKey(), $mappings);

$userMappings = $this->getMappingsForUser($user);
foreach ($userMappings as $userMapping) {
if (in_array($userMapping->getKey(), $mappingKeys, true)) {
return true;
}
}
return false;
}
}
2 changes: 1 addition & 1 deletion lib/Command/ListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ protected function execute(InputInterface $input, OutputInterface $output) {
$folder['groups'] = implode("\n", $groupStrings);
$folder['acl'] = $folder['acl'] ? 'Enabled' : 'Disabled';
$manageStrings = array_map(function ($manage) {
return $manage['id'] . ' (' . $manage['type'] . ')';
return $manage['displayname'] . ' (' . $manage['type'] . ')';
}, $folder['manage']);
$folder['manage'] = implode("\n", $manageStrings);
return $folder;
Expand Down
5 changes: 3 additions & 2 deletions lib/Controller/FolderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,17 @@ private function folderDataForXML(array $data): array {
* @NoAdminRequired
*/
public function aclMappingSearch(int $id, ?int $fileId, string $search = ''): DataResponse {
$users = [];
$groups = [];
$users = $groups = $circles = [];

if ($this->manager->canManageACL($id, $this->user) === true) {
$groups = $this->manager->searchGroups($id, $search);
$users = $this->manager->searchUsers($id, $search);
$circles = $this->manager->searchCircles($id, $search);
}
return new DataResponse([
'users' => $users,
'groups' => $groups,
'circles' => $circles
]);
}
}
Loading

0 comments on commit 1d897a9

Please sign in to comment.