From c80d704c0b94e8bca8d3798ae7e9bbf158cfa8a9 Mon Sep 17 00:00:00 2001 From: Franz Liedke Date: Wed, 22 Jan 2020 23:39:32 +0100 Subject: [PATCH] Convert another test Test the request, not a controller (implementation detail). This also focuses on the observable behavior instead of hacking our way into the middleware pipeline in order to observe internal behavior. The authenticated user is now determined by looking at the API response to compare permissions and (non-)existing JSON keys. --- .../api/Auth/AuthenticateWithApiKeyTest.php | 166 ------------------ .../api/authentication/WithApiKeyTest.php | 121 +++++++++++++ 2 files changed, 121 insertions(+), 166 deletions(-) delete mode 100644 framework/core/tests/integration/api/Auth/AuthenticateWithApiKeyTest.php create mode 100644 framework/core/tests/integration/api/authentication/WithApiKeyTest.php diff --git a/framework/core/tests/integration/api/Auth/AuthenticateWithApiKeyTest.php b/framework/core/tests/integration/api/Auth/AuthenticateWithApiKeyTest.php deleted file mode 100644 index e1943e040..000000000 --- a/framework/core/tests/integration/api/Auth/AuthenticateWithApiKeyTest.php +++ /dev/null @@ -1,166 +0,0 @@ -prepareDatabase([ - 'users' => [ - $this->adminUser(), - $this->normalUser(), - ], - ]); - } - - protected function key(int $user_id = null): ApiKey - { - return ApiKey::unguarded(function () use ($user_id) { - return ApiKey::query()->firstOrCreate([ - 'key' => Str::random(), - 'user_id' => $user_id, - 'created_at' => Carbon::now() - ]); - }); - } - - /** - * @test - */ - public function cannot_authorize_without_key() - { - /** @var Client $api */ - $api = $this->app()->getContainer()->make(Client::class); - - $response = $api->send(CreateGroupController::class, new Guest); - - $this->assertEquals(401, $response->getStatusCode()); - } - - /** - * @test - */ - public function master_token_can_authenticate_as_anyone() - { - $key = $this->key(); - - $request = ServerRequestFactory::fromGlobals() - ->withAddedHeader('Authorization', "Token {$key->key}; userId=1"); - - $pipe = $this->injectAuthorizationPipeline(); - - $response = $pipe->handle($request); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals(1, $response->getHeader('X-Authenticated-As')[0]); - - $key = $key->refresh(); - - $this->assertNotNull($key->last_activity_at); - - $key->delete(); - } - - /** - * @test - */ - public function personal_api_token_cannot_authenticate_as_anyone() - { - $user = User::find(2); - - $key = $this->key($user->id); - - $request = ServerRequestFactory::fromGlobals() - ->withAddedHeader('Authorization', "Token {$key->key}; userId=1"); - - $pipe = $this->injectAuthorizationPipeline(); - - $response = $pipe->handle($request); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals($user->id, $response->getHeader('X-Authenticated-As')[0]); - - $key = $key->refresh(); - - $this->assertNotNull($key->last_activity_at); - - $key->delete(); - } - - /** - * @test - */ - public function personal_api_token_authenticates_user() - { - $user = User::find(2); - - $key = $this->key($user->id); - - $request = ServerRequestFactory::fromGlobals() - ->withAddedHeader('Authorization', "Token {$key->key}"); - - $pipe = $this->injectAuthorizationPipeline(); - - $response = $pipe->handle($request); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertEquals($user->id, $response->getHeader('X-Authenticated-As')[0]); - - $key = $key->refresh(); - - $this->assertNotNull($key->last_activity_at); - - $key->delete(); - } - - protected function injectAuthorizationPipeline(): MiddlewarePipe - { - app()->resolving('flarum.api.middleware', function ($pipeline) { - $pipeline->pipe(new class implements MiddlewareInterface { - public function process( - ServerRequestInterface $request, - RequestHandlerInterface $handler - ): ResponseInterface { - if ($actor = $request->getAttribute('actor')) { - return new Response\EmptyResponse(200, [ - 'X-Authenticated-As' => $actor->id - ]); - } - } - }); - }); - - $pipe = app('flarum.api.middleware'); - - return $pipe; - } -} diff --git a/framework/core/tests/integration/api/authentication/WithApiKeyTest.php b/framework/core/tests/integration/api/authentication/WithApiKeyTest.php new file mode 100644 index 000000000..2d716560d --- /dev/null +++ b/framework/core/tests/integration/api/authentication/WithApiKeyTest.php @@ -0,0 +1,121 @@ +prepareDatabase([ + 'users' => [ + $this->adminUser(), + $this->normalUser(), + ], + 'api_keys' => [], + ]); + } + + protected function key(int $user_id = null): ApiKey + { + return ApiKey::unguarded(function () use ($user_id) { + return ApiKey::query()->firstOrCreate([ + 'key' => Str::random(), + 'user_id' => $user_id, + 'created_at' => Carbon::now() + ]); + }); + } + + /** + * @test + */ + public function cannot_authorize_without_key() + { + $response = $this->send( + $this->request('GET', '/api') + ); + + $data = json_decode($response->getBody(), true); + $this->assertFalse($data['data']['attributes']['canViewUserList']); + } + + /** + * @test + */ + public function master_token_can_authenticate_as_anyone() + { + $key = $this->key(); + + $response = $this->send( + $this->request('GET', '/api') + ->withAddedHeader('Authorization', "Token {$key->key}; userId=1") + ); + + $data = json_decode($response->getBody(), true); + $this->assertTrue($data['data']['attributes']['canViewUserList']); + $this->assertArrayHasKey('adminUrl', $data['data']['attributes']); + + $key->refresh(); + + $this->assertNotNull($key->last_activity_at); + } + + /** + * @test + */ + public function personal_api_token_cannot_authenticate_as_anyone() + { + $key = $this->key(2); + + $response = $this->send( + $this->request('GET', '/api') + ->withAddedHeader('Authorization', "Token {$key->key}; userId=1") + ); + + $data = json_decode($response->getBody(), true); + $this->assertTrue($data['data']['attributes']['canViewUserList']); + $this->assertArrayNotHasKey('adminUrl', $data['data']['attributes']); + + $key->refresh(); + + $this->assertNotNull($key->last_activity_at); + } + + /** + * @test + */ + public function personal_api_token_authenticates_user() + { + $key = $this->key(2); + + $response = $this->send( + $this->request('GET', '/api') + ->withAddedHeader('Authorization', "Token {$key->key}") + ); + + $data = json_decode($response->getBody(), true); + $this->assertTrue($data['data']['attributes']['canViewUserList']); + $this->assertArrayNotHasKey('adminUrl', $data['data']['attributes']); + + $key->refresh(); + + $this->assertNotNull($key->last_activity_at); + } +}