feat: bpn as single source of truth for role and hotel code assignments
This commit is contained in:
@@ -72,9 +72,9 @@ class UserDataHandlerTest extends TestCase
|
||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'manager takes precedence over house manager' => [
|
||||
yield 'manager and house manager yield both markers, the roles stand on their own' => [
|
||||
(new CrmAttributesResponse())->setManager(true)->setHouseManager(true),
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'house manager and teamer' => [
|
||||
@@ -105,10 +105,10 @@ class UserDataHandlerTest extends TestCase
|
||||
[User::PENDING_ROLES['ROLE_ADMIN']],
|
||||
];
|
||||
|
||||
yield 'manager takes precedence over house manager' => [
|
||||
yield 'manager and house manager are marked independently' => [
|
||||
['ROLE_HOUSE_MANAGER', 'ROLE_MANAGER'],
|
||||
(new CrmAttributesResponse())->setManager(true)->setHouseManager(true),
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'house manager' => [
|
||||
@@ -172,14 +172,16 @@ class UserDataHandlerTest extends TestCase
|
||||
$profileResponse,
|
||||
true,
|
||||
['team' => ['selected' => true]],
|
||||
['ROLE_ADMIN', 'ROLE_TEAMER'],
|
||||
['DKS'],
|
||||
);
|
||||
|
||||
$this->assertSame('New', $user->getFirstName());
|
||||
$this->assertSame('Lastname', $user->getLastName());
|
||||
$this->assertSame('[email protected]', $user->getEmail());
|
||||
|
||||
// roles and hotel codes are imported on creation only and stay under manual control
|
||||
$this->assertSame(['XYZ'], $user->getHotelCodes());
|
||||
// the CRM leads: the still claimed role survives, the houses are replaced by its own
|
||||
$this->assertSame(['DKS'], $user->getHotelCodes());
|
||||
$this->assertTrue($user->hasRole('ROLE_ADMIN'));
|
||||
|
||||
$this->assertSame('New', $teamer->getFirstName());
|
||||
@@ -225,44 +227,51 @@ class UserDataHandlerTest extends TestCase
|
||||
{
|
||||
yield 'marker is added when the CRM claims a manager' => [
|
||||
['ROLE_TEAMER'],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_MANAGER', 'ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'marker is dropped when the CRM attribute is gone' => [
|
||||
[User::PENDING_ROLES['ROLE_HOUSE_MANAGER'], 'ROLE_TEAMER'],
|
||||
[],
|
||||
['ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
[],
|
||||
];
|
||||
|
||||
yield 'an approved role is never marked again' => [
|
||||
['ROLE_MANAGER'],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_MANAGER'],
|
||||
['ROLE_MANAGER'],
|
||||
[],
|
||||
];
|
||||
|
||||
yield 'a claim beyond the approved role stays pending' => [
|
||||
['ROLE_MANAGER'],
|
||||
[User::PENDING_ROLES['ROLE_ADMIN'], User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_ADMIN', 'ROLE_MANAGER'],
|
||||
['ROLE_MANAGER'],
|
||||
[User::PENDING_ROLES['ROLE_ADMIN']],
|
||||
];
|
||||
|
||||
yield 'the claimed role changes' => [
|
||||
[User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
['ROLE_MANAGER'],
|
||||
[],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER']],
|
||||
];
|
||||
|
||||
yield 'granted roles are untouched without any claim' => [
|
||||
['ROLE_ADMIN'],
|
||||
yield 'a granted role is revoked once the CRM stops claiming it' => [
|
||||
['ROLE_ADMIN', 'ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
['ROLE_TEAMER'],
|
||||
[],
|
||||
['ROLE_ADMIN'],
|
||||
];
|
||||
|
||||
yield 'a manager who is also a house manager is marked for both' => [
|
||||
[],
|
||||
['ROLE_MANAGER', 'ROLE_HOUSE_MANAGER'],
|
||||
[],
|
||||
[User::PENDING_ROLES['ROLE_MANAGER'], User::PENDING_ROLES['ROLE_HOUSE_MANAGER']],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -277,15 +286,18 @@ class UserDataHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], [User::PENDING_ROLES['ROLE_ADMIN']]);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_ADMIN', 'ROLE_TEAMER']);
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertSame([User::PENDING_ROLES['ROLE_ADMIN']], $user->getPendingRoles());
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserKeepsTheTeamerRoleOfSomebodyTheCrmNoLongerReportsAsTeamer(): void
|
||||
/**
|
||||
* ROLE_TEAMER needs no approval, but it is not exempt from the sync either: the CRM
|
||||
* leads, so the role goes when the attribute does.
|
||||
*/
|
||||
public function testUpdateLocalUserWithdrawsTheTeamerRoleOfSomebodyTheCrmNoLongerReportsAsTeamer(): void
|
||||
{
|
||||
// the role may have been granted manually and must survive a login
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
@@ -294,9 +306,9 @@ class UserDataHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], []);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_ADMIN']);
|
||||
|
||||
$this->assertSame(['ROLE_ADMIN', 'ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserGrantsTheTeamerRoleOnlyOnce(): void
|
||||
@@ -309,11 +321,131 @@ class UserDataHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], []);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_TEAMER']);
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* ROLE_SUPER_ADMIN is not a stored role but a flag getRoles() turns into one, so
|
||||
* revoking ROLE_ADMIN has to take it down explicitly - otherwise the highest privilege
|
||||
* in the application would outlive the role it depends on.
|
||||
*/
|
||||
public function testUpdateLocalUserTakesTheSuperAdminFlagDownWithRoleAdmin(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
||||
->setSuperAdmin(true)
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), true, [], ['ROLE_TEAMER']);
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertFalse($user->isSuperAdmin());
|
||||
$this->assertFalse($user->hasRole('ROLE_SUPER_ADMIN'));
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserKeepsTheSuperAdminFlagOfAStillClaimedAdmin(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
||||
->setSuperAdmin(true)
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_ADMIN']);
|
||||
|
||||
$this->assertTrue($user->isSuperAdmin());
|
||||
$this->assertTrue($user->hasRole('ROLE_SUPER_ADMIN'));
|
||||
}
|
||||
|
||||
public function testUpdateLocalUserReplacesTheHotelCodesWithTheOnesTheCrmReports(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles(['ROLE_HOUSE_MANAGER'])
|
||||
->setHotelCodes(['SSL'])
|
||||
;
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
$handler->updateLocalUser($user, $this->createProfileResponse(), false, [], ['ROLE_HOUSE_MANAGER'], ['DKS']);
|
||||
|
||||
$this->assertSame(['DKS'], $user->getHotelCodes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Approval is the one place a role is granted at all, and it can only ever grant a role
|
||||
* the CRM already claims - the marker is what says so.
|
||||
*/
|
||||
public function testApproveRoleGrantsTheRoleAndClearsItsMarker(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles([
|
||||
'ROLE_TEAMER',
|
||||
User::PENDING_ROLES['ROLE_ADMIN'],
|
||||
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
||||
])
|
||||
;
|
||||
|
||||
$this->entityManager->expects($this->once())->method('flush');
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
|
||||
$this->assertTrue($handler->approveRole($user, 'ROLE_ADMIN'));
|
||||
$this->assertSame(['ROLE_TEAMER', 'ROLE_ADMIN'], $user->getAssignedRoles());
|
||||
|
||||
// the other nomination is untouched: one decision at a time
|
||||
$this->assertSame([User::PENDING_ROLES['ROLE_HOUSE_MANAGER']], $user->getPendingRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider unapprovableRoleProvider
|
||||
*/
|
||||
public function testApproveRoleRefusesARoleWithoutANomination(array $roles, string $role): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setFirstName('First')
|
||||
->setLastName('Last')
|
||||
->setEmail('[email protected]')
|
||||
->setRoles($roles)
|
||||
;
|
||||
|
||||
$this->entityManager->expects($this->never())->method('flush');
|
||||
|
||||
$handler = new UserDataHandler($this->entityManager, $this->logger);
|
||||
|
||||
$this->assertFalse($handler->approveRole($user, $role));
|
||||
$this->assertEqualsCanonicalizing(
|
||||
$roles,
|
||||
[...$user->getAssignedRoles(), ...$user->getPendingRoles()],
|
||||
);
|
||||
}
|
||||
|
||||
public static function unapprovableRoleProvider(): iterable
|
||||
{
|
||||
yield 'the CRM never claimed it' => [['ROLE_TEAMER'], 'ROLE_MANAGER'];
|
||||
|
||||
yield 'a different role is nominated' => [[User::PENDING_ROLES['ROLE_MANAGER']], 'ROLE_ADMIN'];
|
||||
|
||||
yield 'already granted, so there is no marker left' => [['ROLE_ADMIN'], 'ROLE_ADMIN'];
|
||||
|
||||
yield 'teamer has no nomination to approve' => [['ROLE_TEAMER'], 'ROLE_TEAMER'];
|
||||
|
||||
yield 'not a role at all' => [[User::PENDING_ROLES['ROLE_ADMIN']], 'ROLE_SUPER_ADMIN'];
|
||||
}
|
||||
|
||||
public function testDisableForRevokedCrmRolesBlocksTheUserAndDropsThePendingMarkers(): void
|
||||
{
|
||||
$user = (new User())
|
||||
|
||||
@@ -165,4 +165,25 @@ class UserTest extends TestCase
|
||||
->validate($user)
|
||||
;
|
||||
}
|
||||
|
||||
public function testNominatedRolesAreKeyedByTheRoleAndNotByItsMarker(): void
|
||||
{
|
||||
$user = (new User())->setRoles([
|
||||
'ROLE_TEAMER',
|
||||
User::PENDING_ROLES['ROLE_ADMIN'],
|
||||
User::PENDING_ROLES['ROLE_HOUSE_MANAGER'],
|
||||
]);
|
||||
|
||||
$this->assertSame(
|
||||
['ROLE_ADMIN' => 'Admin', 'ROLE_HOUSE_MANAGER' => 'Hausleitung'],
|
||||
$user->getNominatedRoles(),
|
||||
);
|
||||
}
|
||||
|
||||
public function testAGrantedRoleIsNotNominated(): void
|
||||
{
|
||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
||||
|
||||
$this->assertSame([], $user->getNominatedRoles());
|
||||
}
|
||||
}
|
||||
|
||||
+59
-53
@@ -11,88 +11,98 @@ use Symfony\Component\Form\FormFactoryInterface;
|
||||
|
||||
class UserTypeTest extends KernelTestCase
|
||||
{
|
||||
public function testRendersRolesWithoutSynthesizedRoles(): void
|
||||
/**
|
||||
* The form is the account settings and nothing else. Roles and hotel codes are synced
|
||||
* from BusPro and editable nowhere, so they are not fields at all - a disabled field
|
||||
* that cannot be submitted only reads as broken.
|
||||
*/
|
||||
public function testRolesAndHotelCodesAreNotFields(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setRoles(['ROLE_ADMIN'])
|
||||
->setHotelCodes(['DKS'])
|
||||
;
|
||||
|
||||
$form = $this->createForm($user);
|
||||
|
||||
$this->assertFalse($form->has('roles'));
|
||||
$this->assertFalse($form->has('hotelCodes'));
|
||||
$this->assertFalse($form->has('approvedRoles'));
|
||||
}
|
||||
|
||||
public function testNeitherRolesNorHotelCodesCanBeSubmitted(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setRoles(['ROLE_TEAMER'])
|
||||
->setHotelCodes(['SSL'])
|
||||
;
|
||||
|
||||
$form = $this->createForm($user);
|
||||
$form->submit([
|
||||
'roles' => ['ROLE_ADMIN'],
|
||||
'hotelCodes' => ['DKS'],
|
||||
'disabled' => null,
|
||||
]);
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertSame(['SSL'], $user->getHotelCodes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Super admin is an elevation of ROLE_ADMIN, so it is not on offer for anybody else -
|
||||
* offering it would only ever produce the violation from User::validateSuperAdmin().
|
||||
*/
|
||||
public function testSuperAdminIsOnlyOfferedToAnAdmin(): void
|
||||
{
|
||||
$this->assertTrue($this->createForm((new User())->setRoles(['ROLE_ADMIN']))->has('superAdmin'));
|
||||
$this->assertFalse($this->createForm((new User())->setRoles(['ROLE_MANAGER']))->has('superAdmin'));
|
||||
$this->assertFalse($this->createForm((new User())->setRoles([User::PENDING_ROLES['ROLE_ADMIN']]))->has('superAdmin'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception: a flag left over from before its role was revoked has to stay editable,
|
||||
* or that account could not be saved at all while the violation stands.
|
||||
*/
|
||||
public function testSuperAdminStaysEditableWhenTheFlagOutlivedTheRole(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setRoles(['ROLE_MANAGER'])
|
||||
->setSuperAdmin(true)
|
||||
;
|
||||
|
||||
$view = $this->createForm($user)->createView();
|
||||
|
||||
// ROLE_USER and ROLE_SUPER_ADMIN are synthesized by getRoles() and must not leak in
|
||||
$this->assertSame(['ROLE_ADMIN'], $view->children['roles']->vars['data']);
|
||||
}
|
||||
|
||||
public function testApprovingAPendingRoleClearsTheMarker(): void
|
||||
{
|
||||
$user = (new User())->setRoles([User::PENDING_ROLES['ROLE_ADMIN']]);
|
||||
|
||||
$form = $this->createForm($user);
|
||||
|
||||
// the marker is not an assignable choice and must not reach the field
|
||||
$this->assertSame([], $form->createView()->children['roles']->vars['data']);
|
||||
$this->assertTrue($form->has('superAdmin'));
|
||||
|
||||
$form->submit([
|
||||
'roles' => ['ROLE_ADMIN'],
|
||||
'superAdmin' => null,
|
||||
'hotelCodes' => [],
|
||||
'disabled' => null,
|
||||
]);
|
||||
|
||||
$this->assertTrue($form->isValid());
|
||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
||||
$this->assertSame([], $user->getPendingRoles());
|
||||
$this->assertFalse($user->isSuperAdmin());
|
||||
}
|
||||
|
||||
public function testRendersHotelCodesNotCoveredByTheConfiguredMap(): void
|
||||
public function testSuperAdminIsAppointed(): void
|
||||
{
|
||||
$user = (new User())->setHotelCodes(['XYZ']);
|
||||
|
||||
$view = $this->createForm($user)->createView();
|
||||
|
||||
$this->assertSame(['XYZ'], $view->children['hotelCodes']->vars['data']);
|
||||
}
|
||||
|
||||
public function testSubmitStoresAssignedRolesOnly(): void
|
||||
{
|
||||
$user = (new User())->setRoles(['ROLE_TEAMER']);
|
||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
||||
|
||||
$form = $this->createForm($user);
|
||||
$form->submit([
|
||||
'roles' => ['ROLE_ADMIN'],
|
||||
'superAdmin' => '1',
|
||||
'hotelCodes' => [],
|
||||
'disabled' => null,
|
||||
]);
|
||||
|
||||
$this->assertTrue($form->isValid());
|
||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
||||
$this->assertTrue($user->isSuperAdmin());
|
||||
}
|
||||
|
||||
public function testSubmitRejectsSuperAdminWithoutRoleAdmin(): void
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
$form = $this->createForm($user);
|
||||
$form->submit([
|
||||
'roles' => ['ROLE_MANAGER'],
|
||||
'superAdmin' => '1',
|
||||
'hotelCodes' => [],
|
||||
]);
|
||||
|
||||
$this->assertFalse($form->isValid());
|
||||
$this->assertCount(1, $form->get('superAdmin')->getErrors());
|
||||
}
|
||||
|
||||
public function testSubmitBlocksTheAccountWithAReason(): void
|
||||
{
|
||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
||||
|
||||
$form = $this->createForm($user);
|
||||
$form->submit([
|
||||
'roles' => ['ROLE_ADMIN'],
|
||||
'superAdmin' => null,
|
||||
'hotelCodes' => [],
|
||||
'disabled' => '1',
|
||||
'disabledReason' => 'Wegen Fehlverhaltens gesperrt.',
|
||||
'disabledReasonInternal' => 'Siehe Vorgang 4711.',
|
||||
@@ -115,9 +125,7 @@ class UserTypeTest extends KernelTestCase
|
||||
|
||||
$form = $this->createForm($user);
|
||||
$form->submit([
|
||||
'roles' => ['ROLE_ADMIN'],
|
||||
'superAdmin' => null,
|
||||
'hotelCodes' => [],
|
||||
'disabled' => null,
|
||||
'disabledReason' => null,
|
||||
'disabledReasonInternal' => null,
|
||||
@@ -143,9 +151,7 @@ class UserTypeTest extends KernelTestCase
|
||||
|
||||
// the textareas are prefilled, so unchecking the box alone submits the old reasons
|
||||
$form->submit([
|
||||
'roles' => ['ROLE_ADMIN'],
|
||||
'superAdmin' => null,
|
||||
'hotelCodes' => [],
|
||||
'disabled' => null,
|
||||
'disabledReason' => 'Für deinen Account liegt in BusPro keine Berechtigung mehr vor.',
|
||||
'disabledReasonInternal' => 'Automatisch gesperrt: keine Rollen in BusPro.',
|
||||
|
||||
@@ -38,7 +38,7 @@ class BpnAuthenticatorTest extends TestCase
|
||||
{
|
||||
$this->stubApiClient($this->createCrmAttributes());
|
||||
|
||||
$this->userDataHandler->method('collectRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('collectClaimedRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn(null);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('createLocalUser');
|
||||
@@ -55,7 +55,7 @@ class BpnAuthenticatorTest extends TestCase
|
||||
|
||||
$this->stubApiClient($this->createCrmAttributes());
|
||||
|
||||
$this->userDataHandler->method('collectRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('collectClaimedRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn($user);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('updateLocalUser');
|
||||
@@ -69,6 +69,11 @@ class BpnAuthenticatorTest extends TestCase
|
||||
$this->assertSame($user, $this->loadUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* This guard is what stands between a degraded response and a mass revocation: with the
|
||||
* roles led by the CRM, a login that reached updateLocalUser() on an empty payload would
|
||||
* strip every role of every user logging in, one at a time.
|
||||
*/
|
||||
public function testResponseWithoutAttributeGroupsRefusesTheLoginWithoutBlocking(): void
|
||||
{
|
||||
$user = (new User())->setRoles(['ROLE_ADMIN']);
|
||||
@@ -76,14 +81,19 @@ class BpnAuthenticatorTest extends TestCase
|
||||
// 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('collectClaimedRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn($user);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('disableForRevokedCrmRoles');
|
||||
$this->userDataHandler->expects($this->never())->method('updateLocalUser');
|
||||
|
||||
$this->expectException(UserNotFoundException::class);
|
||||
try {
|
||||
$this->loadUser();
|
||||
$this->fail('Expected the login to be refused');
|
||||
} catch (UserNotFoundException) {
|
||||
}
|
||||
|
||||
$this->loadUser();
|
||||
$this->assertSame(['ROLE_ADMIN'], $user->getAssignedRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +107,7 @@ class BpnAuthenticatorTest extends TestCase
|
||||
|
||||
$this->stubApiClient($this->createCrmAttributes());
|
||||
|
||||
$this->userDataHandler->method('collectRoles')->willReturn(['ROLE_TEAMER']);
|
||||
$this->userDataHandler->method('collectClaimedRoles')->willReturn(['ROLE_TEAMER']);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn($user);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('updateLocalUser');
|
||||
@@ -115,7 +125,7 @@ class BpnAuthenticatorTest extends TestCase
|
||||
|
||||
$this->stubApiClient($this->createCrmAttributes());
|
||||
|
||||
$this->userDataHandler->method('collectRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('collectClaimedRoles')->willReturn([]);
|
||||
$this->userDataHandler->method('findLocalUser')->willReturn($user);
|
||||
|
||||
$this->userDataHandler->expects($this->never())->method('disableForRevokedCrmRoles');
|
||||
|
||||
@@ -110,9 +110,10 @@ class MyEpAuthenticatorTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* A super admin's manual demotion has to survive the user's next SSO login.
|
||||
* A claimed administrative role is marked for approval, never granted - not even when
|
||||
* the identity provider reports it outright.
|
||||
*/
|
||||
public function testExistingGrantedRolesAreNeverOverwritten(): void
|
||||
public function testClaimedAdministrativeRolesAreNeverGrantedOnLogin(): void
|
||||
{
|
||||
$user = (new User())->setEmail('[email protected]')->setRoles(['ROLE_TEAMER']);
|
||||
$this->repository->method('findOneBy')->willReturn($user);
|
||||
@@ -130,7 +131,7 @@ class MyEpAuthenticatorTest extends TestCase
|
||||
/**
|
||||
* An already approved role must not be demoted back to a marker on the next login.
|
||||
*/
|
||||
public function testAnAlreadyGrantedAdministrativeRoleIsKept(): void
|
||||
public function testAnAlreadyGrantedAdministrativeRoleIsKeptWhileStillClaimed(): void
|
||||
{
|
||||
$user = (new User())->setEmail('[email protected]')->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER']);
|
||||
$this->repository->method('findOneBy')->willReturn($user);
|
||||
@@ -141,6 +142,32 @@ class MyEpAuthenticatorTest extends TestCase
|
||||
$this->assertSame([], $user->getPendingRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* MyE&P leads exactly as BusPro does: a role it stops reporting is withdrawn on the
|
||||
* next login, and the hotel codes are re-imported with it.
|
||||
*/
|
||||
public function testGrantedRolesNoLongerClaimedAreRevoked(): void
|
||||
{
|
||||
$user = (new User())
|
||||
->setEmail('[email protected]')
|
||||
->setRoles(['ROLE_ADMIN', 'ROLE_TEAMER'])
|
||||
->setSuperAdmin(true)
|
||||
->setHotelCodes(['SSL'])
|
||||
;
|
||||
$this->repository->method('findOneBy')->willReturn($user);
|
||||
|
||||
$this->loadUser($this->createUserinfo(['ROLE_TEAMER']));
|
||||
|
||||
$this->assertSame(['ROLE_TEAMER'], $user->getAssignedRoles());
|
||||
$this->assertSame([], $user->getPendingRoles());
|
||||
|
||||
// the flag would otherwise outlive the role it depends on
|
||||
$this->assertFalse($user->isSuperAdmin());
|
||||
$this->assertNotContains('ROLE_SUPER_ADMIN', $user->getRoles());
|
||||
|
||||
$this->assertSame(['HOTEL'], $user->getHotelCodes());
|
||||
}
|
||||
|
||||
public function testTeamerRoleIsGrantedToAnExistingUser(): void
|
||||
{
|
||||
$user = (new User())->setEmail('[email protected]')->setRoles([User::PENDING_ROLES['ROLE_MANAGER']]);
|
||||
|
||||
Reference in New Issue
Block a user