Skip to content

Commit

Permalink
BUGFIX: Finalize introduction of role and privilege metadata
Browse files Browse the repository at this point in the history
This builds upon the work started with #2166 and

* Fixes the Policy schema
* Adds label & description to the "magic" base roles
* Adds CLI commands in order to make use of the metadata
  within Flow

Usage:

    ./flow security:listRoles --include-abstract
    ./flow security:describeRole Neos.Flow:Everybody

Related: #2162
  • Loading branch information
bwaidelich committed Dec 14, 2020
1 parent c9b3de2 commit bf1a5e2
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 2 deletions.
75 changes: 75 additions & 0 deletions Neos.Flow/Classes/Command/SecurityCommandController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
use Neos\Flow\Cache\CacheManager;
use Neos\Cache\Frontend\VariableFrontend;
use Neos\Flow\Cli\CommandController;
use Neos\Flow\Configuration\Exception\InvalidConfigurationTypeException;
use Neos\Flow\Mvc\Controller\AbstractController;
use Neos\Flow\ObjectManagement\ObjectManagerInterface;
use Neos\Flow\Reflection\ReflectionService;
use Neos\Flow\Security\Cryptography\RsaWalletServicePhp;
use Neos\Flow\Security\Exception as SecurityException;
use Neos\Flow\Security\Exception\NoSuchRoleException;
use Neos\Flow\Security\Policy\PolicyService;
use Neos\Flow\Security\Authorization\Privilege\Method\MethodPrivilegeInterface;
Expand Down Expand Up @@ -347,4 +349,77 @@ public function showMethodsForPrivilegeTargetCommand(string $privilegeTarget)
$this->outputLine();
}
}

/**
* List all configured roles
*
* @param bool $includeAbstract Set this flag to include abstract roles
* @throws InvalidConfigurationTypeException | SecurityException
*/
public function listRolesCommand(bool $includeAbstract = false): void
{
$roles = $this->policyService->getRoles($includeAbstract);
$this->output->outputTable(array_map(static function(Role $role) {
$id = $role->getIdentifier();
if ($role->isAbstract()) {
$id .= ' (*)';
}
return [$id, $role->getLabel()];
}, $roles), ['Id', 'Label']);
if ($includeAbstract) {
$this->outputLine(' (*) = abstract role');
}
$this->outputLine();
$this->outputLine('Run <i>./flow security:describeRole <id></i> to show details for a role');
}

/**
* Show details of a specified role
*
* @param string $role identifier of the role to describe (for example "Neos.Flow:Everybody")
* @throws InvalidConfigurationTypeException | SecurityException
*/
public function describeRoleCommand(string $role): void
{
$roleInstance = $this->policyService->getRole($role);
$this->outputLine('Details of the <b>%s</b> role:', [$roleInstance->getIdentifier()]);
$this->outputLine();
if ($roleInstance->isAbstract()) {
$this->outputLine('<b>Note:</b> This is an <i>abstract</i> role so it\'t can\'t be assigned to accounts directly');
$this->outputLine();
}
$this->outputLine('<b>Name:</b> %s', [$roleInstance->getName()]);
$this->outputLine('<b>Package:</b> %s', [$roleInstance->getPackageKey()]);
if ($roleInstance->getLabel() !== $roleInstance->getName()) {
$this->outputLine('<b>Label:</b> %s', [$roleInstance->getLabel()]);
}
if (!empty($roleInstance->getDescription())) {
$this->outputLine('<b>Description:</b>');
$this->outputFormatted($roleInstance->getDescription(), [], 1);
}
$this->outputLine();
$this->outputLine('<b>Parent role(s):</b>');
$parentRoles = $roleInstance->getAllParentRoles();
if ($parentRoles === []) {
$this->outputLine('-');
} else {
foreach ($parentRoles as $parentRole) {
$this->outputLine(' * %s', [$parentRole->getIdentifier()]);
}
}
$privileges = $roleInstance->getPrivileges();
$this->outputLine();
$this->outputLine('<b>Privileges:</b>');
if ($privileges === []) {
$this->outputLine('-');
} else {
foreach ($privileges as $privilege) {
$target = $privilege->getPrivilegeTarget();
$this->outputLine(' * %s: <i>%s</i>', [$privilege->getPrivilegeTargetIdentifier(), strtoupper($privilege->getPermission())]);
if ($target->getLabel() !== $privilege->getPrivilegeTargetIdentifier()) {
$this->outputFormatted($target->getLabel(), [], 5);
}
}
}
}
}
2 changes: 1 addition & 1 deletion Neos.Flow/Classes/Security/Policy/PolicyService.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ protected function initialize(): void
$privilegeTargetsForEverybody = $this->privilegeTargets;

$this->roles = [];
$everybodyRole = new Role('Neos.Flow:Everybody');
$everybodyRole = new Role('Neos.Flow:Everybody', [], (string)($this->policyConfiguration['roles']['Neos.Flow:Everybody']['label'] ?? ''), (string)($this->policyConfiguration['roles']['Neos.Flow:Everybody']['description'] ?? ''));
$everybodyRole->setAbstract(true);
if (isset($this->policyConfiguration['roles'])) {
foreach ($this->policyConfiguration['roles'] as $roleIdentifier => $roleConfiguration) {
Expand Down
6 changes: 6 additions & 0 deletions Neos.Flow/Configuration/Policy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@
roles:
'Neos.Flow:Everybody':
abstract: true
label: 'Magic "everybody" role'
description: 'This magic role is always active, even if no account is authenticated'

'Neos.Flow:Anonymous':
abstract: true
label: 'Magic "anonymous" role'
description: 'This magic role is active if no account is authenticated'

'Neos.Flow:AuthenticatedUser':
abstract: true
label: 'Magic "authenticated user" role'
description: 'This magic role is active if an account is authenticated'

privilegeTargets: []
5 changes: 4 additions & 1 deletion Neos.Flow/Resources/Private/Schema/Policy.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ properties:
type: dictionary
additionalProperties: false
properties:
'label': {type: string}
'matcher':
type: string
required: true
Expand All @@ -29,6 +30,8 @@ properties:
additionalProperties: false
properties:
'abstract': {type: boolean}
'label': {type: string}
'description': {type: string}
'parentRoles':
type: array
items: {type: string}
Expand All @@ -40,4 +43,4 @@ properties:
properties:
'privilegeTarget': {type: string}
'parameters': {type: dictionary}
'permission': {type: string, enum: ['GRANT', 'DENY', 'ABSTAIN']}
'permission': {type: string, enum: ['GRANT', 'DENY', 'ABSTAIN']}

0 comments on commit bf1a5e2

Please sign in to comment.