public function authenticate(EventInterface $event)
{
$response = $event->getResponse();
$request = $event->getRequest();
$config = $event->getConfig();
// 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();
$privateKey = $event->getAccessControl()->getPrivateKey($publicKey);
$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), '&?');
}
// See if we should modify the protocol for the incoming request
$uris = [$url];
$protocol = $config['authentication']['protocol'];
if ($protocol === 'both') {
$uris = [preg_replace('#^https?#', 'http', $url), preg_replace('#^https?#', 'https', $url)];
} else {
if (in_array($protocol, ['http', 'https'])) {
$uris = [preg_replace('#^https?#', $protocol, $url)];
}
}
// Add the URL used for auth to the response headers
$response->headers->set('X-Imbo-AuthUrl', implode(', ', $uris));
foreach ($uris as $uri) {
if ($this->signatureIsValid($request->getMethod(), $uri, $publicKey, $privateKey, $timestamp, $signature)) {
return;
}
}
$exception = new RuntimeException('Signature mismatch', 400);
$exception->setImboErrorCode(Exception::AUTH_SIGNATURE_MISMATCH);
throw $exception;
}