Re-usable ACL checks on teams (#5925)

This commit is contained in:
Kevin Papst
2026-04-26 17:06:59 +02:00
committed by GitHub
parent 7a559a09e6
commit 20c7b03bd9
14 changed files with 1393 additions and 149 deletions

View File

@@ -17,6 +17,7 @@ use App\Voter\ProjectVoter;
use PHPUnit\Framework\Attributes\CoversClass;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\User\InMemoryUser;
#[CoversClass(ProjectVoter::class)]
class ProjectVoterTest extends AbstractVoterTestCase
@@ -137,4 +138,140 @@ class ProjectVoterTest extends AbstractVoterTestCase
$this->assertVote($user, $project, 'edit', VoterInterface::ACCESS_GRANTED);
}
public function testAccessGrantedWhenProjectAndCustomerHaveNoTeams(): void
{
$project = new Project();
$project->setCustomer(new Customer('foo'));
$this->assertVote(new User(), $project, 'access', VoterInterface::ACCESS_GRANTED);
}
public function testAccessGrantedWhenProjectHasNoCustomer(): void
{
// checkTeamAccessProject() skips the customer chain when project->getCustomer() is null.
$project = new Project();
$this->assertVote(new User(), $project, 'access', VoterInterface::ACCESS_GRANTED);
}
public function testAccessGrantedForCanSeeAllDataDespiteRestrictiveTeams(): void
{
$project = new Project();
$customer = new Customer('foo');
$customer->addTeam(new Team('customerTeam'));
$project->setCustomer($customer);
$project->addTeam(new Team('projectTeam'));
$user = new User();
$user->initCanSeeAllData(true);
$this->assertVote($user, $project, 'access', VoterInterface::ACCESS_GRANTED);
}
public function testAccessGrantedWhenUserMemberOfCustomerTeamAndNoProjectTeams(): void
{
$customerTeam = new Team('customerTeam');
$customer = new Customer('foo');
$customer->addTeam($customerTeam);
$project = new Project();
$project->setCustomer($customer);
$user = new User();
$customerTeam->addUser($user);
$this->assertVote($user, $project, 'access', VoterInterface::ACCESS_GRANTED);
}
public function testAccessGrantedWhenUserMemberOfProjectTeamAndNoCustomerTeams(): void
{
$project = new Project();
$project->setCustomer(new Customer('foo'));
$projectTeam = new Team('projectTeam');
$project->addTeam($projectTeam);
$user = new User();
$projectTeam->addUser($user);
$this->assertVote($user, $project, 'access', VoterInterface::ACCESS_GRANTED);
}
public function testAccessGrantedWhenUserMemberOfBothCustomerAndProjectTeams(): void
{
$customerTeam = new Team('customerTeam');
$customer = new Customer('foo');
$customer->addTeam($customerTeam);
$project = new Project();
$project->setCustomer($customer);
$projectTeam = new Team('projectTeam');
$project->addTeam($projectTeam);
$user = new User();
$customerTeam->addUser($user);
$projectTeam->addUser($user);
$this->assertVote($user, $project, 'access', VoterInterface::ACCESS_GRANTED);
}
public function testAccessDeniedWhenCustomerTeamBlocks(): void
{
$customer = new Customer('foo');
$customer->addTeam(new Team('customerTeam'));
$project = new Project();
$project->setCustomer($customer);
// project has no teams of its own — would otherwise be permissive
$this->assertVote(new User(), $project, 'access', VoterInterface::ACCESS_DENIED);
}
public function testAccessDeniedWhenCustomerOkButProjectTeamBlocks(): void
{
$customerTeam = new Team('customerTeam');
$customer = new Customer('foo');
$customer->addTeam($customerTeam);
$project = new Project();
$project->setCustomer($customer);
$project->addTeam(new Team('projectTeam'));
$user = new User();
$customerTeam->addUser($user);
$this->assertVote($user, $project, 'access', VoterInterface::ACCESS_DENIED);
}
public function testAccessDeniedWhenProjectTeamBlocksAndCustomerHasNoTeams(): void
{
$project = new Project();
$project->setCustomer(new Customer('foo'));
$project->addTeam(new Team('projectTeam'));
$this->assertVote(new User(), $project, 'access', VoterInterface::ACCESS_DENIED);
}
public function testAccessDeniedForUserInUnrelatedTeam(): void
{
$unrelated = new Team('unrelated');
$user = new User();
$unrelated->addTeamlead($user);
$customer = new Customer('foo');
$customer->addTeam(new Team('customerTeam'));
$project = new Project();
$project->setCustomer($customer);
$this->assertVote($user, $project, 'access', VoterInterface::ACCESS_DENIED);
}
public function testAccessDeniedForNonUserToken(): void
{
$project = new Project();
$token = new UsernamePasswordToken(new InMemoryUser('anon', null), 'bar', []);
$sut = $this->getVoter(ProjectVoter::class);
self::assertEquals(VoterInterface::ACCESS_DENIED, $sut->vote($token, $project, ['access']));
}
}