From b2a1c86d479a99260514d612290579bfe81563c5 Mon Sep 17 00:00:00 2001 From: Felix Huber Date: Thu, 23 Sep 2021 14:08:38 +0200 Subject: [PATCH 1/3] rename test workflow --- .github/workflows/run-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 88dd99c..a1e6598 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -7,7 +7,7 @@ on: branches: [ main, develop ] jobs: - laravel: + run-tests: runs-on: ubuntu-latest From e01a0cf63ddf19a57b77c7ab7f0f009612c71d97 Mon Sep 17 00:00:00 2001 From: Felix Huber Date: Fri, 1 Oct 2021 21:25:53 +0200 Subject: [PATCH 2/3] improve EsiAuthentication.php * allow of construction of container without secret and client_id * implement correct method to get scopes from the container --- composer.json | 3 +- src/DataTransferObjects/EsiAuthentication.php | 11 +++-- tests/Pest.php | 27 ++++++++++-- tests/Unit/EsiAuthenticationTest.php | 14 +++++++ .../Unit/Services/RefreshTokenServiceTest.php | 42 +++++++++++++------ 5 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 tests/Unit/EsiAuthenticationTest.php diff --git a/composer.json b/composer.json index 8b2625c..9008425 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ "mockery/mockery": "^1.4", "nunomaduro/collision": "^5.3", "pestphp/pest-plugin-laravel": "^1.1", - "mikey179/vfsstream": "^1" + "mikey179/vfsstream": "^1", + "ext-openssl": "*" }, "autoload": { "psr-4": { diff --git a/src/DataTransferObjects/EsiAuthentication.php b/src/DataTransferObjects/EsiAuthentication.php index 7553315..35f8fc1 100644 --- a/src/DataTransferObjects/EsiAuthentication.php +++ b/src/DataTransferObjects/EsiAuthentication.php @@ -2,20 +2,23 @@ namespace Seatplus\EsiClient\DataTransferObjects; +use Firebase\JWT\JWT; use Spatie\DataTransferObject\DataTransferObject; class EsiAuthentication extends DataTransferObject { - public int $client_id; - public string $secret; + public ?int $client_id; + public ?string $secret; public string $access_token; public string $refresh_token; public string $token_expires = '1970-01-01 00:00:00'; public function getScopes() : array { - $jwt = json_decode($this->access_token); + $jwt_payload_base64_encoded = explode('.', $this->access_token)[1]; - return $jwt->scp ?? []; + $jwt_payload = JWT::urlsafeB64Decode($jwt_payload_base64_encoded); + + return data_get(json_decode($jwt_payload), 'scp', []); } } diff --git a/tests/Pest.php b/tests/Pest.php index 78eceb5..6e57342 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -12,6 +12,7 @@ */ +use Firebase\JWT\JWT; use PHPUnit\Framework\TestCase; uses(TestCase::class) @@ -60,15 +61,35 @@ function buildEsiAuthentication(array $params = []) $factory_array = [ 'client_id' => $faker->randomNumber, 'secret' => $faker->md5, - 'access_token' => json_encode([ + 'access_token' => buildJWT(json_encode([ 'scp' => [], - ]), + ])), 'refresh_token' => $faker->sha1, ]; foreach ($params as $key => $value) { - $factory_array[$key] = $value; + + $factory_array[$key] = $key === 'access_token' ? buildJWT($value) : $value; } return new \Seatplus\EsiClient\DataTransferObjects\EsiAuthentication($factory_array); } + +function buildJWT(string $payload): string +{ + $jwt_header = json_encode([ + "alg" => "RS256", + "kid" => "JWT-Signature-Key", + "typ" => "JWT", + ]); + + $data = JWT::urlsafeB64Encode($jwt_header) . "." . JWT::urlsafeB64Encode($payload); + + $signature = hash_hmac( + 'sha256', + $data, + 'test' + ); + + return "${data}.${signature}"; +} diff --git a/tests/Unit/EsiAuthenticationTest.php b/tests/Unit/EsiAuthenticationTest.php new file mode 100644 index 0000000..da15fb5 --- /dev/null +++ b/tests/Unit/EsiAuthenticationTest.php @@ -0,0 +1,14 @@ + 'access_token', + 'refresh_token' => 'access_token', + 'token_expires' => 'now', + ]); + + expect($authenticaton) + ->toBeInstanceOf(\Seatplus\EsiClient\DataTransferObjects\EsiAuthentication::class) + ->token_expires->toBe('now'); + +}); diff --git a/tests/Unit/Services/RefreshTokenServiceTest.php b/tests/Unit/Services/RefreshTokenServiceTest.php index 688de4a..df36056 100644 --- a/tests/Unit/Services/RefreshTokenServiceTest.php +++ b/tests/Unit/Services/RefreshTokenServiceTest.php @@ -1,11 +1,20 @@ 'sha256', + 'private_key_bits' => 1024, + 'private_key_type' => OPENSSL_KEYTYPE_RSA)); + + // define the payload + $payload = [ "scp" => [ "esi-skills.read_skills.v1", "esi-skills.read_skillqueue.v1", @@ -16,16 +25,21 @@ "azp" => "my3rdpartyclientid", "name" => "Some Bloke", "owner" => "8PmzCeTKb4VFUDrHLc/AeZXDSWM=", - "exp" => 1534412504, + "exp" => now()->addHour()->timestamp, "iss" => "login.eveonline.com", - ]); + ]; + // encode the jwt token + $jwt_token = JWT::encode($payload, $privKey, 'RS256'); + + // build the authentication container $authentication = buildEsiAuthentication([ 'access_token' => $jwt_token, ]); + // create the client mock and responses from said client $mock = new \GuzzleHttp\Handler\MockHandler([ - new Response(200, [], json_encode(['access_token' => 'bar'])), + new Response(200, [], json_encode(['access_token' => $jwt_token, 'foo' => 'bar'])), new Response(200, [], json_encode(['jwks' => ['one', 'two', 'three']])), ]); @@ -33,19 +47,23 @@ 'handler' => HandlerStack::create($mock), ]); - // mock JWT - $jwt_mock = Mockery::mock('overload:' . \Firebase\JWT\JWT::class); - $jwt_mock->shouldReceive('decode')->once()->andReturn([ - "iss" => "login.eveonline.com", - "exp" => now()->addHour()->timestamp, - ]); + // get the public key which we need to decode the jwt token + $pubKey = openssl_pkey_get_details($privKey); + $pubKey = $pubKey['key']; + // mock the JWK static method and return the pub key $jwk_mock = Mockery::mock('overload:' . \Firebase\JWT\JWK::class); - $jwk_mock->shouldReceive('parseKeySet')->once()->andReturn([]); + $jwk_mock->shouldReceive('parseKeySet')->once()->andReturn($pubKey); + // construct the service $service = new \Seatplus\EsiClient\Services\RefreshToken($authentication, $client); + // use service to get the refresh Token $response = $service->getRefreshTokenResponse(); - expect($response)->toBe(['access_token' => 'bar']); + // assert the expected result. See the mocked response as reference + expect($response) + ->toBeArray() + ->toHaveKey('access_token',$jwt_token) + ->toHaveKey('foo', 'bar'); }); From bfbe8b3e61b6f863507403e60f723ca79c837776 Mon Sep 17 00:00:00 2001 From: herpaderpaldent Date: Fri, 1 Oct 2021 19:26:47 +0000 Subject: [PATCH 3/3] Fix styling --- tests/Pest.php | 1 - tests/Unit/EsiAuthenticationTest.php | 1 - tests/Unit/Services/RefreshTokenServiceTest.php | 6 +++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/Pest.php b/tests/Pest.php index 6e57342..96d3f3f 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -68,7 +68,6 @@ function buildEsiAuthentication(array $params = []) ]; foreach ($params as $key => $value) { - $factory_array[$key] = $key === 'access_token' ? buildJWT($value) : $value; } diff --git a/tests/Unit/EsiAuthenticationTest.php b/tests/Unit/EsiAuthenticationTest.php index da15fb5..ac14cfd 100644 --- a/tests/Unit/EsiAuthenticationTest.php +++ b/tests/Unit/EsiAuthenticationTest.php @@ -10,5 +10,4 @@ expect($authenticaton) ->toBeInstanceOf(\Seatplus\EsiClient\DataTransferObjects\EsiAuthentication::class) ->token_expires->toBe('now'); - }); diff --git a/tests/Unit/Services/RefreshTokenServiceTest.php b/tests/Unit/Services/RefreshTokenServiceTest.php index df36056..53a1f8b 100644 --- a/tests/Unit/Services/RefreshTokenServiceTest.php +++ b/tests/Unit/Services/RefreshTokenServiceTest.php @@ -9,9 +9,9 @@ it('updates access token with refresh token', function () { // create a private key for signing the JWT Token - $privKey = openssl_pkey_new(array('digest_alg' => 'sha256', + $privKey = openssl_pkey_new(['digest_alg' => 'sha256', 'private_key_bits' => 1024, - 'private_key_type' => OPENSSL_KEYTYPE_RSA)); + 'private_key_type' => OPENSSL_KEYTYPE_RSA, ]); // define the payload $payload = [ @@ -64,6 +64,6 @@ // assert the expected result. See the mocked response as reference expect($response) ->toBeArray() - ->toHaveKey('access_token',$jwt_token) + ->toHaveKey('access_token', $jwt_token) ->toHaveKey('foo', 'bar'); });