/** * {@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); }
/** * Handle other requests * * @param EventInterface $event The event instance */ public function queueRequest(EventInterface $event) { $request = $event->getRequest(); $eventName = $event->getName(); $urls = (array) $this->params[$eventName]; $data = ['event' => $eventName, 'url' => $request->getRawUri(), 'imageIdentifier' => $request->getImageIdentifier(), 'publicKey' => $request->getPublicKey()]; foreach ($urls as $url) { $this->requestQueue[] = $this->getHttpClient()->post($url, null, $data); } }
/** * {@inheritdoc} */ public function checkAccessToken(EventInterface $event) { $request = $event->getRequest(); $response = $event->getResponse(); $query = $request->query; $eventName = $event->getName(); $config = $event->getConfig(); 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 = [$request->getRawUri(), $request->getUriAsIs()]; $privateKey = $event->getAccessControl()->getPrivateKey($request->getPublicKey()); // append uris with [] expanded or [0] reduced $uris[] = $this->getUnescapedAlternativeURL($request->getRawUri()); $uris[] = $this->getEscapedAlternativeURL($request->getRawUri()); // See if we should modify the protocol for the incoming request $protocol = $config['authentication']['protocol']; if ($protocol === 'both') { $uris = array_reduce($uris, function ($dest, $uri) { $baseUrl = preg_replace('#^https?#', '', $uri); $dest[] = 'http' . $baseUrl; $dest[] = 'https' . $baseUrl; return $dest; }, []); } else { if (in_array($protocol, ['http', 'https'])) { $uris = array_map(function ($uri) use($protocol) { return preg_replace('#^https?#', $protocol, $uri); }, $uris); } } 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), '&?'); $correctToken = hash_hmac('sha256', $uri, $privateKey); if ($correctToken === $token) { return; } } throw new RuntimeException('Incorrect access token', 400); }
/** * Inject the image blob from the image model into the shared imagick instance * * @param EventInterface $event The event instance */ public function readImageBlob(EventInterface $event) { if ($event->hasArgument('image')) { // The image has been specified as an argument to the event $image = $event->getArgument('image'); } else { if ($event->getName() === 'images.post') { // The image is found in the request $image = $event->getRequest()->getImage(); } else { // The image is found in the response $image = $event->getResponse()->getModel(); } } // Inject the image blob $this->imagick->readImageBlob($image->getBlob()); }
/** * Delete all short URLs for a given image * * @param EventInterface $event */ public function deleteImageShortUrls(EventInterface $event) { $request = $event->getRequest(); $publicKey = $request->getPublicKey(); $imageIdentifier = $request->getImageIdentifier(); $event->getDatabase()->deleteShortUrls($publicKey, $imageIdentifier); if ($event->getName() === 'shorturls.delete') { // If the request is against the shorturls resource directly we need to supply a // response model. If this method is triggered because of an image has been deleted // the image resource will supply the response model $model = new ArrayModel(); $model->setData(array('imageIdentifier' => $imageIdentifier)); $event->getResponse()->setModel($model); } }
/** * Check if the public key used has access to this resource for this user * * @param EventInterface $event * @throws RuntimeException If public key does not have access to the resource */ public function checkAccess(EventInterface $event) { if ($event->hasArgument('skipAccessControl') && $event->getArgument('skipAccessControl') === true) { return; } $request = $event->getRequest(); $aclAdapter = $event->getAccessControl(); $resource = $event->getName(); $publicKey = $request->getPublicKey(); $user = $request->getUser(); $hasAccess = $aclAdapter->hasAccess($publicKey, $resource, $user); if ($hasAccess) { return; } // If we're asking for info on a public key, and that public key happens to be the one // used to sign the request, accept this as a valid request and let the user have access // to the resource. Note that this requires the accessToken listener to be in place - // if disabled, any user can ask for the access rules for all public keys if (in_array($resource, $this->ownPublicKeyAllowedResources)) { $routePubKey = $request->getRoute()->get('publickey'); if ($routePubKey === $publicKey) { return; } } // If a public key has access to resources within a resource group, allow the // public key to access the group resource to see which resources it contains if (in_array($resource, $this->groupLookupResources)) { $routeGroup = $request->getRoute()->get('group'); $aclList = $aclAdapter->getAccessListForPublicKey($publicKey); foreach ($aclList as $aclRule) { if (isset($aclRule['groups']) && in_array($routeGroup, $aclRule['groups'])) { return; } } } throw new RuntimeException('Permission denied (public key)', 400); }