2024-11-06 22:11:16 +01:00
< ? php
namespace OCA\OrganizationFolders\Security ;
use OCP\IUser ;
use OCP\IGroupManager ;
use OCA\OrganizationFolders\Db\Resource ;
2024-11-18 18:04:40 +01:00
use OCA\OrganizationFolders\Model\OrganizationFolder ;
use OCA\OrganizationFolders\Service\OrganizationFolderService ;
2024-11-16 03:23:19 +01:00
use OCA\OrganizationFolders\Service\OrganizationFolderMemberService ;
2024-11-06 22:11:16 +01:00
use OCA\OrganizationFolders\Service\ResourceService ;
use OCA\OrganizationFolders\Service\ResourceMemberService ;
2024-11-16 03:06:21 +01:00
use OCA\OrganizationFolders\Enum\ResourceMemberPermissionLevel ;
2024-11-12 15:36:07 +01:00
use OCA\OrganizationFolders\Enum\PrincipalType ;
2024-11-06 22:11:16 +01:00
use OCA\OrganizationFolders\OrganizationProvider\OrganizationProviderManager ;
2024-11-18 18:04:40 +01:00
use OCA\OrganizationFolders\Security\OrganizationFolderVoter ;
2024-11-06 22:11:16 +01:00
class ResourceVoter extends Voter {
public function __construct (
2024-11-18 18:04:40 +01:00
private OrganizationFolderService $organizationFolderService ,
2024-11-16 03:23:19 +01:00
private OrganizationFolderMemberService $organizationFolderMemberService ,
2024-11-06 22:11:16 +01:00
private ResourceService $resourceService ,
private ResourceMemberService $resourceMemberService ,
private IGroupManager $groupManager ,
private OrganizationProviderManager $organizationProviderManager ,
2024-11-18 18:04:40 +01:00
private OrganizationFolderVoter $organizationFolderVoter ,
2024-11-06 22:11:16 +01:00
) {
}
protected function supports ( string $attribute , mixed $subject ) : bool {
return $subject instanceof Resource || $subject === Resource :: class ;
}
protected function voteOnAttribute ( string $attribute , mixed $subject , ? IUser $user ) : bool {
if ( ! $user ) {
return false ;
}
/** @var Resource */
$resource = $subject ;
return match ( $attribute ) {
2024-11-25 15:28:40 +01:00
'READ' => $this -> isGranted ( $user , $resource ),
// can read limited information about the resource (true: limited read is allowed, full read may be allowed, false: limited read is not allowed, full read may be allowed (!))
'READ_LIMITED' => $this -> isGrantedLimitedRead ( $user , $resource ),
2024-11-06 22:11:16 +01:00
'UPDATE' => $this -> isGranted ( $user , $resource ),
'DELETE' => $this -> isGranted ( $user , $resource ),
2024-11-12 15:36:07 +01:00
'UPDATE_MEMBERS' => $this -> isGranted ( $user , $resource ),
2024-11-16 03:06:21 +01:00
'CREATE_SUBRESOURCE' => $this -> isGranted ( $user , $resource ),
2024-11-06 22:11:16 +01:00
default => throw new \LogicException ( 'This code should not be reached!' )
};
}
2024-11-18 18:04:40 +01:00
private function allowedToManageAllResourcesInOrganizationFolder ( IUser $user , OrganizationFolder $resourceOrganizationFolder ) : bool {
return $this -> organizationFolderVoter -> vote ( $user , $resourceOrganizationFolder , [ " MANAGE_ALL_RESOURCES " ]) === self :: ACCESS_GRANTED ;
2024-11-06 22:11:16 +01:00
}
/**
* @ param IUser $user
* @ param Resource $resource
* @ return bool
*/
2024-11-18 18:04:40 +01:00
private function isResourceManager ( IUser $user , Resource $resource , OrganizationFolder $resourceOrganizationFolder ) : bool {
2024-11-06 22:11:16 +01:00
$resourceMembers = $this -> resourceMemberService -> findAll ( $resource -> getId ());
foreach ( $resourceMembers as $resourceMember ) {
2024-11-16 03:06:21 +01:00
if ( $resourceMember -> getPermissionLevel () === ResourceMemberPermissionLevel :: MANAGER -> value ) {
2024-11-12 15:36:07 +01:00
$principal = $resourceMember -> getPrincipal ();
if ( $principal -> getType () === PrincipalType :: USER ) {
if ( $principal -> getId () === $user -> getUID ()) {
2024-11-06 22:11:16 +01:00
return true ;
}
2024-11-12 15:36:07 +01:00
} else if ( $principal -> getType () === PrincipalType :: GROUP ) {
2024-11-16 03:06:21 +01:00
if ( $this -> userIsInGroup ( $user , $principal -> getId ())) {
2024-11-06 22:11:16 +01:00
return true ;
}
2024-11-12 15:36:07 +01:00
} else if ( $principal -> getType () === PrincipalType :: ROLE ) {
[ $organizationProviderId , $roleId ] = explode ( " : " , $principal -> getId (), 2 );
2024-11-06 22:11:16 +01:00
2024-11-16 03:06:21 +01:00
if ( $this -> userHasRole ( $user , $organizationProviderId , $roleId )) {
2024-11-06 22:11:16 +01:00
return true ;
}
}
}
}
2024-11-18 18:04:40 +01:00
// inherit manager permissions from level above
2024-11-06 22:11:16 +01:00
if ( $resource -> getInheritManagers ()) {
2024-11-18 18:04:40 +01:00
if ( ! is_null ( $resource -> getParentResource ())) {
// not top-level resource -> allowed to manage resource if allowed to manage parent resource
$parentResource = $this -> resourceService -> getParentResource ( $resource );
2024-11-06 22:11:16 +01:00
2024-11-18 18:04:40 +01:00
if ( ! is_null ( $parentResource )) {
return $this -> isResourceManager ( $user , $parentResource , $resourceOrganizationFolder );
}
} else {
// top-level resource -> allowed to manage resource if manager of organization folder
return $this -> organizationFolderVoter -> vote ( $user , $resourceOrganizationFolder , [ " MANAGE_TOP_LEVEL_RESOURCES " ]) === self :: ACCESS_GRANTED ;
2024-11-06 22:11:16 +01:00
}
}
return false ;
}
protected function isGranted ( IUser $user , Resource $resource ) : bool {
2024-11-18 18:04:40 +01:00
$resourceOrganizationFolder = $this -> organizationFolderService -> find ( $resource -> getOrganizationFolderId ());
return $this -> allowedToManageAllResourcesInOrganizationFolder ( $user , $resourceOrganizationFolder )
|| $this -> isResourceManager ( $user , $resource , $resourceOrganizationFolder );
2024-11-06 22:11:16 +01:00
}
2024-11-16 03:06:21 +01:00
2024-11-25 15:28:40 +01:00
protected function isGrantedLimitedRead ( IUser $user , Resource $resource ) : bool {
$subResources = $this -> resourceService -> getAllSubResources ( $resource );
foreach ( $subResources as $subResource ) {
if ( $this -> isManagerOfAnySubresource ( $user , $subResource )) {
return true ;
}
}
return false ;
}
protected function isManagerOfAnySubresource ( IUser $user , Resource $resource ) {
if ( $this -> isGranted ( $user , $resource )) {
return true ;
}
$subResources = $this -> resourceService -> getAllSubResources ( $resource );
foreach ( $subResources as $subResource ) {
if ( $this -> isManagerOfAnySubresource ( $user , $subResource )) {
return true ;
}
}
return false ;
}
2024-11-16 03:06:21 +01:00
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 ());
2024-11-16 03:23:19 +01:00
}
2024-11-06 22:11:16 +01:00
}