Commit | Line | Data |
---|---|---|
66ea2662 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
41498ac5 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
66ea2662 | 5 | | | |
41498ac5 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
66ea2662 TO |
9 | +--------------------------------------------------------------------+ |
10 | */ | |
11 | namespace Civi\API\Subscriber; | |
12 | ||
13 | use Civi\API\Events; | |
14 | use Civi\API\Event\AuthorizeEvent; | |
15 | use Civi\API\Event\RespondEvent; | |
66ea2662 TO |
16 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
17 | ||
18 | /** | |
19 | * The WhitelistSubscriber listens to API requests and matches them against | |
20 | * a whitelist of allowed API calls. If an API call does NOT appear in the | |
21 | * whitelist, then it generates an error. | |
22 | * | |
23 | * @package Civi | |
ca5cec67 | 24 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
66ea2662 TO |
25 | */ |
26 | class WhitelistSubscriber implements EventSubscriberInterface { | |
27 | ||
28 | /** | |
29 | * @return array | |
30 | */ | |
31 | public static function getSubscribedEvents() { | |
c64f69d9 CW |
32 | return [ |
33 | Events::AUTHORIZE => ['onApiAuthorize', Events::W_EARLY], | |
34 | Events::RESPOND => ['onApiRespond', Events::W_MIDDLE], | |
35 | ]; | |
66ea2662 TO |
36 | } |
37 | ||
38 | /** | |
39 | * Array(WhitelistRule). | |
40 | * | |
41 | * @var array | |
42 | */ | |
43 | protected $rules; | |
44 | ||
45 | /** | |
46 | * Array (scalar $reqId => WhitelistRule $rule). | |
47 | * | |
48 | * @var array | |
49 | */ | |
50 | protected $activeRules; | |
51 | ||
52 | /** | |
53 | * @param array $rules | |
54 | * Array of WhitelistRule. | |
55 | * @see WhitelistRule | |
066c4638 | 56 | * @throws \CRM_Core_Exception |
66ea2662 TO |
57 | */ |
58 | public function __construct($rules) { | |
c64f69d9 | 59 | $this->rules = []; |
66ea2662 | 60 | foreach ($rules as $rule) { |
34f3bbd9 | 61 | /** @var \Civi\API\WhitelistRule $rule */ |
66ea2662 TO |
62 | if ($rule->isValid()) { |
63 | $this->rules[] = $rule; | |
64 | } | |
65 | else { | |
66 | throw new \CRM_Core_Exception("Invalid rule"); | |
67 | } | |
68 | } | |
69 | } | |
70 | ||
71 | /** | |
72 | * Determine which, if any, whitelist rules apply this request. | |
73 | * Reject unauthorized requests. | |
74 | * | |
34f3bbd9 | 75 | * @param \Civi\API\Event\AuthorizeEvent $event |
66ea2662 TO |
76 | * @throws \CRM_Core_Exception |
77 | */ | |
78 | public function onApiAuthorize(AuthorizeEvent $event) { | |
79 | $apiRequest = $event->getApiRequest(); | |
80 | if (empty($apiRequest['params']['check_permissions']) || $apiRequest['params']['check_permissions'] !== 'whitelist') { | |
81 | return; | |
82 | } | |
83 | foreach ($this->rules as $rule) { | |
84 | if (TRUE === $rule->matches($apiRequest)) { | |
85 | $this->activeRules[$apiRequest['id']] = $rule; | |
86 | return; | |
87 | } | |
88 | } | |
89 | throw new \CRM_Core_Exception('The request does not match any active API authorizations.'); | |
90 | } | |
91 | ||
92 | /** | |
93 | * Apply any filtering rules based on the chosen whitelist rule. | |
34f3bbd9 | 94 | * @param \Civi\API\Event\RespondEvent $event |
66ea2662 TO |
95 | */ |
96 | public function onApiRespond(RespondEvent $event) { | |
97 | $apiRequest = $event->getApiRequest(); | |
98 | $id = $apiRequest['id']; | |
99 | if (isset($this->activeRules[$id])) { | |
100 | $event->setResponse($this->activeRules[$id]->filter($apiRequest, $event->getResponse())); | |
101 | unset($this->activeRules[$id]); | |
102 | } | |
103 | } | |
104 | ||
105 | } |