Skip to content

Commit f5c2e19

Browse files
committed
TASK: Allow only FE user roles to be assigned
1 parent 28252c0 commit f5c2e19

1 file changed

Lines changed: 91 additions & 19 deletions

File tree

Classes/Controller/ModuleController.php

Lines changed: 91 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,21 @@ public function newAction(): void
130130
public function createAction(string $username, array $password, User $user, ?\DateTime $expirationDate, array $roleIdentifiers = []): void
131131
{
132132
// make sure self::$roleIdentifier is always added
133-
$roleIdentifiers = array_unique(array_merge($roleIdentifiers, [self::$roleIdentifier]));
134-
$user = $this->userService->addUser($username, $password[0], $user, $roleIdentifiers, self::$authenticationProviderName);
133+
$roleIdentifiersToSet = array_unique(array_merge($roleIdentifiers, [self::$roleIdentifier]));
134+
if ($this->onlyFrontendRoles($roleIdentifiersToSet)) {
135+
$user = $this->userService->addUser($username, $password[0], $user, $roleIdentifiersToSet, self::$authenticationProviderName);
135136

136-
if ($expirationDate !== null) {
137-
/** @var Account $account */
138-
$account = $user->getAccounts()->first();
139-
$expirationDate->setTime(0, 0, 0);
140-
$account->setExpirationDate($expirationDate);
141-
}
137+
if ($expirationDate !== null) {
138+
/** @var Account $account */
139+
$account = $user->getAccounts()->first();
140+
$expirationDate->setTime(0, 0);
141+
$account->setExpirationDate($expirationDate);
142+
}
142143

143-
$this->addFlashMessage('The user "%s" has been created.', 'User created', Message::SEVERITY_OK, [htmlspecialchars($username)], 1416225561);
144+
$this->addFlashMessage('The user "%s" has been created.', 'User created', Message::SEVERITY_OK, [htmlspecialchars($username)], 1416225561);
145+
} else {
146+
$this->throwStatus(403, 'Not allowed to assign the given roles');
147+
}
144148
$this->redirect('index');
145149
}
146150

@@ -243,17 +247,25 @@ public function updateAccountAction(Account $account, array $roleIdentifiers = [
243247
{
244248
if ($this->checkAccount($account)) {
245249
// make sure self::$roleIdentifier is always added
246-
$roleIdentifiers = array_unique(array_merge($roleIdentifiers, [self::$roleIdentifier]));
247-
$this->userService->setRolesForAccount($account, $roleIdentifiers);
248-
$user = $this->userService->getUser($account->getAccountIdentifier(), $account->getAuthenticationProviderName());
249-
$password = array_shift($password);
250-
if (trim((string)$password) !== '') {
251-
$this->userService->setUserPassword($user, $password);
252-
}
253-
$this->accountRepository->update($account);
250+
$roleIdentifiersToSet = array_unique(array_merge($roleIdentifiers, [self::$roleIdentifier]));
251+
252+
if ($this->onlyFrontendRoles($roleIdentifiersToSet)) {
253+
// add any non-FE roles from the current roles to keep them unchanged
254+
$roleIdentifiersToSet = $this->addExistingNonFrontendUserRoles($roleIdentifiersToSet, $account);
254255

255-
$this->addFlashMessage('The account has been updated.', 'Account updated', Message::SEVERITY_OK);
256-
$this->redirect('edit', null, null, ['user' => $user]);
256+
$this->userService->setRolesForAccount($account, $roleIdentifiersToSet);
257+
$user = $this->userService->getUser($account->getAccountIdentifier(), $account->getAuthenticationProviderName());
258+
$password = array_shift($password);
259+
if (trim((string)$password) !== '') {
260+
$this->userService->setUserPassword($user, $password);
261+
}
262+
$this->accountRepository->update($account);
263+
264+
$this->addFlashMessage('The account has been updated.', 'Account updated');
265+
$this->redirect('edit', null, null, ['user' => $user]);
266+
} else {
267+
$this->throwStatus(403, 'Not allowed to assign the given roles');
268+
}
257269
} else {
258270
$this->throwStatus(403, 'Not allowed to update that account');
259271
}
@@ -321,4 +333,64 @@ protected function getFrontendUserRoles(): array
321333
return $role->getIdentifier() === self::$roleIdentifier || array_key_exists(self::$roleIdentifier, $role->getAllParentRoles());
322334
});
323335
}
336+
337+
/**
338+
* Returns an array with all roles of a user's accounts, including parent roles, the "Everybody" role and the
339+
* "AuthenticatedUser" role, assuming that the user is logged in.
340+
*
341+
* @param Account $account
342+
* @return Role[] indexed by role identifier
343+
*/
344+
private function getAllRolesForAccount(Account $account): array
345+
{
346+
$roles = [];
347+
$accountRoles = $account->getRoles();
348+
foreach ($accountRoles as $currentRole) {
349+
if (!in_array($currentRole, $roles, true)) {
350+
$roles[$currentRole->getIdentifier()] = $currentRole;
351+
}
352+
foreach ($currentRole->getAllParentRoles() as $currentParentRole) {
353+
if (!in_array($currentParentRole, $roles, true)) {
354+
$roles[$currentParentRole->getIdentifier()] = $currentParentRole;
355+
}
356+
}
357+
}
358+
359+
return $roles;
360+
}
361+
362+
/**
363+
* Returns whether it is allowed to add/remove the changed roles.
364+
*
365+
* - Roles not being "FE user roles" can never be set
366+
*
367+
* @param array $roleIdentifiersToSet
368+
* @return bool
369+
*/
370+
private function onlyFrontendRoles(array $roleIdentifiersToSet): bool
371+
{
372+
$frontendUserRoleIdentifiers = array_keys($this->getFrontendUserRoles());
373+
374+
return array_diff($roleIdentifiersToSet, $frontendUserRoleIdentifiers) === [];
375+
}
376+
377+
/**
378+
* Add any non-FE roles from the current $account roles to $roleIdentifiersToSet
379+
*
380+
* @param array $roleIdentifiersToSet
381+
* @param Account $account
382+
* @return array
383+
*/
384+
protected function addExistingNonFrontendUserRoles(array $roleIdentifiersToSet, Account $account): array
385+
{
386+
return array_unique(array_merge(
387+
$roleIdentifiersToSet,
388+
array_keys(array_filter(
389+
$this->getAllRolesForAccount($account),
390+
static function (Role $role) {
391+
return !$role->isAbstract() && !($role->getIdentifier() === self::$roleIdentifier || array_key_exists(self::$roleIdentifier, $role->getAllParentRoles()));
392+
}
393+
))
394+
));
395+
}
324396
}

0 commit comments

Comments
 (0)