Skip to content

Commit

Permalink
Move enforcer instance into factory (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
akadlec authored Jul 21, 2024
1 parent 4609fe0 commit b59217f
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 70 deletions.
90 changes: 46 additions & 44 deletions src/DI/SimpleAuthExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ public function getConfigSchema(): Schema\Schema
]);
}

/**
* @throws Exceptions\Logical
*/
public function loadConfiguration(): void
{
$builder = $this->getContainerBuilder();
Expand Down Expand Up @@ -151,6 +154,49 @@ public function loadConfiguration(): void
$builder->addDefinition($this->prefix('security.user'), new DI\Definitions\ServiceDefinition())
->setType(Security\User::class);

/**
* Casbin
*/

if ($configuration->enable->casbin->database) {
$adapter = $builder->addDefinition(
$this->prefix('casbin.adapter'),
new DI\Definitions\ServiceDefinition(),
)
->setType(SimpleAuth\Models\Casbin\Adapter::class)
->setArguments([
'policyFile' => $configuration->casbin->policy,
]);

$builder->addDefinition($this->prefix('casbin.subscriber'), new DI\Definitions\ServiceDefinition())
->setType(Subscribers\Policy::class);
} else {
$policyFile = $configuration->casbin->policy;

if (!is_string($policyFile) || !is_file($policyFile)) {
throw new Exceptions\Logical('Casbin policy file is not configured');
}

$adapter = $builder->addDefinition($this->prefix('casbin.adapter'), new DI\Definitions\ServiceDefinition())
->setType(Casbin\Persist\Adapters\FileAdapter::class)
->setArguments([
'filePath' => $policyFile,
]);
}

$modelFile = $configuration->casbin->model;

if (!is_string($modelFile) || !is_file($modelFile)) {
throw new Exceptions\Logical('Casbin model file is not configured');
}

$builder->addDefinition($this->prefix('casbin.enforcerFactory'), new DI\Definitions\ServiceDefinition())
->setType(Security\EnforcerFactory::class)
->setArguments([
'modelFile' => $modelFile,
'adapter' => $adapter,
]);

/**
* Web server extension
*/
Expand Down Expand Up @@ -206,7 +252,6 @@ public function loadConfiguration(): void

/**
* @throws DI\MissingServiceException
* @throws Exceptions\Logical
*/
public function beforeCompile(): void
{
Expand All @@ -216,49 +261,6 @@ public function beforeCompile(): void
$configuration = $this->getConfig();
assert($configuration instanceof stdClass);

/**
* Casbin
*/

if ($configuration->enable->casbin->database) {
$adapter = $builder->addDefinition(
$this->prefix('casbin.adapter'),
new DI\Definitions\ServiceDefinition(),
)
->setType(SimpleAuth\Models\Casbin\Adapter::class)
->setArguments([
'policyFile' => $configuration->casbin->policy,
]);

$builder->addDefinition($this->prefix('casbin.subscriber'), new DI\Definitions\ServiceDefinition())
->setType(Subscribers\Policy::class);
} else {
$policyFile = $configuration->casbin->policy;

if (!is_string($policyFile) || !is_file($policyFile)) {
throw new Exceptions\Logical('Casbin policy file is not configured');
}

$adapter = $builder->addDefinition($this->prefix('casbin.adapter'), new DI\Definitions\ServiceDefinition())
->setType(Casbin\Persist\Adapters\FileAdapter::class)
->setArguments([
'filePath' => $policyFile,
]);
}

$modelFile = $configuration->casbin->model;

if (!is_string($modelFile) || !is_file($modelFile)) {
throw new Exceptions\Logical('Casbin model file is not configured');
}

$builder->addDefinition($this->prefix('casbin.enforcer'), new DI\Definitions\ServiceDefinition())
->setType(Casbin\CachedEnforcer::class)
->setArguments([
$modelFile,
$adapter,
]);

/**
* Doctrine extension
*/
Expand Down
1 change: 1 addition & 0 deletions src/Middleware/Access.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function __construct(
/**
* @throws Exceptions\ForbiddenAccess
* @throws Exceptions\InvalidArgument
* @throws Exceptions\InvalidState
*/
public function process(
ServerRequestInterface $request,
Expand Down
5 changes: 5 additions & 0 deletions src/Security/AnnotationChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class AnnotationChecker
* @param class-string $controllerClass
*
* @throws Exceptions\InvalidArgument
* @throws Exceptions\InvalidState
*/
public function checkAccess(
User|null $user,
Expand Down Expand Up @@ -82,6 +83,7 @@ public function checkAccess(

/**
* @throws Exceptions\InvalidArgument
* @throws Exceptions\InvalidState
*/
private function isAllowed(User|null $user, Reflector $element): bool
{
Expand Down Expand Up @@ -175,6 +177,9 @@ private function checkUser(User $user, Reflector $element): bool
return true;
}

/**
* @throws Exceptions\InvalidState
*/
private function checkRoles(User $user, Reflector $element): bool
{
// Check if element has @Secured\Role annotation
Expand Down
57 changes: 57 additions & 0 deletions src/Security/EnforcerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php declare(strict_types = 1);

/**
* EnforcerFactory.php
*
* @license More in LICENSE.md
* @copyright https://www.fastybird.com
* @author Adam Kadlec <[email protected]>
* @package FastyBird:SimpleAuth!
* @subpackage Security
* @since 0.1.0
*
* @date 21.07.24
*/

namespace FastyBird\SimpleAuth\Security;

use Casbin;
use FastyBird\SimpleAuth\Exceptions;

/**
* Class security annotation checker
*
* @package FastyBird:SimpleAuth!
* @subpackage Security
*
* @author Adam Kadlec <[email protected]>
*/
class EnforcerFactory
{

private Casbin\CachedEnforcer|null $enforcer = null;

public function __construct(
private readonly string $modelFile,
private readonly Casbin\Persist\Adapter $adapter,
)
{
}

/**
* @throws Exceptions\InvalidState
*/
public function getEnforcer(): Casbin\Enforcer
{
if ($this->enforcer === null) {
try {
$this->enforcer = new Casbin\CachedEnforcer($this->modelFile, $this->adapter);
} catch (Casbin\Exceptions\CasbinException $ex) {
throw new Exceptions\InvalidState('Failed to create an enforcer', $ex->getCode(), $ex);
}
}

return $this->enforcer;
}

}
14 changes: 10 additions & 4 deletions src/Security/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

namespace FastyBird\SimpleAuth\Security;

use Casbin;
use Closure;
use FastyBird\SimpleAuth;
use FastyBird\SimpleAuth\Exceptions;
Expand Down Expand Up @@ -46,7 +45,7 @@ class User

public function __construct(
protected readonly Security\IUserStorage $storage,
protected readonly Casbin\CachedEnforcer $enforcer,
protected readonly Security\EnforcerFactory $enforcerFactory,
protected readonly Security\IAuthenticator|null $authenticator = null,
)
{
Expand Down Expand Up @@ -101,24 +100,31 @@ public function isLoggedIn(): bool
return $this->storage->isAuthenticated();
}

/**
* @throws Exceptions\InvalidState
*/
public function isInRole(string $role): bool
{
return $this->enforcer->hasRoleForUser(
return $this->enforcerFactory->getEnforcer()->hasRoleForUser(
$this->getId()?->toString() ?? SimpleAuth\Constants::USER_ANONYMOUS,
$role,
);
}

/**
* @return array<string>
*
* @throws Exceptions\InvalidState
*/
public function getRoles(): array
{
if (!$this->isLoggedIn()) {
return [SimpleAuth\Constants::ROLE_ANONYMOUS];
}

return $this->enforcer->getRolesForUser($this->getId()?->toString() ?? SimpleAuth\Constants::USER_ANONYMOUS);
return $this->enforcerFactory->getEnforcer()->getRolesForUser(
$this->getId()?->toString() ?? SimpleAuth\Constants::USER_ANONYMOUS,
);
}

}
37 changes: 30 additions & 7 deletions src/Subscribers/Policy.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use Doctrine\ORM;
use Doctrine\Persistence;
use FastyBird\SimpleAuth\Entities;
use FastyBird\SimpleAuth\Exceptions;
use FastyBird\SimpleAuth\Security;
use Nette;
use function count;

Expand All @@ -38,7 +40,7 @@ final class Policy implements Common\EventSubscriber

public function __construct(
private readonly ORM\EntityManagerInterface $entityManager,
private readonly Casbin\CachedEnforcer $enforcer,
private readonly Security\EnforcerFactory $enforcerFactory,
)
{
}
Expand All @@ -54,6 +56,8 @@ public function getSubscribedEvents(): array

/**
* @param Persistence\Event\LifecycleEventArgs<ORM\EntityManagerInterface> $eventArgs
*
* @throws Exceptions\InvalidState
*/
public function postPersist(Persistence\Event\LifecycleEventArgs $eventArgs): void
{
Expand All @@ -65,12 +69,19 @@ public function postPersist(Persistence\Event\LifecycleEventArgs $eventArgs): vo
return;
}

$this->enforcer->invalidateCache();
$this->enforcer->loadPolicy();
$enforcer = $this->enforcerFactory->getEnforcer();

if ($enforcer instanceof Casbin\CachedEnforcer) {
$enforcer->invalidateCache();
}

$enforcer->loadPolicy();
}

/**
* @param Persistence\Event\LifecycleEventArgs<ORM\EntityManagerInterface> $eventArgs
*
* @throws Exceptions\InvalidState
*/
public function postUpdate(Persistence\Event\LifecycleEventArgs $eventArgs): void
{
Expand All @@ -95,12 +106,19 @@ public function postUpdate(Persistence\Event\LifecycleEventArgs $eventArgs): voi
return;
}

$this->enforcer->invalidateCache();
$this->enforcer->loadPolicy();
$enforcer = $this->enforcerFactory->getEnforcer();

if ($enforcer instanceof Casbin\CachedEnforcer) {
$enforcer->invalidateCache();
}

$enforcer->loadPolicy();
}

/**
* @param Persistence\Event\LifecycleEventArgs<ORM\EntityManagerInterface> $eventArgs
*
* @throws Exceptions\InvalidState
*/
public function postRemove(Persistence\Event\LifecycleEventArgs $eventArgs): void
{
Expand All @@ -112,8 +130,13 @@ public function postRemove(Persistence\Event\LifecycleEventArgs $eventArgs): voi
return;
}

$this->enforcer->invalidateCache();
$this->enforcer->loadPolicy();
$enforcer = $this->enforcerFactory->getEnforcer();

if ($enforcer instanceof Casbin\CachedEnforcer) {
$enforcer->invalidateCache();
}

$enforcer->loadPolicy();
}

}
Loading

0 comments on commit b59217f

Please sign in to comment.