/** * {@inheritdoc} */ public function checkAccessToken(EventInterface $event) { $request = $event->getRequest(); $response = $event->getResponse(); $query = $request->query; $eventName = $event->getName(); if (($eventName === 'image.get' || $eventName === 'image.head') && $this->isWhitelisted($request)) { // All transformations in the request are whitelisted. Skip the access token check return; } // If the response has a short URL header, we can skip the access token check if ($response->headers->has('X-Imbo-ShortUrl')) { return; } if (!$query->has('accessToken')) { throw new RuntimeException('Missing access token', 400); } $token = $query->get('accessToken'); // First the the raw un-encoded URI, then the URI as is $uris = array($request->getRawUri(), $request->getUriAsIs()); $privateKeys = $event->getUserLookup()->getPrivateKeys($request->getPublicKey()) ?: []; foreach ($uris as $uri) { // Remove the access token from the query string as it's not used to generate the HMAC $uri = rtrim(preg_replace('/(?<=(\\?|&))accessToken=[^&]+&?/', '', $uri), '&?'); foreach ($privateKeys as $privateKey) { $correctToken = hash_hmac('sha256', $uri, $privateKey); if ($correctToken === $token) { return; } } } throw new RuntimeException('Incorrect access token', 400); }
/** * Load stats * * @param EventInterface $event An event instance */ public function loadStats(EventInterface $event) { $response = $event->getResponse(); $database = $event->getDatabase(); $userLookup = $event->getUserLookup(); $publicKeys = $userLookup->getPublicKeys(); $users = array(); foreach ($publicKeys as $key) { $users[$key] = array('numImages' => $database->getNumImages($key), 'numBytes' => $database->getNumBytes($key)); } $statsModel = new Model\Stats(); $statsModel->setUsers($users); $response->setModel($statsModel); }
/** * {@inheritdoc} */ public function authenticate(EventInterface $event) { $response = $event->getResponse(); $request = $event->getRequest(); // Whether or not the authentication info is in the request headers $fromHeaders = $request->headers->has('x-imbo-authenticate-timestamp') && $request->headers->has('x-imbo-authenticate-signature'); // Fetch timestamp header, fallback to query param $timestamp = $request->headers->get('x-imbo-authenticate-timestamp', $request->query->get('timestamp')); if (!$timestamp) { $exception = new RuntimeException('Missing authentication timestamp', 400); $exception->setImboErrorCode(Exception::AUTH_MISSING_PARAM); } else { if (!$this->timestampIsValid($timestamp)) { $exception = new RuntimeException('Invalid timestamp: ' . $timestamp, 400); $exception->setImboErrorCode(Exception::AUTH_INVALID_TIMESTAMP); } else { if ($this->timestampHasExpired($timestamp)) { $exception = new RuntimeException('Timestamp has expired: ' . $timestamp, 400); $exception->setImboErrorCode(Exception::AUTH_TIMESTAMP_EXPIRED); } } } if (isset($exception)) { throw $exception; } // Fetch signature header, fallback to query param $signature = $request->headers->get('x-imbo-authenticate-signature', $request->query->get('signature')); if (!$signature) { $exception = new RuntimeException('Missing authentication signature', 400); $exception->setImboErrorCode(Exception::AUTH_MISSING_PARAM); } if (isset($exception)) { throw $exception; } $publicKey = $request->getPublicKey(); $privateKeys = $event->getUserLookup()->getPrivateKeys($publicKey, UserLookupInterface::MODE_READ_WRITE) ?: []; $url = $request->getRawUri(); if (!$fromHeaders) { // Remove the signature and timestamp from the query parameters as they are not used // when generating the HMAC $url = rtrim(preg_replace('/(?<=(\\?|&))(signature|timestamp)=[^&]+&?/', '', $url), '&?'); } // Add the URL used for auth to the response headers $response->headers->set('X-Imbo-AuthUrl', $url); if (!$this->signatureIsValid($request->getMethod(), $url, $publicKey, $privateKeys, $timestamp, $signature)) { $exception = new RuntimeException('Signature mismatch', 400); $exception->setImboErrorCode(Exception::AUTH_SIGNATURE_MISMATCH); throw $exception; } }