Skip to content

Commit

Permalink
fix(date-in-constructor) move date from constructor param to param of…
Browse files Browse the repository at this point in the history
… signature calculation methods

Co-Authored-By: istvan.szenasi@emarsys.com
  • Loading branch information
fqqdk committed Dec 13, 2018
1 parent c62531a commit 3393a15
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 38 deletions.
29 changes: 18 additions & 11 deletions src/Escher/Escher.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,21 @@ class Escher
const UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD';

private $credentialScope;
private $date;
private $clockSkew = self::DEFAULT_CLOCK_SKEW;
private $hashAlgo = self::DEFAULT_HASH_ALGORITHM;
private $algoPrefix = self::DEFAULT_ALGO_PREFIX;
private $vendorKey = self::DEFAULT_VENDOR_KEY;
private $authHeaderKey = self::DEFAULT_AUTH_HEADER_KEY;
private $dateHeaderKey = self::DEFAULT_DATE_HEADER_KEY;

public function __construct($credentialScope, \DateTime $date)
public function __construct($credentialScope)
{
$this->credentialScope = $credentialScope;
$this->date = $date;
}

public static function create($credentialScope, \DateTime $date = null)
public static function create($credentialScope)
{
return new Escher($credentialScope, $date ? $date : self::now());
return new Escher($credentialScope);
}

/**
Expand All @@ -45,6 +43,13 @@ private static function now()
return new \DateTime('now', new \DateTimeZone('GMT'));
}

/**
* @param $keyDB
* @param array|null $serverVars
* @param null $requestBody
* @return mixed
* @throws Exception
*/
public function authenticate($keyDB, array $serverVars = null, $requestBody = null)
{
$serverVars = null === $serverVars ? $_SERVER : $serverVars;
Expand All @@ -63,15 +68,16 @@ public function authenticate($keyDB, array $serverVars = null, $requestBody = nu
return $authElements->getAccessKeyId();
}

public function presignUrl($accessKeyId, $secretKey, $url, $expires = Escher::DEFAULT_EXPIRES)
public function presignUrl($accessKeyId, $secretKey, $url, $expires = Escher::DEFAULT_EXPIRES, \DateTime $date = null)
{
$url = $this->appendSigningParams($accessKeyId, $url, $this->date, $expires);
$date = $date ? $date : self::now();
$url = $this->appendSigningParams($accessKeyId, $url, $date, $expires);

list($host, $path, $query) = $this->parseUrl($url);

$signature = $this->calculateSignature(
$secretKey,
$this->date,
$date,
'GET',
$path,
$query,
Expand All @@ -84,18 +90,19 @@ public function presignUrl($accessKeyId, $secretKey, $url, $expires = Escher::DE
return $url;
}

public function signRequest($accessKeyId, $secretKey, $method, $url, $requestBody, $headerList = array(), $headersToSign = array())
public function signRequest($accessKeyId, $secretKey, $method, $url, $requestBody, $headerList = array(), $headersToSign = array(), \DateTime $date = null)
{
$date = $date ? $date : self::now();
list($host, $path, $query) = $this->parseUrl($url);
list($headerList, $headersToSign) = $this->addMandatoryHeaders(
$headerList, $headersToSign, $this->dateHeaderKey, $this->date, $host
$headerList, $headersToSign, $this->dateHeaderKey, $date, $host
);

return $headerList + $this->generateAuthHeader(
$secretKey,
$accessKeyId,
$this->authHeaderKey,
$this->date,
$date,
$method,
$path,
$query,
Expand Down
33 changes: 28 additions & 5 deletions test/unit/AuthenticateRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class AuthenticateRequestTest extends TestBase
{
/**
* @test
* @throws Exception
*/
public function itShouldAuthenticateRequestUsingAuthHeader()
{
Expand All @@ -32,6 +33,12 @@ public function itShouldAuthenticateRequestUsingAuthHeader()
/**
* @test
* @dataProvider validPortProvider
* @param $httpHost
* @param $serverName
* @param $serverPort
* @param $https
* @param $signature
* @throws Exception
*/
public function itShouldAuthenticateRequestRegardlessDefaultPortProvidedOrNot($httpHost, $serverName, $serverPort, $https, $signature)
{
Expand Down Expand Up @@ -70,6 +77,11 @@ public function validPortProvider()
/**
* @test
* @dataProvider requestTamperingProvider
* @param $tamperedKey
* @param $tamperedValue
* @param $expectedErrorMessage
* @param $expectedErrorCode
* @throws Exception
*/
public function itShouldFailToValidateInvalidRequests($tamperedKey, $tamperedValue, $expectedErrorMessage, $expectedErrorCode)
{
Expand Down Expand Up @@ -118,6 +130,7 @@ public function requestTamperingProvider()

/**
* @test
* @throws Exception
*/
public function itShouldValidateRequestUsingQueryString()
{
Expand All @@ -137,6 +150,7 @@ public function itShouldValidateRequestUsingQueryString()

/**
* @test
* @throws Exception
*/
public function itShouldValidatePresignedUrlRequestWithSpecialCharacters()
{
Expand All @@ -151,7 +165,7 @@ public function itShouldValidatePresignedUrlRequestWithSpecialCharacters()
'SERVER_NAME' => 'service.example.com',
);
$keyDB = array('service_api_key' => 'service_secret');
$this->createEscher('eu/service/ems_request', new \DateTime('20150310T173248Z', new \DateTimeZone('GMT')))->authenticate($keyDB, $serverVars);
$this->createEscher('eu/service/ems_request')->authenticate($keyDB, $serverVars);
}

/**
Expand Down Expand Up @@ -179,6 +193,7 @@ public function itShouldFailToValidateInvalidQueryStrings()

/**
* @test
* @throws Exception
*/
public function itShouldValidatePresignedUrlRequestWithUnindexedArray()
{
Expand All @@ -193,11 +208,12 @@ public function itShouldValidatePresignedUrlRequestWithUnindexedArray()
'SERVER_NAME' => 'service.example.com',
);
$keyDB = array('service_api_key' => 'service_secret');
$this->createEscher('eu/service/ems_request', new \DateTime('20150310T173248Z', new \DateTimeZone('GMT')))->authenticate($keyDB, $serverVars);
$this->createEscher('eu/service/ems_request')->authenticate($keyDB, $serverVars);
}

/**
* @test
* @throws Exception
*/
public function itShouldValidatePresignedUrlRequestWithIndexedArray()
{
Expand All @@ -212,11 +228,12 @@ public function itShouldValidatePresignedUrlRequestWithIndexedArray()
'SERVER_NAME' => 'service.example.com',
);
$keyDB = array('service_api_key' => 'service_secret');
$this->createEscher('eu/service/ems_request', new \DateTime('20150310T173248Z', new \DateTimeZone('GMT')))->authenticate($keyDB, $serverVars);
$this->createEscher('eu/service/ems_request')->authenticate($keyDB, $serverVars);
}

/**
* @test
* @throws Exception
*/
public function itShouldValidatePresignedUrlIfSignatureIsTheFirstParam()
{
Expand All @@ -231,11 +248,12 @@ public function itShouldValidatePresignedUrlIfSignatureIsTheFirstParam()
'SERVER_NAME' => 'service.example.com',
);
$keyDB = array('service_api_key' => 'service_secret');
$this->createEscher('eu/service/ems_request', new \DateTime('20150310T173248Z', new \DateTimeZone('GMT')))->authenticate($keyDB, $serverVars);
$this->createEscher('eu/service/ems_request')->authenticate($keyDB, $serverVars);
}

/**
* @test
* @throws Exception
*/
public function itShouldValidatePresignedUrlIfSignatureIsInTheMiddleOfTheQueryString()
{
Expand All @@ -250,9 +268,14 @@ public function itShouldValidatePresignedUrlIfSignatureIsInTheMiddleOfTheQuerySt
'SERVER_NAME' => 'service.example.com',
);
$keyDB = array('service_api_key' => 'service_secret');
$this->createEscher('eu/service/ems_request', new \DateTime('20150310T173248Z', new \DateTimeZone('GMT')))->authenticate($keyDB, $serverVars);
$this->createEscher('eu/service/ems_request')->authenticate($keyDB, $serverVars);
}

/**
* @param $dateString
* @return string
* @throws Exception
*/
private function strtotime($dateString)
{
return Utils::parseLongDate($dateString)->format('U');
Expand Down
20 changes: 10 additions & 10 deletions test/unit/SignRequestUsingHeaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function itShouldSignRequest()
$headersToSign = array('content-type', 'host', 'x-ems-date');
$actualHeaders = $this->createEscher('us-east-1/iam/aws4_request')->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEqualMaps($expectedHeaders, $actualHeaders);
}
Expand All @@ -47,7 +47,7 @@ public function itShouldSignRequestWithUppercaseHeader()
$headersToSign = array('content-type', 'host', 'x-ems-date', 'TEST');
$actualHeaders = $this->createEscher('us-east-1/iam/aws4_request')->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEqualMaps($expectedHeaders, $actualHeaders);
}
Expand All @@ -70,7 +70,7 @@ public function itShouldAutomagicallyAddHostHeader()
$headersToSign = array('content-type', 'host', 'x-ems-date');
$actualHeaders = $this->createEscher('us-east-1/iam/aws4_request')->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEqualMaps($expectedHeaders, $actualHeaders);
}
Expand All @@ -88,7 +88,7 @@ public function itShouldAutomagicallyAddHostHeaderWithPort($url, $expectedHost)
$headersToSign = array('content-type', 'host', 'x-ems-date');
$actualHeaders = $this->createEscher('us-east-1/iam/aws4_request')->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', $url, 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', $url, 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEquals($expectedHost, $actualHeaders['host']);
}
Expand Down Expand Up @@ -125,7 +125,7 @@ public function itShouldAutomagicallyAddDateAndHostToSignedHeaders()
$headersToSign = array('content-type');
$actualHeaders = $this->createEscher('us-east-1/iam/aws4_request')->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEqualMaps($expectedHeaders, $actualHeaders);
}
Expand All @@ -151,7 +151,7 @@ public function itShouldOnlySignHeadersExplicitlySetToBeSigned()
$headersToSign = array('content-type', 'host', 'x-ems-date');
$actualHeaders = $this->createEscher('us-east-1/iam/aws4_request')->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEqualMaps($expectedHeaders, $actualHeaders);
}
Expand All @@ -175,7 +175,7 @@ public function itShouldUseTheProvidedAuthHeaderName()
$headersToSign = array('content-type', 'host', 'x-ems-date');
$actualHeaders = $this->createEscher('us-east-1/iam/aws4_request')->setAuthHeaderKey('Custom-Auth-Header')->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEqualMaps($expectedHeaders, $actualHeaders);
}
Expand All @@ -200,7 +200,7 @@ public function itShouldUseTheProvidedAlgoPrefix()
$headersToSign = array('content-type', 'host', 'x-ems-date');
$actualHeaders = $escher->signRequest(
'AKIDEXAMPLE', 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign
'POST', 'http://iam.amazonaws.com/', 'Action=ListUsers&Version=2010-05-08', $inputHeaders, $headersToSign, $this->getDate()
);
$this->assertEqualMaps($expectedHeaders, $actualHeaders);
}
Expand All @@ -216,11 +216,11 @@ public function itShouldGenerateSignedHeaders()
);

$date = new DateTime('2011/05/11 12:00:00', new DateTimeZone("UTC"));
$escher = $this->createEscher('us-east-1/host/aws4_request', $date);
$escher = $this->createEscher('us-east-1/host/aws4_request');

$actualHeaders = $escher->signRequest(
'th3K3y', 'very_secure',
'GET', 'http://example.com/something', '', $inputHeaders, array()
'GET', 'http://example.com/something', '', $inputHeaders, array(), $date
);

$expectedHeaders = array(
Expand Down
13 changes: 8 additions & 5 deletions test/unit/SignRequestUsingQueryStringTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class SignRequestUsingQueryStringTest extends TestBase
*/
public function itShouldGenerateSignedUrl()
{
$signedUrl = $this->createEscher()->presignUrl('th3K3y', 'very_secure', 'http://example.com/something?foo=bar&baz=barbaz', $this->expires);
$signedUrl = $this->createEscher()->presignUrl('th3K3y', 'very_secure', 'http://example.com/something?foo=bar&baz=barbaz', $this->expires, $this->getDate());

$expectedSignedUrl = 'http://example.com/something?foo=bar&baz=barbaz&X-EMS-Algorithm=EMS-HMAC-SHA256&X-EMS-Credentials=th3K3y%2F20110511%2Fus-east-1%2Fhost%2Faws4_request&X-EMS-Date=20110511T120000Z&X-EMS-Expires=123456&X-EMS-SignedHeaders=host&X-EMS-Signature=fbc9dbb91670e84d04ad2ae7505f4f52ab3ff9e192b8233feeae57e9022c2b67';

Expand All @@ -21,7 +21,7 @@ public function itShouldGenerateSignedUrl()
*/
public function itShouldHandlePort()
{
$signedUrl = $this->createEscher()->presignUrl('th3K3y', 'very_secure', 'http://example.com:5000/something?foo=bar&baz=barbaz', $this->expires);
$signedUrl = $this->createEscher()->presignUrl('th3K3y', 'very_secure', 'http://example.com:5000/something?foo=bar&baz=barbaz', $this->expires, $this->getDate());

$expectedSignedUrl = 'http://example.com:5000/something?foo=bar&baz=barbaz&X-EMS-Algorithm=EMS-HMAC-SHA256&X-EMS-Credentials=th3K3y%2F20110511%2Fus-east-1%2Fhost%2Faws4_request&X-EMS-Date=20110511T120000Z&X-EMS-Expires=123456&X-EMS-SignedHeaders=host&X-EMS-Signature=7f7032b393945a0167fe65d35a7e2827a781ecab9019d814adf95c23bfa5e458';

Expand All @@ -33,7 +33,7 @@ public function itShouldHandlePort()
*/
public function itShouldRespectWhenUrlHasLocationHash()
{
$signedUrl = $this->createEscher()->presignUrl('th3K3y', 'very_secure', 'http://example.com:5000/something?foo=bar&baz=barbaz#/client_fragment', $this->expires);
$signedUrl = $this->createEscher()->presignUrl('th3K3y', 'very_secure', 'http://example.com:5000/something?foo=bar&baz=barbaz#/client_fragment', $this->expires, $this->getDate());

$expectedSignedUrl = 'http://example.com:5000/something?foo=bar&baz=barbaz&X-EMS-Algorithm=EMS-HMAC-SHA256&X-EMS-Credentials=th3K3y%2F20110511%2Fus-east-1%2Fhost%2Faws4_request&X-EMS-Date=20110511T120000Z&X-EMS-Expires=123456&X-EMS-SignedHeaders=host&X-EMS-Signature=7f7032b393945a0167fe65d35a7e2827a781ecab9019d814adf95c23bfa5e458#/client_fragment';

Expand All @@ -45,10 +45,13 @@ public function itShouldRespectWhenUrlHasLocationHash()
*/
public function itShouldRespectWhenUrlHasSpecialChars()
{
$signedUrl = $this->createEscher('eu/service/ems_request', new DateTime('20150310T173248Z', new DateTimeZone('GMT')))->presignUrl(
$date = new DateTime('20150310T173248Z', new DateTimeZone('GMT'));
$signedUrl = $this->createEscher('eu/service/ems_request')->presignUrl(
'service_api_key',
'service_secret',
'https://service.example.com/login?id=12345678&domain=login.example.com&redirect_to=https%3A%2F%2Fhome.dev%2Fbootstrap.php%3Fr%3Dservice%2Findex%26service%3Dservice_name%3F'
'https://service.example.com/login?id=12345678&domain=login.example.com&redirect_to=https%3A%2F%2Fhome.dev%2Fbootstrap.php%3Fr%3Dservice%2Findex%26service%3Dservice_name%3F',
\Escher\Escher::DEFAULT_EXPIRES,
$date
);

$expectedSignedUrl = 'https://service.example.com/login?id=12345678&domain=login.example.com&redirect_to=https%3A%2F%2Fhome.dev%2Fbootstrap.php%3Fr%3Dservice%2Findex%26service%3Dservice_name%3F&X-EMS-Algorithm=EMS-HMAC-SHA256&X-EMS-Credentials=service_api_key%2F20150310%2Feu%2Fservice%2Fems_request&X-EMS-Date=20150310T173248Z&X-EMS-Expires=86400&X-EMS-SignedHeaders=host&X-EMS-Signature=661f2147c77b6784be5a60a8b842a96de6327653f1ed5d4305da43103c69a6f5';
Expand Down
9 changes: 2 additions & 7 deletions test/unit/TestBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,11 @@ protected function assertEqualMaps(array $expected, array $actual, $message = ''

/**
* @param string $credentialScope
* @param DateTime $date
* @return Escher
*/
protected function createEscher($credentialScope = 'us-east-1/host/aws4_request', $date = null)
protected function createEscher($credentialScope = 'us-east-1/host/aws4_request')
{
if (is_null($date))
{
$date = $this->getDate();
}
return Escher::create($credentialScope, $date)
return Escher::create($credentialScope)
->setAlgoPrefix('EMS')->setVendorKey('EMS')->setAuthHeaderKey('X-Ems-Auth')->setDateHeaderKey('X-Ems-Date');
}

Expand Down

0 comments on commit 3393a15

Please sign in to comment.