Initial pass at implementing Laravel Sanctum for authorization on the API

This commit is contained in:
DaneEveritt 2022-05-22 14:57:06 -04:00
parent e313dff674
commit bd37978a98
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
13 changed files with 324 additions and 220 deletions

View file

@ -2,19 +2,59 @@
namespace Pterodactyl\Models;
use Illuminate\Support\Str;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Pterodactyl\Models\ApiKey.
*
* @property int $id
* @property int $user_id
* @property int $key_type
* @property string $identifier
* @property string|null $identifier
* @property string $token
* @property array $allowed_ips
* @property string $memo
* @property \Carbon\Carbon|null $last_used_at
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property array|null $allowed_ips
* @property string|null $memo
* @property \Illuminate\Support\Carbon|null $last_used_at
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property int $r_servers
* @property int $r_nodes
* @property int $r_allocations
* @property int $r_users
* @property int $r_locations
* @property int $r_nests
* @property int $r_eggs
* @property int $r_database_hosts
* @property int $r_server_databases
* @property \Pterodactyl\Models\User $tokenable
* @property \Pterodactyl\Models\User $user
*
* @method static \Database\Factories\ApiKeyFactory factory(...$parameters)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey query()
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereAllowedIps($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereIdentifier($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereKeyType($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereLastUsedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereMemo($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRAllocations($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRDatabaseHosts($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereREggs($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRLocations($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRNests($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRNodes($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRServerDatabases($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRServers($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereRUsers($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereToken($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ApiKey whereUserId($value)
* @mixin \Eloquent
*/
class ApiKey extends Model
{
@ -23,21 +63,21 @@ class ApiKey extends Model
* API representation using fractal.
*/
public const RESOURCE_NAME = 'api_key';
/**
* Different API keys that can exist on the system.
*/
public const TYPE_NONE = 0;
public const TYPE_ACCOUNT = 1;
/* @deprecated */
public const TYPE_APPLICATION = 2;
/* @deprecated */
public const TYPE_DAEMON_USER = 3;
/* @deprecated */
public const TYPE_DAEMON_APPLICATION = 4;
/**
* The length of API key identifiers.
*/
public const IDENTIFIER_LENGTH = 16;
/**
* The length of the actual API key that is encrypted and stored
* in the database.
@ -124,4 +164,47 @@ class ApiKey extends Model
self::UPDATED_AT,
'last_used_at',
];
/**
* Returns the user this token is assigned to.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Required for support with Laravel Sanctum.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*
* @see \Laravel\Sanctum\Guard::supportsTokens()
*/
public function tokenable()
{
return $this->user();
}
/**
* Finds the model matching the provided token.
*
* @param string $token
*
* @return self|null
*/
public static function findToken($token)
{
$id = Str::substr($token, 0, self::IDENTIFIER_LENGTH);
$token = Str::substr($token, strlen($id));
return static::where('identifier', $id)->where('token', encrypt($token))->first();
}
/**
* Generates a new identifier for an API key.
*/
public static function generateTokenIdentifier(): string
{
return 'ptdl_' . Str::random(self::IDENTIFIER_LENGTH - 5);
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace Pterodactyl\Models\Traits;
use Illuminate\Support\Str;
use Laravel\Sanctum\Sanctum;
use Pterodactyl\Models\ApiKey;
use Laravel\Sanctum\HasApiTokens;
use Pterodactyl\Extensions\Laravel\Sanctum\NewAccessToken;
/**
* @mixin \Pterodactyl\Models\Model
*/
trait HasAccessTokens
{
use HasApiTokens;
public function tokens()
{
return $this->hasMany(Sanctum::$personalAccessTokenModel);
}
public function createToken(string $name, array $abilities = ['*'])
{
/** @var \Pterodactyl\Models\ApiKey $token */
$token = $this->tokens()->create([
'user_id' => $this->id,
'key_type' => ApiKey::TYPE_ACCOUNT,
'identifier' => ApiKey::generateTokenIdentifier(),
'token' => encrypt($plain = Str::random(ApiKey::KEY_LENGTH)),
'memo' => $name,
'allowed_ips' => [],
]);
return new NewAccessToken($token, $token->identifier . $plain);
}
}

View file

@ -3,6 +3,7 @@
namespace Pterodactyl\Models;
use Pterodactyl\Rules\Username;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Support\Collection;
use Illuminate\Validation\Rules\In;
use Illuminate\Auth\Authenticatable;
@ -18,7 +19,7 @@ use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification;
/**
* \Pterodactyl\Models\User.
* Pterodactyl\Models\User.
*
* @property int $id
* @property string|null $external_id
@ -28,27 +29,28 @@ use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification;
* @property string|null $name_first
* @property string|null $name_last
* @property string $password
* @property string|null $remeber_token
* @property string|null $remember_token
* @property string $language
* @property bool $root_admin
* @property bool $use_totp
* @property string|null $totp_secret
* @property \Carbon\Carbon|null $totp_authenticated_at
* @property \Illuminate\Support\Carbon|null $totp_authenticated_at
* @property bool $gravatar
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property string $name
* @property \Pterodactyl\Models\ApiKey[]|\Illuminate\Database\Eloquent\Collection $apiKeys
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
* @property \Pterodactyl\Models\RecoveryToken[]|\Illuminate\Database\Eloquent\Collection $recoveryTokens
* @property string|null $remember_token
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\ApiKey[] $apiKeys
* @property int|null $api_keys_count
* @property string $name
* @property \Illuminate\Notifications\DatabaseNotificationCollection|\Illuminate\Notifications\DatabaseNotification[] $notifications
* @property int|null $notifications_count
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\RecoveryToken[] $recoveryTokens
* @property int|null $recovery_tokens_count
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Server[] $servers
* @property int|null $servers_count
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\UserSSHKey[] $sshKeys
* @property int|null $ssh_keys_count
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\ApiKey[] $tokens
* @property int|null $tokens_count
*
* @method static \Database\Factories\UserFactory factory(...$parameters)
* @method static Builder|User newModelQuery()
@ -82,6 +84,7 @@ class User extends Model implements
use Authorizable;
use AvailableLanguages;
use CanResetPassword;
use HasApiTokens;
use Notifiable;
public const USER_LEVEL_USER = 0;