fix: drop the implicit ROLE_USER from the userinfo roles claim
This commit is contained in:
@@ -8,6 +8,7 @@ use App\BusProNet\Model\Notification;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\Entity\User;
|
||||
use App\Security\Crypt;
|
||||
use App\Security\Role;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -52,8 +53,9 @@ class UserinfoController extends AbstractController
|
||||
return new JsonResponse(['message' => $data->message, 'code' => $data->code], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Patch current user's roles
|
||||
$data->roles = $user->getRoles();
|
||||
// Patch current user's roles. The implicit ROLE_USER says nothing about the
|
||||
// account — every authenticated user holds it — and is not exported.
|
||||
$data->roles = Role::assignedOnly($user->getRoles());
|
||||
|
||||
// Patch current user's hotel codes
|
||||
$data->hotelCodes = $user->getHotelCodes();
|
||||
|
||||
+14
-1
@@ -72,6 +72,19 @@ final class Role
|
||||
return [] === $importable ? [self::CUSTOMER] : $importable;
|
||||
}
|
||||
|
||||
/**
|
||||
* The roles actually assigned to an account — everything except the implicit ROLE_USER,
|
||||
* which User::getRoles() prepends and which is never stored.
|
||||
*
|
||||
* @param string[] $roles
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function assignedOnly(array $roles): array
|
||||
{
|
||||
return array_values(array_diff($roles, [self::USER]));
|
||||
}
|
||||
|
||||
/**
|
||||
* The non-privileged half of a role set: what BpnAuthenticator syncs from the BusPro CRM.
|
||||
*
|
||||
@@ -81,7 +94,7 @@ final class Role
|
||||
*/
|
||||
public static function syncedOnly(array $roles): array
|
||||
{
|
||||
return array_values(array_diff($roles, self::PRIVILEGED, [self::USER]));
|
||||
return array_values(array_diff(self::assignedOnly($roles), self::PRIVILEGED));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -141,11 +141,7 @@ class AppRuntime implements RuntimeExtensionInterface
|
||||
|
||||
$mapped = [];
|
||||
|
||||
foreach ($roles as $role) {
|
||||
if ('ROLE_USER' === $role) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (Role::assignedOnly($roles) as $role) {
|
||||
$mapped[] = $labels[$role] ?? $role;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,15 @@ class RoleTest extends TestCase
|
||||
self::assertSame([Role::CUSTOMER], Role::filterImportable([]));
|
||||
}
|
||||
|
||||
public function testAssignedOnlyDropsTheImplicitRoleUser(): void
|
||||
{
|
||||
$roles = Role::assignedOnly([Role::USER, Role::TEAMER, Role::GROUPS_ADMIN]);
|
||||
|
||||
self::assertSame([Role::TEAMER, Role::GROUPS_ADMIN], $roles);
|
||||
// The value is JSON-encoded into the userinfo response and must not become an object.
|
||||
self::assertSame(array_keys($roles), range(0, \count($roles) - 1));
|
||||
}
|
||||
|
||||
public function testCombineKeepsEachHalfInItsOwnLane(): void
|
||||
{
|
||||
$roles = Role::combine([Role::TEAMER, Role::ADMIN], [Role::GROUPS_ADMIN, Role::TEAMER]);
|
||||
|
||||
Reference in New Issue
Block a user