From c2f0493d6a1e8f51919a86828c9f2a8a05353ac2 Mon Sep 17 00:00:00 2001 From: basakest Date: Wed, 24 Mar 2021 22:51:14 +0800 Subject: [PATCH 1/3] feat: support Casbin FilteredAdapter interface fix: add property fix: include necessary class --- src/Adapters/DatabaseAdapter.php | 66 ++++++++++++++++++++++- src/Contracts/FilteredDatabaseAdapter.php | 9 ++++ tests/DatabaseAdapterTest.php | 37 ++++++++++++- 3 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 src/Contracts/FilteredDatabaseAdapter.php diff --git a/src/Adapters/DatabaseAdapter.php b/src/Adapters/DatabaseAdapter.php index 2709253..770b0eb 100755 --- a/src/Adapters/DatabaseAdapter.php +++ b/src/Adapters/DatabaseAdapter.php @@ -7,7 +7,9 @@ use Lauthz\Models\Rule; use Lauthz\Contracts\DatabaseAdapter as DatabaseAdapterContract; use Lauthz\Contracts\BatchDatabaseAdapter as BatchDatabaseAdapterContract; -use Lauthz\Contracts\UpdatableDatabaseAdapter as UpdatableDatabaseAdapterContract; +use Lauthz\Contracts\UpdatableDatabaseAdapter as UpdatableDatabaseAdapterContract; +use Lauthz\Contracts\FilteredDatabaseAdapter as FilteredDatabaseAdapterContract; +use Casbin\Persist\Adapters\Filter; use Casbin\Model\Model; use Casbin\Persist\AdapterHelper; use DateTime; @@ -16,10 +18,15 @@ * * @author techlee@qq.com */ -class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterContract, UpdatableDatabaseAdapterContract +class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterContract, UpdatableDatabaseAdapterContract, FilteredDatabaseAdapterContract { use AdapterHelper; + /** + * @var bool + */ + private $filtered = false; + /** * Rules eloquent model. * @@ -232,4 +239,59 @@ public function updatePolicy(string $sec, string $ptype, array $oldRule, array $ } $instance->update($update); } + + /** + * Loads only policy rules that match the filter. + * + * @param Model $model + * @param mixed $filter + */ + public function loadFilteredPolicy(Model $model, $filter): void + { + $instance = $this->eloquent; + + if (is_string($filter)) { + $filter = str_replace(' ', '', $filter); + $filter = explode('=', $filter); + $instance = $instance->where($filter[0], $filter[1]); + } else if ($filter instanceof Filter) { + foreach($filter->p as $k => $v) { + $where[$v] = $filter->g[$k]; + $instance = $instance->where($v, $filter->g[$k]); + } + } else if ($filter instanceof \Closure) { + $filter($instance); + } else { + throw new \Exception('invalid filter type'); + } + $rows = $instance->get()->makeHidden(['created_at','updated_at', 'id'])->toArray(); + foreach ($rows as $row) { + $row = array_filter($row, function($value) { return !is_null($value) && $value !== ''; }); + $line = implode(', ', array_filter($row, function ($val) { + return '' != $val && !is_null($val); + })); + $this->loadPolicyLine(trim($line), $model); + } + $this->setFiltered(true); + } + + /** + * Returns true if the loaded policy has been filtered. + * + * @return bool + */ + public function isFiltered(): bool + { + return $this->filtered; + } + + /** + * Sets filtered parameter. + * + * @param bool $filtered + */ + public function setFiltered(bool $filtered): void + { + $this->filtered = $filtered; + } } diff --git a/src/Contracts/FilteredDatabaseAdapter.php b/src/Contracts/FilteredDatabaseAdapter.php new file mode 100644 index 0000000..4a30d53 --- /dev/null +++ b/src/Contracts/FilteredDatabaseAdapter.php @@ -0,0 +1,9 @@ +initTable(); + Enforcer::clearPolicy(); + $this->initConfig(); + $adapter = Enforcer::getAdapter(); + $adapter->setFiltered(true); + $this->assertEquals([], Enforcer::getPolicy()); + + // string + $filter = "v0 = bob"; + Enforcer::loadFilteredPolicy($filter); + $this->assertEquals([ + ['bob', 'data2', 'write'] + ], Enforcer::getPolicy()); + + // Filter + $filter = new Filter(['v2'], ['read']); + Enforcer::loadFilteredPolicy($filter); + $this->assertEquals([ + ['alice', 'data1', 'read'], + ['data2_admin', 'data2', 'read'], + ], Enforcer::getPolicy()); + + // Closure + Enforcer::loadFilteredPolicy(function (Rule &$rule) { + $rule = $rule->where('v1', 'data1'); + }); + + $this->assertEquals([ + ['alice', 'data1', 'read'], + ], Enforcer::getPolicy()); + } } From a4547b1291e57864bf8bf40d724b3b1015051989 Mon Sep 17 00:00:00 2001 From: basakest Date: Thu, 25 Mar 2021 09:26:49 +0800 Subject: [PATCH 2/3] fix: add support for invalid filter type --- src/Adapters/DatabaseAdapter.php | 3 ++- tests/DatabaseAdapterTest.php | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Adapters/DatabaseAdapter.php b/src/Adapters/DatabaseAdapter.php index 770b0eb..4aa601c 100755 --- a/src/Adapters/DatabaseAdapter.php +++ b/src/Adapters/DatabaseAdapter.php @@ -13,6 +13,7 @@ use Casbin\Model\Model; use Casbin\Persist\AdapterHelper; use DateTime; +use Casbin\Exceptions\InvalidFilterTypeException; /** * DatabaseAdapter. * @@ -262,7 +263,7 @@ public function loadFilteredPolicy(Model $model, $filter): void } else if ($filter instanceof \Closure) { $filter($instance); } else { - throw new \Exception('invalid filter type'); + throw new InvalidFilterTypeException('invalid filter type'); } $rows = $instance->get()->makeHidden(['created_at','updated_at', 'id'])->toArray(); foreach ($rows as $row) { diff --git a/tests/DatabaseAdapterTest.php b/tests/DatabaseAdapterTest.php index 403ee76..3decf27 100644 --- a/tests/DatabaseAdapterTest.php +++ b/tests/DatabaseAdapterTest.php @@ -6,6 +6,7 @@ use Illuminate\Foundation\Testing\DatabaseMigrations; use Casbin\Persist\Adapters\Filter; use Lauthz\Models\Rule; +use Casbin\Exceptions\InvalidFilterTypeException; class DatabaseAdapterTest extends TestCase { use DatabaseMigrations; @@ -139,6 +140,12 @@ public function testLoadFilteredPolicy() $adapter->setFiltered(true); $this->assertEquals([], Enforcer::getPolicy()); + // invalid filter type + $this->expectException(InvalidFilterTypeException::class); + $this->expectExceptionMessage('invalid filter type'); + $filter = ['alice', 'data1', 'read']; + Enforcer::loadFilteredPolicy($filter); + // string $filter = "v0 = bob"; Enforcer::loadFilteredPolicy($filter); From 8b3cd3ee504f16155a8e9263a40f32c9459c32eb Mon Sep 17 00:00:00 2001 From: basakest Date: Thu, 25 Mar 2021 09:31:52 +0800 Subject: [PATCH 3/3] fix: use try catch to invalid filter type --- tests/DatabaseAdapterTest.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/DatabaseAdapterTest.php b/tests/DatabaseAdapterTest.php index 3decf27..64d138a 100644 --- a/tests/DatabaseAdapterTest.php +++ b/tests/DatabaseAdapterTest.php @@ -141,10 +141,14 @@ public function testLoadFilteredPolicy() $this->assertEquals([], Enforcer::getPolicy()); // invalid filter type - $this->expectException(InvalidFilterTypeException::class); - $this->expectExceptionMessage('invalid filter type'); - $filter = ['alice', 'data1', 'read']; - Enforcer::loadFilteredPolicy($filter); + try { + $filter = ['alice', 'data1', 'read']; + Enforcer::loadFilteredPolicy($filter); + $e = InvalidFilterTypeException::class; + $this->fail("Expected exception $e not thrown"); + } catch (InvalidFilterTypeException $e) { + $this->assertEquals("invalid filter type", $e->getMessage()); + } // string $filter = "v0 = bob";