permittedPaths = $apiUrls['permittedPaths']; $this->simplePaths = $apiUrls['simplePaths']; $this->externalPaths = $apiUrls['externalPaths']; } protected array $permittedPaths; protected array $simplePaths; protected array $externalPaths; public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { if ($this->validExternal($request)) { return $handler->handle($request); } try { $key = $this->apiService->getKey($request); } catch (MissingAuthorizationHeader $exception) { $this->logger->warning($exception, [ 'headers' => $request->getHeaders() ]); return $this->responseFactory->createResponse(401); } if ($this->validateSimpleKey($request, $key)) { return $handler->handle($request); } if ($this->validate($request, $key)) { return $handler->handle($request); } $this->logger->warning("Forbidden.", [ 'headers' => $request->getHeaders() ]); return $this->responseFactory->createResponse(403); } protected function validate(ServerRequestInterface $request, $incoming_key): bool { $selector = null; $token = null; if (str_contains($incoming_key, $this->loginService->getSeparator())) { list($incoming_key, $selector, $token) = explode($this->loginService->getSeparator(), $incoming_key, 3); if (!$this->loginService->isIn($selector, $token)) { return false; } } if (!$this->loginService->isIn($selector, $token) and !$this->validPermitted($request)) { return false; } return $incoming_key === md5($this->key); } protected function validateSimpleKey(ServerRequestInterface $request, $incoming_key): bool { return $incoming_key === md5($this->key) and $this->noComplexKeyNeeded($request); } protected function noComplexKeyNeeded(ServerRequestInterface $request): bool { $uri = $request->getUri(); return in_array($uri->getPath(), $this->simplePaths); } protected function validPermitted(ServerRequestInterface $request): bool { $uri = $request->getUri(); return in_array($uri->getPath(), $this->permittedPaths); } protected function validExternal(ServerRequestInterface $request): bool { $uri = $request->getUri(); foreach ($this->externalPaths as $basePath => $paths) { if (!str_starts_with($uri->getPath(), strtolower($basePath))) { continue; } foreach ($paths as $subPath => $key) { $fullPath = strtolower("{$basePath}{$subPath}"); if ($uri->getPath() === $fullPath) { return $this->validateExternalKey($request, $basePath, $subPath); } } } return false; } protected function validateExternalKey(ServerRequestInterface $request, $basePath, $subPath): bool { $data = $this->externalPaths[$basePath][$subPath]; if (isset($data['validator'])) { $method = [$data['validator'], 'validateToken']; if ($method($request, $data)) { $this->logger->info("Validated external key", [ 'path' => $request->getUri()->getPath(), 'headers' => $request->getHeaders(), 'body' => $request->getBody()->getContents() ]); return true; } } if (isset($data['header']) and $request->hasHeader($data['header'])) { $token = $request->getHeaderLine($data['header']); if ($token === $this->externalPaths[$basePath][$subPath]['token']) { return true; } } if ($request->hasHeader('x-api-key')) { $key = $request->getHeaderLine('x-api-key'); if ($key === $this->externalPaths[$basePath][$subPath]) { return true; } } if ($request->hasHeader('Authorization')) { $key = $request->getHeaderLine('Authorization'); if (str_starts_with($key, 'Bearer ')) { $key = substr($key, 7); if ($key === $this->externalPaths[$basePath][$subPath]) { return true; } } } $this->logger->warning("Failed to validate external key", [ 'path' => $request->getUri()->getPath(), 'headers' => $request->getHeaders(), 'token' => $this->externalPaths[$basePath][$subPath], 'body' => $request->getBody()->getContents() ]); return false; } }