Basics of auth

This commit is contained in:
2026-01-01 10:32:17 -05:00
parent 23f2b6432b
commit 9f895bbb85
66 changed files with 5967 additions and 156 deletions

View File

@@ -0,0 +1,206 @@
<?php
declare(strict_types=1);
namespace Siteworxpro\App\OAuth\Entities;
use Defuse\Crypto\Exception\BadFormatException;
use Defuse\Crypto\Exception\EnvironmentIsBrokenException;
use Defuse\Crypto\Key;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use Random\RandomException;
use Siteworxpro\App\Helpers\Rand;
use Siteworxpro\App\Models\ClientRedirectUri;
use Siteworxpro\App\Models\ClientScope;
use Siteworxpro\App\Models\ClientUser;
use Siteworxpro\App\Models\Model;
use Siteworxpro\App\Models\User;
use Siteworxpro\App\OAuth\AccessTokenRepository;
use Siteworxpro\App\OAuth\ClientRepository;
use Siteworxpro\App\OAuth\ScopeRepository;
/**
* Class Client
* @package Siteworxpro\App\Models
*
* @property string $id
* @property string $client_id
* @property string $client_secret
* @property string $name
* @property string $description
* @property string $private_key
* @property string $encryption_key
* @property string[] $grant_types
* @property bool $confidential
*
* @property-read ClientCapabilities $capabilities
* @property-read Collection<ClientRedirectUri> $clientRedirectUris
* @property-read Scope[]|Collection $scopes
*/
class Client extends Model implements ClientEntityInterface
{
use EntityTrait;
protected $casts = [
'id' => 'string',
'grant_types' => 'collection',
'confidential' => 'boolean',
];
/**
* @throws RandomException|EnvironmentIsBrokenException
*/
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->client_id = Rand::string(32);
$this->client_secret = Rand::string(64);
$this->generatePrivateKey();
}
public static function byClientId(string $clientId): ?Client
{
return self::where('client_id', $clientId)->first();
}
/**
* @return void
* @throws EnvironmentIsBrokenException
*/
private function generatePrivateKey(): void
{
// generate rsa private and public key pair
$config = [
"digest_alg" => "sha256",
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
];
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privateKey);
$this->private_key = $privateKey;
$this->encryption_key = Key::createNewRandomKey()->saveToAsciiSafeString();
}
/**
* @return HasMany
*/
public function clientRedirectUris(): HasMany
{
return $this->hasMany(ClientRedirectUri::class);
}
/**
* @return HasManyThrough
*/
public function scopes(): HasManyThrough
{
return $this->hasManyThrough(Scope::class, ClientScope::class);
}
/**
* @return HasManyThrough
*/
public function users(): HasManyThrough
{
return $this->hasManyThrough(User::class, ClientUser::class);
}
/**
* @return string
*/
public function getIdentifier(): string
{
return $this->id;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return string|array
*/
public function getRedirectUri(): string|array
{
return $this->clientRedirectUris->pluck('redirect_uri')->toArray();
}
/**
* @return bool
*/
public function isConfidential(): bool
{
return $this->confidential;
}
public function getCapabilitiesAttribute(string $capabilities): ClientCapabilities
{
return ClientCapabilities::fromJson($capabilities);
}
/**
* @throws \JsonException
*/
public function setCapabilitiesAttribute(ClientCapabilities $capabilities): void
{
$this->attributes->capabilities = $capabilities->toJson();
}
/**
* @throws BadFormatException
* @throws EnvironmentIsBrokenException
* @throws \Exception
*/
public function getAuthorizationServer(): AuthorizationServer
{
$authorizationServer = new AuthorizationServer(
new ClientRepository($this),
new AccessTokenRepository(),
new ScopeRepository(),
$this->private_key,
Key::loadFromAsciiSafeString($this->encryption_key)
);
if (!empty($this->grant_types)) {
foreach ($this->grant_types as $grantType) {
switch ($grantType) {
case 'authorization_code':
$grant = new \League\OAuth2\Server\Grant\AuthCodeGrant(
new \Siteworxpro\App\OAuth\AuthCodeRepository(),
new \Siteworxpro\App\OAuth\RefreshTokenRepository(),
new \DateInterval('PT10M')
);
$grant->setRefreshTokenTTL(new \DateInterval('P1M'));
break;
case 'client_credentials':
$grant = new \League\OAuth2\Server\Grant\ClientCredentialsGrant();
break;
case 'refresh_token':
$grant = new \League\OAuth2\Server\Grant\RefreshTokenGrant(
new \Siteworxpro\App\OAuth\RefreshTokenRepository()
);
$grant->setRefreshTokenTTL(new \DateInterval('P1M'));
break;
default:
continue 2;
}
$authorizationServer->enableGrantType($grant);
}
}
return $authorizationServer;
}
}