Add support for allowing subusers to access SFTP. (#918)
This commit is contained in:
parent
f61a5fa0cb
commit
d8be167a9c
10 changed files with 64 additions and 70 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -5,7 +5,9 @@
|
|||
.vscode/*
|
||||
storage/framework/*
|
||||
/.idea
|
||||
/nbproject
|
||||
|
||||
package-lock.json
|
||||
composer.lock
|
||||
node_modules
|
||||
|
||||
|
|
|
@ -90,12 +90,12 @@ class Permission extends Model implements CleansAttributes, ValidableContract
|
|||
'view-startup' => null,
|
||||
'edit-startup' => null,
|
||||
],
|
||||
'sftp' => [
|
||||
'view-sftp' => null,
|
||||
'view-sftp-password' => null,
|
||||
'reset-sftp' => 's:set-password',
|
||||
'database' => [
|
||||
'view-databases' => null,
|
||||
'reset-db-password' => null,
|
||||
],
|
||||
'file' => [
|
||||
'access-sftp' => null,
|
||||
'list-files' => 's:files:get',
|
||||
'edit-files' => 's:files:read',
|
||||
'save-files' => 's:files:post',
|
||||
|
@ -106,7 +106,7 @@ class Permission extends Model implements CleansAttributes, ValidableContract
|
|||
'create-files' => 's:files:create',
|
||||
'upload-files' => 's:files:upload',
|
||||
'delete-files' => 's:files:delete',
|
||||
'download-files' => null,
|
||||
'download-files' => 's:files:download',
|
||||
],
|
||||
'task' => [
|
||||
'list-schedules' => null,
|
||||
|
@ -117,10 +117,6 @@ class Permission extends Model implements CleansAttributes, ValidableContract
|
|||
'create-schedule' => null,
|
||||
'delete-schedule' => null,
|
||||
],
|
||||
'database' => [
|
||||
'view-databases' => null,
|
||||
'reset-db-password' => null,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,7 @@ use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
|||
use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService;
|
||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
class AuthenticateUsingPasswordService
|
||||
|
@ -25,20 +26,28 @@ class AuthenticateUsingPasswordService
|
|||
*/
|
||||
private $userRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface
|
||||
*/
|
||||
private $subuserRepository;
|
||||
|
||||
/**
|
||||
* AuthenticateUsingPasswordService constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface $subuserRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $userRepository
|
||||
*/
|
||||
public function __construct(
|
||||
DaemonKeyProviderService $keyProviderService,
|
||||
ServerRepositoryInterface $repository,
|
||||
SubuserRepositoryInterface $subuserRepository,
|
||||
UserRepositoryInterface $userRepository
|
||||
) {
|
||||
$this->keyProviderService = $keyProviderService;
|
||||
$this->repository = $repository;
|
||||
$this->subuserRepository = $subuserRepository;
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
|
@ -73,10 +82,19 @@ class AuthenticateUsingPasswordService
|
|||
}
|
||||
|
||||
$server = $this->repository->setColumns(['id', 'node_id', 'owner_id', 'uuid', 'installed', 'suspended'])->getByUuid($server);
|
||||
if ($server->node_id !== $node || (! $user->root_admin && $server->owner_id !== $user->id)) {
|
||||
if ($server->node_id !== $node) {
|
||||
throw new RecordNotFoundException;
|
||||
}
|
||||
|
||||
if (! $user->root_admin && $server->owner_id !== $user->id) {
|
||||
$subuser = $this->subuserRepository->getWithPermissionsUsingUserAndServer($user->id, $server->id);
|
||||
$permissions = $subuser->getRelation('permissions')->pluck('permission')->toArray();
|
||||
|
||||
if (! in_array('access-sftp', $permissions)) {
|
||||
throw new RecordNotFoundException;
|
||||
}
|
||||
}
|
||||
|
||||
if ($server->installed !== 1 || $server->suspended) {
|
||||
throw new BadRequestHttpException;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,6 @@ return [
|
|||
'subuser_header' => 'Subuser Verwaltung',
|
||||
'server_header' => 'Server Verwaltung',
|
||||
'task_header' => 'Schedule Verwaltung',
|
||||
'sftp_header' => 'SFTP Verwaltung',
|
||||
'database_header' => 'Database Verwaltung',
|
||||
'power_start' => [
|
||||
'title' => 'Start Server',
|
||||
|
@ -125,17 +124,21 @@ return [
|
|||
'title' => 'Send Console Command',
|
||||
'description' => 'Der User darf die Konsole benutzen.',
|
||||
],
|
||||
'view_sftp' => [
|
||||
'title' => 'SFTP erlaubt',
|
||||
'description' => 'Ermöglicht dem Benutzer, eine Verbindung mit dem vom Daemon bereitgestellten SFTP-Server herzustellen.',
|
||||
],
|
||||
'list_files' => [
|
||||
'title' => 'List Files',
|
||||
'description' => 'Der User darf die Server-Dateien sehen.',
|
||||
],
|
||||
'edit_files' => [
|
||||
'title' => 'Edit Files',
|
||||
'description' => 'Der User darf die Server-Dateien sehen.',
|
||||
'description' => 'Der User darf die Server-Dateien sehen. SFTP ist von dieser Erlaubnis nicht betroffen.',
|
||||
],
|
||||
'save_files' => [
|
||||
'title' => 'Save Files',
|
||||
'description' => 'Der User darf die Server-Dateien bearbeiten.',
|
||||
'description' => 'Der User darf die Server-Dateien bearbeiten. SFTP ist von dieser Erlaubnis nicht betroffen.',
|
||||
],
|
||||
'move_files' => [
|
||||
'title' => 'Rename & Move Files',
|
||||
|
@ -233,18 +236,6 @@ return [
|
|||
'title' => 'Delete Schedule',
|
||||
'description' => 'Der User darf geplante Aktionen für den Server löschen.',
|
||||
],
|
||||
'view_sftp' => [
|
||||
'title' => 'View SFTP Details',
|
||||
'description' => 'Der User darf die SFTP Informationen sehen (nicht das Passwort).',
|
||||
],
|
||||
'view_sftp_password' => [
|
||||
'title' => 'View SFTP Password',
|
||||
'description' => 'Der User darf dass SFTP Passwort sehen.',
|
||||
],
|
||||
'reset_sftp' => [
|
||||
'title' => 'Reset SFTP Password',
|
||||
'description' => 'Der User darf dass SFTP Passwort zurücksetzen.',
|
||||
],
|
||||
'view_databases' => [
|
||||
'title' => 'View Database Details',
|
||||
'description' => 'Der User darf die Datenbankinformationen sehen.',
|
||||
|
@ -298,7 +289,6 @@ return [
|
|||
'sftp' => [
|
||||
'header' => 'SFTP Information',
|
||||
'header_sub' => 'Details für eine SFTP verbindung.',
|
||||
'change_pass' => 'Passwort ändern',
|
||||
'details' => 'SFTP Details',
|
||||
'conn_addr' => 'Adresse',
|
||||
'warning' => 'Bitte benutze SFTP und nicht FTP!.',
|
||||
|
|
|
@ -107,7 +107,6 @@ return [
|
|||
'subuser_header' => 'Subuser Management',
|
||||
'server_header' => 'Server Management',
|
||||
'task_header' => 'Schedule Management',
|
||||
'sftp_header' => 'SFTP Management',
|
||||
'database_header' => 'Database Management',
|
||||
'power_start' => [
|
||||
'title' => 'Start Server',
|
||||
|
@ -129,17 +128,21 @@ return [
|
|||
'title' => 'Send Console Command',
|
||||
'description' => 'Allows sending a command from the console. If the user does not have stop or restart permissions they cannot send the application\'s stop command.',
|
||||
],
|
||||
'view_sftp' => [
|
||||
'title' => 'SFTP Allowed',
|
||||
'description' => 'Allows user to connect to the SFTP server provided by the daemon.',
|
||||
],
|
||||
'list_files' => [
|
||||
'title' => 'List Files',
|
||||
'description' => 'Allows user to list all files and folders on the server but not view file contents.',
|
||||
],
|
||||
'edit_files' => [
|
||||
'title' => 'Edit Files',
|
||||
'description' => 'Allows user to open a file for viewing only.',
|
||||
'description' => 'Allows user to open a file for viewing only. SFTP is not effected by this permission.',
|
||||
],
|
||||
'save_files' => [
|
||||
'title' => 'Save Files',
|
||||
'description' => 'Allows user to save modified file contents.',
|
||||
'description' => 'Allows user to save modified file contents. SFTP is not effected by this permission.',
|
||||
],
|
||||
'move_files' => [
|
||||
'title' => 'Rename & Move Files',
|
||||
|
@ -237,18 +240,6 @@ return [
|
|||
'title' => 'Delete Schedule',
|
||||
'description' => 'Allows a user to delete a schedule from the server.',
|
||||
],
|
||||
'view_sftp' => [
|
||||
'title' => 'View SFTP Details',
|
||||
'description' => 'Allows user to view the server\'s SFTP information but not the password.',
|
||||
],
|
||||
'view_sftp_password' => [
|
||||
'title' => 'View SFTP Password',
|
||||
'description' => 'Allows user to view the SFTP password for the server.',
|
||||
],
|
||||
'reset_sftp' => [
|
||||
'title' => 'Reset SFTP Password',
|
||||
'description' => 'Allows user to change the SFTP password for the server.',
|
||||
],
|
||||
'view_databases' => [
|
||||
'title' => 'View Database Details',
|
||||
'description' => 'Allows user to view all databases associated with this server including the usernames and passwords for the databases.',
|
||||
|
@ -302,7 +293,6 @@ return [
|
|||
'sftp' => [
|
||||
'header' => 'SFTP Configuration',
|
||||
'header_sub' => 'Account details for SFTP connections.',
|
||||
'change_pass' => 'Change SFTP Password',
|
||||
'details' => 'SFTP Details',
|
||||
'conn_addr' => 'Connection Address',
|
||||
'warning' => 'The SFTP password is your account password. Ensure that your client is set to use SFTP and not FTP or FTPS for connections, there is a difference between the protocols.',
|
||||
|
|
|
@ -103,7 +103,6 @@ return [
|
|||
'subuser_header' => 'Subuser De Gestión',
|
||||
'server_header' => 'Administración Del Servidor',
|
||||
'task_header' => 'La Programación De La Administración',
|
||||
'sftp_header' => 'SFTP Gestión',
|
||||
'database_header' => 'Administración De Base De Datos',
|
||||
'power_start' => [
|
||||
'title' => 'Inicio Del Servidor',
|
||||
|
@ -125,17 +124,21 @@ return [
|
|||
'title' => 'Enviar Comandos De La Consola',
|
||||
'description' => 'Permite el envío de un comando desde la consola. Si el usuario no tiene permiso para detener o reiniciar, no puede enviar el comando de detención de la aplicación.',
|
||||
],
|
||||
'view_sftp' => [
|
||||
'title' => 'SFTP permitido',
|
||||
'description' => 'Permite al usuario conectarse al servidor SFTP proporcionado por el daemon.',
|
||||
],
|
||||
'list_files' => [
|
||||
'title' => 'Lista De Archivos',
|
||||
'description' => 'Permite al usuario a la lista de todos los archivos y carpetas en el servidor, pero no ver el contenido del archivo.',
|
||||
],
|
||||
'edit_files' => [
|
||||
'title' => 'Editar Archivos',
|
||||
'description' => 'Permite al usuario abrir un archivo solo para visualización.',
|
||||
'description' => 'Permite al usuario abrir un archivo solo para visualización. SFTP no se ve afectado por este permiso.',
|
||||
],
|
||||
'save_files' => [
|
||||
'title' => 'Guardar Archivos',
|
||||
'description' => 'Permite que el usuario guarde el archivo modificado contenido.',
|
||||
'description' => 'Permite que el usuario guarde el archivo modificado contenido. SFTP no se ve afectado por este permiso.',
|
||||
],
|
||||
'move_files' => [
|
||||
'title' => 'Renombrar Y Mover Archivos',
|
||||
|
@ -229,18 +232,6 @@ return [
|
|||
'title' => 'Eliminar Horario',
|
||||
'description' => 'Permite a un usuario para eliminar un programa desde el servidor.',
|
||||
],
|
||||
'view_sftp' => [
|
||||
'title' => 'Ver SFTP Detalles',
|
||||
'description' => 'Permite al usuario ver la información SFTP del servidor pero no la contraseña.',
|
||||
],
|
||||
'view_sftp_password' => [
|
||||
'title' => 'Ver SFTP Contraseña',
|
||||
'description' => 'Permite al usuario ver el SFTP contraseña para el servidor.',
|
||||
],
|
||||
'reset_sftp' => [
|
||||
'title' => 'Restablecer Contraseña SFTP',
|
||||
'description' => 'Le permite al usuario cambiar el SFTP contraseña para el servidor.',
|
||||
],
|
||||
'view_databases' => [
|
||||
'title' => 'Ver Detalles De Base De Datos',
|
||||
'description' => 'Permite al usuario ver todas las bases de datos asociadas con este servidor, incluidos los nombres de usuario y contraseñas de las bases de datos de.',
|
||||
|
@ -294,7 +285,6 @@ return [
|
|||
'sftp' => [
|
||||
'header' => 'SFTP Configuración',
|
||||
'header_sub' => 'Detalles de la cuenta para SFTP.',
|
||||
'change_pass' => 'Cambiar Contraseña SFTP',
|
||||
'details' => 'SFTP Detalles',
|
||||
'conn_addr' => 'Dirección De Conexión',
|
||||
'warning' => 'Asegúrese de que su cliente está configurado para utilizar SFTP y FTP no o FTPS para las conexiones, hay una diferencia entre los protocolos.',
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
@if(Gate::allows('view-startup', $server) || Gate::allows('view-sftp', $server) || Gate::allows('view-allocation', $server))
|
||||
@if(Gate::allows('view-startup', $server) || Gate::allows('access-sftp', $server) || Gate::allows('view-allocation', $server))
|
||||
<li class="treeview
|
||||
@if(starts_with(Route::currentRouteName(), 'server.settings'))
|
||||
active
|
||||
|
@ -183,7 +183,7 @@
|
|||
@can('view-allocation', $server)
|
||||
<li class="{{ Route::currentRouteName() !== 'server.settings.allocation' ?: 'active' }}"><a href="{{ route('server.settings.allocation', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> @lang('navigation.server.port_allocations')</a></li>
|
||||
@endcan
|
||||
@can('view-sftp', $server)
|
||||
@can('access-sftp', $server)
|
||||
<li class="{{ Route::currentRouteName() !== 'server.settings.sftp' ?: 'active' }}"><a href="{{ route('server.settings.sftp', $server->uuidShort) }}"><i class="fa fa-angle-right"></i> @lang('navigation.server.sftp_settings')</a></li>
|
||||
@endcan
|
||||
@can('view-startup', $server)
|
||||
|
|
|
@ -11,6 +11,7 @@ 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
|
||||
{
|
||||
|
@ -24,6 +25,11 @@ class AuthenticateUsingPasswordServiceTest extends TestCase
|
|||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface|\Mockery\Mock
|
||||
*/
|
||||
private $subuserRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface|\Mockery\Mock
|
||||
*/
|
||||
|
@ -38,6 +44,7 @@ class AuthenticateUsingPasswordServiceTest extends TestCase
|
|||
|
||||
$this->keyProviderService = m::mock(DaemonKeyProviderService::class);
|
||||
$this->repository = m::mock(ServerRepositoryInterface::class);
|
||||
$this->subuserRepository = m::mock(SubuserRepositoryInterface::class);
|
||||
$this->userRepository = m::mock(UserRepositoryInterface::class);
|
||||
}
|
||||
|
||||
|
@ -130,8 +137,8 @@ class AuthenticateUsingPasswordServiceTest extends TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* Test that an exception is thrown if the user is not the owner of the server
|
||||
* and is not an administrator.
|
||||
* 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
|
||||
*/
|
||||
|
@ -146,6 +153,8 @@ class AuthenticateUsingPasswordServiceTest extends TestCase
|
|||
$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);
|
||||
}
|
||||
|
||||
|
@ -214,6 +223,6 @@ class AuthenticateUsingPasswordServiceTest extends TestCase
|
|||
*/
|
||||
private function getService(): AuthenticateUsingPasswordService
|
||||
{
|
||||
return new AuthenticateUsingPasswordService($this->keyProviderService, $this->repository, $this->userRepository);
|
||||
return new AuthenticateUsingPasswordService($this->keyProviderService, $this->repository, $this->subuserRepository, $this->userRepository);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,12 +42,11 @@ class PermissionCreationServiceTest extends TestCase
|
|||
*/
|
||||
public function testPermissionsAreAssignedCorrectly()
|
||||
{
|
||||
$permissions = ['reset-sftp', 'view-sftp'];
|
||||
$permissions = ['access-sftp'];
|
||||
|
||||
$this->repository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf()
|
||||
->shouldReceive('insert')->with([
|
||||
['subuser_id' => 1, 'permission' => 'reset-sftp'],
|
||||
['subuser_id' => 1, 'permission' => 'view-sftp'],
|
||||
['subuser_id' => 1, 'permission' => 'access-sftp'],
|
||||
])->once()->andReturn(true);
|
||||
|
||||
$this->service->handle(1, $permissions);
|
||||
|
|
|
@ -121,7 +121,7 @@ class SubuserCreationServiceTest extends TestCase
|
|||
*/
|
||||
public function testExistingUserCanBeAddedAsASubuser()
|
||||
{
|
||||
$permissions = ['view-sftp', 'reset-sftp'];
|
||||
$permissions = ['access-sftp'];
|
||||
$server = factory(Server::class)->make();
|
||||
$user = factory(User::class)->make();
|
||||
$subuser = factory(Subuser::class)->make(['user_id' => $user->id, 'server_id' => $server->id]);
|
||||
|
|
Loading…
Reference in a new issue