117 lines
3.8 KiB
PHP
117 lines
3.8 KiB
PHP
<?php declare(strict_types = 1);
|
|
|
|
namespace Notes\Security;
|
|
|
|
use Notes\Common\ReflectedAttribute;
|
|
use Taxus\Taxus;
|
|
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
use Notes\ObjectResolver;
|
|
use Taxus\TaxusGrantEnum;
|
|
|
|
class SecurityHandler {
|
|
|
|
protected ResponseInterface $redirectResponse;
|
|
|
|
protected \Closure|ResponseInterface|null $unauthorizeResponse;
|
|
|
|
protected ? Taxus $taxus;
|
|
|
|
public function __construct(ResponseInterface $redirectResponse, \Closure|ResponseInterface|null $unauthorizeResponse = null, ? Taxus $taxus = null) {
|
|
$this->redirectResponse = $redirectResponse;
|
|
$this->unauthorizeResponse = $unauthorizeResponse;
|
|
$this->taxus = $taxus;
|
|
}
|
|
|
|
public function verify(string $className, string $methodName) : ? ResponseInterface
|
|
{
|
|
return $this->isLocked($className, $methodName) ? $this->redirectResponse : null;
|
|
}
|
|
|
|
# @TODO Must HANDLE REALM !
|
|
public function isLocked(string $className, string $methodName) : bool
|
|
{
|
|
# Searching method first and fallbacking on object if none found
|
|
if ( $list = $this->findAttributes(Attribute\Security::class, $className, $methodName) ) {
|
|
return array_shift($list)->locked;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function taxus(string $className, string $methodName, ... $arguments) : ? ResponseInterface
|
|
{
|
|
$granted = $this->hasGrantPermission($className , $methodName, ...$arguments);
|
|
|
|
if ($granted) {
|
|
return null;
|
|
}
|
|
else {
|
|
if ($this->unauthorizeResponse) {
|
|
if ($this->unauthorizeResponse instanceof ResponseInterface) {
|
|
return $this->unauthorizeResponse;
|
|
}
|
|
|
|
return call_user_func_array($this->unauthorizeResponse, [ ...$arguments, ['method' => $methodName, 'object' => $className ], $className, $methodName ]);
|
|
}
|
|
else {
|
|
throw new \ErrorException("Unauthorized response given.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public function hasGrantPermission(string $className, string $methodName, ... $arguments) : bool
|
|
{
|
|
$fromObject = $this->findAttributes(Attribute\Taxus::class, $className);
|
|
$fromMethod = $this->findAttributes(Attribute\Taxus::class, $className, $methodName);
|
|
|
|
if ($fromMethod) {
|
|
return $this->taxusGrantPermission($fromMethod, ... $arguments);
|
|
}
|
|
elseif ($fromObject) {
|
|
return $this->taxusGrantPermission($fromObject, ... $arguments);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected function findAttributes(string $attribute, string $class, ? string $method = null) : array
|
|
{
|
|
$objectResolver = new ObjectResolver($class);
|
|
|
|
if ($method) {
|
|
$fromMethod = $objectResolver->reflectedClass->getMethods( false );
|
|
|
|
if (isset($fromMethod[$method])) {
|
|
$attributeList = $fromMethod[$method]->getAttributes($attribute);
|
|
|
|
if ($attributeList) {
|
|
return array_map(fn(ReflectedAttribute $ref) => $ref->object, $attributeList);
|
|
}
|
|
}
|
|
}
|
|
|
|
$attributeList = $objectResolver->reflectedClass->getAttributes(false, $attribute) ?: $objectResolver->reflectedClass->getAttributes(true, $attribute);
|
|
|
|
if ($attributeList) {
|
|
return array_map(fn(ReflectedAttribute $ref) => $ref->object, $attributeList);
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
protected function taxusGrantPermission(array $attributeList, ...$arguments) : bool
|
|
{
|
|
foreach ($attributeList as $item) {
|
|
if ( $grant = $this->taxus->granted($item->privilege, ... array_merge($arguments, [ $item ])) ) {
|
|
if (is_bool($grant) ? $grant : $grant === TaxusGrantEnum::Authorized) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|