mirror of
https://github.com/verdigado/organization_folders.git
synced 2024-11-25 14:10:26 +01:00
135 lines
5.6 KiB
PHP
135 lines
5.6 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace OCA\OrganizationFolders\Security;
|
||
|
|
||
|
use OCP\IUser;
|
||
|
use OCP\IGroupManager;
|
||
|
|
||
|
use OCA\OrganizationFolders\Model\Principal;
|
||
|
use OCA\OrganizationFolders\Model\OrganizationFolder;
|
||
|
use OCA\OrganizationFolders\Service\OrganizationFolderMemberService;
|
||
|
use OCA\OrganizationFolders\Enum\OrganizationFolderMemberPermissionLevel;
|
||
|
use OCA\OrganizationFolders\Enum\PrincipalType;
|
||
|
use OCA\OrganizationFolders\OrganizationProvider\OrganizationProviderManager;
|
||
|
|
||
|
class OrganizationFolderVoter extends Voter {
|
||
|
public function __construct(
|
||
|
private OrganizationFolderMemberService $organizationFolderMemberService,
|
||
|
private IGroupManager $groupManager,
|
||
|
private OrganizationProviderManager $organizationProviderManager,
|
||
|
) {
|
||
|
}
|
||
|
protected function supports(string $attribute, mixed $subject): bool {
|
||
|
return $subject instanceof OrganizationFolder || $subject === OrganizationFolder::class;
|
||
|
}
|
||
|
|
||
|
|
||
|
protected function voteOnAttribute(string $attribute, mixed $subject, ?IUser $user): bool {
|
||
|
if (!$user) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/** @var OrganizationFolder */
|
||
|
$organizationFolder = $subject;
|
||
|
return match ($attribute) {
|
||
|
// Admin permissions required
|
||
|
'READ' => $this->isOrganizationFolderAdmin($user, $organizationFolder),
|
||
|
'UPDATE' => $this->isOrganizationFolderAdmin($user, $organizationFolder),
|
||
|
'DELETE' => $this->isOrganizationFolderAdmin($user, $organizationFolder),
|
||
|
'UPDATE_MEMBERS' => $this->isOrganizationFolderAdmin($user, $organizationFolder),
|
||
|
'MANAGE_ALL_RESOURCES' => $this->isOrganizationFolderAdmin($user, $organizationFolder),
|
||
|
|
||
|
// At least Manager permissions required
|
||
|
'READ_LIMITED' => $this->isOrganizationFolderAdminOrManager($user, $organizationFolder),
|
||
|
'CREATE_RESOURCE' => $this->isOrganizationFolderAdminOrManager($user, $organizationFolder),
|
||
|
'MANAGE_TOP_LEVEL_RESOURCES' => $this->isOrganizationFolderAdminOrManager($user, $organizationFolder),
|
||
|
|
||
|
default => throw new \LogicException('This code should not be reached!')
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param IUser $user
|
||
|
* @param OrganizationFolder $organizationFolder
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function isOrganizationFolderMember(IUser $user, OrganizationFolder $organizationFolder): bool {
|
||
|
$organizationFolderMembers = $this->organizationFolderMemberService->findAll($organizationFolder->getId());
|
||
|
|
||
|
foreach($organizationFolderMembers as $organizationFolderMember) {
|
||
|
if($this->userIsPrincipal($user, $organizationFolderMember->getPrincipal())) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param IUser $user
|
||
|
* @param OrganizationFolder $organizationFolder
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function isOrganizationFolderAdmin(IUser $user, OrganizationFolder $organizationFolder): bool {
|
||
|
$organizationFolderMembers = $this->organizationFolderMemberService->findAll($organizationFolder->getId(), [
|
||
|
"permissionLevel" => OrganizationFolderMemberPermissionLevel::ADMIN,
|
||
|
]);
|
||
|
|
||
|
foreach($organizationFolderMembers as $organizationFolderMember) {
|
||
|
// should be true for all returned members because of the filter, double check because of the big security implications
|
||
|
if($organizationFolderMember->getPermissionLevel() === OrganizationFolderMemberPermissionLevel::ADMIN->value) {
|
||
|
if($this->userIsPrincipal($user, $organizationFolderMember->getPrincipal())) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param IUser $user
|
||
|
* @param OrganizationFolder $organizationFolder
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function isOrganizationFolderAdminOrManager(IUser $user, OrganizationFolder $organizationFolder): bool {
|
||
|
$organizationFolderMembers = $this->organizationFolderMemberService->findAll($organizationFolder->getId());
|
||
|
|
||
|
foreach($organizationFolderMembers as $organizationFolderMember) {
|
||
|
$permissionLevel = $organizationFolderMember->getPermissionLevel();
|
||
|
if($permissionLevel === OrganizationFolderMemberPermissionLevel::ADMIN->value || $permissionLevel === OrganizationFolderMemberPermissionLevel::MANAGER->value) {
|
||
|
if($this->userIsPrincipal($user, $organizationFolderMember->getPrincipal())) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private function userIsInGroup(IUser $user, string $groupId): bool {
|
||
|
return $this->groupManager->isInGroup($user->getUID(), $groupId);
|
||
|
}
|
||
|
|
||
|
private function userHasRole(IUser $user, string $organizationProviderId, string $roleId): bool {
|
||
|
$organizationProvider = $this->organizationProviderManager->getOrganizationProvider($organizationProviderId);
|
||
|
$role = $organizationProvider->getRole($roleId);
|
||
|
|
||
|
return $this->userIsInGroup($user, $role->getMembersGroup());
|
||
|
}
|
||
|
|
||
|
private function userIsPrincipal(IUser $user, Principal $principal): bool {
|
||
|
if($principal->getType() === PrincipalType::GROUP) {
|
||
|
return $this->userIsInGroup($user, $principal->getId());
|
||
|
} else if($principal->getType() === PrincipalType::ROLE) {
|
||
|
[$organizationProviderId, $roleId] = explode(":", $principal->getId(), 2);
|
||
|
|
||
|
return $this->userHasRole($user, $organizationProviderId, $roleId);
|
||
|
} else {
|
||
|
// user principals are not supported by Organization Folder Members and
|
||
|
// a principal object with that type should have never been put into this function
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|