mirror of
https://github.com/webmasterskaya/joomla-oauth-server.git
synced 2024-11-24 02:44:51 +03:00
Первый тест - Success
This commit is contained in:
parent
1efe232439
commit
2636bebd60
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Administrator\Event\Scope;
|
||||||
|
|
||||||
|
use Joomla\CMS\Event\AbstractEvent;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Entity\Scope;
|
||||||
|
|
||||||
|
class ScopeResolveEvent extends AbstractEvent
|
||||||
|
{
|
||||||
|
private bool $is_constructed;
|
||||||
|
|
||||||
|
public function __construct(array $scopes, string $grant, object $client, ?int $user_id)
|
||||||
|
{
|
||||||
|
$arguments = [
|
||||||
|
'scopes' => $scopes,
|
||||||
|
'grant' => $grant,
|
||||||
|
'client' => $client,
|
||||||
|
'user_id' => $user_id
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->is_constructed = false;
|
||||||
|
|
||||||
|
parent::__construct('onOauthServerScopeResolve', $arguments);
|
||||||
|
|
||||||
|
$this->is_constructed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function onSetScopes(array $scopes): array
|
||||||
|
{
|
||||||
|
foreach ($scopes as &$scope) {
|
||||||
|
if (!($scope instanceof Scope)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Argument "scopes" must be array of "%s" in class "%s". "%s" given.',
|
||||||
|
Scope::class,
|
||||||
|
get_class($this),
|
||||||
|
get_debug_type($scope)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function onSetGrant(string $grant)
|
||||||
|
{
|
||||||
|
if ($this->is_constructed) {
|
||||||
|
$grant = $this->getArgument('grant');
|
||||||
|
}
|
||||||
|
return $grant;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function onSetClient(object $client)
|
||||||
|
{
|
||||||
|
if ($this->is_constructed) {
|
||||||
|
$client = $this->getArgument('client');
|
||||||
|
}
|
||||||
|
return $client;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function onSetUser_id(?int $user_id)
|
||||||
|
{
|
||||||
|
if ($this->is_constructed) {
|
||||||
|
$user_id = $this->getArgument('user_id');
|
||||||
|
}
|
||||||
|
return $user_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeArgument($name)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException(
|
||||||
|
sprintf(
|
||||||
|
'Cannot remove the argument %s of the event %s.',
|
||||||
|
$name,
|
||||||
|
$this->name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clearArguments()
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException(
|
||||||
|
sprintf(
|
||||||
|
'Cannot clear arguments of the event %s.',
|
||||||
|
$this->name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
64
com_oauthserver/administrator/src/Model/AuthCodeModel.php
Normal file
64
com_oauthserver/administrator/src/Model/AuthCodeModel.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Administrator\Model;
|
||||||
|
|
||||||
|
use Joomla\CMS\Factory;
|
||||||
|
use Joomla\CMS\Form\Form;
|
||||||
|
use Joomla\CMS\Form\FormFactoryInterface;
|
||||||
|
use Joomla\CMS\MVC\Factory\LegacyFactory;
|
||||||
|
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||||
|
use Joomla\CMS\MVC\Model\AdminModel;
|
||||||
|
|
||||||
|
class AuthCodeModel extends AdminModel implements RevokedModelInterface
|
||||||
|
{
|
||||||
|
use GetItemByIdentifierTrait;
|
||||||
|
use RevokedModelTrait;
|
||||||
|
|
||||||
|
public function __construct($config = [], MVCFactoryInterface $factory = null, FormFactoryInterface $formFactory = null)
|
||||||
|
{
|
||||||
|
$this->name = 'AuthCode';
|
||||||
|
parent::__construct($config, $factory, $formFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTable($name = 'AuthCode', $prefix = 'Administrator', $options = [])
|
||||||
|
{
|
||||||
|
return parent::getTable($name, $prefix, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getForm($data = [], $loadData = true): Form|bool
|
||||||
|
{
|
||||||
|
$form = $this->loadForm('com_oauthserver.auth_code', 'auth_code', ['control' => 'jform', 'load_data' => $loadData]);
|
||||||
|
|
||||||
|
if (empty($form)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadFormData(): mixed
|
||||||
|
{
|
||||||
|
// Check the session for previously entered form data.
|
||||||
|
$data = Factory::getApplication()->getUserState('com_oauthserver.edit.auth_code.data', []);
|
||||||
|
|
||||||
|
if (empty($data)) {
|
||||||
|
$data = $this->getItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->preprocessData('com_oauthserver.auth_code', $data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Webmasterskaya\Component\OauthServer\Administrator\Table\AuthCodeTable $table
|
||||||
|
* @return void
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
protected function prepareTable($table)
|
||||||
|
{
|
||||||
|
if ($table->expiry instanceof \DateTime || $table->expiry instanceof \DateTimeImmutable) {
|
||||||
|
$table->expiry = $table->expiry->format($table->getDbo()->getDateFormat());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@ namespace Webmasterskaya\Component\OauthServer\Administrator\Model;
|
|||||||
|
|
||||||
use Joomla\CMS\Language\Text;
|
use Joomla\CMS\Language\Text;
|
||||||
use Joomla\CMS\Object\CMSObject;
|
use Joomla\CMS\Object\CMSObject;
|
||||||
use Joomla\Registry\Registry;
|
|
||||||
use Joomla\Utilities\ArrayHelper;
|
use Joomla\Utilities\ArrayHelper;
|
||||||
|
|
||||||
trait GetItemByIdentifierTrait
|
trait GetItemByIdentifierTrait
|
||||||
@ -37,7 +36,7 @@ trait GetItemByIdentifierTrait
|
|||||||
$all_properties = $table->getProperties(false);
|
$all_properties = $table->getProperties(false);
|
||||||
|
|
||||||
if (!empty($all_properties['_jsonEncode'])) {
|
if (!empty($all_properties['_jsonEncode'])) {
|
||||||
foreach ($all_properties['$_jsonEncode'] as $prop) {
|
foreach ($all_properties['_jsonEncode'] as $prop) {
|
||||||
if (array_key_exists($prop, $properties) && is_string($properties[$prop])) {
|
if (array_key_exists($prop, $properties) && is_string($properties[$prop])) {
|
||||||
$properties[$prop] = json_decode($properties[$prop]);
|
$properties[$prop] = json_decode($properties[$prop]);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Administrator\Model;
|
||||||
|
|
||||||
|
use Joomla\CMS\Factory;
|
||||||
|
use Joomla\CMS\Form\Form;
|
||||||
|
use Joomla\CMS\MVC\Model\AdminModel;
|
||||||
|
|
||||||
|
class RefreshTokenModel extends AdminModel implements RevokedModelInterface
|
||||||
|
{
|
||||||
|
use GetItemByIdentifierTrait;
|
||||||
|
use RevokedModelTrait;
|
||||||
|
|
||||||
|
public function getForm($data = [], $loadData = true): Form|bool
|
||||||
|
{
|
||||||
|
$form = $this->loadForm('com_oauthserver.refresh_token', 'refresh_token', ['control' => 'jform', 'load_data' => $loadData]);
|
||||||
|
|
||||||
|
if (empty($form)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadFormData(): mixed
|
||||||
|
{
|
||||||
|
// Check the session for previously entered form data.
|
||||||
|
$data = Factory::getApplication()->getUserState('com_oauthserver.edit.refresh_token.data', []);
|
||||||
|
|
||||||
|
if (empty($data)) {
|
||||||
|
$data = $this->getItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->preprocessData('com_oauthserver.refresh_token', $data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
26
com_oauthserver/administrator/src/Model/ScopeModel.php
Normal file
26
com_oauthserver/administrator/src/Model/ScopeModel.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Administrator\Model;
|
||||||
|
|
||||||
|
use Joomla\CMS\Component\ComponentHelper;
|
||||||
|
use Joomla\CMS\MVC\Model\BaseModel;
|
||||||
|
use Joomla\CMS\MVC\Model\ItemModelInterface;
|
||||||
|
|
||||||
|
class ScopeModel extends BaseModel implements ItemModelInterface
|
||||||
|
{
|
||||||
|
private static array $_storage;
|
||||||
|
|
||||||
|
private const PREDEFINED_SCOPES = ['userinfo', 'email'];
|
||||||
|
|
||||||
|
public function getItem($pk = null)
|
||||||
|
{
|
||||||
|
// TODO: Implement getItem() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fillStorage(): void
|
||||||
|
{
|
||||||
|
$config = ComponentHelper::getParams('com_oauthserver');
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
43
com_oauthserver/administrator/src/Table/AuthCodeTable.php
Normal file
43
com_oauthserver/administrator/src/Table/AuthCodeTable.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Administrator\Table;
|
||||||
|
|
||||||
|
use Joomla\CMS\Table\Table;
|
||||||
|
use Joomla\Database\DatabaseDriver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $identifier
|
||||||
|
* @property \DateTimeImmutable|\DateTime|string $expiry
|
||||||
|
* @property int|null $user_id
|
||||||
|
* @property string|array|null $scopes
|
||||||
|
* @property int $revoked
|
||||||
|
* @property int $client_id
|
||||||
|
*
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
class AuthCodeTable extends Table implements RevokedTableInterface
|
||||||
|
{
|
||||||
|
use RevokedTableTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that columns fully support the NULL value in the database
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
protected $_supportNullValue = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of key names to be json encoded in the bind function
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
protected $_jsonEncode = ['scopes'];
|
||||||
|
|
||||||
|
public function __construct(DatabaseDriver $db)
|
||||||
|
{
|
||||||
|
parent::__construct('#__webmasterskaya_oauthserver_authorization_codes', 'id', $db);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Administrator\Table;
|
||||||
|
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Joomla\CMS\Table\Table;
|
||||||
|
use Joomla\Database\DatabaseDriver;
|
||||||
|
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $identifier
|
||||||
|
* @property \DateTimeImmutable|\DateTime|string $expiry
|
||||||
|
* @property int $revoked
|
||||||
|
* @property int|null $access_token_id
|
||||||
|
*
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
class RefreshTokenTable extends Table implements RevokedTableInterface
|
||||||
|
{
|
||||||
|
use RevokedTableTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that columns fully support the NULL value in the database
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
protected $_supportNullValue = true;
|
||||||
|
|
||||||
|
public function __construct(DatabaseDriver $db)
|
||||||
|
{
|
||||||
|
parent::__construct('#__webmasterskaya_oauthserver_refresh_tokens', 'id', $db);
|
||||||
|
}
|
||||||
|
}
|
@ -4,5 +4,5 @@ namespace Webmasterskaya\Component\OauthServer\Administrator\Table;
|
|||||||
|
|
||||||
interface RevokedTableInterface
|
interface RevokedTableInterface
|
||||||
{
|
{
|
||||||
public function revoke($pks = null, $userId = 0): bool;
|
public function revoke($pks = null): bool;
|
||||||
}
|
}
|
@ -45,11 +45,8 @@ trait RevokedTableTrait
|
|||||||
|
|
||||||
abstract public function appendPrimaryKeys($query, $pk = null);
|
abstract public function appendPrimaryKeys($query, $pk = null);
|
||||||
|
|
||||||
public function revoke($pks = null, $userId = 0): bool
|
public function revoke($pks = null): bool
|
||||||
{
|
{
|
||||||
// Sanitize input
|
|
||||||
$userId = (int)$userId;
|
|
||||||
|
|
||||||
// Pre-processing by observers
|
// Pre-processing by observers
|
||||||
$event = AbstractEvent::create(
|
$event = AbstractEvent::create(
|
||||||
'onTableBeforeRevoke',
|
'onTableBeforeRevoke',
|
||||||
|
@ -3,12 +3,21 @@
|
|||||||
namespace Webmasterskaya\Component\OauthServer\Site\Controller;
|
namespace Webmasterskaya\Component\OauthServer\Site\Controller;
|
||||||
|
|
||||||
use Joomla\CMS\Application\CMSApplication;
|
use Joomla\CMS\Application\CMSApplication;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Entity\User as UserEntity;
|
||||||
use Joomla\CMS\MVC\Controller\BaseController;
|
use Joomla\CMS\MVC\Controller\BaseController;
|
||||||
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
|
||||||
use Joomla\CMS\Router\Route;
|
use Joomla\CMS\Router\Route;
|
||||||
use Joomla\Input\Input;
|
use Joomla\Input\Input;
|
||||||
use Joomla\CMS\Uri\Uri;
|
use Joomla\CMS\Uri\Uri;
|
||||||
|
use Laminas\Diactoros\ResponseFactory;
|
||||||
|
use Laminas\Diactoros\ServerRequestFactory;
|
||||||
|
use League\OAuth2\Server\AuthorizationServer;
|
||||||
|
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Repository\AccessTokenRepository;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Repository\AuthCodeRepository;
|
||||||
use Webmasterskaya\Component\OauthServer\Site\Repository\ClientRepository;
|
use Webmasterskaya\Component\OauthServer\Site\Repository\ClientRepository;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Repository\RefreshTokenRepository;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Repository\ScopeRepository;
|
||||||
|
|
||||||
class LoginController extends BaseController
|
class LoginController extends BaseController
|
||||||
{
|
{
|
||||||
@ -17,20 +26,104 @@ class LoginController extends BaseController
|
|||||||
parent::__construct($config, $factory, $app, $input);
|
parent::__construct($config, $factory, $app, $input);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authorize()
|
/**
|
||||||
|
* @return void
|
||||||
|
* @throws \Exception
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
public function authorize(): void
|
||||||
{
|
{
|
||||||
$app = $this->app;
|
$app = $this->app;
|
||||||
$user = $app->getIdentity();
|
$user = $app->getIdentity();
|
||||||
|
$uri = Uri::getInstance();
|
||||||
|
|
||||||
if (!$user->id) {
|
if (!$user->id) {
|
||||||
$return = http_build_query(['return' => base64_encode(Uri::getInstance()->toString(['scheme', 'user', 'pass', 'host', 'port', 'path']))]);
|
$return = http_build_query(['return' => base64_encode($uri->toString(['scheme', 'user', 'pass', 'host', 'port', 'path']))]);
|
||||||
$this->app->setUserState('oauthserver.login.authorize.request', Uri::getInstance()->getQuery(true));
|
$this->app->setUserState('oauthserver.login.authorize.request', $uri->getQuery(true));
|
||||||
$this->app->enqueueMessage('Необходимо авторизоваться!');
|
$this->app->enqueueMessage('Необходимо авторизоваться!');
|
||||||
$this->app->redirect(Route::_('index.php?option=com_users&view=login&' . $return));
|
$this->app->redirect(Route::_('index.php?option=com_users&view=login&' . $return));
|
||||||
}
|
}
|
||||||
|
|
||||||
$clientRepository = new ClientRepository($this->factory);
|
$state_request = $this->app->getUserState('oauthserver.login.authorize.request');
|
||||||
var_dump($this->app->getUserState('oauthserver.login.authorize.request'));
|
if (!empty($state_request) && empty($uri->getQuery(true))) {
|
||||||
|
foreach ($state_request as $k => $v) {
|
||||||
|
$uri->setVar($k, $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->app->setUserState('oauthserver.login.authorize.request', []);
|
||||||
|
|
||||||
|
/** @var \Webmasterskaya\Component\OauthServer\Administrator\Model\ClientModel $clientModel */
|
||||||
|
$clientModel = $this->factory->createModel('Client', 'Administrator', ['request_ignore' => true]);
|
||||||
|
$clientRepository = new ClientRepository($clientModel);
|
||||||
|
|
||||||
|
/** @var \Webmasterskaya\Component\OauthServer\Administrator\Model\AccessTokenModel $accessTokenModel */
|
||||||
|
$accessTokenModel = $this->factory->createModel('AccessToken', 'Administrator', ['request_ignore' => true]);
|
||||||
|
$accessTokenRepository = new AccessTokenRepository($accessTokenModel, $clientModel);
|
||||||
|
|
||||||
|
$scopeRepository = new ScopeRepository($clientModel);
|
||||||
|
$scopeRepository->setDispatcher($this->getDispatcher());
|
||||||
|
|
||||||
|
/** @var \Webmasterskaya\Component\OauthServer\Administrator\Model\AuthCodeModel $authCodeModel */
|
||||||
|
$authCodeModel = $this->factory->createModel('AuthCode', 'Administrator', ['request_ignore' => true]);
|
||||||
|
$authCodeRepository = new AuthCodeRepository($authCodeModel, $clientModel);
|
||||||
|
|
||||||
|
/** @var \Webmasterskaya\Component\OauthServer\Administrator\Model\RefreshTokenModel $refreshTokenModel */
|
||||||
|
$refreshTokenModel = $this->factory->createModel('RefreshToken', 'Administrator', ['request_ignore' => true]);
|
||||||
|
$refreshTokenRepository = new RefreshTokenRepository($refreshTokenModel, $accessTokenModel);
|
||||||
|
|
||||||
|
$key = openssl_pkey_new([
|
||||||
|
"digest_alg" => "sha512",
|
||||||
|
"private_key_bits" => 4096,
|
||||||
|
"private_key_type" => OPENSSL_KEYTYPE_RSA,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$ppk = '';
|
||||||
|
openssl_pkey_export($key, $ppk);
|
||||||
|
|
||||||
|
// Extract the public key from $res to $pubKey
|
||||||
|
// $pub = openssl_pkey_get_details($key);
|
||||||
|
// $pub = $pub["key"];
|
||||||
|
|
||||||
|
// var_dump($this->app->getUserState('oauthserver.login.authorize.request'));
|
||||||
|
|
||||||
|
$server = new AuthorizationServer(
|
||||||
|
$clientRepository,
|
||||||
|
$accessTokenRepository,
|
||||||
|
$scopeRepository,
|
||||||
|
$ppk,
|
||||||
|
$this->app->get('secret')
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant = new AuthCodeGrant(
|
||||||
|
$authCodeRepository,
|
||||||
|
$refreshTokenRepository,
|
||||||
|
new \DateInterval('PT10M') // authorization codes will expire after 10 minutes
|
||||||
|
);
|
||||||
|
|
||||||
|
$grant->setRefreshTokenTTL(new \DateInterval('P1M')); // refresh tokens will expire after 1 month
|
||||||
|
|
||||||
|
$server->enableGrantType(
|
||||||
|
$grant,
|
||||||
|
new \DateInterval('PT1H') // access tokens will expire after 1 hour
|
||||||
|
);
|
||||||
|
|
||||||
|
$serverRequest = ServerRequestFactory::fromGlobals();
|
||||||
|
$serverResponse = $this->app->getResponse();
|
||||||
|
|
||||||
|
// var_dump($serverRequest->getQueryParams()); die();
|
||||||
|
|
||||||
|
$authRequest = $server->validateAuthorizationRequest($serverRequest);
|
||||||
|
$authRequest->setUser(new UserEntity($user));
|
||||||
|
$authRequest->setAuthorizationApproved(true);
|
||||||
|
|
||||||
|
$this->app->setResponse($server->completeAuthorizationRequest($authRequest, $serverResponse));
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
echo "<pre>";
|
||||||
|
|
||||||
|
var_dump();
|
||||||
|
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
}
|
}
|
26
com_oauthserver/site/src/Entity/AuthCode.php
Normal file
26
com_oauthserver/site/src/Entity/AuthCode.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Site\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\AuthCodeTrait;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||||
|
|
||||||
|
class AuthCode implements AuthCodeEntityInterface
|
||||||
|
{
|
||||||
|
use AuthCodeTrait;
|
||||||
|
use EntityTrait;
|
||||||
|
use TokenEntityTrait;
|
||||||
|
|
||||||
|
public function getData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'identifier' => $this->getIdentifier(),
|
||||||
|
'expiry' => $this->getExpiryDateTime(),
|
||||||
|
'user_id' => $this->getUserIdentifier(),
|
||||||
|
'scopes' => $this->getScopes(),
|
||||||
|
'client_identifier' => $this->getClient()->getIdentifier()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
22
com_oauthserver/site/src/Entity/RefreshToken.php
Normal file
22
com_oauthserver/site/src/Entity/RefreshToken.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Site\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
|
||||||
|
|
||||||
|
class RefreshToken implements RefreshTokenEntityInterface
|
||||||
|
{
|
||||||
|
use EntityTrait;
|
||||||
|
use RefreshTokenTrait;
|
||||||
|
|
||||||
|
public function getData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'identifier' => $this->getIdentifier(),
|
||||||
|
'expiry' => $this->getExpiryDateTime(),
|
||||||
|
'access_token_identifier' => $this->getAccessToken()->getIdentifier()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
48
com_oauthserver/site/src/Entity/Scope.php
Normal file
48
com_oauthserver/site/src/Entity/Scope.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Site\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||||
|
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||||
|
|
||||||
|
final class Scope implements ScopeEntityInterface
|
||||||
|
{
|
||||||
|
use EntityTrait;
|
||||||
|
|
||||||
|
protected ?string $description;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
public function jsonSerialize(): mixed
|
||||||
|
{
|
||||||
|
return $this->getIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string|null
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
public function getDescription(): ?string
|
||||||
|
{
|
||||||
|
return $this->description ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $description
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
public function setDescription(string $description): void
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return $this->identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
16
com_oauthserver/site/src/Entity/User.php
Normal file
16
com_oauthserver/site/src/Entity/User.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Webmasterskaya\Component\OauthServer\Site\Entity;
|
||||||
|
|
||||||
|
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||||
|
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||||
|
|
||||||
|
class User implements UserEntityInterface
|
||||||
|
{
|
||||||
|
use EntityTrait;
|
||||||
|
|
||||||
|
public function __construct(\Joomla\CMS\User\User $user)
|
||||||
|
{
|
||||||
|
$this->setIdentifier($user->id);
|
||||||
|
}
|
||||||
|
}
|
@ -3,28 +3,75 @@
|
|||||||
namespace Webmasterskaya\Component\OauthServer\Site\Repository;
|
namespace Webmasterskaya\Component\OauthServer\Site\Repository;
|
||||||
|
|
||||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||||
|
use Wamania\Snowball\NotFoundException;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Administrator\Model\AuthCodeModel;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Administrator\Model\ClientModel;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Entity\AuthCode;
|
||||||
|
|
||||||
class AuthCodeRepository implements AuthCodeRepositoryInterface
|
class AuthCodeRepository implements AuthCodeRepositoryInterface
|
||||||
{
|
{
|
||||||
|
private AuthCodeModel $authCodeModel;
|
||||||
|
|
||||||
public function getNewAuthCode()
|
private ClientModel $clientModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Webmasterskaya\Component\OauthServer\Administrator\Model\AuthCodeModel $authCodeModel
|
||||||
|
* @param \Webmasterskaya\Component\OauthServer\Administrator\Model\ClientModel $clientModel
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
public function __construct(AuthCodeModel $authCodeModel, ClientModel $clientModel)
|
||||||
{
|
{
|
||||||
// TODO: Implement getNewAuthCode() method.
|
$this->authCodeModel = $authCodeModel;
|
||||||
|
$this->clientModel = $clientModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNewAuthCode(): AuthCode
|
||||||
|
{
|
||||||
|
return new AuthCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
|
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
|
||||||
{
|
{
|
||||||
// TODO: Implement persistNewAuthCode() method.
|
$found = false;
|
||||||
|
try {
|
||||||
|
$authCode = $this->authCodeModel->getItemByIdentifier($authCodeEntity->getIdentifier());
|
||||||
|
|
||||||
|
if ($authCode->id > 0) {
|
||||||
|
$found = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($found) {
|
||||||
|
throw UniqueTokenIdentifierConstraintViolationException::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $authCodeEntity->getData();
|
||||||
|
|
||||||
|
$client = $this->clientModel->getItemByIdentifier($authCodeEntity->getClient()->getIdentifier());
|
||||||
|
|
||||||
|
$data['client_id'] = $client->id;
|
||||||
|
unset($data['client_identifier']);
|
||||||
|
|
||||||
|
$this->authCodeModel->save($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function revokeAuthCode($codeId)
|
public function revokeAuthCode($codeId)
|
||||||
{
|
{
|
||||||
// TODO: Implement revokeAuthCode() method.
|
$this->authCodeModel->revoke($codeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isAuthCodeRevoked($codeId)
|
public function isAuthCodeRevoked($codeId)
|
||||||
{
|
{
|
||||||
// TODO: Implement isAuthCodeRevoked() method.
|
$authCode = $this->authCodeModel->getItemByIdentifier($codeId);
|
||||||
|
|
||||||
|
if (empty($authCode->id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!$authCode->revoked;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,28 +3,67 @@
|
|||||||
namespace Webmasterskaya\Component\OauthServer\Site\Repository;
|
namespace Webmasterskaya\Component\OauthServer\Site\Repository;
|
||||||
|
|
||||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||||
|
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
|
||||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Administrator\Model\AccessTokenModel;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Administrator\Model\RefreshTokenModel;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Entity\RefreshToken;
|
||||||
|
|
||||||
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
|
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
public function getNewRefreshToken()
|
private RefreshTokenModel $refreshTokenModel;
|
||||||
|
|
||||||
|
private AccessTokenModel $accessTokenModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Webmasterskaya\Component\OauthServer\Administrator\Model\RefreshTokenModel $refreshTokenModel
|
||||||
|
* @param \Webmasterskaya\Component\OauthServer\Administrator\Model\AccessTokenModel $accessTokenModel
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
public function __construct(RefreshTokenModel $refreshTokenModel, AccessTokenModel $accessTokenModel)
|
||||||
{
|
{
|
||||||
// TODO: Implement getNewRefreshToken() method.
|
$this->refreshTokenModel = $refreshTokenModel;
|
||||||
|
$this->accessTokenModel = $accessTokenModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getNewRefreshToken(): RefreshToken
|
||||||
|
{
|
||||||
|
return new RefreshToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity)
|
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity)
|
||||||
{
|
{
|
||||||
// TODO: Implement persistNewRefreshToken() method.
|
$refreshToken = $this->refreshTokenModel->getItemByIdentifier($refreshTokenEntity->getIdentifier());
|
||||||
|
|
||||||
|
if ($refreshToken->id > 0) {
|
||||||
|
throw UniqueTokenIdentifierConstraintViolationException::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $refreshTokenEntity->getData();
|
||||||
|
|
||||||
|
$accessToken = $this->accessTokenModel->getItemByIdentifier($refreshTokenEntity->getAccessToken());
|
||||||
|
|
||||||
|
unset($data['access_token_identifier']);
|
||||||
|
$data['access_token_id'] = $accessToken->id;
|
||||||
|
|
||||||
|
$this->refreshTokenModel->save($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function revokeRefreshToken($tokenId)
|
public function revokeRefreshToken($tokenId): void
|
||||||
{
|
{
|
||||||
// TODO: Implement revokeRefreshToken() method.
|
$this->refreshTokenModel->revoke($tokenId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isRefreshTokenRevoked($tokenId)
|
public function isRefreshTokenRevoked($tokenId): bool
|
||||||
{
|
{
|
||||||
// TODO: Implement isRefreshTokenRevoked() method.
|
$refreshToken = $this->refreshTokenModel->getItemByIdentifier($tokenId);
|
||||||
|
|
||||||
|
if (empty($refreshToken->id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!$refreshToken->revoked;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,19 +2,107 @@
|
|||||||
|
|
||||||
namespace Webmasterskaya\Component\OauthServer\Site\Repository;
|
namespace Webmasterskaya\Component\OauthServer\Site\Repository;
|
||||||
|
|
||||||
|
use Joomla\CMS\Plugin\PluginHelper;
|
||||||
|
use Joomla\Event\DispatcherAwareInterface;
|
||||||
|
use Joomla\Event\DispatcherAwareTrait;
|
||||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||||
|
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Administrator\Event\Scope\ScopeResolveEvent;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Administrator\Model\ClientModel;
|
||||||
|
use Webmasterskaya\Component\OauthServer\Site\Entity\Scope;
|
||||||
|
|
||||||
class ScopeRepository implements ScopeRepositoryInterface
|
class ScopeRepository implements ScopeRepositoryInterface, DispatcherAwareInterface
|
||||||
{
|
{
|
||||||
|
use DispatcherAwareTrait;
|
||||||
|
|
||||||
public function getScopeEntityByIdentifier($identifier)
|
private ClientModel $clientModel;
|
||||||
|
|
||||||
|
public function __construct(ClientModel $clientModel)
|
||||||
{
|
{
|
||||||
// TODO: Implement getScopeEntityByIdentifier() method.
|
$this->clientModel = $clientModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getScopeEntityByIdentifier($identifier): ?Scope
|
||||||
|
{
|
||||||
|
$defined = ['userinfo', 'email'];
|
||||||
|
|
||||||
|
if (!in_array($identifier, $defined)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope = new Scope();
|
||||||
|
$scope->setIdentifier($identifier);
|
||||||
|
|
||||||
|
return $scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Scope[] $scopes
|
||||||
|
* @param $grantType
|
||||||
|
* @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity
|
||||||
|
* @param null $userIdentifier
|
||||||
|
* @return mixed
|
||||||
|
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
public function finalizeScopes(array $scopes, $grantType, ClientEntityInterface $clientEntity, $userIdentifier = null)
|
public function finalizeScopes(array $scopes, $grantType, ClientEntityInterface $clientEntity, $userIdentifier = null)
|
||||||
{
|
{
|
||||||
// TODO: Implement finalizeScopes() method.
|
$client = $this->clientModel->getItemByIdentifier($clientEntity->getIdentifier());
|
||||||
|
|
||||||
|
$scopes = $this->setupScopes($client, array_values($scopes));
|
||||||
|
|
||||||
|
PluginHelper::importPlugin('oauthserver');
|
||||||
|
|
||||||
|
$event = new ScopeResolveEvent(
|
||||||
|
$scopes,
|
||||||
|
$grantType,
|
||||||
|
$client,
|
||||||
|
$userIdentifier
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->getDispatcher()
|
||||||
|
->dispatch($event->getName(), $event)
|
||||||
|
->getArgument('scopes', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $client
|
||||||
|
* @param array $requestedScopes
|
||||||
|
* @return array
|
||||||
|
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||||
|
* @since version
|
||||||
|
*/
|
||||||
|
private function setupScopes(object $client, array $requestedScopes): array
|
||||||
|
{
|
||||||
|
$clientScopes = $client->scopes;
|
||||||
|
|
||||||
|
if (empty($clientScopes)) {
|
||||||
|
return $requestedScopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clientScopes = array_map(function ($item) {
|
||||||
|
$scope = new Scope();
|
||||||
|
$scope->setIdentifier((string)$item);
|
||||||
|
return $scope;
|
||||||
|
}, $clientScopes);
|
||||||
|
|
||||||
|
if (empty($requestedScopes)) {
|
||||||
|
return $clientScopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
$finalizedScopes = [];
|
||||||
|
$clientScopesAsStrings = array_map('strval', $clientScopes);
|
||||||
|
|
||||||
|
foreach ($requestedScopes as $requestedScope) {
|
||||||
|
$requestedScopeAsString = (string)$requestedScope;
|
||||||
|
if (!\in_array($requestedScopeAsString, $clientScopesAsStrings, true)) {
|
||||||
|
throw OAuthServerException::invalidScope($requestedScopeAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
$finalizedScopes[] = $requestedScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $finalizedScopes;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,6 +16,7 @@
|
|||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.0",
|
"php": "^8.0",
|
||||||
"league/oauth2-server": "^8.5"
|
"league/oauth2-server": "^8.5",
|
||||||
|
"ext-openssl": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user