feat: streamlined role-revocation logic
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Security;
|
||||
|
||||
use App\BusProNet\ApiClient;
|
||||
use App\BusProNet\Model\CrmAttributeGroup;
|
||||
use App\BusProNet\Model\CrmAttributesResponse;
|
||||
use App\BusProNet\Model\ProfileResponse;
|
||||
use App\BusProNet\UserDataHandler;
|
||||
use App\Entity\User;
|
||||
use App\RequiredTeamerCheck\RequiredTeamerCheckRegistry;
|
||||
use App\Security\BpnAuthenticator;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||
|
||||
class BpnAuthenticatorTest extends TestCase
|
||||
{
|
||||
private ApiClient&MockObject $apiClient;
|
||||
private UserDataHandler&MockObject $userDataHandler;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->apiClient = $this->createMock(ApiClient::class);
|
||||
$this->userDataHandler = $this->createMock(UserDataHandler::class);
|
||||
}
|
||||
|
||||
public function testUnknownUserWithoutClaimedRolesIsNeverCreated(): void
|
||||
{
|
||||
$this->stubApiClient($this->createCrmAttributes());
|
||||
|
||||
$this->userDataHandler->method('collectRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn(null);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('createLocalUser');
|
||||
$this->userDataHandler->expects($this->never())->method('disableForRevokedCrmRoles');
|
||||
|
||||
$this->expectException(UserNotFoundException::class);
|
||||
|
||||
$this->loadUser();
|
||||
}
|
||||
|
||||
public function testExistingUserWithoutClaimedRolesIsBlockedAndReturned(): void
|
||||
{
|
||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
||||
|
||||
$this->stubApiClient($this->createCrmAttributes());
|
||||
|
||||
$this->userDataHandler->method('collectRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn($user);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('updateLocalUser');
|
||||
$this->userDataHandler
|
||||
->expects($this->once())
|
||||
->method('disableForRevokedCrmRoles')
|
||||
->with($user)
|
||||
;
|
||||
|
||||
// returned rather than refused, so the UserChecker can explain the block
|
||||
$this->assertSame($user, $this->loadUser());
|
||||
}
|
||||
|
||||
public function testResponseWithoutAttributeGroupsRefusesTheLoginWithoutBlocking(): void
|
||||
{
|
||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
||||
|
||||
// an empty payload carries no roles either and must not read as a revocation
|
||||
$this->stubApiClient(new CrmAttributesResponse());
|
||||
|
||||
$this->userDataHandler->method('collectRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn($user);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('disableForRevokedCrmRoles');
|
||||
|
||||
$this->expectException(UserNotFoundException::class);
|
||||
|
||||
$this->loadUser();
|
||||
}
|
||||
|
||||
private function createCrmAttributes(): CrmAttributesResponse
|
||||
{
|
||||
return (new CrmAttributesResponse())->setAttributeGroups([new CrmAttributeGroup()]);
|
||||
}
|
||||
|
||||
private function stubApiClient(CrmAttributesResponse $crmAttributes): void
|
||||
{
|
||||
$this->apiClient->method('getProfile')->willReturn(new ProfileResponse());
|
||||
$this->apiClient->method('getCrmAttributes')->willReturn($crmAttributes);
|
||||
}
|
||||
|
||||
private function loadUser(): ?User
|
||||
{
|
||||
$authenticator = new BpnAuthenticator(
|
||||
$this->createMock(UrlGeneratorInterface::class),
|
||||
$this->createMock(EntityManagerInterface::class),
|
||||
$this->apiClient,
|
||||
$this->createMock(LoggerInterface::class),
|
||||
$this->userDataHandler,
|
||||
$this->createMock(RequiredTeamerCheckRegistry::class),
|
||||
);
|
||||
|
||||
$request = new Request(request: [
|
||||
'_username' => '[email protected]',
|
||||
'_password' => 'secret',
|
||||
'_csrf_token' => 'token',
|
||||
]);
|
||||
$request->setSession(new Session(new MockArraySessionStorage()));
|
||||
|
||||
$passport = $authenticator->authenticate($request);
|
||||
|
||||
/** @var UserBadge $badge */
|
||||
$badge = $passport->getBadge(UserBadge::class);
|
||||
|
||||
/* @var User $user */
|
||||
return $badge->getUser();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user