Add test coverage for 2fa
This commit is contained in:
parent
fc261fe20c
commit
4cb95d8063
2 changed files with 162 additions and 4 deletions
|
@ -61,11 +61,11 @@ class TwoFactorController extends ClientApiController
|
|||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($request->user()->totp_enabled) {
|
||||
if ($request->user()->use_totp) {
|
||||
throw new BadRequestHttpException('Two-factor authentication is already enabled on this account.');
|
||||
}
|
||||
|
||||
return JsonResponse::create([
|
||||
return new JsonResponse([
|
||||
'data' => [
|
||||
'image_url_data' => $this->setupService->handle($request->user()),
|
||||
],
|
||||
|
@ -98,7 +98,7 @@ class TwoFactorController extends ClientApiController
|
|||
|
||||
$this->toggleTwoFactorService->handle($request->user(), $request->input('code'), true);
|
||||
|
||||
return JsonResponse::create([], Response::HTTP_NO_CONTENT);
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,6 +124,6 @@ class TwoFactorController extends ClientApiController
|
|||
'use_totp' => false,
|
||||
]);
|
||||
|
||||
return JsonResponse::create([], Response::HTTP_NO_CONTENT);
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
158
tests/Integration/Api/Client/TwoFactorControllerTest.php
Normal file
158
tests/Integration/Api/Client/TwoFactorControllerTest.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Tests\Integration\Api\Client;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Pterodactyl\Models\User;
|
||||
use Illuminate\Http\Response;
|
||||
use PragmaRX\Google2FA\Google2FA;
|
||||
use Pterodactyl\Tests\Integration\IntegrationTestCase;
|
||||
|
||||
class TwoFactorControllerTest extends IntegrationTestCase
|
||||
{
|
||||
/**
|
||||
* Clean up after tests have run.
|
||||
*/
|
||||
protected function tearDown(): void
|
||||
{
|
||||
User::query()->forceDelete();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that image data for enabling 2FA is returned by the endpoint and that the user
|
||||
* record in the database is updated as expected.
|
||||
*/
|
||||
public function testTwoFactorImageDataIsReturned()
|
||||
{
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = factory(User::class)->create(['use_totp' => false]);
|
||||
|
||||
$this->assertFalse($user->use_totp);
|
||||
$this->assertEmpty($user->totp_secret);
|
||||
$this->assertEmpty($user->totp_authenticated_at);
|
||||
|
||||
$response = $this->actingAs($user)->getJson('/api/client/account/two-factor');
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertJsonStructure(['data' => ['image_url_data']]);
|
||||
|
||||
$user = $user->refresh();
|
||||
|
||||
$this->assertFalse($user->use_totp);
|
||||
$this->assertNotEmpty($user->totp_secret);
|
||||
$this->assertEmpty($user->totp_authenticated_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an error is returned if the user's account already has 2FA enabled on it.
|
||||
*/
|
||||
public function testErrorIsReturnedWhenTwoFactorIsAlreadyEnabled()
|
||||
{
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = factory(User::class)->create(['use_totp' => true]);
|
||||
|
||||
$response = $this->actingAs($user)->getJson('/api/client/account/two-factor');
|
||||
|
||||
$response->assertStatus(Response::HTTP_BAD_REQUEST);
|
||||
$response->assertJsonPath('errors.0.code', 'BadRequestHttpException');
|
||||
$response->assertJsonPath('errors.0.detail', 'Two-factor authentication is already enabled on this account.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a validation error is thrown if invalid data is passed to the 2FA endpoint.
|
||||
*/
|
||||
public function testValidationErrorIsReturnedIfInvalidDataIsPassedToEnabled2FA()
|
||||
{
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = factory(User::class)->create(['use_totp' => false]);
|
||||
|
||||
$response = $this->actingAs($user)->postJson('/api/client/account/two-factor', [
|
||||
'code' => '',
|
||||
]);
|
||||
|
||||
$response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
$response->assertJsonPath('errors.0.code', 'required');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that 2FA can be enabled on an account for the user.
|
||||
*/
|
||||
public function testTwoFactorCanBeEnabledOnAccount()
|
||||
{
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = factory(User::class)->create(['use_totp' => false]);
|
||||
|
||||
// Make the initial call to get the account setup for 2FA.
|
||||
$this->actingAs($user)->getJson('/api/client/account/two-factor')->assertOk();
|
||||
|
||||
$user = $user->refresh();
|
||||
$this->assertNotNull($user->totp_secret);
|
||||
|
||||
/** @var \PragmaRX\Google2FA\Google2FA $service */
|
||||
$service = $this->app->make(Google2FA::class);
|
||||
|
||||
$secret = decrypt($user->totp_secret);
|
||||
$token = $service->getCurrentOtp($secret);
|
||||
|
||||
$response = $this->actingAs($user)->postJson('/api/client/account/two-factor', [
|
||||
'code' => $token,
|
||||
]);
|
||||
|
||||
$response->assertStatus(Response::HTTP_NO_CONTENT);
|
||||
|
||||
$user = $user->refresh();
|
||||
|
||||
$this->assertTrue($user->use_totp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that two factor authentication can be disabled on an account as long as the password
|
||||
* provided is valid for the account.
|
||||
*/
|
||||
public function testTwoFactorCanBeDisabledOnAccount()
|
||||
{
|
||||
Carbon::setTestNow(Carbon::now());
|
||||
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = factory(User::class)->create(['use_totp' => true]);
|
||||
|
||||
$response = $this->actingAs($user)->deleteJson('/api/client/account/two-factor', [
|
||||
'password' => 'invalid',
|
||||
]);
|
||||
|
||||
$response->assertStatus(Response::HTTP_BAD_REQUEST);
|
||||
$response->assertJsonPath('errors.0.code', 'BadRequestHttpException');
|
||||
$response->assertJsonPath('errors.0.detail', 'The password provided was not valid.');
|
||||
|
||||
$response = $this->actingAs($user)->deleteJson('/api/client/account/two-factor', [
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertStatus(Response::HTTP_NO_CONTENT);
|
||||
|
||||
$user = $user->refresh();
|
||||
$this->assertFalse($user->use_totp);
|
||||
$this->assertNotNull($user->totp_authenticated_at);
|
||||
$this->assertSame(Carbon::now()->toIso8601String(), $user->totp_authenticated_at->toIso8601String());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that no error is returned when trying to disabled two factor on an account where it
|
||||
* was not enabled in the first place.
|
||||
*/
|
||||
public function testNoErrorIsReturnedIfTwoFactorIsNotEnabled()
|
||||
{
|
||||
Carbon::setTestNow(Carbon::now());
|
||||
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = factory(User::class)->create(['use_totp' => false]);
|
||||
|
||||
$response = $this->actingAs($user)->deleteJson('/api/client/account/two-factor', [
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertStatus(Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue