<?php namespace Tests\Unit\Services\Sftp; use Mockery as m; use Tests\TestCase; use Pterodactyl\Models\User; use Pterodactyl\Models\Server; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Services\Sftp\AuthenticateUsingPasswordService; use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface; class AuthenticateUsingPasswordServiceTest extends TestCase { /** * @var \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService|\Mockery\Mock */ private $keyProviderService; /** * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface|\Mockery\Mock */ private $repository; /** * @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface|\Mockery\Mock */ private $subuserRepository; /** * @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface|\Mockery\Mock */ private $userRepository; /** * Setup tests. */ public function setUp() { parent::setUp(); $this->keyProviderService = m::mock(DaemonKeyProviderService::class); $this->repository = m::mock(ServerRepositoryInterface::class); $this->subuserRepository = m::mock(SubuserRepositoryInterface::class); $this->userRepository = m::mock(UserRepositoryInterface::class); } /** * Test that an account can be authenticated. */ public function testNonAdminAccountIsAuthenticated() { $user = factory(User::class)->make(['root_admin' => 0]); $server = factory(Server::class)->make(['node_id' => 1, 'owner_id' => $user->id]); $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', $user->username]])->once()->andReturn($user); $this->repository->shouldReceive('setColumns')->with(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); $this->keyProviderService->shouldReceive('handle')->with($server, $user)->once()->andReturn('server_token'); $response = $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); $this->assertNotEmpty($response); $this->assertArrayHasKey('server', $response); $this->assertArrayHasKey('token', $response); $this->assertSame($server->uuid, $response['server']); $this->assertSame('server_token', $response['token']); } /** * Test that an administrative user can access servers that they are not * set as the owner of. */ public function testAdminAccountIsAuthenticated() { $user = factory(User::class)->make(['root_admin' => 1]); $server = factory(Server::class)->make(['node_id' => 1, 'owner_id' => $user->id + 1]); $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', $user->username]])->once()->andReturn($user); $this->repository->shouldReceive('setColumns')->with(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); $this->keyProviderService->shouldReceive('handle')->with($server, $user)->once()->andReturn('server_token'); $response = $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); $this->assertNotEmpty($response); $this->assertArrayHasKey('server', $response); $this->assertArrayHasKey('token', $response); $this->assertSame($server->uuid, $response['server']); $this->assertSame('server_token', $response['token']); } /** * Test exception gets thrown if no server is passed into the function. * * @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function testExceptionIsThrownIfNoServerIsProvided() { $this->getService()->handle('username', 'password', 1); } /** * Test that an exception is thrown if the user account exists but the wrong * credentials are passed. * * @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function testExceptionIsThrownIfUserDetailsAreIncorrect() { $user = factory(User::class)->make(); $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', $user->username]])->once()->andReturn($user); $this->getService()->handle($user->username, 'wrongpassword', 1, '1234'); } /** * Test that an exception is thrown if no user account is found. * * @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function testExceptionIsThrownIfNoUserAccountIsFound() { $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', 'something']])->once()->andThrow(new RecordNotFoundException); $this->getService()->handle('something', 'password', 1, '1234'); } /** * Test that an exception is thrown if the user is not the owner of the server, * is not a sub user and is not an administrator. * * @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function testExceptionIsThrownIfUserDoesNotOwnServer() { $user = factory(User::class)->make(['root_admin' => 0]); $server = factory(Server::class)->make(['node_id' => 1, 'owner_id' => $user->id + 1]); $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', $user->username]])->once()->andReturn($user); $this->repository->shouldReceive('setColumns')->with(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); $this->subuserRepository->shouldReceive('getWithPermissionsUsingUserAndServer')->with($user->id, $server->id)->once()->andThrow(new RecordNotFoundException); $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); } /** * Test that an exception is thrown if the requested server does not belong to * the node that the request is made from. * * @expectedException \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function testExceptionIsThrownIfServerDoesNotExistOnCurrentNode() { $user = factory(User::class)->make(['root_admin' => 0]); $server = factory(Server::class)->make(['node_id' => 2, 'owner_id' => $user->id]); $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', $user->username]])->once()->andReturn($user); $this->repository->shouldReceive('setColumns')->with(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); } /** * Test that a suspended server throws an exception. * * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException */ public function testSuspendedServer() { $user = factory(User::class)->make(['root_admin' => 1]); $server = factory(Server::class)->make(['node_id' => 1, 'owner_id' => $user->id + 1, 'suspended' => 1]); $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', $user->username]])->once()->andReturn($user); $this->repository->shouldReceive('setColumns')->with(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); } /** * Test that a server that is not yet installed throws an exception. * * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException */ public function testNotInstalledServer() { $user = factory(User::class)->make(['root_admin' => 1]); $server = factory(Server::class)->make(['node_id' => 1, 'owner_id' => $user->id + 1, 'installed' => 0]); $this->userRepository->shouldReceive('setColumns')->with(['id', 'root_admin', 'password'])->once()->andReturnSelf(); $this->userRepository->shouldReceive('findFirstWhere')->with([['username', '=', $user->username]])->once()->andReturn($user); $this->repository->shouldReceive('setColumns')->with(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->once()->andReturnSelf(); $this->repository->shouldReceive('getByUuid')->with($server->uuidShort)->once()->andReturn($server); $this->getService()->handle($user->username, 'password', 1, $server->uuidShort); } /** * Return an instance of the service with mocked dependencies. * * @return \Pterodactyl\Services\Sftp\AuthenticateUsingPasswordService */ private function getService(): AuthenticateUsingPasswordService { return new AuthenticateUsingPasswordService($this->keyProviderService, $this->repository, $this->subuserRepository, $this->userRepository); } }