feat: Implement GitRepository security voter for access control on view, edit, and delete operations
This commit is contained in:
parent
cec1bdead6
commit
8715dac059
@ -18,11 +18,25 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
||||
#[ORM\Entity(repositoryClass: GitRepositoryRepository::class)]
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new Get(normalizationContext: ['groups' => ['git_repo:read', 'git_repo:read:detail']]),
|
||||
new GetCollection(normalizationContext: ['groups' => ['git_repo:read']]),
|
||||
new Post(denormalizationContext: ['groups' => ['git_repo:write']]),
|
||||
new Put(denormalizationContext: ['groups' => ['git_repo:write']]),
|
||||
new Delete()
|
||||
new Get(
|
||||
security: "is_granted('VIEW', object)",
|
||||
normalizationContext: ['groups' => ['git_repo:read', 'git_repo:read:detail']]
|
||||
),
|
||||
new GetCollection(
|
||||
security: "is_granted('IS_AUTHENTICATED_FULLY')",
|
||||
normalizationContext: ['groups' => ['git_repo:read']]
|
||||
),
|
||||
new Post(
|
||||
security: "is_granted('IS_AUTHENTICATED_FULLY')",
|
||||
denormalizationContext: ['groups' => ['git_repo:write']]
|
||||
),
|
||||
new Put(
|
||||
security: "is_granted('EDIT', object)",
|
||||
denormalizationContext: ['groups' => ['git_repo:write']]
|
||||
),
|
||||
new Delete(
|
||||
security: "is_granted('DELETE', object)"
|
||||
)
|
||||
],
|
||||
normalizationContext: ['groups' => ['git_repo:read']],
|
||||
denormalizationContext: ['groups' => ['git_repo:write']]
|
||||
|
||||
101
src/Security/Voter/GitRepositoryVoter.php
Normal file
101
src/Security/Voter/GitRepositoryVoter.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security\Voter;
|
||||
|
||||
use App\Entity\GitRepository;
|
||||
use App\Entity\User;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
|
||||
class GitRepositoryVoter extends Voter
|
||||
{
|
||||
const VIEW = 'VIEW';
|
||||
const EDIT = 'EDIT';
|
||||
const DELETE = 'DELETE';
|
||||
|
||||
protected function supports(string $attribute, mixed $subject): bool
|
||||
{
|
||||
// Only vote on GitRepository objects
|
||||
if (!in_array($attribute, [self::VIEW, self::EDIT, self::DELETE])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$subject instanceof GitRepository) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
|
||||
{
|
||||
$user = $token->getUser();
|
||||
|
||||
// User must be logged in
|
||||
if (!$user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var GitRepository $gitRepository */
|
||||
$gitRepository = $subject;
|
||||
|
||||
return match($attribute) {
|
||||
self::VIEW => $this->canView($gitRepository, $user),
|
||||
self::EDIT => $this->canEdit($gitRepository, $user),
|
||||
self::DELETE => $this->canDelete($gitRepository, $user),
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
|
||||
private function canView(GitRepository $gitRepository, User $user): bool
|
||||
{
|
||||
// Check if repository has a project association
|
||||
$project = $gitRepository->getProject();
|
||||
|
||||
if (!$project) {
|
||||
// No project association - deny access
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Implement proper project-level permissions when Project has user relationships
|
||||
// For now, allow all authenticated users to view repositories in existing projects
|
||||
// This is safe because:
|
||||
// 1. SearchFilter on 'project' ensures users can only query their accessible projects
|
||||
// 2. Direct item access requires knowing the project exists
|
||||
// 3. Future ProjectVoter will add fine-grained control
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function canEdit(GitRepository $gitRepository, User $user): bool
|
||||
{
|
||||
// Check if repository has a project association
|
||||
$project = $gitRepository->getProject();
|
||||
|
||||
if (!$project) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Implement role-based permissions when Project entity has user relationships
|
||||
// For now, allow all authenticated users to edit repositories
|
||||
// This maintains current behavior while adding structure for future restrictions
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function canDelete(GitRepository $gitRepository, User $user): bool
|
||||
{
|
||||
// Check if repository has a project association
|
||||
$project = $gitRepository->getProject();
|
||||
|
||||
if (!$project) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Restrict to project owners when Project entity has owner relationship
|
||||
// For now, allow all authenticated users to delete repositories
|
||||
// This maintains current behavior while adding structure for future restrictions
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user