1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Tonic\Component\ApiLayer\JsonRpcExtensions\Security\Method; |
4
|
|
|
|
5
|
|
|
use Doctrine\Common\Annotations\Reader; |
6
|
|
|
use Symfony\Component\PropertyAccess\PropertyAccessor; |
7
|
|
|
use Tonic\Component\ApiLayer\JsonRpc\Method\MethodInvokerInterface; |
8
|
|
|
use Tonic\Component\ApiLayer\JsonRpcExtensions\Security\Annotation\Attribute; |
9
|
|
|
use Tonic\Component\ApiLayer\JsonRpcExtensions\Security\Exception\AccessDeniedException; |
10
|
|
|
use Tonic\Component\ApiLayer\JsonRpcExtensions\Security\GuardInterface; |
11
|
|
|
use Tonic\Component\ApiLayer\JsonRpcExtensions\Security\UserProviderInterface; |
12
|
|
|
use Tonic\Component\Reflection\ReflectionFunctionFactory; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Decorator for method invoker, which allows to secure method invokation. |
16
|
|
|
*/ |
17
|
|
|
class SecurableMethodInvoker implements MethodInvokerInterface |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* @var MethodInvokerInterface |
21
|
|
|
*/ |
22
|
|
|
private $methodInvoker; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var UserProviderInterface |
26
|
|
|
*/ |
27
|
|
|
private $userProvider; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var GuardInterface |
31
|
|
|
*/ |
32
|
|
|
private $guard; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var Reader |
36
|
|
|
*/ |
37
|
|
|
private $annotationReader; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var PropertyAccessor |
41
|
|
|
*/ |
42
|
|
|
private $propertyAccessor; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @param MethodInvokerInterface $methodInvoker |
46
|
|
|
* @param UserProviderInterface $userProvider |
47
|
|
|
* @param GuardInterface $guard |
48
|
|
|
* @param Reader $annotationReader |
49
|
|
|
* @param PropertyAccessor $propertyAccessor |
50
|
|
|
*/ |
51
|
|
|
public function __construct( |
52
|
|
|
MethodInvokerInterface $methodInvoker, |
53
|
|
|
UserProviderInterface $userProvider, |
54
|
|
|
GuardInterface $guard, |
55
|
|
|
Reader $annotationReader, |
56
|
|
|
PropertyAccessor $propertyAccessor |
57
|
|
|
) { |
58
|
|
|
$this->methodInvoker = $methodInvoker; |
59
|
|
|
$this->userProvider = $userProvider; |
60
|
|
|
$this->guard = $guard; |
61
|
|
|
$this->annotationReader = $annotationReader; |
62
|
|
|
$this->propertyAccessor = $propertyAccessor; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* {@inheritdoc} |
67
|
|
|
*/ |
68
|
|
|
public function invoke(callable $callable, $requestObject) |
69
|
|
|
{ |
70
|
|
|
/** @var Attribute $attributeAnnotation */ |
71
|
|
|
$attributeAnnotation = $this->annotationReader->getMethodAnnotation(ReflectionFunctionFactory::createFromCallable($callable), Attribute::class); |
|
|
|
|
72
|
|
|
$attributeName = $attributeAnnotation->name; |
73
|
|
|
$attributeValue = $this->propertyAccessor->getValue($requestObject, $attributeAnnotation->valueAt); |
74
|
|
|
|
75
|
|
|
$userId = $this->userProvider->getUserId(); |
76
|
|
|
if ((!is_array($attributeValue)) && (!$this->guard->isGranted($userId, $attributeName, $attributeValue))) { |
77
|
|
|
throw new AccessDeniedException(); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
if (is_array($attributeValue)) { |
81
|
|
|
$attributeValue = $this->guard->filterGranted($userId, $attributeName, $attributeValue); |
82
|
|
|
$this->propertyAccessor->setValue($requestObject, $attributeAnnotation->valueAt, $attributeValue); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
return $this->methodInvoker->invoke($callable, $requestObject); |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.