From cd1cd7aa0e9202ef4b22074db722ac771f007486 Mon Sep 17 00:00:00 2001 From: Gabriel Ramos Date: Sat, 27 Jul 2024 18:12:20 -0300 Subject: [PATCH] create microsoft entra id tests --- src/Authentication/MicrosoftEntraId.php | 7 +- tests/Fakes/ClientFake.php | 78 +++++++++++++++++++ .../Authentication/MicrosoftEntraIdTest.php | 57 ++++++++++++++ .../Authentication/SharedKeyAuthTest.php | 7 ++ tests/Feature/Http/RequestTest.php | 73 +++-------------- 5 files changed, 156 insertions(+), 66 deletions(-) create mode 100644 tests/Fakes/ClientFake.php create mode 100644 tests/Feature/Authentication/MicrosoftEntraIdTest.php diff --git a/src/Authentication/MicrosoftEntraId.php b/src/Authentication/MicrosoftEntraId.php index be0fc4c..9ac0241 100644 --- a/src/Authentication/MicrosoftEntraId.php +++ b/src/Authentication/MicrosoftEntraId.php @@ -48,7 +48,7 @@ public function getAccount(): string public function getAuthentication(Request $request): string { - if (!empty($this->token) && $this->tokenExpiresAt > new DateTime()) { + if (!empty($this->token) && $this->tokenExpiresAt && $this->tokenExpiresAt > new DateTime()) { return $this->token; } @@ -71,9 +71,12 @@ protected function authenticate(): void 'scope' => 'https://storage.azure.com/.default', ], ]); + + // @codeCoverageIgnoreStart } catch (RequestExceptionInterface $e) { throw RequestException::createFromRequestException($e); } + // @codeCoverageIgnoreEnd /** @var array{token_type: string, expires_in: int, access_token: string} $body */ $body = json_decode((string) $response->getBody(), true); @@ -85,7 +88,7 @@ protected function authenticate(): void protected function getRequestClient(): ClientInterface { if (!isset($this->client)) { - $this->client = new Client(); + $this->client = new Client(); // @codeCoverageIgnore } return $this->client; diff --git a/tests/Fakes/ClientFake.php b/tests/Fakes/ClientFake.php new file mode 100644 index 0000000..2648e8d --- /dev/null +++ b/tests/Fakes/ClientFake.php @@ -0,0 +1,78 @@ +}> */ + protected array $requests = []; + + protected int $status = 200; + + protected array $headers = []; + + protected ?string $body = null; + + public function withResponseFake(?string $body = null, array $headers = [], int $status = 200): self + { + $this->status = $status; + $this->headers = $headers; + $this->body = $body; + + return $this; + } + + /** @param array $options */ + public function send(RequestInterface $request, array $options = []): ResponseInterface + { + return new Response($this->status, $this->headers, $this->body); + } + + /** @param array $options */ + public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface + { + return new Promise(); + } + + /** @param array $options */ + public function request(string $method, mixed $uri, array $options = []): ResponseInterface + { + /** @phpstan-ignore-next-line */ + $this->requests[$method] = [ + 'uri' => $uri, + 'options' => $options, + ]; + + return new Response($this->status, $this->headers, $this->body); + } + + /** @param array $options */ + public function requestAsync(string $method, mixed $uri, array $options = []): PromiseInterface + { + return new Promise(); + } + + public function getConfig(?string $option = null): mixed + { + return []; + } + + public function assertRequestSent(string $method, string $uri, ?Closure $options = null): void + { + Assert::assertArrayHasKey($method, $this->requests, 'Request not sent'); + Assert::assertSame($uri, $this->requests[$method]['uri'], 'Invalid URI'); + + if (!is_null($options)) { + Assert::assertTrue($options($this->requests[$method]['options']), 'Invalid options'); + } + } +} diff --git a/tests/Feature/Authentication/MicrosoftEntraIdTest.php b/tests/Feature/Authentication/MicrosoftEntraIdTest.php new file mode 100644 index 0000000..c473f29 --- /dev/null +++ b/tests/Feature/Authentication/MicrosoftEntraIdTest.php @@ -0,0 +1,57 @@ +group('authentications'); + +it('should implements Auth interface', function () { + expect(MicrosoftEntraId::class) + ->toImplement(Auth::class); +}); + +it('should get date formatted correctly', function () { + $auth = new MicrosoftEntraId('account', 'directory', 'application', 'secret'); + + expect($auth->getDate()) + ->toBe(gmdate('D, d M Y H:i:s T')); +}); + +it('should get the authentication account', function () { + $auth = new MicrosoftEntraId('account', 'directory', 'application', 'secret'); + + expect($auth->getAccount()) + ->toBe('account'); +}); + +it('should get correctly the authentication signature from a login request', function () { + $client = (new ClientFake()) + ->withResponseFake(json_encode([ + 'token_type' => $tokeType = 'Bearer', + 'access_token' => $token = 'token', + 'expires_in' => 3600, + ])); + + $auth = (new MicrosoftEntraId('account', 'directory', $application = 'application', $secret = 'secret')) + ->withRequestClient($client); + + expect($auth->getAuthentication(new RequestFake())) + ->toBe("{$tokeType} {$token}"); + + expect($auth->getAuthentication(new RequestFake())) + ->toBe("{$tokeType} {$token}"); + + $client->assertRequestSent(HttpVerb::POST->value, 'https://login.microsoftonline.com/directory/oauth2/v2.0/token', fn (array $options): bool => $options === [ + 'form_params' => [ + 'grant_type' => 'client_credentials', + 'client_id' => $application, + 'client_secret' => $secret, + 'scope' => 'https://storage.azure.com/.default', + ], + ]); +}); diff --git a/tests/Feature/Authentication/SharedKeyAuthTest.php b/tests/Feature/Authentication/SharedKeyAuthTest.php index da18ae0..7ca335c 100644 --- a/tests/Feature/Authentication/SharedKeyAuthTest.php +++ b/tests/Feature/Authentication/SharedKeyAuthTest.php @@ -23,6 +23,13 @@ ->toBe(gmdate('D, d M Y H:i:s T')); }); +it('should get the authentication account', function () { + $auth = new SharedKeyAuth('account', 'key'); + + expect($auth->getAccount()) + ->toBe('account'); +}); + it('should get correctly the authentication signature for all http methods', function (HttpVerb $verb) { $decodedKey = 'my-decoded-account-key'; diff --git a/tests/Feature/Http/RequestTest.php b/tests/Feature/Http/RequestTest.php index 7b59ddb..04de3b7 100644 --- a/tests/Feature/Http/RequestTest.php +++ b/tests/Feature/Http/RequestTest.php @@ -2,23 +2,19 @@ declare(strict_types=1); -use GuzzleHttp\ClientInterface; -use GuzzleHttp\Promise\{Promise, PromiseInterface}; -use GuzzleHttp\Psr7\Response; -use PHPUnit\Framework\Assert; -use Psr\Http\Message\{RequestInterface, ResponseInterface}; use Xray\AzureStoragePhpSdk\Authentication\SharedKeyAuth; use Xray\AzureStoragePhpSdk\BlobStorage\Enums\HttpVerb; use Xray\AzureStoragePhpSdk\BlobStorage\{Config, Resource}; use Xray\AzureStoragePhpSdk\Contracts\Http\Response as HttpResponse; use Xray\AzureStoragePhpSdk\Http\{Headers, Request}; +use Xray\Tests\Fakes\ClientFake; uses()->group('http'); it('should send get, delete, and options requests', function (string $method, HttpVerb $verb): void { $auth = new SharedKeyAuth('my_account', 'bar'); - $request = (new Request($auth, client: $client = new Client())) + $request = (new Request($auth, client: $client = new ClientFake())) ->withAuthentication() ->usingAccount(fn (): string => 'foo') ->withOptions(['foo' => 'bar']); @@ -43,7 +39,7 @@ it('should send post and put requests', function (string $method, HttpVerb $verb): void { $auth = new SharedKeyAuth('my_account', 'bar'); - $request = (new Request($auth, client: $client = new Client())) + $request = (new Request($auth, client: $client = new ClientFake())) ->withoutAuthentication() ->withHeaders(['foo' => 'bar']); @@ -73,21 +69,21 @@ $auth = new SharedKeyAuth('my_account', 'bar'); $config = new Config(); - expect((new Request($auth, $config, new Client()))->getConfig()) + expect((new Request($auth, $config, new ClientFake()))->getConfig()) ->toBe($config); }); it('should get request auth', function (): void { $auth = new SharedKeyAuth('my_account', 'bar'); - expect((new Request($auth, client: new Client()))->getAuth()) + expect((new Request($auth, client: new ClientFake()))->getAuth()) ->toBe($auth); }); it('should get the http verb from request', function (HttpVerb $verb) { $auth = new SharedKeyAuth('my_account', 'bar'); - $request = (new Request($auth, client: new Client())) + $request = (new Request($auth, client: new ClientFake())) ->withVerb($verb); expect($request->getVerb()) @@ -98,7 +94,7 @@ it('should get the resource from request', function (): void { $auth = new SharedKeyAuth('my_account', 'bar'); - $request = (new Request($auth, client: new Client())) + $request = (new Request($auth, client: new ClientFake())) ->withResource('endpoint'); expect($request->getResource()) @@ -108,7 +104,7 @@ it('should get the headers from request', function (): void { $auth = new SharedKeyAuth('my_account', 'bar'); - $request = (new Request($auth, client: new Client())) + $request = (new Request($auth, client: new ClientFake())) ->withHttpHeaders(new Headers()); expect($request->getHttpHeaders()) @@ -118,60 +114,9 @@ it('should get the body from request', function (): void { $auth = new SharedKeyAuth('my_account', 'bar'); - $request = (new Request($auth, client: new Client())) + $request = (new Request($auth, client: new ClientFake())) ->withBody('body'); expect($request->getBody()) ->toBe('body'); }); - -class Client implements ClientInterface -{ - /** @var array}> */ - protected array $requests = []; - - /** @param array $options */ - public function send(RequestInterface $request, array $options = []): ResponseInterface - { - return new Response(); - } - - /** @param array $options */ - public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface - { - return new Promise(); - } - - /** @param array $options */ - public function request(string $method, mixed $uri, array $options = []): ResponseInterface - { - /** @phpstan-ignore-next-line */ - $this->requests[$method] = [ - 'uri' => $uri, - 'options' => $options, - ]; - - return new Response(); - } - - /** @param array $options */ - public function requestAsync(string $method, mixed $uri, array $options = []): PromiseInterface - { - return new Promise(); - } - - public function getConfig(?string $option = null): mixed - { - return []; - } - - public function assertRequestSent(string $method, string $uri, ?Closure $options = null): void - { - Assert::assertArrayHasKey($method, $this->requests, 'Request not sent'); - Assert::assertSame($uri, $this->requests[$method]['uri'], 'Invalid URI'); - - if (!is_null($options)) { - Assert::assertTrue($options($this->requests[$method]['options']), 'Invalid options'); - } - } -}