/** * {@inheritDoc} */ public function authenticate(RequestInterface $request) { $authHeader = AuthorizationHeader::createFromRequest($request); $signature = $authHeader->getSignature(); // Check whether the timestamp is valid. $comparison = $this->compareTimestamp($request, $this->expiry); if (-1 == $comparison) { throw new TimestampOutOfRangeException('Request is too old'); } elseif (1 == $comparison) { throw new TimestampOutOfRangeException('Request is too far in the future'); } // Load the API Key and sign the request. if (!($key = $this->keyLoader->load($authHeader->getId()))) { throw new KeyNotFoundException('API key not found'); } // Generate the signature from the passed authorization header. // If it matches the request signature, the request is authenticated. $compareRequest = $request->withoutHeader('Authorization'); $authHeaderBuilder = new AuthorizationHeaderBuilder($compareRequest, $key); $authHeaderBuilder->setRealm($authHeader->getRealm()); $authHeaderBuilder->setId($authHeader->getId()); $authHeaderBuilder->setNonce($authHeader->getNonce()); $authHeaderBuilder->setVersion($authHeader->getVersion()); $authHeaderBuilder->setCustomHeaders($authHeader->getCustomHeaders()); $compareAuthHeader = $authHeaderBuilder->getAuthorizationHeader(); $compareSignature = $compareAuthHeader->getSignature(); if (!hash_equals($compareSignature, $signature)) { throw new InvalidSignatureException('Signature not valid'); } return $key; }
/** * Ensures an exception is thrown if the request has expired. * * @expectedException \Acquia\Hmac\Exception\TimestampOutOfRangeException */ public function testExpiredRequest() { $authId = key($this->keys); $headers = ['Content-Type' => 'text/plain', 'X-Authorization-Timestamp' => 1, 'Authorization' => 'acquia-http-hmac realm="Pipet service",' . 'id="' . $authId . '",' . 'nonce="d1954337-5319-4821-8427-115542e08d10",' . 'version="2.0",' . 'headers="",' . 'signature="bRlPr/Z1WQz2sMthcaEqETRMw4gPYXlPcTpaLWS2gcc="']; $request = new Request('GET', 'https://example.com/test', $headers); $authHeader = AuthorizationHeader::createFromRequest($request); $authenticator = new MockRequestAuthenticator(new MockKeyLoader($this->keys), $authHeader); $authenticator->authenticate($request); }
/** * {@inheritDoc} */ public function signResponse(ResponseInterface $response) { $authHeader = AuthorizationHeader::createFromRequest($this->request); $parts = [$authHeader->getNonce(), $this->request->getHeaderLine('X-Authorization-Timestamp'), (string) $response->getBody()]; $message = implode("\n", $parts); $signature = $this->digest->sign($message, $this->key->getSecret()); /** @var \Psr\Http\Message\ResponseInterface $response */ $response = $response->withHeader('X-Server-Authorization-HMAC-SHA256', $signature); return $response; }
/** * {@inheritDoc} */ public function getAuthorizedRequest(RequestInterface $request, array $customHeaders = []) { if ($request->hasHeader('Authorization')) { $authHeader = AuthorizationHeader::createFromRequest($request); } else { $authHeader = $this->buildAuthorizationHeader($request, $customHeaders); } /** @var RequestInterface $request */ $request = $request->withHeader('Authorization', (string) $authHeader); return $request; }
/** * Ensures an exception is thrown when a required field is missing. * * @param $field * The authorization header field. * * @dataProvider requiredFieldsProvider * * @expectedException \Acquia\Hmac\Exception\MalformedRequestException * @expectedExceptionMessage Authorization header requires a realm, id, version, nonce and a signature. */ public function testParseAuthorizationHeaderRequiredFields($field) { $headers = ['Authorization' => preg_replace('/' . $field . '=/', '', $this->header)]; $request = new Request('GET', 'http://example.com', $headers); try { AuthorizationHeader::createFromRequest($request); } catch (MalformedRequestException $e) { $this->assertSame($request, $e->getRequest()); throw $e; } }