refactored permissions for simpler customizations (#808)

This commit is contained in:
Kevin Papst
2019-05-25 17:23:15 +02:00
committed by GitHub
parent d18019159b
commit ebff4a765a
24 changed files with 299 additions and 161 deletions

View File

@@ -11,10 +11,6 @@ namespace App\Controller;
use App\Constants;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Annotation\Route;
/**
@@ -43,11 +39,6 @@ class AboutController extends AbstractController
* @return \Symfony\Component\HttpFoundation\Response
*/
public function debugAction()
{
return $this->getAboutView();
}
protected function getAboutView(array $additional = [])
{
$phpInfo = $this->getPhpInfo();
unset($phpInfo[0]);
@@ -89,8 +80,7 @@ class AboutController extends AbstractController
],
'info' => $phpInfo,
'settings' => $settings,
],
$additional
]
));
}
@@ -119,28 +109,6 @@ class AboutController extends AbstractController
]);
}
/**
* @Route(path="/flush-cache", name="system_flush_cache", methods={"GET"})
*
* @Security("is_granted('system_actions')")
*/
public function rebuildContainer(KernelInterface $kernel)
{
$application = new Application($kernel);
$application->setAutoExit(false);
$input = new ArrayInput([
'command' => 'cache:clear',
'--env' => $kernel->getEnvironment(),
'-n',
]);
$output = new BufferedOutput();
$application->run($input, $output);
return $this->getAboutView(['content_action' => $output->fetch()]);
}
/**
* @author https://php.net/manual/en/function.phpinfo.php#117961
* @return array

View File

@@ -14,6 +14,7 @@ use App\Entity\User;
use App\Form\Toolbar\UserToolbarForm;
use App\Form\UserCreateType;
use App\Repository\Query\UserQuery;
use App\Security\RolePermissionManager;
use Pagerfanta\Pagerfanta;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
@@ -173,6 +174,22 @@ class UserController extends AbstractController
);
}
/**
* @Route(path="/permissions", name="admin_user_permissions", methods={"GET", "POST"})
* @Security("is_granted('role_permissions')")
*
* @param RolePermissionManager $manager
* @return \Symfony\Component\HttpFoundation\Response
*/
public function permissions(RolePermissionManager $manager)
{
return $this->render('user/permissions.html.twig', [
'roles' => $manager->getRoles(),
'permissions' => $manager->getPermissions(),
'manager' => $manager,
]);
}
/**
* @param UserQuery $query
* @return \Symfony\Component\Form\FormInterface

View File

@@ -71,14 +71,8 @@ class AppExtension extends Extension
*/
protected function createPermissionParameter(array $config, ContainerBuilder $container)
{
$roles = [];
foreach ($config['maps'] as $role => $sets) {
if (!isset($config['roles'][$role])) {
$exception = new InvalidConfigurationException(
'Configured permission set includes unknown role "' . $role . '"'
);
$exception->setPath('kimai.permissions.maps.' . $role);
throw $exception;
}
foreach ($sets as $set) {
if (!isset($config['sets'][$set])) {
$exception = new InvalidConfigurationException(
@@ -87,12 +81,59 @@ class AppExtension extends Extension
$exception->setPath('kimai.permissions.maps.' . $role);
throw $exception;
}
$config['roles'][$role] = array_unique(array_merge($config['roles'][$role], $config['sets'][$set]));
$roles[$role] = array_merge($roles[$role] ?? [], $this->getFilteredPermissions(
$this->extractSinglePermissionsFromSet($config, $set)
));
}
}
// delete forbidden permissions from roles
foreach (array_keys($config['maps']) as $name) {
$config['roles'][$name] = $this->getFilteredPermissions(
array_unique(array_merge($roles[$name], $config['roles'][$name] ?? []))
);
}
$container->setParameter('kimai.permissions', $config['roles']);
}
protected function getFilteredPermissions(array $permissions): array
{
$deleteFromArray = array_filter($permissions, function ($permission) {
return $permission[0] == '!';
});
return array_filter($permissions, function ($permission) use ($deleteFromArray) {
if ($permission[0] == '!') {
return false;
}
return !in_array('!' . $permission, $deleteFromArray);
});
}
protected function extractSinglePermissionsFromSet(array $permissions, string $name): array
{
if (!isset($permissions['sets'][$name])) {
throw new InvalidConfigurationException('Unknown permission set "' . $name . '"');
}
$result = [];
foreach ($permissions['sets'][$name] as $permissionName) {
if ($permissionName[0] == '@') {
$result = array_merge(
$result,
$this->extractSinglePermissionsFromSet($permissions, substr($permissionName, 1))
);
} else {
$result[] = $permissionName;
}
}
return $result;
}
/**
* @param array $config
* @param ContainerBuilder $container

View File

@@ -434,7 +434,6 @@ class Configuration implements ConfigurationInterface
->arrayNode('sets')
->requiresAtLeastOneElement()
->useAttributeAsKey('key')
->performNoDeepMerging()
->arrayPrototype()
->useAttributeAsKey('key')
->isRequired()
@@ -445,7 +444,6 @@ class Configuration implements ConfigurationInterface
->arrayNode('maps')
->requiresAtLeastOneElement()
->useAttributeAsKey('key')
->performNoDeepMerging()
->arrayPrototype()
->useAttributeAsKey('key')
->isRequired()
@@ -456,13 +454,18 @@ class Configuration implements ConfigurationInterface
->arrayNode('roles')
->requiresAtLeastOneElement()
->useAttributeAsKey('key')
->performNoDeepMerging()
->arrayPrototype()
->useAttributeAsKey('key')
->isRequired()
->prototype('scalar')->end()
->defaultValue([])
->end()
->defaultValue([
'ROLE_USER' => [],
'ROLE_TEAMLEAD' => [],
'ROLE_ADMIN' => [],
'ROLE_SUPER_ADMIN' => [],
])
->end()
->end()
;

View File

@@ -9,6 +9,7 @@
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
@@ -55,7 +56,7 @@ class UserCreateType extends UserEditType
public function __configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'class' => 'Kimai:User',
'class' => User::class,
]);
}
}

View File

@@ -16,13 +16,10 @@ class RolePermissionManager
*/
protected $permissions = [];
/**
* @var array
* @var string[]
*/
protected $knownPermissions = [];
/**
* @param array $permissions
*/
public function __construct(array $permissions)
{
$this->permissions = $permissions;
@@ -33,30 +30,12 @@ class RolePermissionManager
$this->knownPermissions = array_unique($this->knownPermissions);
}
/**
* @param string $permission
* @return bool
*/
public function isRegisteredPermission($permission)
public function isRegisteredPermission(string $permission): bool
{
return in_array($permission, $this->knownPermissions);
}
/**
* @param string $role
* @return bool
*/
public function roleHasPermission($role)
{
return isset($this->permissions[$role]);
}
/**
* @param string $role
* @param string $permission
* @return bool
*/
public function hasPermission($role, $permission)
public function hasPermission(string $role, string $permission): bool
{
if (!isset($this->permissions[$role])) {
return false;
@@ -64,4 +43,19 @@ class RolePermissionManager
return in_array($permission, $this->permissions[$role]);
}
public function getRoles(): array
{
return array_keys($this->permissions);
}
public function roleHasPermission(string $role): bool
{
return isset($this->permissions[$role]);
}
public function getPermissions(): array
{
return $this->knownPermissions;
}
}

View File

@@ -94,6 +94,8 @@ class Extensions extends AbstractExtension
'profile-stats' => 'far fa-chart-bar',
'profile' => 'fas fa-user-edit',
'warning' => 'fas fa-exclamation-triangle',
'permissions' => 'fas fa-user-lock',
'back' => 'fas fa-long-arrow-alt-left',
];
/**