tests(unit): fix RequireTwoFactorAuthenticationTest

This commit is contained in:
Matthew Penner 2022-10-31 13:20:06 -06:00
parent d7d5da6beb
commit ce7c913e18
No known key found for this signature in database
5 changed files with 55 additions and 51 deletions

View file

@ -50,9 +50,7 @@ class RequireTwoFactorAuthentication
// send them right through, nothing else needs to be checked. // send them right through, nothing else needs to be checked.
// //
// If the level is set as admin and the user is not an admin, pass them through as well. // If the level is set as admin and the user is not an admin, pass them through as well.
if ($level === self::LEVEL_NONE || $user->has2FAEnabled()) { if ($level === self::LEVEL_NONE || $user->has2FAEnabled() || ($level === self::LEVEL_ADMIN && !$user->root_admin)) {
return $next($request);
} elseif ($level === self::LEVEL_ADMIN && !$user->root_admin) {
return $next($request); return $next($request);
} }

View file

@ -17,7 +17,7 @@
} }
], ],
"require": { "require": {
"php": "^8.0.2 || ^8.1 || ^8.2", "php": "^8.1 || ^8.2",
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-pdo": "*", "ext-pdo": "*",

4
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "1e13394cf95fb955fbf12cb9f71e215d", "content-hash": "04a0ce5d940be3c570a4705b0d009641",
"packages": [ "packages": [
{ {
"name": "aws/aws-crt-php", "name": "aws/aws-crt-php",
@ -12074,7 +12074,7 @@
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "^8.0.2 || ^8.1 || ^8.2", "php": "^8.1 || ^8.2",
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-pdo": "*", "ext-pdo": "*",

View file

@ -24,20 +24,16 @@ class SecurityKeyFactory extends Factory
{ {
return [ return [
'uuid' => Uuid::uuid4()->toString(), 'uuid' => Uuid::uuid4()->toString(),
'user_id' => User::factory(),
'name' => $this->faker->word, 'name' => $this->faker->word,
'type' => 'public-key', 'type' => 'public-key',
'transports' => [], 'transports' => [],
'attestation_type' => 'none', 'attestation_type' => 'none',
'trust_path' => new EmptyTrustPath(), 'trust_path' => new EmptyTrustPath(),
'user_handle' => function (array $attributes) {
return User::find($attributes['user_id'])->uuid;
},
'counter' => 0, 'counter' => 0,
]; ];
} }
public function withUser(User $user): self
{
return $this->state([
'user_id' => $user->id,
'user_handle' => $user->uuid,
]);
}
} }

View file

@ -19,6 +19,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertFalse($user->use_totp); $this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isEmpty());
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null); $this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
@ -39,6 +40,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertTrue($user->use_totp); $this->assertTrue($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isEmpty());
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null); $this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
@ -49,21 +51,21 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$middleware->handle($this->request, $this->getClosureAssertions()); $middleware->handle($this->request, $this->getClosureAssertions());
} }
public function testNoRequirementUserWithWebauthn2fa() public function testNoRequirementUserWithSecurityKey2fa()
{ {
// Disable the 2FA requirement // Disable the 2FA requirement
config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_NONE); config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_NONE);
/** @var \Pterodactyl\Models\User $user */ /** @var \Pterodactyl\Models\User $user */
$user = User::factory() $user = User::factory()
->has(SecurityKey::factory()->count(1)) ->make(['use_totp' => false])
->create(['use_totp' => false]); ->setRelation('securityKeys', SecurityKey::factory()->count(1)->make());
$this->setRequestUserModel($user); $this->setRequestUserModel($user);
$this->assertFalse($user->use_totp); $this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertNotEmpty($user->securityKeys); $this->assertTrue($user->securityKeys->isNotEmpty());
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null); $this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
@ -102,7 +104,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertFalse($user->use_totp); $this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertEmpty($user->securityKeys); $this->assertTrue($user->securityKeys->isEmpty());
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null); $this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
@ -123,6 +125,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertTrue($user->use_totp); $this->assertTrue($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isEmpty());
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null); $this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
@ -133,21 +136,21 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$middleware->handle($this->request, $this->getClosureAssertions()); $middleware->handle($this->request, $this->getClosureAssertions());
} }
public function testAllRequirementRuserWithWebauthn2fa() public function testAllRequirementUserWithSecurityKey2fa()
{ {
// Disable the 2FA requirement // Disable the 2FA requirement
config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_ALL); config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_ALL);
/** @var \Pterodactyl\Models\User $user */ /** @var \Pterodactyl\Models\User $user */
$user = User::factory() $user = User::factory()
->has(SecurityKey::factory()->count(1)) ->make(['use_totp' => false])
->create(['use_totp' => false]); ->setRelation('securityKeys', SecurityKey::factory()->count(1)->make());
$this->setRequestUserModel($user); $this->setRequestUserModel($user);
$this->assertFalse($user->use_totp); $this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertNotEmpty($user->securityKeys); $this->assertTrue($user->securityKeys->isNotEmpty());
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null); $this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
@ -184,6 +187,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertFalse($user->use_totp); $this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isEmpty());
$this->assertFalse($user->root_admin); $this->assertFalse($user->root_admin);
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
@ -207,6 +211,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertFalse($user->use_totp); $this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isEmpty());
$this->assertTrue($user->root_admin); $this->assertTrue($user->root_admin);
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
@ -228,6 +233,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertTrue($user->use_totp); $this->assertTrue($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isEmpty());
$this->assertFalse($user->root_admin); $this->assertFalse($user->root_admin);
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
@ -249,6 +255,7 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$this->assertTrue($user->use_totp); $this->assertTrue($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isEmpty());
$this->assertTrue($user->root_admin); $this->assertTrue($user->root_admin);
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
@ -260,45 +267,22 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$middleware->handle($this->request, $this->getClosureAssertions()); $middleware->handle($this->request, $this->getClosureAssertions());
} }
public function testAdminRequirementUserWithWebauthn2fa() public function testAdminRequirementUserWithSecurityKey2fa()
{
// Disable the 2FA requirement
config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_ADMIN);
/** @var \Pterodactyl\Models\User $user */
$user = User::factory()->has(SecurityKey::factory()->count(1))->create(['use_totp' => false]);
$this->setRequestUserModel($user);
$this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at);
$this->assertFalse($user->root_admin);
$this->assertNotEmpty($user->securityKeys);
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
$this->request->shouldReceive('isJson')->withNoArgs()->andReturn(true);
/** @var \Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication $controller */
$middleware = $this->app->make(RequireTwoFactorAuthentication::class);
$middleware->handle($this->request, $this->getClosureAssertions());
}
public function testAdminRequirementAdminUserWithWebauthn2fa()
{ {
// Disable the 2FA requirement // Disable the 2FA requirement
config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_ADMIN); config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_ADMIN);
/** @var \Pterodactyl\Models\User $user */ /** @var \Pterodactyl\Models\User $user */
$user = User::factory() $user = User::factory()
->has(SecurityKey::factory()->count(1)) ->make(['use_totp' => false])
->create(['use_totp' => false, 'root_admin' => true]); ->setRelation('securityKeys', SecurityKey::factory()->count(1)->make());
$this->setRequestUserModel($user); $this->setRequestUserModel($user);
$this->assertFalse($user->use_totp); $this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret); $this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at); $this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->root_admin); $this->assertFalse($user->root_admin);
$this->assertTrue($user->securityKeys->isNotEmpty());
$this->assertNotEmpty($user->securityKeys); $this->assertNotEmpty($user->securityKeys);
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/'); $this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
@ -310,6 +294,32 @@ class RequireTwoFactorAuthenticationTest extends MiddlewareTestCase
$middleware->handle($this->request, $this->getClosureAssertions()); $middleware->handle($this->request, $this->getClosureAssertions());
} }
public function testAdminRequirementAdminUserWithSecurityKey2fa()
{
// Disable the 2FA requirement
config()->set('pterodactyl.auth.2fa_required', RequireTwoFactorAuthentication::LEVEL_ADMIN);
/** @var \Pterodactyl\Models\User $user */
$user = User::factory()
->make(['use_totp' => false, 'root_admin' => true])
->setRelation('securityKeys', SecurityKey::factory()->count(1)->make());
$this->setRequestUserModel($user);
$this->assertFalse($user->use_totp);
$this->assertEmpty($user->totp_secret);
$this->assertEmpty($user->totp_authenticated_at);
$this->assertTrue($user->securityKeys->isNotEmpty());
$this->assertTrue($user->root_admin);
$this->request->shouldReceive('getRequestUri')->withNoArgs()->andReturn('/');
$this->request->shouldReceive('route->getName')->withNoArgs()->andReturn(null);
$this->request->shouldReceive('isJson')->withNoArgs()->andReturn(true);
/** @var \Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication $controller */
$middleware = $this->app->make(RequireTwoFactorAuthentication::class);
$middleware->handle($this->request, $this->getClosureAssertions());
}
public function testAdminRequirementGuestUser() public function testAdminRequirementGuestUser()
{ {
// Disable the 2FA requirement // Disable the 2FA requirement