Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
4rthem committed Sep 9, 2022
0 parents commit 2381551
Show file tree
Hide file tree
Showing 41 changed files with 9,707 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/vendor
.phpunit.*
.php_cs.cache
13 changes: 13 additions & 0 deletions .php_cs.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
;

return PhpCsFixer\Config::create()
->setRules([
'@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
])
->setFinder($finder)
;
11 changes: 11 additions & 0 deletions AclObjectInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Alchemy\AclBundle;

interface AclObjectInterface
{
public function getId(): string;
public function getAclOwnerId(): string;
}
40 changes: 40 additions & 0 deletions Admin/PermissionTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Alchemy\AclBundle\Admin;

use Symfony\Component\Routing\Annotation\Route;

trait PermissionTrait
{
protected PermissionView $permissionView;

/**
* @required
*/
public function setPermissionView(PermissionView $permissionView): void
{
$this->permissionView = $permissionView;
}

public function permissionsAction()
{
return $this->render('@AlchemyAcl/permissions/entity/acl.html.twig',
$this->permissionView->getViewParameters(
$this->permissionView->getObjectKey($this->entity['class']),
$this->request->query->get('id')
));
}

/**
* @Route(path="/aces/{type}/global", name="admin_global_permissions")
*/
public function globalPermissionsAction(string $type)
{
return $this->render(
'@AlchemyAcl/permissions/global/acl.html.twig',
$this->permissionView->getViewParameters($type, null)
);
}
}
106 changes: 106 additions & 0 deletions Admin/PermissionView.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace Alchemy\AclBundle\Admin;

use Alchemy\AclBundle\Entity\AccessControlEntry;
use Alchemy\AclBundle\Mapping\ObjectMapping;
use Alchemy\RemoteAuthBundle\Repository\GroupRepositoryInterface;
use Alchemy\RemoteAuthBundle\Repository\UserRepositoryInterface;
use Alchemy\AclBundle\Repository\PermissionRepositoryInterface;
use Alchemy\AclBundle\Security\PermissionInterface;
use Doctrine\ORM\EntityManagerInterface;

class PermissionView
{
private ObjectMapping $objectMapping;
private PermissionRepositoryInterface $repository;
private UserRepositoryInterface $userRepository;
private GroupRepositoryInterface $groupRepository;
private EntityManagerInterface $em;

public function __construct(
ObjectMapping $objectMapping,
PermissionRepositoryInterface $repository,
UserRepositoryInterface $userRepository,
GroupRepositoryInterface $groupRepository,
EntityManagerInterface $em
) {
$this->objectMapping = $objectMapping;
$this->repository = $repository;
$this->userRepository = $userRepository;
$this->groupRepository = $groupRepository;
$this->em = $em;
}

public function getObjectKey(string $entityClass): string
{
return $this->objectMapping->getObjectKey($entityClass);
}

public function getViewParameters(string $objectKey, ?string $id): array
{
$permissions = PermissionInterface::PERMISSIONS;
$aces = [];
if (null !== $id) {
$aces = array_merge($aces, $this->repository->getObjectAces($objectKey, null));
}
$aces = array_merge($aces, $this->repository->getObjectAces($objectKey, $id));

$users = [
AccessControlEntry::USER_WILDCARD => 'All users',
];
foreach ($this->userRepository->getUsers() as $user) {
$users[$user['id']] = $user['username'];
}
$groups = [];
foreach ($this->groupRepository->getGroups() as $group) {
$groups[$group['id']] = $group['name'];
}

$aces = array_map(function (AccessControlEntry $ace) use ($users, $groups, $permissions): array {
$name = $ace->getUserId();
switch ($ace->getUserType()) {
case AccessControlEntry::TYPE_USER_VALUE:
$name = $ace->getUserId() ? ($users[$ace->getUserId()] ?? $name) : AccessControlEntry::USER_WILDCARD;
break;
case AccessControlEntry::TYPE_GROUP_VALUE:
$name = $groups[$ace->getUserId()] ?? $name;
break;
}

return [
'userType' => $ace->getUserTypeString(),
'userId' => $ace->getUserId() ?? AccessControlEntry::USER_WILDCARD,
'name' => $name,
'objectId' => $ace->getObjectId(),
'permissions' => array_map(fn(int $p): bool => $ace->hasPermission($p), $permissions),
];
}, $aces);

$objectTitle = null;
if ($id) {
$object = $this->em->getRepository($this->objectMapping->getClassName($objectKey))->find($id);
if (null !== $object && method_exists($object, '__toString')) {
$objectTitle = (string)$object;
}
}

$params = [
'USER_WILDCARD' => AccessControlEntry::USER_WILDCARD,
'permissions' => $permissions,
'aces' => $aces,
'users' => $users,
'groups' => $groups,
'object_type' => $objectKey,
'object_title' => $objectTitle,
];

if (null !== $id) {
$params['object_id'] = $id;
}

return $params;
}
}
11 changes: 11 additions & 0 deletions AlchemyAclBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Alchemy\AclBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class AlchemyAclBundle extends Bundle
{
}
163 changes: 163 additions & 0 deletions Controller/PermissionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<?php

declare(strict_types=1);

namespace Alchemy\AclBundle\Controller;

use Alchemy\AclBundle\AclObjectInterface;
use Alchemy\AclBundle\Mapping\ObjectMapping;
use Alchemy\AclBundle\Model\AccessControlEntryInterface;
use Alchemy\RemoteAuthBundle\Repository\GroupRepositoryInterface;
use Alchemy\RemoteAuthBundle\Repository\UserRepositoryInterface;
use Alchemy\AclBundle\Repository\PermissionRepositoryInterface;
use Alchemy\AclBundle\Security\PermissionInterface;
use Alchemy\AclBundle\Security\PermissionManager;
use Alchemy\AclBundle\Serializer\AceSerializer;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;

class PermissionController extends AbstractController
{
private PermissionManager $permissionManager;
private EntityManagerInterface $em;
private ObjectMapping $objectMapping;

public function __construct(PermissionManager $permissionManager, EntityManagerInterface $em, ObjectMapping $objectMapping)
{
$this->permissionManager = $permissionManager;
$this->em = $em;
$this->objectMapping = $objectMapping;
}

private function validateAuthorization(?Request $request = null): void
{
if ($this->isGranted('ROLE_ADMIN')) {
return;
}

if ($request instanceof Request) {
$objectType = $request->get('objectType');
$objectId = $request->get('objectId');

if ($objectType && $objectId) {
$object = $this->em->find($this->objectMapping->getClassName($objectType), $objectId);

if (
$object instanceof AclObjectInterface
&& $this->isGranted(PermissionInterface::OWNER, $object)
) {
return;
}
}
}

throw new AccessDeniedHttpException();
}

/**
* @Route("/ace", methods={"PUT"}, name="ace")
*/
public function setAce(Request $request): Response
{
$this->validateAuthorization($request);

$objectType = $request->request->get('objectType');
$objectId = $request->request->get('objectId');
$userType = $request->request->get('userType');
$userId = $request->request->get('userId');
$mask = (int) $request->request->get('mask', 0);

$objectId = !empty($objectId) ? $objectId : null;

$this->permissionManager->updateOrCreateAce($userType, $userId, $objectType, $objectId, $mask);

return new JsonResponse(true);
}

/**
* @Route("/aces", methods={"GET"}, name="aces_index")
*/
public function indexAces(
Request $request,
PermissionRepositoryInterface $repository,
AceSerializer $aceSerializer
): Response
{
$this->validateAuthorization($request);

$params = [
'objectType' => $request->query->get('objectType', false),
'objectId' => $request->query->get('objectId', false),
'userType' => $request->query->get('userType', false),
'userId' => $request->query->get('userId', false),
];

$params = array_filter($params, function ($entry): bool {
return false !== $entry;
});
$params = array_map(function ($p): ?string {
return '' === $p || 'null' === $p ? null: $p;
}, $params);

if (!empty($params['userType'])) {
$params['userType'] = AccessControlEntryInterface::USER_TYPES[$params['userType']] ?? false;
if (false === $params['userType']) {
throw new BadRequestHttpException('Invalid userType');
}
}

$aces = $repository->findAces($params);

return new JsonResponse(array_map(function (AccessControlEntryInterface $ace) use ($aceSerializer): array {
return $aceSerializer->serialize($ace);
}, $aces));
}

/**
* @Route("/ace", methods={"DELETE"}, name="ace_delete")
*/
public function deleteAce(Request $request): Response
{
$this->validateAuthorization($request);
$objectType = $request->request->get('objectType');
$objectId = $request->request->get('objectId');
$userType = $request->request->get('userType');
$userId = $request->request->get('userId');

$objectId = !empty($objectId) ? $objectId : null;

$this->permissionManager->deleteAce($userType, $userId, $objectType, $objectId);

return new JsonResponse(true);
}

/**
* @Route("/users", methods={"GET"}, name="users")
*/
public function getUsers(Request $request, UserRepositoryInterface $repository): Response
{
$this->validateAuthorization();
$limit = $request->query->get('limit');
$offset = $request->query->get('offset');

return new JsonResponse($repository->getUsers($limit, $offset));
}

/**
* @Route("/groups", methods={"GET"}, name="groups")
*/
public function getGroups(Request $request, GroupRepositoryInterface $repository): Response
{
$this->validateAuthorization();
$limit = $request->query->get('limit');
$offset = $request->query->get('offset');

return new JsonResponse($repository->getGroups($limit, $offset));
}
}
Loading

0 comments on commit 2381551

Please sign in to comment.