mirror of
https://github.com/flarum/framework.git
synced 2024-11-30 13:36:10 +08:00
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.
This commit is contained in:
parent
6697d3fb5e
commit
c80d704c0b
|
@ -1,166 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of Flarum.
|
|
||||||
*
|
|
||||||
* For detailed copyright and license information, please view the
|
|
||||||
* LICENSE file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Flarum\Tests\integration\api\Auth;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Flarum\Api\ApiKey;
|
|
||||||
use Flarum\Api\Client;
|
|
||||||
use Flarum\Api\Controller\CreateGroupController;
|
|
||||||
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
|
||||||
use Flarum\Tests\integration\TestCase;
|
|
||||||
use Flarum\User\Guest;
|
|
||||||
use Flarum\User\User;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Laminas\Diactoros\Response;
|
|
||||||
use Laminas\Diactoros\ServerRequestFactory;
|
|
||||||
use Laminas\Stratigility\MiddlewarePipe;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
|
||||||
use Psr\Http\Server\MiddlewareInterface;
|
|
||||||
use Psr\Http\Server\RequestHandlerInterface;
|
|
||||||
|
|
||||||
class AuthenticateWithApiKeyTest extends TestCase
|
|
||||||
{
|
|
||||||
use RetrievesAuthorizedUsers;
|
|
||||||
|
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
$this->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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Flarum\Tests\integration\api\authentication;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Flarum\Api\ApiKey;
|
||||||
|
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
||||||
|
use Flarum\Tests\integration\TestCase;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class WithApiKeyTest extends TestCase
|
||||||
|
{
|
||||||
|
use RetrievesAuthorizedUsers;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user