diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 0000000..91a46ff --- /dev/null +++ b/codeception.yml @@ -0,0 +1,15 @@ +actor: Tester +paths: + tests: tests + log: tests/_output + data: tests/_data + helpers: tests/_support +settings: + bootstrap: _bootstrap.php + colors: true + memory_limit: 1024M +coverage: + enabled: true + remote: false + include: + - lib/* diff --git a/composer.json b/composer.json index 5301ed8..21c5726 100644 --- a/composer.json +++ b/composer.json @@ -1,19 +1,16 @@ { - "name": "legalthings/authorizer", - "description": "Authorizer for HTTP requests", - "license": "MIT", - "require": { - "guzzle/guzzle": "v3.9.3" - }, - "require-dev": { - "codeception/specify": "0.4.1", - "codeception/phpbuiltinserver": "v1.2.1", - "codeception/codeception": "2.0.13", - "aws/aws-sdk-php": "^3.12" - }, - "autoload": { - "psr-4": { - "LegalThings\\": "src/" - } - } + "name" : "legalthings/authorizer", + "description" : "Authorizer for HTTP requests", + "license" : "MIT", + "require" : { + "guzzlehttp/guzzle": "^6.1" + }, + "require-dev" : { + "codeception/codeception": "^2.1" + }, + "autoload" : { + "psr-4" : { + "LegalThings\\" : "src/" + } + } } diff --git a/src/Authorizer.php b/src/Authorizer.php index 2d58e0a..ff74ce0 100644 --- a/src/Authorizer.php +++ b/src/Authorizer.php @@ -34,13 +34,13 @@ class Authorizer * Time restrictions are unix timestamps, but may be omitted * @return string $encryptedSecret An utf8_encoded encrypted secret */ - public static function sign($allowedResource, $authzgen) + public static function sign($allowedResource, $authzgen, $handler = null) { if (!isset(self::$globalSecret)) trigger_error('$globalSecret is not set', E_USER_WARNING); list($cerfiticateUrl, $timeStart, $timeEnd) = explode(';', $authzgen) + [null, null, null]; - $publicKey = self::downloadSigningKey($cerfiticateUrl); + $publicKey = self::downloadSigningKey($cerfiticateUrl, ['handler' => $handler]); $resourceSecret = join(';', [ $timeStart, @@ -114,6 +114,10 @@ public static function getPublicKey() if (!isset(self::$publicKeyPath)) { throw new \RuntimeException('Path to the authorizer public key is not set'); } + + if(!file_exists (self::$publicKeyPath)) { + throw new \RuntimeException('Path to public key does not exist'); + } $publicKey = file_get_contents(self::$publicKeyPath); self::assertIsValidKey('public', $publicKey, self::$publicKeyPath); @@ -131,12 +135,67 @@ protected static function getPrivateKey() if (!isset(self::$privateKeyPath)) { throw new \RuntimeException('Path to the authorizer private key is not set'); } + + if(!file_exists (self::$privateKeyPath)) { + throw new \RuntimeException('Path to private key does not exist'); + } $privateKey = file_get_contents(self::$privateKeyPath); self::assertIsValidKey('private', $privateKey, self::$privateKeyPath); return $privateKey; } + + /** + * Generate a private key + * + * @param array $options + * @throws RuntimeException + * @return string + */ + public static function createPrivateKey($options = []) { + + if (!isset(self::$privateKeyPath)) { + throw new \RuntimeException('Path to the authorizer private key is not set'); + } + + if(file_exists (self::$privateKeyPath)) { + throw new \RuntimeException('Private key already exists'); + } + + $config = array( + "digest_alg" => "sha512", + "private_key_bits" => 2048, + "private_key_type" => OPENSSL_KEYTYPE_RSA, + ); + + $config = $options + $config; + + $res = openssl_pkey_new($config); + openssl_pkey_export($res, $key); + file_put_contents(self::$privateKeyPath, $key); + return $key; + } + + /** + * Generate a public based on existing private keyu + * @throws \RuntimeException + * @return string + */ + public static function createPublicKey() { + if (!isset(self::$publicKeyPath)) { + throw new \RuntimeException('Path to the authorizer public key is not set'); + } + + if(file_exists (self::$publicKeyPath)) { + throw new \RuntimeException('Public key already exists'); + } + $privateKey = openssl_get_privatekey(self::getPrivateKey()); + $pubKey = openssl_pkey_get_details($privateKey); + $key = $pubKey["key"]; + file_put_contents(self::$publicKeyPath, $key); + return $key; + } /** * Get a public key through a remote url diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php new file mode 100644 index 0000000..6c8c4f5 --- /dev/null +++ b/tests/_bootstrap.php @@ -0,0 +1,3 @@ +getScenario()->runStep(new \Codeception\Step\Action('assertEquals', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that two variables are not equal + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotEquals() + */ + public function assertNotEquals($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEquals', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that two variables are same + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertSame() + */ + public function assertSame($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertSame', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that two variables are not same + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotSame() + */ + public function assertNotSame($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotSame', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that actual is greater than expected + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertGreaterThan() + */ + public function assertGreaterThan($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThan', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * @deprecated + * @see \Codeception\Module\Asserts::assertGreaterThen() + */ + public function assertGreaterThen($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThen', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that actual is greater or equal than expected + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertGreaterThanOrEqual() + */ + public function assertGreaterThanOrEqual($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThanOrEqual', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * @deprecated + * @see \Codeception\Module\Asserts::assertGreaterThenOrEqual() + */ + public function assertGreaterThenOrEqual($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertGreaterThenOrEqual', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that actual is less than expected + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertLessThan() + */ + public function assertLessThan($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThan', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that actual is less or equal than expected + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertLessThanOrEqual() + */ + public function assertLessThanOrEqual($expected, $actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertLessThanOrEqual', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that haystack contains needle + * + * @param $needle + * @param $haystack + * @param string $message + * @see \Codeception\Module\Asserts::assertContains() + */ + public function assertContains($needle, $haystack, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertContains', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that haystack doesn't contain needle. + * + * @param $needle + * @param $haystack + * @param string $message + * @see \Codeception\Module\Asserts::assertNotContains() + */ + public function assertNotContains($needle, $haystack, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotContains', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that string match with pattern + * + * @param string $pattern + * @param string $string + * @param string $message + * @see \Codeception\Module\Asserts::assertRegExp() + */ + public function assertRegExp($pattern, $string, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertRegExp', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that string not match with pattern + * + * @param string $pattern + * @param string $string + * @param string $message + * @see \Codeception\Module\Asserts::assertNotRegExp() + */ + public function assertNotRegExp($pattern, $string, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotRegExp', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is empty. + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertEmpty() + */ + public function assertEmpty($actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEmpty', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is not empty. + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotEmpty() + */ + public function assertNotEmpty($actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotEmpty', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is NULL + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNull() + */ + public function assertNull($actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNull', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is not NULL + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotNull() + */ + public function assertNotNull($actual, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertNotNull', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that condition is positive. + * + * @param $condition + * @param string $message + * @see \Codeception\Module\Asserts::assertTrue() + */ + public function assertTrue($condition, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertTrue', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that condition is negative. + * + * @param $condition + * @param string $message + * @see \Codeception\Module\Asserts::assertFalse() + */ + public function assertFalse($condition, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFalse', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if file exists + * + * @param string $filename + * @param string $message + * @see \Codeception\Module\Asserts::assertFileExists() + */ + public function assertFileExists($filename, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileExists', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if file doesn't exist + * + * @param string $filename + * @param string $message + * @see \Codeception\Module\Asserts::assertFileNotExists() + */ + public function assertFileNotExists($filename, $message = null) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('assertFileNotExists', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Fails the test with message. + * + * @param $message + * @see \Codeception\Module\Asserts::fail() + */ + public function fail($message) { + return $this->getScenario()->runStep(new \Codeception\Step\Action('fail', func_get_args())); + } +} diff --git a/tests/unit.suite.yml b/tests/unit.suite.yml new file mode 100644 index 0000000..c5bcf4b --- /dev/null +++ b/tests/unit.suite.yml @@ -0,0 +1,11 @@ +class_name: UnitTester +modules: + enabled: + - Asserts + - UnitHelper + +coverage: + enabled: true + remote: false + include: + - lib/* \ No newline at end of file diff --git a/tests/unit/AuthorizerTest.php b/tests/unit/AuthorizerTest.php new file mode 100644 index 0000000..56af3a3 --- /dev/null +++ b/tests/unit/AuthorizerTest.php @@ -0,0 +1,95 @@ +assertTrue($this->checkKey("private", $privateKey)); + } + + public function testGeneratePrivateAndPublicKey() { + + $privateKey = Authorizer::createPrivateKey(); + $this->assertTrue($this->checkKey("private", $privateKey)); + + $publicKey = Authorizer::createPublicKey(); + $this->assertTrue($this->checkKey("public", $publicKey)); + } + + public function testGetPublicKey() { + + Authorizer::$privateKeyPath = "tests/_data/private_key.pem"; + Authorizer::$publicKeyPath = "tests/_data/public_key.pem"; + + $publicKey = Authorizer::getPublicKey(); + $this->assertTrue($this->checkKey("public", $publicKey)); + } + + public function testSignDecryptingAndVerifying() { + + Authorizer::$privateKeyPath = "tests/_data/private_key.pem"; + Authorizer::$publicKeyPath = "tests/_data/public_key.pem"; + + $_SERVER['HTTP_HOST'] = "example.com"; + + $resource = "secret resource"; + $startTime = time(); + $endTime = $startTime + 500; + + $mock = new MockHandler([ + new Response(200, [], Authorizer::getPublicKey()) + ]); + $handler = HandlerStack::create($mock); + $encryptedSecret = Authorizer::sign($resource, "http://example.com/public_key.pem;$startTime;$endTime", $handler); + + $decrypted = Authorizer::decrypt($encryptedSecret); + $values = explode(";", $decrypted); + $this->assertEquals($startTime, $values[0]); + $this->assertEquals($endTime, $values[1]); + + $this->assertTrue(Authorizer::verify($resource, $decrypted)); + } + + protected function checkKey($type, $key) { + if (!preg_match('/^-----BEGIN (RSA |DSA )?' . strtoupper($type) . ' KEY-----/', $key)) { + return false; + } + + return true; + } +} +?> \ No newline at end of file diff --git a/tests/unit/UnitTester.php b/tests/unit/UnitTester.php new file mode 100644 index 0000000..c1e0334 --- /dev/null +++ b/tests/unit/UnitTester.php @@ -0,0 +1,300 @@ +scenario->runStep(new \Codeception\Step\Action('assertEquals', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that two variables are not equal + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotEquals() + */ + public function assertNotEquals($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertNotEquals', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that two variables are same + * + * @param $expected + * @param $actual + * @param string $message + * + * @return mixed + * @see \Codeception\Module\Asserts::assertSame() + */ + public function assertSame($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertSame', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that two variables are not same + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotSame() + */ + public function assertNotSame($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertNotSame', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that expected is greater than actual + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertGreaterThan() + */ + public function assertGreaterThan($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThan', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * @deprecated + * @see \Codeception\Module\Asserts::assertGreaterThen() + */ + public function assertGreaterThen($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThen', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that expected is greater or equal than actual + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertGreaterThanOrEqual() + */ + public function assertGreaterThanOrEqual($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThanOrEqual', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * @deprecated + * @see \Codeception\Module\Asserts::assertGreaterThenOrEqual() + */ + public function assertGreaterThenOrEqual($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThenOrEqual', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that expected is less than actual + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertLessThan() + */ + public function assertLessThan($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertLessThan', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that expected is less or equal than actual + * + * @param $expected + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertLessThanOrEqual() + */ + public function assertLessThanOrEqual($expected, $actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertLessThanOrEqual', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that haystack contains needle + * + * @param $needle + * @param $haystack + * @param string $message + * @see \Codeception\Module\Asserts::assertContains() + */ + public function assertContains($needle, $haystack, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertContains', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that haystack doesn't contain needle. + * + * @param $needle + * @param $haystack + * @param string $message + * @see \Codeception\Module\Asserts::assertNotContains() + */ + public function assertNotContains($needle, $haystack, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertNotContains', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is empty. + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertEmpty() + */ + public function assertEmpty($actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertEmpty', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is not empty. + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotEmpty() + */ + public function assertNotEmpty($actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertNotEmpty', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is NULL + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNull() + */ + public function assertNull($actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertNull', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that variable is not NULL + * + * @param $actual + * @param string $message + * @see \Codeception\Module\Asserts::assertNotNull() + */ + public function assertNotNull($actual, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertNotNull', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that condition is positive. + * + * @param $condition + * @param string $message + * @see \Codeception\Module\Asserts::assertTrue() + */ + public function assertTrue($condition, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertTrue', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that condition is negative. + * + * @param $condition + * @param string $message + * @see \Codeception\Module\Asserts::assertFalse() + */ + public function assertFalse($condition, $message = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('assertFalse', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Fails the test with message. + * + * @param $message + * @see \Codeception\Module\Asserts::fail() + */ + public function fail($message) { + return $this->scenario->runStep(new \Codeception\Step\Action('fail', func_get_args())); + } +} diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php new file mode 100644 index 0000000..8a88555 --- /dev/null +++ b/tests/unit/_bootstrap.php @@ -0,0 +1,2 @@ +