PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Request / AuthenticationToken.php
matomo / app / core / Request Last commit date
AuthenticationToken.php 3 months ago
AuthenticationToken.php
190 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik\Request;
10
11 use Piwik\API\Request as ApiRequest;
12 use Piwik\Http\BadRequestException;
13 use Piwik\Piwik;
14 use Piwik\Request;
15 use Piwik\SettingsServer;
16 /**
17 * Main class to handle actions related to auth tokens.
18 */
19 class AuthenticationToken
20 {
21 /** @var string */
22 protected $authToken = '';
23 /** @var bool */
24 protected $wasTokenProvidedSecurely = \false;
25 /** @var bool */
26 protected $isSessionToken = \false;
27 /** @var bool */
28 protected $isConflictingAuthValidationDone = \false;
29 /** @var bool */
30 protected $isJsonRequestBodyTokenLoaded = \false;
31 /** @var string|null */
32 protected $jsonRequestBodyTokenAuth = null;
33 /**
34 * @param array<string, mixed>|null $request
35 */
36 public function getAuthToken(?array $request = null) : string
37 {
38 $this->detectToken();
39 if ($request !== null) {
40 return (new Request($request))->getStringParameter('token_auth', '');
41 }
42 return $this->authToken;
43 }
44 /**
45 * Returns true if a token_auth parameter was supplied via a secure mechanism and is not present as a URL parameter
46 *
47 * @return bool True if token was supplied in a secure way
48 */
49 public function wasTokenAuthProvidedSecurely() : bool
50 {
51 $this->detectToken();
52 return $this->wasTokenProvidedSecurely;
53 }
54 public function isSessionToken() : bool
55 {
56 $this->detectToken();
57 return $this->isSessionToken;
58 }
59 private function detectToken() : void
60 {
61 $this->validateNoConflictingAuthParameters();
62 $this->initTokenFromHeader() || $this->initTokenFromJsonRequestBody() || $this->initTokenFromPostRequest() || $this->initTokenFromGetRequest();
63 }
64 private function validateNoConflictingAuthParameters() : void
65 {
66 if ($this->isConflictingAuthValidationDone || $this->shouldSkipConflictingAuthValidation()) {
67 return;
68 }
69 $this->isConflictingAuthValidationDone = \true;
70 $tokenAuthBySource = [];
71 $forceApiSessionBySource = [];
72 $headerTokenAuth = $this->getTokenAuthFromHeader();
73 if (!empty($headerTokenAuth)) {
74 $tokenAuthBySource['header'] = $headerTokenAuth;
75 }
76 $jsonTokenAuth = $this->getTokenAuthFromJsonRequestBody();
77 if (!empty($jsonTokenAuth)) {
78 $tokenAuthBySource['json'] = $jsonTokenAuth;
79 }
80 $post = Request::fromPost();
81 $postTokenAuth = $post->getStringParameter('token_auth', '');
82 if (!empty($postTokenAuth)) {
83 $tokenAuthBySource['post'] = $postTokenAuth;
84 }
85 if (array_key_exists('force_api_session', $_POST)) {
86 $forceApiSessionBySource['post'] = $post->getBoolParameter('force_api_session', \false);
87 }
88 $get = Request::fromGet();
89 $getTokenAuth = $get->getStringParameter('token_auth', '');
90 if (!empty($getTokenAuth)) {
91 $tokenAuthBySource['get'] = $getTokenAuth;
92 }
93 if (array_key_exists('force_api_session', $_GET)) {
94 $forceApiSessionBySource['get'] = $get->getBoolParameter('force_api_session', \false);
95 }
96 $this->throwIfValuesConflict($tokenAuthBySource);
97 $this->throwIfValuesConflict($forceApiSessionBySource);
98 }
99 private function shouldSkipConflictingAuthValidation() : bool
100 {
101 return ApiRequest::isRootRequestApiRequest() && !ApiRequest::isCurrentApiRequestTheRootApiRequest();
102 }
103 /**
104 * @param array<string, bool|string> $valuesBySource
105 */
106 private function throwIfValuesConflict(array $valuesBySource) : void
107 {
108 if (count($valuesBySource) < 2) {
109 return;
110 }
111 $firstValue = array_shift($valuesBySource);
112 foreach ($valuesBySource as $value) {
113 if ($value !== $firstValue) {
114 throw new BadRequestException(Piwik::translate('General_ConflictingAuthenticationParametersProvided'));
115 }
116 }
117 }
118 private function initTokenFromHeader() : bool
119 {
120 $tokenAuth = $this->getTokenAuthFromHeader();
121 if ($tokenAuth !== null) {
122 $this->authToken = $tokenAuth;
123 $this->wasTokenProvidedSecurely = \true;
124 return \true;
125 }
126 return \false;
127 }
128 private function initTokenFromJsonRequestBody() : bool
129 {
130 $tokenAuth = $this->getTokenAuthFromJsonRequestBody();
131 if (!empty($tokenAuth)) {
132 $this->authToken = $tokenAuth;
133 $this->wasTokenProvidedSecurely = \true;
134 return \true;
135 }
136 return \false;
137 }
138 private function initTokenFromPostRequest() : bool
139 {
140 $request = Request::fromPost();
141 $tokenAuth = $request->getStringParameter('token_auth', '');
142 if ($tokenAuth !== '') {
143 $this->authToken = $tokenAuth;
144 $this->wasTokenProvidedSecurely = \true;
145 $this->isSessionToken = $request->getBoolParameter('force_api_session', \false);
146 return \true;
147 }
148 return \false;
149 }
150 private function initTokenFromGetRequest() : bool
151 {
152 $request = Request::fromGet();
153 $tokenAuth = $request->getStringParameter('token_auth', '');
154 if ($tokenAuth !== '') {
155 $this->authToken = $tokenAuth;
156 $this->wasTokenProvidedSecurely = \false;
157 $this->isSessionToken = $request->getBoolParameter('force_api_session', \false);
158 return \true;
159 }
160 return \false;
161 }
162 private function getTokenAuthFromHeader() : ?string
163 {
164 if (!empty($_SERVER['HTTP_AUTHORIZATION']) && strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer ') === 0) {
165 return substr($_SERVER['HTTP_AUTHORIZATION'], 7);
166 }
167 return null;
168 }
169 private function getTokenAuthFromJsonRequestBody() : ?string
170 {
171 if ($this->isJsonRequestBodyTokenLoaded) {
172 return $this->jsonRequestBodyTokenAuth;
173 }
174 $this->isJsonRequestBodyTokenLoaded = \true;
175 $this->jsonRequestBodyTokenAuth = null;
176 // Token in JSON request body is only supported for tracking requests
177 if (!SettingsServer::isTrackerApiRequest()) {
178 return null;
179 }
180 $requestBody = file_get_contents('php://input');
181 if (!empty($requestBody) && strpos($requestBody, '{') === 0) {
182 $jsonContent = json_decode($requestBody, \true);
183 if (is_array($jsonContent) && !empty($jsonContent['token_auth']) && is_string($jsonContent['token_auth'])) {
184 $this->jsonRequestBodyTokenAuth = $jsonContent['token_auth'];
185 }
186 }
187 return $this->jsonRequestBodyTokenAuth;
188 }
189 }
190