Skip to content

Commit

Permalink
Using custom database adapter for casbin
Browse files Browse the repository at this point in the history
  • Loading branch information
akadlec committed Jul 20, 2024
1 parent f0d6d99 commit 76851f6
Show file tree
Hide file tree
Showing 8 changed files with 405 additions and 70 deletions.
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"php": ">=8.1.0",
"ext-openssl": "*",
"casbin/casbin": "^3.23",
"casbin/dbal-adapter": "^2.4",
"contributte/event-dispatcher": "^0.9",
"cweagans/composer-patches": "^1.7",
"fastybird/datetime-factory": "^0.6",
Expand Down
50 changes: 5 additions & 45 deletions src/DI/SimpleAuthExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
namespace FastyBird\SimpleAuth\DI;

use Casbin;
use CasbinAdapter;
use Doctrine\DBAL\Connection;
use Doctrine\Persistence;
use FastyBird\SimpleAuth;
use FastyBird\SimpleAuth\Events;
Expand Down Expand Up @@ -93,17 +91,6 @@ public function getConfigSchema(): Schema\Schema
),
'policy' => Schema\Expect::string(),
]),
'database' => Schema\Expect::anyOf(
Schema\Expect::null(),
Schema\Expect::structure([
'driver' => Schema\Expect::string('pdo_mysql'),
'host' => Schema\Expect::string('127.0.0.1'),
'port' => Schema\Expect::int(3_306),
'database' => Schema\Expect::string('security'),
'user' => Schema\Expect::string('root'),
'password' => Schema\Expect::string(),
]),
),
]);
}

Expand Down Expand Up @@ -294,38 +281,11 @@ public function beforeCompile(): void
*/

if ($configuration->enable->casbin->database) {
$connectionServiceName = $builder->getByType(Connection::class);

if ($connectionServiceName !== null) {
$connectionService = $builder->getDefinition($connectionServiceName);

$adapter = $builder->addDefinition(
$this->prefix('casbin.adapter'),
new DI\Definitions\ServiceDefinition(),
)
->setType(CasbinAdapter\DBAL\Adapter::class)
->setArguments([
'connection' => $connectionService,
])
->addSetup('$policyTableName', ['fb_security_policies']);
} else {
$adapter = $builder->addDefinition(
$this->prefix('casbin.adapter'),
new DI\Definitions\ServiceDefinition(),
)
->setType(CasbinAdapter\DBAL\Adapter::class)
->setArguments([
'connection' => [
'driver' => $configuration->database->driver,
'host' => $configuration->database->host,
'port' => $configuration->database->port,
'dbname' => $configuration->database->database,
'user' => $configuration->database->user,
'password' => $configuration->database->password,
'policy_table_name' => 'fb_security_policies',
],
]);
}
$adapter = $builder->addDefinition(
$this->prefix('casbin.adapter'),
new DI\Definitions\ServiceDefinition(),
)
->setType(SimpleAuth\Models\Casbin\Adapter::class);

$builder->addDefinition($this->prefix('casbin.subscriber'), new DI\Definitions\ServiceDefinition())
->setType(Subscribers\Policy::class);
Expand Down
40 changes: 28 additions & 12 deletions src/Entities/Policies/Policy.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#[ORM\Table(
name: 'fb_security_policies',
indexes: [
new ORM\Index(columns: ['p_type'], name: 'p_type_idx'),
new ORM\Index(columns: ['policy_type'], name: 'policy_type_idx'),
],
options: [
'collate' => 'utf8mb4_general_ci',
Expand All @@ -34,8 +34,7 @@
],
)]
#[ORM\InheritanceType('SINGLE_TABLE')]
#[ORM\DiscriminatorColumn(name: 'policy_type', type: 'string', length: 100)]
#[ORM\MappedSuperclass]
#[ORM\DiscriminatorColumn(name: 'policy_policy_type', type: 'string', length: 100)]
class Policy implements DoctrineCrud\Entities\IEntity
{

Expand All @@ -46,35 +45,35 @@ class Policy implements DoctrineCrud\Entities\IEntity

#[IPubDoctrine\Crud(required: true, writable: true)]
#[ORM\Column(
name: 'p_type',
name: 'policy_type',
type: 'string',
nullable: false,
enumType: Types\PolicyType::class,
)]
protected Types\PolicyType $type;

#[IPubDoctrine\Crud(writable: true)]
#[ORM\Column(name: 'v0', type: 'string', length: 150, nullable: true, options: ['default' => null])]
#[ORM\Column(name: 'policy_v0', type: 'string', length: 150, nullable: true, options: ['default' => null])]
protected string|null $v0 = null;

#[IPubDoctrine\Crud(writable: true)]
#[ORM\Column(name: 'v1', type: 'string', length: 150, nullable: true, options: ['default' => null])]
#[ORM\Column(name: 'policy_v1', type: 'string', length: 150, nullable: true, options: ['default' => null])]
protected string|null $v1 = null;

#[IPubDoctrine\Crud(writable: true)]
#[ORM\Column(name: 'v2', type: 'string', length: 150, nullable: true, options: ['default' => null])]
#[ORM\Column(name: 'policy_v2', type: 'string', length: 150, nullable: true, options: ['default' => null])]
protected string|null $v2 = null;

#[IPubDoctrine\Crud(writable: true)]
#[ORM\Column(name: 'v3', type: 'string', length: 150, nullable: true, options: ['default' => null])]
#[ORM\Column(name: 'policy_v3', type: 'string', length: 150, nullable: true, options: ['default' => null])]
protected string|null $v3 = null;

#[IPubDoctrine\Crud(writable: true)]
#[ORM\Column(name: 'v4', type: 'string', length: 150, nullable: true, options: ['default' => null])]
#[ORM\Column(name: 'policy_v4', type: 'string', length: 150, nullable: true, options: ['default' => null])]
protected string|null $v4 = null;

#[IPubDoctrine\Crud(writable: true)]
#[ORM\Column(name: 'v5', type: 'string', length: 150, nullable: true, options: ['default' => null])]
#[ORM\Column(name: 'policy_v5', type: 'string', length: 150, nullable: true, options: ['default' => null])]
protected string|null $v5 = null;

public function __construct(
Expand All @@ -99,9 +98,9 @@ public function getId(): Uuid\UuidInterface
return $this->id;
}

public function getType(): string
public function getType(): Types\PolicyType
{
return $this->type->value;
return $this->type;
}

public function getV0(): string|null
Expand Down Expand Up @@ -164,4 +163,21 @@ public function setV5(string|null $v5): void
$this->v5 = $v5;
}

/**
* @return array<string, string|null>
*/
public function toArray(): array
{
return [
'id' => $this->id->toString(),
'type' => $this->type->value,
'v0' => $this->v0,
'v1' => $this->v1,
'v2' => $this->v2,
'v3' => $this->v3,
'v4' => $this->v4,
'v5' => $this->v5,
];
}

}
178 changes: 178 additions & 0 deletions src/Models/Casbin/Adapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php declare(strict_types = 1);

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

namespace FastyBird\SimpleAuth\Models\Casbin;

use Casbin\Model as CasbinModel;
use Casbin\Persist as CasbinPersist;
use FastyBird\SimpleAuth\Exceptions;
use FastyBird\SimpleAuth\Models;
use FastyBird\SimpleAuth\Queries;
use FastyBird\SimpleAuth\Types\PolicyType;
use IPub\DoctrineCrud\Exceptions as DoctrineCrudExceptions;
use Nette\Utils\ArrayHash;
use TypeError;
use ValueError;
use function array_filter;
use function count;
use function implode;
use function intval;
use function range;
use function strval;
use function trim;
use function var_dump;

/**
* Casbin database adapter
*
* @package FastyBird:SimpleAuth!
* @subpackage Models
* @author Adam Kadlec <[email protected]>
*/
class Adapter implements CasbinPersist\Adapter
{

use CasbinPersist\AdapterHelper;

public function __construct(
private readonly Models\Policies\Repository $policiesRepository,
private readonly Models\Policies\Manager $policiesManager,
)
{
}

/**
* @param array<string, string|null> $rule
*
* @throws TypeError
* @throws ValueError
*/
public function savePolicyLine(string $ptype, array $rule): void
{
$data = [
'type' => PolicyType::from($ptype),
];

foreach ($rule as $key => $value) {
$data['v' . strval($key)] = $value;
}

$this->policiesManager->create(ArrayHash::from($data));
}

/**
* @throws Exceptions\InvalidState
*/
public function loadPolicy(CasbinModel\Model $model): void
{
$findPoliciesQuery = new Queries\FindPolicies();

$policies = $this->policiesRepository->findAllBy($findPoliciesQuery);

foreach ($policies as $policy) {
$data = [
$policy->getType()->value,
$policy->getV0(),
$policy->getV1(),
$policy->getV2(),
$policy->getV3(),
$policy->getV4(),
$policy->getV5(),
];

$line = implode(', ', array_filter($data, static fn ($val) => $val != '' && $val !== null));

$this->loadPolicyLine(trim($line), $model);
}
}

/**
* @throws TypeError
* @throws ValueError
*/
public function savePolicy(CasbinModel\Model $model): void
{
foreach ($model['p'] ?? [] as $type => $ast) {
foreach ($ast->policy as $rule) {
$this->savePolicyLine($type, $rule);
}
}

foreach ($model['g'] ?? [] as $type => $ast) {
foreach ($ast->policy as $rule) {
$this->savePolicyLine($type, $rule);
}
}
}

/**
* @throws TypeError
* @throws ValueError
*/
public function addPolicy(string $sec, string $ptype, array $rule): void
{
$this->savePolicyLine($ptype, $rule);
}

/**
* @throws DoctrineCrudExceptions\InvalidArgumentException
* @throws Exceptions\InvalidState
* @throws TypeError
* @throws ValueError
*/
public function removePolicy(string $sec, string $ptype, array $rule): void
{
$findPoliciesQuery = new Queries\FindPolicies();
$findPoliciesQuery->byType(PolicyType::from($ptype));

foreach ($rule as $key => $value) {
$findPoliciesQuery->byValue(intval($key), $value);
}

$policies = $this->policiesRepository->findAllBy($findPoliciesQuery);

foreach ($policies as $policy) {
$this->policiesManager->delete($policy);
}
}

/**
* @throws DoctrineCrudExceptions\InvalidArgumentException
* @throws Exceptions\InvalidState
* @throws TypeError
* @throws ValueError
*/
public function removeFilteredPolicy(string $sec, string $ptype, int $fieldIndex, string ...$fieldValues): void
{
var_dump('REMOVE 2');
$findPoliciesQuery = new Queries\FindPolicies();
$findPoliciesQuery->byType(PolicyType::from($ptype));

foreach (range(0, 5) as $value) {
if ($fieldIndex <= $value && $value < $fieldIndex + count($fieldValues)) {
if ($fieldValues[$value - $fieldIndex] != '') {
$findPoliciesQuery->byValue(intval($value), $fieldValues[$value - $fieldIndex]);
}
}
}

$policies = $this->policiesRepository->findAllBy($findPoliciesQuery);

foreach ($policies as $policy) {
$this->policiesManager->delete($policy);
}
}

}
10 changes: 10 additions & 0 deletions src/Queries/FindPolicies.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use FastyBird\SimpleAuth\Types;
use IPub\DoctrineOrmQuery;
use Ramsey\Uuid;
use function assert;

/**
* Find tokens entities query
Expand Down Expand Up @@ -55,6 +56,15 @@ public function byType(Types\PolicyType $type): void
};
}

public function byValue(int $key, string|null $value): void
{
assert($key >= 0 && $key <= 5);

$this->filter[] = static function (ORM\QueryBuilder $qb) use ($key, $value): void {
$qb->andWhere('p.v' . $key . ' = :v' . $key . 'value')->setParameter('v' . $key . 'value', $value);
};
}

/**
* @param ORM\EntityRepository<T> $repository
*/
Expand Down
Loading

0 comments on commit 76851f6

Please sign in to comment.