kopia lustrzana https://github.com/pixelfed/pixelfed
				
				
				
			Add HTTPSignature tests
							rodzic
							
								
									c01dc18d04
								
							
						
					
					
						commit
						75fa22ea0f
					
				|  | @ -0,0 +1,20 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use App\Util\HttpSignatures\HeaderList; | ||||
| 
 | ||||
| class HeaderListTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     public function testToString() | ||||
|     { | ||||
|         $hl = new HeaderList(['(request-target)', 'Date']); | ||||
|         $this->assertEquals('(request-target) date', $hl->string()); | ||||
|     } | ||||
| 
 | ||||
|     public function testFromStringRoundTripNormalized() | ||||
|     { | ||||
|         $hl = HeaderList::fromString('(request-target) Accept'); | ||||
|         $this->assertEquals('(request-target) accept', $hl->string()); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,190 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use GuzzleHttp\Psr7\Request; | ||||
| use App\Util\HttpSignatures\Context; | ||||
| 
 | ||||
| class HmacContextTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     private $context; | ||||
| 
 | ||||
|     public function setUp() | ||||
|     { | ||||
|         $this->noDigestContext = new Context([ | ||||
|             'keys' => ['pda' => 'secret'], | ||||
|             'algorithm' => 'hmac-sha256', | ||||
|             'headers' => ['(request-target)', 'date'], | ||||
|         ]); | ||||
|         $this->withDigestContext = new Context([ | ||||
|             'keys' => ['pda' => 'secret'], | ||||
|             'algorithm' => 'hmac-sha256', | ||||
|             'headers' => ['(request-target)', 'date', 'digest'], | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     public function testSignerNoDigestAction() | ||||
|     { | ||||
|         $message = new Request('GET', '/path?query=123', ['date' => 'today', 'accept' => 'llamas']); | ||||
|         $message = $this->noDigestContext->signer()->sign($message); | ||||
| 
 | ||||
|         $expectedString = implode(',', [ | ||||
|             'keyId="pda"', | ||||
|             'algorithm="hmac-sha256"', | ||||
|             'headers="(request-target) date"', | ||||
|             'signature="SFlytCGpsqb/9qYaKCQklGDvwgmrwfIERFnwt+yqPJw="', | ||||
|         ]); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedString, | ||||
|             $message->getHeader('Signature')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             'Signature '.$expectedString, | ||||
|             $message->getHeader('Authorization')[0] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSignerAddDigestToHeadersList() | ||||
|     { | ||||
|         $message = new Request( | ||||
|             'POST', '/path/to/things?query=123', | ||||
|             ['date' => 'today', 'accept' => 'llamas'], | ||||
|             'Thing to POST'); | ||||
|         $message = $this->noDigestContext->signer()->signWithDigest($message); | ||||
| 
 | ||||
|         $expectedString = implode(',', [ | ||||
|             'keyId="pda"', | ||||
|             'algorithm="hmac-sha256"', | ||||
|             'headers="(request-target) date digest"', | ||||
|             'signature="HH6R3OJmJbKUFqqL0tGVIIb7xi1WbbSh/HBXHUtLkUs="', ]); | ||||
|         $expectedDigestHeader = | ||||
|           'SHA-256=rEcNhYZoBKiR29D30w1JcgArNlF8rXIXf5MnIL/4kcc='; | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedString, | ||||
|             $message->getHeader('Signature')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedDigestHeader, | ||||
|             $message->getHeader('Digest')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             'Signature '.$expectedString, | ||||
|             $message->getHeader('Authorization')[0] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSignerReplaceDigest() | ||||
|     { | ||||
|         $message = new Request( | ||||
|             'PUT', '/things/thething?query=123', | ||||
|               ['date' => 'today', | ||||
|               'accept' => 'llamas', | ||||
|               'Digest' => 'SHA-256=E/P+4y4x6EySO9qNAjCtQKxVwE1xKsNI/k+cjK+vtLU=', ], | ||||
|             'Thing to PUT at /things/thething please...'); | ||||
|         $message = $this->noDigestContext->signer()->signWithDigest($message); | ||||
| 
 | ||||
|         $expectedString = implode(',', [ | ||||
|             'keyId="pda"', | ||||
|             'algorithm="hmac-sha256"', | ||||
|             'headers="(request-target) date digest"', | ||||
|             'signature="Hyatt1lSR/4XLI9Gcx8XOEKiG8LVktH7Lfr+0tmhwRU="', ]); | ||||
|         $expectedDigestHeader = | ||||
|           'SHA-256=mulOx+77mQU1EbPET50SCGA4P/4bYxVCJA1pTwJsaMw='; | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedString, | ||||
|             $message->getHeader('Signature')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedDigestHeader, | ||||
|             $message->getHeader('Digest')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             'Signature '.$expectedString, | ||||
|             $message->getHeader('Authorization')[0] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSignerNewDigestIsInHeaderList() | ||||
|     { | ||||
|         $message = new Request( | ||||
|             'POST', '/path?query=123', | ||||
|               ['date' => 'today', | ||||
|               'accept' => 'llamas', ], | ||||
|             'Stuff that belongs in /path'); | ||||
|         $message = $this->withDigestContext->signer()->signWithDigest($message); | ||||
| 
 | ||||
|         $expectedString = implode(',', [ | ||||
|             'keyId="pda"', | ||||
|             'algorithm="hmac-sha256"', | ||||
|             'headers="(request-target) date digest"', | ||||
|             'signature="p8gQHs59X2WzQLUecfmxm1YO0OBTCNKldRZZBQsepfk="', ]); | ||||
|         $expectedDigestHeader = | ||||
|           'SHA-256=jnSMEfBSum4Rh2k6/IVFyvLuQLmGYwMAGBS9WybyDqQ='; | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedString, | ||||
|             $message->getHeader('Signature')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedDigestHeader, | ||||
|             $message->getHeader('Digest')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             'Signature '.$expectedString, | ||||
|             $message->getHeader('Authorization')[0] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSignerNewDigestWithoutBody() | ||||
|     { | ||||
|         $message = new Request( | ||||
|             'GET', '/path?query=123', | ||||
|               ['date' => 'today', | ||||
|               'accept' => 'llamas', ]); | ||||
|         $message = $this->withDigestContext->signer()->signWithDigest($message); | ||||
| 
 | ||||
|         $expectedString = implode(',', [ | ||||
|             'keyId="pda"', | ||||
|             'algorithm="hmac-sha256"', | ||||
|             'headers="(request-target) date digest"', | ||||
|             'signature="7iFqqryI6I9opV/Zp3eEg6PDY1tKw/3GqioOM7ACHHA="', ]); | ||||
|         $zeroLengthStringDigest = | ||||
|           'SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='; | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedString, | ||||
|             $message->getHeader('Signature')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $zeroLengthStringDigest, | ||||
|             $message->getHeader('Digest')[0] | ||||
|         ); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             'Signature '.$expectedString, | ||||
|             $message->getHeader('Authorization')[0] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testVerifier() | ||||
|     { | ||||
|         $message = $this->noDigestContext->signer()->sign(new Request('GET', '/path?query=123', [ | ||||
|             'Signature' => 'keyId="pda",algorithm="hmac-sha1",headers="date",signature="x"', | ||||
|             'Date' => 'x', | ||||
|         ])); | ||||
| 
 | ||||
|         // assert it works without errors; correctness of results tested elsewhere.
 | ||||
|         $this->assertTrue(is_bool($this->noDigestContext->verifier()->isValid($message))); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,16 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use App\Util\HttpSignatures\KeyStore; | ||||
| 
 | ||||
| class KeyStoreHmacTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     public function testFetchHmacSuccess() | ||||
|     { | ||||
|         $ks = new KeyStore(['hmacsecret' => 'ThisIsASecretKey']); | ||||
|         $key = $ks->fetch('hmacsecret'); | ||||
|         $this->assertEquals(['hmacsecret', 'ThisIsASecretKey', 'ThisIsASecretKey', 'secret'], [ | ||||
|           $key->getId(), $key->getVerifyingKey(), $key->getSigningKey(), $key->getType(), ]); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,114 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use App\Util\HttpSignatures\KeyStore; | ||||
| use App\Util\HttpSignatures\Key; | ||||
| use Tests\Unit\HttpSignatures\TestKeys; | ||||
| 
 | ||||
| class KeyStoreRsaTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     public function setUp() | ||||
|     { | ||||
|         openssl_pkey_export( | ||||
|             openssl_pkey_get_private(TestKeys::rsaPrivateKey), | ||||
|             $this->testRsaPrivateKeyPEM | ||||
|         ); | ||||
|         $this->testRsaPublicKeyPEM = openssl_pkey_get_details( | ||||
|             openssl_get_publickey(TestKeys::rsaPublicKey) | ||||
|         )['key']; | ||||
|         $this->testRsaCert = TestKeys::rsaCert; | ||||
|     } | ||||
| 
 | ||||
|     public function testParseX509inObject() | ||||
|     { | ||||
|         $keySpec = ['rsaCert' => [TestKeys::rsaCert]]; | ||||
|         $this->assertTrue(Key::hasX509Certificate($keySpec)); | ||||
| 
 | ||||
|         $ks = new KeyStore($keySpec); | ||||
|         $publicKey = $ks->fetch('rsaCert')->getVerifyingKey(); | ||||
|         $this->assertEquals('asymmetric', $ks->fetch('rsaCert')->getType()); | ||||
|         $this->assertEquals(TestKeys::rsaPublicKey, $publicKey); | ||||
|     } | ||||
| 
 | ||||
|     public function testParseRsaPublicKeyinObject() | ||||
|     { | ||||
|         $keySpec = ['rsaPubKey' => [TestKeys::rsaPublicKey]]; | ||||
|         $this->assertTrue(Key::hasPublicKey($keySpec)); | ||||
| 
 | ||||
|         $ks = new KeyStore($keySpec); | ||||
|         $publicKey = $ks->fetch('rsaPubKey')->getVerifyingKey(); | ||||
|         $this->assertEquals('asymmetric', $ks->fetch('rsaPubKey')->getType()); | ||||
|         $this->assertEquals(TestKeys::rsaPublicKey, $publicKey); | ||||
|     } | ||||
| 
 | ||||
|     public function testParsePrivateKeyinObject() | ||||
|     { | ||||
|         $keySpec = ['rsaPrivKey' => [TestKeys::rsaPrivateKey]]; | ||||
|         $this->assertTrue(Key::hasPrivateKey($keySpec)); | ||||
| 
 | ||||
|         $ks = new KeyStore($keySpec); | ||||
|         $publicKey = $ks->fetch('rsaPrivKey')->getSigningKey(); | ||||
|         $this->assertEquals('asymmetric', $ks->fetch('rsaPrivKey')->getType()); | ||||
|         $this->assertEquals($this->testRsaPrivateKeyPEM, $publicKey); | ||||
|     } | ||||
| 
 | ||||
|     public function testFetchRsaSigningKeySuccess() | ||||
|     { | ||||
|         $ks = new KeyStore(['rsakey' => TestKeys::rsaPrivateKey]); | ||||
|         $key = $ks->fetch('rsakey'); | ||||
|         openssl_pkey_export($key->getSigningKey(), $keyStoreSigningKey); | ||||
|         $this->assertEquals(['rsakey', $this->testRsaPrivateKeyPEM, null, 'asymmetric'], [ | ||||
|           $key->getId(), $keyStoreSigningKey, $key->getVerifyingKey(), $key->getType(), ]); | ||||
|     } | ||||
| 
 | ||||
|     public function testFetchRsaVerifyingKeyFromCertificateSuccess() | ||||
|     { | ||||
|         $ks = new KeyStore(['rsacert' => TestKeys::rsaCert]); | ||||
|         $key = $ks->fetch('rsacert'); | ||||
|         $keyStoreVerifyingKey = $key->getVerifyingKey(); | ||||
|         $this->assertEquals(['rsacert', null, $this->testRsaPublicKeyPEM, 'asymmetric'], [ | ||||
|           $key->getId(), $key->getSigningKey(), $keyStoreVerifyingKey, $key->getType(), ]); | ||||
|     } | ||||
| 
 | ||||
|     public function testFetchRsaVerifyingKeyFromPublicKeySuccess() | ||||
|     { | ||||
|         $ks = new KeyStore(['rsapubkey' => TestKeys::rsaPublicKey]); | ||||
|         $key = $ks->fetch('rsapubkey'); | ||||
|         $keyStoreVerifyingKey = $key->getVerifyingKey(); | ||||
|         $this->assertEquals(['rsapubkey', null, $this->testRsaPublicKeyPEM, 'asymmetric'], [ | ||||
|           $key->getId(), $key->getSigningKey(), $keyStoreVerifyingKey, $key->getType(), ]); | ||||
|     } | ||||
| 
 | ||||
|     public function testFetchRsaBothSuccess() | ||||
|     { | ||||
|         $ks = new KeyStore(['rsaboth' => [TestKeys::rsaCert, TestKeys::rsaPrivateKey]]); | ||||
|         $key = $ks->fetch('rsaboth'); | ||||
|         $keyStoreVerifyingKey = $key->getVerifyingKey(); | ||||
|         $keyStoreSigningKey = $key->getSigningKey(); | ||||
|         $this->assertEquals(['rsaboth', $this->testRsaPrivateKeyPEM, $this->testRsaPublicKeyPEM, 'asymmetric'], [ | ||||
|           $key->getId(), $keyStoreSigningKey, $keyStoreVerifyingKey, $key->getType(), ]); | ||||
|     } | ||||
| 
 | ||||
|     public function testFetchRsaBothSuccessSwitched() | ||||
|     { | ||||
|         $ks = new KeyStore(['rsabothswitch' => [TestKeys::rsaPrivateKey, TestKeys::rsaCert]]); | ||||
|         $key = $ks->fetch('rsabothswitch'); | ||||
|         $keyStoreVerifyingKey = $key->getVerifyingKey(); | ||||
|         $keyStoreSigningKey = $key->getSigningKey(); | ||||
|         $this->assertEquals(['rsabothswitch', $this->testRsaPrivateKeyPEM, $this->testRsaPublicKeyPEM, 'asymmetric'], [ | ||||
|           $key->getId(), $keyStoreSigningKey, $keyStoreVerifyingKey, $key->getType(), ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @expectedException \App\Util\HttpSignatures\KeyException | ||||
|      */ | ||||
|     public function testRsaMismatch() | ||||
|     { | ||||
|         $privateKey = openssl_pkey_new([ | ||||
|           'private_key_type' => 'OPENSSL_KEYTYPE_RSA', | ||||
|           'private_key_bits' => 1024, ] | ||||
|         ); | ||||
|         $ks = new Key('badpki', [TestKeys::rsaCert, $privateKey]); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,17 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use App\Util\HttpSignatures\KeyStore; | ||||
| 
 | ||||
| class KeyStoreTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     /** | ||||
|      * @expectedException App\Util\HttpSignatures\Exception | ||||
|      */ | ||||
|     public function testFetchFail() | ||||
|     { | ||||
|         $ks = new KeyStore(['id' => 'secret']); | ||||
|         $key = $ks->fetch('nope'); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,84 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use GuzzleHttp\Psr7\Request; | ||||
| use App\Util\HttpSignatures\Context; | ||||
| use Tests\Unit\HttpSignatures\TestKeys; | ||||
| 
 | ||||
| class RsaContextTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     private $context; | ||||
| 
 | ||||
|     public function setUp() | ||||
|     { | ||||
|         $this->sha1context = new Context([ | ||||
|             'keys' => ['rsa1' => TestKeys::rsaPrivateKey], | ||||
|             'algorithm' => 'rsa-sha1', | ||||
|             'headers' => ['(request-target)', 'date'], | ||||
|         ]); | ||||
|         $this->sha256context = new Context([ | ||||
|             'keys' => ['rsa1' => TestKeys::rsaPrivateKey], | ||||
|             'algorithm' => 'rsa-sha256', | ||||
|             'headers' => ['(request-target)', 'date'], | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     public function testSha1Signer() | ||||
|     { | ||||
|         $message = new Request('GET', '/path?query=123', ['date' => 'today', 'accept' => 'llamas']); | ||||
| 
 | ||||
|         $message = $this->sha1context->signer()->sign($message); | ||||
|         $expectedSha1String = implode(',', [ | ||||
|             'keyId="rsa1"', | ||||
|             'algorithm="rsa-sha1"', | ||||
|             'headers="(request-target) date"', | ||||
|             'signature="YIR3DteE3Jmz1VAnUMTgjTn3vTKfQuZl1CJhMBvGOZpnzwKeYBXA'. | ||||
|               'H108FojnbSeVG/AXq9pcrA6AFK0peg0aueqxpaFlo+4L/q5XzJ+QoryY3dlSr'. | ||||
|               'xwVnE5s5M19xmFm/6YkZR/KPeANCsG4SPL82Um/PCEMU0tmKd6sSx+IIzAYbX'. | ||||
|               'G/VrFMDeQAdXqpU1EhgxopKEAapN8rChb49+1JfR/RxlSKiLukJJ6auurm2zM'. | ||||
|               'n2D40fR1d2umA5LAO7vRt2iQwVbtwiFkVlRqkMvGftCNZByu8jJ6StI5H7Efu'. | ||||
|               'ANSHAZXKXWNH8yxpBUW/QCHCZjPd0ugM0QJJIc7i8JbGlA=="', | ||||
|         ]); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedSha1String, | ||||
|             $message->getHeader('Signature')[0] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSha256Signer() | ||||
|     { | ||||
|         $message = new Request('GET', '/path?query=123', ['date' => 'today', 'accept' => 'llamas']); | ||||
| 
 | ||||
|         $message = $this->sha256context->signer()->sign($message); | ||||
|         $expectedSha256String = implode(',', [ | ||||
|             'keyId="rsa1"', | ||||
|             'algorithm="rsa-sha256"', | ||||
|             'headers="(request-target) date"', | ||||
|             'signature="WGIegQCC3GEwxbkuXtq67CAqeDhkwblxAH2uoDx5kfWurhLRA5WB'. | ||||
|             'FDA/aktsZAjuUoimG1w4CGxSecziER1ez44PBlHP2fCW4ArLgnQgcjkdN2cOf/g'. | ||||
|             'j0OVL8s2usG4o4tud/+jjF3nxTxLl3HC+erBKsJakwXbw9kt4Cr028BToVfNXsW'. | ||||
|             'oMFpv0IjcgBH2V41AVlX/mYBMMJAihBCIcpgAcGrrxmG2gkfvSn09wtTttkGHft'. | ||||
|             'PIp3VpB53zbemlJS9Yw3tmmHr6cvWSXqQy/bTsEOoQJ2REfn5eiyzsJu3GiOpiI'. | ||||
|             'LK67i/WH9moltJtlfV57TV72cgYtjWa6yqhtFg=="', | ||||
|         ]); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             $expectedSha256String, | ||||
|             $message->getHeader('Signature')[0] | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @expectedException     App\Util\HttpSignatures\AlgorithmException | ||||
|      */ | ||||
|     public function testRsaBadalgorithm() | ||||
|     { | ||||
|         $sha224context = new Context([ | ||||
|               'keys' => ['rsa1' => TestKeys::rsaPrivateKey], | ||||
|               'algorithm' => 'rsa-sha224', | ||||
|               'headers' => ['(request-target)', 'date'], | ||||
|           ]); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,156 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use GuzzleHttp\Psr7\Request; | ||||
| use App\Util\HttpSignatures\KeyStore; | ||||
| use App\Util\HttpSignatures\Verifier; | ||||
| use Tests\Unit\HttpSignatures\TestKeys; | ||||
| 
 | ||||
| class VerifierRsaTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     const DATE = 'Fri, 01 Aug 2014 13:44:32 -0700'; | ||||
|     const DATE_DIFFERENT = 'Fri, 01 Aug 2014 13:44:33 -0700'; | ||||
| 
 | ||||
|     /** | ||||
|      * @var Verifier | ||||
|      */ | ||||
|     private $verifier; | ||||
| 
 | ||||
|     /** | ||||
|      * @var Request | ||||
|      */ | ||||
|     private $message; | ||||
| 
 | ||||
|     public function setUp() | ||||
|     { | ||||
|         $this->setUpRsaVerifier(); | ||||
| 
 | ||||
|         $sha1SignatureHeader = | ||||
|         'keyId="rsa1",algorithm="rsa-sha1",headers="(request-target) date",'. | ||||
|         'signature="YIR3DteE3Jmz1VAnUMTgjTn3vTKfQuZl1CJhMBvGOZpnzwKeYBXAH10'. | ||||
|         '8FojnbSeVG/AXq9pcrA6AFK0peg0aueqxpaFlo+4L/q5XzJ+QoryY3dlSrxwVnE5s5'. | ||||
|         'M19xmFm/6YkZR/KPeANCsG4SPL82Um/PCEMU0tmKd6sSx+IIzAYbXG/VrFMDeQAdXq'. | ||||
|         'pU1EhgxopKEAapN8rChb49+1JfR/RxlSKiLukJJ6auurm2zMn2D40fR1d2umA5LAO7'. | ||||
|         'vRt2iQwVbtwiFkVlRqkMvGftCNZByu8jJ6StI5H7EfuANSHAZXKXWNH8yxpBUW/QCH'. | ||||
|         'CZjPd0ugM0QJJIc7i8JbGlA=="'; | ||||
| 
 | ||||
|         $this->sha1Message = new Request('GET', '/path?query=123', [ | ||||
|             'Date' => 'today', | ||||
|             'Signature' => $sha1SignatureHeader, | ||||
|         ]); | ||||
| 
 | ||||
|         $sha256SignatureHeader = | ||||
|         'keyId="rsa1",algorithm="rsa-sha256",headers="(request-target) date",'. | ||||
|         'signature="WGIegQCC3GEwxbkuXtq67CAqeDhkwblxAH2uoDx5kfWurhLRA5WBFDA/a'. | ||||
|         'ktsZAjuUoimG1w4CGxSecziER1ez44PBlHP2fCW4ArLgnQgcjkdN2cOf/gj0OVL8s2us'. | ||||
|         'G4o4tud/+jjF3nxTxLl3HC+erBKsJakwXbw9kt4Cr028BToVfNXsWoMFpv0IjcgBH2V4'. | ||||
|         '1AVlX/mYBMMJAihBCIcpgAcGrrxmG2gkfvSn09wtTttkGHftPIp3VpB53zbemlJS9Yw3'. | ||||
|         'tmmHr6cvWSXqQy/bTsEOoQJ2REfn5eiyzsJu3GiOpiILK67i/WH9moltJtlfV57TV72c'. | ||||
|         'gYtjWa6yqhtFg=="'; | ||||
| 
 | ||||
|         $this->sha256Message = new Request('GET', '/path?query=123', [ | ||||
|             'Date' => 'today', | ||||
|             'Signature' => $sha256SignatureHeader, | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     private function setUpRsaVerifier() | ||||
|     { | ||||
|         $keyStore = new KeyStore(['rsa1' => TestKeys::rsaPublicKey]); | ||||
|         $this->verifier = new Verifier($keyStore); | ||||
|     } | ||||
| 
 | ||||
|     public function testVerifyValidRsaMessage() | ||||
|     { | ||||
|         $this->assertTrue($this->verifier->isValid($this->sha1Message)); | ||||
|         $this->assertTrue($this->verifier->isValid($this->sha256Message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testVerifyValidRsaMessageAuthorizationHeader() | ||||
|     { | ||||
|         $message = $this->sha1Message->withHeader( | ||||
|           'Authorization', | ||||
|           "Signature {$this->sha1Message->getHeader('Signature')[0]}"); | ||||
|         $message = $this->sha1Message->withoutHeader('Signature'); | ||||
| 
 | ||||
|         $this->assertTrue($this->verifier->isValid($this->sha1Message)); | ||||
| 
 | ||||
|         $message = $this->sha256Message->withHeader( | ||||
|           'Authorization', | ||||
|           "Signature {$this->sha256Message->getHeader('Signature')[0]}"); | ||||
|         $message = $this->sha256Message->withoutHeader('Signature'); | ||||
| 
 | ||||
|         $this->assertTrue($this->verifier->isValid($this->sha256Message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectTamperedRsaRequestMethod() | ||||
|     { | ||||
|         $message = $this->sha1Message->withMethod('POST'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|         $message = $this->sha256Message->withMethod('POST'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectTamperedRsaDate() | ||||
|     { | ||||
|         $message = $this->sha1Message->withHeader('Date', self::DATE_DIFFERENT); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|         $message = $this->sha256Message->withHeader('Date', self::DATE_DIFFERENT); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectTamperedRsaSignature() | ||||
|     { | ||||
|         $message = $this->sha1Message->withHeader( | ||||
|             'Signature', | ||||
|             preg_replace('/signature="/', 'signature="x', $this->sha1Message->getHeader('Signature')[0]) | ||||
|         ); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|         $message = $this->sha256Message->withHeader( | ||||
|             'Signature', | ||||
|             preg_replace('/signature="/', 'signature="x', $this->sha256Message->getHeader('Signature')[0]) | ||||
|         ); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectRsaMessageWithoutSignatureHeader() | ||||
|     { | ||||
|         $message = $this->sha1Message->withoutHeader('Signature'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|         $message = $this->sha256Message->withoutHeader('Signature'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectRsaMessageWithGarbageSignatureHeader() | ||||
|     { | ||||
|         $message = $this->sha1Message->withHeader('Signature', 'not="a",valid="signature"'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|         $message = $this->sha256Message->withHeader('Signature', 'not="a",valid="signature"'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectRsaMessageWithPartialSignatureHeader() | ||||
|     { | ||||
|         $message = $this->sha1Message->withHeader('Signature', 'keyId="aa",algorithm="bb"'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|         $message = $this->sha256Message->withHeader('Signature', 'keyId="aa",algorithm="bb"'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectsRsaMessageWithUnknownKeyId() | ||||
|     { | ||||
|         $keyStore = new KeyStore(['nope' => 'secret']); | ||||
|         $verifier = new Verifier($keyStore); | ||||
|         $this->assertFalse($verifier->isValid($this->sha1Message)); | ||||
|         $this->assertFalse($verifier->isValid($this->sha256Message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectsRsaMessageMissingSignedHeaders() | ||||
|     { | ||||
|         $message = $this->sha1Message->withoutHeader('Date'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|         $message = $this->sha256Message->withoutHeader('Date'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,44 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use App\Util\HttpSignatures\SignatureParametersParser; | ||||
| 
 | ||||
| class SignatureParametersParserTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     public function testParseReturnsExpectedAssociativeArray() | ||||
|     { | ||||
|         $parser = new SignatureParametersParser( | ||||
|             'keyId="example",algorithm="hmac-sha1",headers="(request-target) date",signature="b64"' | ||||
|         ); | ||||
|         $this->assertEquals( | ||||
|             [ | ||||
|                 'keyId' => 'example', | ||||
|                 'algorithm' => 'hmac-sha1', | ||||
|                 'headers' => '(request-target) date', | ||||
|                 'signature' => 'b64', | ||||
|             ], | ||||
|             $parser->parse() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @expectedException App\Util\HttpSignatures\SignatureParseException | ||||
|      */ | ||||
|     public function testParseThrowsTypedException() | ||||
|     { | ||||
|         $parser = new SignatureParametersParser('nope'); | ||||
|         $parser->parse(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @expectedException App\Util\HttpSignatures\SignatureParseException | ||||
|      */ | ||||
|     public function testParseExceptionForMissingComponents() | ||||
|     { | ||||
|         $parser = new SignatureParametersParser( | ||||
|             'keyId="example",algorithm="hmac-sha1",headers="(request-target) date"' | ||||
|         ); | ||||
|         $parser->parse(); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,58 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use App\Util\HttpSignatures\HeaderList; | ||||
| use App\Util\HttpSignatures\HmacAlgorithm; | ||||
| use App\Util\HttpSignatures\RsaAlgorithm; | ||||
| use App\Util\HttpSignatures\Key; | ||||
| use App\Util\HttpSignatures\SignatureParameters; | ||||
| 
 | ||||
| class SignatureParametersTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     public function testHmacToString() | ||||
|     { | ||||
|         $key = new Key('pda', 'secret'); | ||||
|         $algorithm = new HmacAlgorithm('sha256'); | ||||
|         $headerList = new HeaderList(['(request-target)', 'date']); | ||||
| 
 | ||||
|         $signature = $this->getMockBuilder('HttpSignatures\Signature') | ||||
|             ->disableOriginalConstructor() | ||||
|             ->getMock(); | ||||
| 
 | ||||
|         $signature | ||||
|             ->expects($this->any()) | ||||
|             ->method('string') | ||||
|             ->will($this->returnValue('thesignature')); | ||||
| 
 | ||||
|         $sp = new SignatureParameters($key, $algorithm, $headerList, $signature); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             'keyId="pda",algorithm="hmac-sha256",headers="(request-target) date",signature="dGhlc2lnbmF0dXJl"', | ||||
|             $sp->string() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testRsaToString() | ||||
|     { | ||||
|         $key = new Key('pda', TestKeys::rsaPrivateKey); | ||||
|         $algorithm = new RsaAlgorithm('sha256'); | ||||
|         $headerList = new HeaderList(['(request-target)', 'date']); | ||||
| 
 | ||||
|         $signature = $this->getMockBuilder('HttpSignatures\Signature') | ||||
|             ->disableOriginalConstructor() | ||||
|             ->getMock(); | ||||
| 
 | ||||
|         $signature | ||||
|             ->expects($this->any()) | ||||
|             ->method('string') | ||||
|             ->will($this->returnValue('thesignature')); | ||||
| 
 | ||||
|         $sp = new SignatureParameters($key, $algorithm, $headerList, $signature); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             'keyId="pda",algorithm="rsa-sha256",headers="(request-target) date",signature="dGhlc2lnbmF0dXJl"', | ||||
|             $sp->string() | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,93 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use GuzzleHttp\Psr7\Request; | ||||
| use App\Util\HttpSignatures\HeaderList; | ||||
| use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory; | ||||
| use App\Util\HttpSignatures\SigningString; | ||||
| use Symfony\Component\HttpFoundation\Request as SymfonyRequest; | ||||
| 
 | ||||
| class SigningStringTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     public function testWithoutQueryString() | ||||
|     { | ||||
|         $headerList = new HeaderList(['(request-target)']); | ||||
|         $ss = new SigningString($headerList, $this->message('/path')); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             '(request-target): get /path', | ||||
|             $ss->string() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSigningStringWithOrderedQueryParameters() | ||||
|     { | ||||
|         $headerList = new HeaderList(['(request-target)', 'date']); | ||||
|         $ss = new SigningString($headerList, $this->message('/path?a=antelope&z=zebra')); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             "(request-target): get /path?a=antelope&z=zebra\ndate: Mon, 28 Jul 2014 15:39:13 -0700", | ||||
|             $ss->string() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSigningStringWithUnorderedQueryParameters() | ||||
|     { | ||||
|         $headerList = new HeaderList(['(request-target)', 'date']); | ||||
|         $ss = new SigningString($headerList, $this->message('/path?z=zebra&a=antelope')); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             "(request-target): get /path?z=zebra&a=antelope\ndate: Mon, 28 Jul 2014 15:39:13 -0700", | ||||
|             $ss->string() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSigningStringWithOrderedQueryParametersSymfonyRequest() | ||||
|     { | ||||
|         $headerList = new HeaderList(['(request-target)', 'date']); | ||||
|         $ss = new SigningString($headerList, $this->symfonyMessage('/path?a=antelope&z=zebra')); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             "(request-target): get /path?a=antelope&z=zebra\ndate: Mon, 28 Jul 2014 15:39:13 -0700", | ||||
|             $ss->string() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     public function testSigningStringWithUnorderedQueryParametersSymfonyRequest() | ||||
|     { | ||||
|         $headerList = new HeaderList(['(request-target)', 'date']); | ||||
|         $ss = new SigningString($headerList, $this->symfonyMessage('/path?z=zebra&a=antelope')); | ||||
| 
 | ||||
|         $this->assertEquals( | ||||
|             "(request-target): get /path?z=zebra&a=antelope\ndate: Mon, 28 Jul 2014 15:39:13 -0700", | ||||
|             $ss->string() | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @expectedException App\Util\HttpSignatures\Exception | ||||
|      */ | ||||
|     public function testSigningStringErrorForMissingHeader() | ||||
|     { | ||||
|         $headerList = new HeaderList(['nope']); | ||||
|         $ss = new SigningString($headerList, $this->message('/')); | ||||
|         $ss->string(); | ||||
|     } | ||||
| 
 | ||||
|     private function message($path) | ||||
|     { | ||||
|         return new Request('GET', $path, ['date' => 'Mon, 28 Jul 2014 15:39:13 -0700']); | ||||
|     } | ||||
| 
 | ||||
|     private function symfonyMessage($path) | ||||
|     { | ||||
|         $symfonyRequest = SymfonyRequest::create($path, 'GET'); | ||||
|         $symfonyRequest->headers->replace(['date' => 'Mon, 28 Jul 2014 15:39:13 -0700']); | ||||
| 
 | ||||
|         $psr7Factory = new DiactorosFactory(); | ||||
|         $psrRequest = $psr7Factory->createRequest($symfonyRequest)->withRequestTarget($symfonyRequest->getRequestUri()); | ||||
| 
 | ||||
|         return $psrRequest; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,64 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| abstract class TestKeys | ||||
| { | ||||
|     const rsaPrivateKey = | ||||
| '-----BEGIN RSA PRIVATE KEY----- | ||||
| MIIEpAIBAAKCAQEAxyfPtnW/CakdLpZVh90sR+hpRwiBBdS/za6wal0pFddl2xcL | ||||
| sHY/IA1u348xOc4LEY2D0807o1IXSEaqrt9eUkAh+yLGKgDCWLGzW026HBMgojhn | ||||
| Y702pmRI2CGqP0xtzrynCSmSMvhdKM9IMc7DGf7Wdo4Y0En0KPat+IyCZpbf7jUX | ||||
| cGL/tjxMKS3fXNgthGWVDU2TBSQRFM+fgeH9egODd4DfpzfaUoUDcoB/CZ1FEa4+ | ||||
| wNfXR5CZ4WjIaeVbCQ09maup07J+KaGe8SQ9LjcUuityyuNBjy5nvQkbmDfAh082 | ||||
| 2lZQYR62FM5EAlNptThODg6q4wkIQ+spLv1dSwIDAQABAoIBAQCXYQyCvVd7qV80 | ||||
| JTNYNWbONbuoMa+Y1hEA77LK9osfPf3/HbJV7FupKmzHY5lgPdyt9+pnWQ3m46Qs | ||||
| 3QIqMEEKthLeSJ1mGfOf5VrWoOtBIczhYYw9BPsAWSQBnP1CZf7lcQJqdX3aXmy5 | ||||
| c22F5oroPIuZzALSeBQt+utcDLml7dr4D2TbFkmh3ocGGK1SDUATGBVQG+MAVGFQ | ||||
| J5BYLFPUp8QC2o1672/aqNkx1XO08vIoANtWz5Rjf2hCRrdw1liAN30nnZ+l9h3x | ||||
| mbof0sUQMPxxmZ/u+HGPShkN+Y/DLfIyjHlpXI127WBwFLr5P/iL6+DDbsn4Iav3 | ||||
| L57kSxhhAoGBAO6v/ojuZFE0h3mKHy+SdWggcRqe8Re2C5QTODTy7hRwdUv791lk | ||||
| jFnONqlcn51H/hDQwP8nnG8HFxJYl4IoCCdcWfeFlQ82oerIWmsX6H4BFBfF7I9Y | ||||
| 3Muo1BWj4vif/mwwsL0NOAn5XCO/Gi1nF7YZBd/or+X/x4XLSWKnBISRAoGBANWZ | ||||
| xzhpUltGPfKWgfE+ETbZC++Nqsd1MHAdZOhOaeBY615DdmfVv7ryaTWJ1kRbRmq0 | ||||
| 9eKmopEYqfCwyfKZ/8+2dudhndnnEqmiJPu2WFyEiR9sb8NMPcOOjKPhUMgP0ZNx | ||||
| Ynz/oTvBOylvU2MfC0hpLghq50JeEJSiGxzE9kIbAoGAejcpeMnAGghwmd4Ma9pt | ||||
| PXznDP93aXGwagiRTiNZnqOam+aPV3lxmAZL3NptbCZRxCBvwfZxVjRmLuGn6mA/ | ||||
| FJBoDKKcmWaa79HY4l8ij2pT9HxGzXttyuZOeiopbK7XomQoCxU6rXi+IhuW9sqD | ||||
| zJzxch39+yHF8w8NK3Njj9ECgYEAj8ZXu5fhEIECV5SJWKmvipykFRXleyZdeUm/ | ||||
| z0Jgr9sKasO8In5U9PAQczIZYJ+TkWXHEE2bpVDVqqZE+KBB+T1XYb1qM+7+t+Hl | ||||
| ROzjIzsu1VD3FZzvAf+kmPajmlZTegxa/8pNa9xQBz7hARo3TQFHM/FJQnnwbSuE | ||||
| VmQZYjsCgYA9ADxvlgGQmo3uHup6u54S7MgwvzIK7WiXKkuoI5rp0B0mwTr3loVt | ||||
| 3r3tZBH4+z17fVhmoQ4a4kYT8ixn0XpaL0LOv8s02b36XCNlrfPlafOwhHfOHmlz | ||||
| zQnzviLiUOgXyD8FwZlYx+hTM09CYPcdJWSPl6JVF7uxm2fX/HdS3w== | ||||
| -----END RSA PRIVATE KEY-----'; | ||||
|     const rsaCert = | ||||
| '-----BEGIN CERTIFICATE----- | ||||
| MIICmjCCAYICCQDIxrpvPCnqRjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0 | ||||
| ZXN0MB4XDTE4MDgxODEyMjMzMloXDTI4MDgxNTEyMjMzMlowDzENMAsGA1UEAwwE | ||||
| dGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcnz7Z1vwmpHS6W | ||||
| VYfdLEfoaUcIgQXUv82usGpdKRXXZdsXC7B2PyANbt+PMTnOCxGNg9PNO6NSF0hG | ||||
| qq7fXlJAIfsixioAwlixs1tNuhwTIKI4Z2O9NqZkSNghqj9Mbc68pwkpkjL4XSjP | ||||
| SDHOwxn+1naOGNBJ9Cj2rfiMgmaW3+41F3Bi/7Y8TCkt31zYLYRllQ1NkwUkERTP | ||||
| n4Hh/XoDg3eA36c32lKFA3KAfwmdRRGuPsDX10eQmeFoyGnlWwkNPZmrqdOyfimh | ||||
| nvEkPS43FLorcsrjQY8uZ70JG5g3wIdPNtpWUGEethTORAJTabU4Tg4OquMJCEPr | ||||
| KS79XUsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAgnvP8UDFND0G/R5ptKeaAUvF | ||||
| xmDWnyBOv8/GWb8i9zesBfgjmjoKfjIgbYS/z0ZqMHApuv6td6NovsCVgpfEpLAv | ||||
| zxtljLtOWEeQ/25bespBiTiOVp1w8BzEZ2IhNX6M0LxXQkUXgeyOC2wnH6SH9rTW | ||||
| USM0aZhhDcdOZ4q+OkpAN6uux3r0QNJLdU8vInBGoyE3s+7MjEun30HQy24HSgEA | ||||
| p/Ee+dkqU2Jp7wr5omMzurGrEwre0KjNLbrDvcb/0u8r7RA5sghHiE7MUe8acGqR | ||||
| GyMYMn7AX97SD2yxYgwt7i/v65wkAC5oxXA2Yg1TTJZrLD6obGv+wELnePhKgw== | ||||
| -----END CERTIFICATE----- | ||||
| '; | ||||
|     const rsaPublicKey = | ||||
| '-----BEGIN PUBLIC KEY----- | ||||
| MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxyfPtnW/CakdLpZVh90s | ||||
| R+hpRwiBBdS/za6wal0pFddl2xcLsHY/IA1u348xOc4LEY2D0807o1IXSEaqrt9e | ||||
| UkAh+yLGKgDCWLGzW026HBMgojhnY702pmRI2CGqP0xtzrynCSmSMvhdKM9IMc7D | ||||
| Gf7Wdo4Y0En0KPat+IyCZpbf7jUXcGL/tjxMKS3fXNgthGWVDU2TBSQRFM+fgeH9 | ||||
| egODd4DfpzfaUoUDcoB/CZ1FEa4+wNfXR5CZ4WjIaeVbCQ09maup07J+KaGe8SQ9 | ||||
| LjcUuityyuNBjy5nvQkbmDfAh0822lZQYR62FM5EAlNptThODg6q4wkIQ+spLv1d | ||||
| SwIDAQAB | ||||
| -----END PUBLIC KEY----- | ||||
| '; | ||||
| } | ||||
|  | @ -0,0 +1,116 @@ | |||
| <?php | ||||
| 
 | ||||
| namespace Tests\Unit\HttpSignatures; | ||||
| 
 | ||||
| use GuzzleHttp\Psr7\Request; | ||||
| use App\Util\HttpSignatures\KeyStore; | ||||
| use App\Util\HttpSignatures\Verifier; | ||||
| 
 | ||||
| class VerifierHmacTest extends \PHPUnit\Framework\TestCase | ||||
| { | ||||
|     const DATE = 'Fri, 01 Aug 2014 13:44:32 -0700'; | ||||
|     const DATE_DIFFERENT = 'Fri, 01 Aug 2014 13:44:33 -0700'; | ||||
| 
 | ||||
|     /** | ||||
|      * @var Verifier | ||||
|      */ | ||||
|     private $verifier; | ||||
| 
 | ||||
|     /** | ||||
|      * @var Request | ||||
|      */ | ||||
|     private $message; | ||||
| 
 | ||||
|     public function setUp() | ||||
|     { | ||||
|         $this->setUpHmacVerifier(); | ||||
|         $this->setUpValidHmacMessage(); | ||||
|     } | ||||
| 
 | ||||
|     private function setUpHmacVerifier() | ||||
|     { | ||||
|         $keyStore = new KeyStore(['secret1' => 'secret']); | ||||
|         $this->verifier = new Verifier($keyStore); | ||||
|     } | ||||
| 
 | ||||
|     private function setUpValidHmacMessage() | ||||
|     { | ||||
|         $signatureHeader = sprintf( | ||||
|             'keyId="%s",algorithm="%s",headers="%s",signature="%s"', | ||||
|             'secret1', | ||||
|             'hmac-sha256', | ||||
|             '(request-target) date', | ||||
|             'cS2VvndvReuTLy52Ggi4j6UaDqGm9hMb4z0xJZ6adqU=' | ||||
|         ); | ||||
| 
 | ||||
|         $this->message = new Request('GET', '/path?query=123', [ | ||||
|             'Date' => self::DATE, | ||||
|             'Signature' => $signatureHeader, | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     public function testVerifyValidHmacMessage() | ||||
|     { | ||||
|         $this->assertTrue($this->verifier->isValid($this->message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testVerifyValidHmacMessageAuthorizationHeader() | ||||
|     { | ||||
|         $message = $this->message->withHeader('Authorization', "Signature {$this->message->getHeader('Signature')[0]}"); | ||||
|         $message = $message->withoutHeader('Signature'); | ||||
| 
 | ||||
|         $this->assertTrue($this->verifier->isValid($this->message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectTamperedHmacRequestMethod() | ||||
|     { | ||||
|         $message = $this->message->withMethod('POST'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectTamperedHmacDate() | ||||
|     { | ||||
|         $message = $this->message->withHeader('Date', self::DATE_DIFFERENT); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectTamperedHmacSignature() | ||||
|     { | ||||
|         $message = $this->message->withHeader( | ||||
|             'Signature', | ||||
|             preg_replace('/signature="/', 'signature="x', $this->message->getHeader('Signature')[0]) | ||||
|         ); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectHmacMessageWithoutSignatureHeader() | ||||
|     { | ||||
|         $message = $this->message->withoutHeader('Signature'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectHmacMessageWithGarbageSignatureHeader() | ||||
|     { | ||||
|         $message = $this->message->withHeader('Signature', 'not="a",valid="signature"'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectHmacMessageWithPartialSignatureHeader() | ||||
|     { | ||||
|         $message = $this->message->withHeader('Signature', 'keyId="aa",algorithm="bb"'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectsHmacMessageWithUnknownKeyId() | ||||
|     { | ||||
|         $keyStore = new KeyStore(['nope' => 'secret']); | ||||
|         $verifier = new Verifier($keyStore); | ||||
|         $this->assertFalse($verifier->isValid($this->message)); | ||||
|     } | ||||
| 
 | ||||
|     public function testRejectsHmacMessageMissingSignedHeaders() | ||||
|     { | ||||
|         $message = $this->message->withoutHeader('Date'); | ||||
|         $this->assertFalse($this->verifier->isValid($message)); | ||||
|     } | ||||
| } | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 Daniel Supernault
						Daniel Supernault