yet another iteration
This commit is contained in:
parent
9dc6243822
commit
b999c1bd62
6
.env
6
.env
@ -41,9 +41,3 @@ MESSENGER_TRANSPORT_DSN_HIGH=doctrine://default?queue_name=high
|
||||
MESSENGER_TRANSPORT_DSN_LOW=doctrine://default?queue_name=low
|
||||
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
|
||||
###< symfony/messenger ###
|
||||
|
||||
###> trikoder/oauth2-bundle ###
|
||||
# Fallback OAuth2 encryption key
|
||||
# Please override this with a secure value: https://oauth2.thephpleague.com/installation/#string-password
|
||||
OAUTH2_ENCRYPTION_KEY=6cfc355e274dc909f82730c8741eb1e0
|
||||
###< trikoder/oauth2-bundle ###
|
||||
|
1071
composer.lock
generated
1071
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,4 @@ return [
|
||||
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
|
||||
Knp\Bundle\TimeBundle\KnpTimeBundle::class => ['all' => true],
|
||||
Fidry\PsyshBundle\PsyshBundle::class => ['all' => true],
|
||||
Trikoder\Bundle\OAuth2Bundle\TrikoderOAuth2Bundle::class => ['all' => true],
|
||||
Ajgarlag\Bundle\PsrHttpMessageBundle\AjgarlagPsrHttpMessageBundle::class => ['all' => true],
|
||||
SymfonyBundles\JsonRequestBundle\JsonRequestBundle::class => ['all' => true],
|
||||
];
|
||||
|
@ -31,9 +31,7 @@ security:
|
||||
pattern: ^/api/
|
||||
security: true
|
||||
stateless: true
|
||||
guard:
|
||||
authenticators:
|
||||
- Trikoder\Bundle\OAuth2Bundle\Security\Guard\Authenticator\OAuth2Authenticator
|
||||
|
||||
main:
|
||||
entry_point: App\Security\Authenticator
|
||||
guard:
|
||||
|
@ -1,32 +0,0 @@
|
||||
trikoder_oauth2:
|
||||
|
||||
authorization_server:
|
||||
private_key: '%kernel.project_dir%/var/oauth/private.key'
|
||||
private_key_passphrase: null # Passphrase of the private key, if any
|
||||
|
||||
encryption_key: '%env(string:OAUTH2_ENCRYPTION_KEY)%' # (Optional) Change this
|
||||
|
||||
grant_types:
|
||||
authorization_code:
|
||||
enable: true
|
||||
client_credentials:
|
||||
enable: true
|
||||
implicit:
|
||||
enable: true
|
||||
password:
|
||||
enable: true
|
||||
refresh_token:
|
||||
enable: true
|
||||
|
||||
resource_server:
|
||||
public_key: '%kernel.project_dir%/var/oauth/public.key'
|
||||
|
||||
persistence:
|
||||
doctrine: null
|
||||
|
||||
# Scopes that you wish to utilize in your application.
|
||||
# This should be a simple array of strings.
|
||||
scopes:
|
||||
- read
|
||||
- write
|
||||
- follow
|
@ -1,7 +0,0 @@
|
||||
oauth2_authorization_code:
|
||||
controller: Trikoder\Bundle\OAuth2Bundle\Controller\AuthorizationController::indexAction
|
||||
path: '/oauth/authorize'
|
||||
|
||||
oauth2_token:
|
||||
controller: Trikoder\Bundle\OAuth2Bundle\Controller\TokenController::indexAction
|
||||
path: '/oauth/token'
|
85
plugins/IndieAuth/Controller/Apps.php
Normal file
85
plugins/IndieAuth/Controller/Apps.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* ActivityPub implementation for GNU social
|
||||
*
|
||||
* @package OAuth2
|
||||
* @category API
|
||||
*
|
||||
* @author Diogo Peralta Cordeiro <@diogo.site>
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Plugin\IndieAuth\Controller;
|
||||
|
||||
use App\Core\Controller;
|
||||
use App\Core\DB\DB;
|
||||
use App\Core\Log;
|
||||
use App\Util\Common;
|
||||
use Plugin\IndieAuth\Entity\OAuth2Client;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
/**
|
||||
* App Management Endpoint
|
||||
*
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class Apps extends Controller
|
||||
{
|
||||
public function onPost(): JsonResponse
|
||||
{
|
||||
Log::debug('OAuth2 Apps: Received a POST request.');
|
||||
Log::debug('OAuth2 Apps: Request content: ', [$body = $this->request->getContent()]);
|
||||
$args = json_decode($body, true);
|
||||
|
||||
$identifier = hash('md5', random_bytes(16));
|
||||
// Random string Length should be between 43 and 128
|
||||
$secret = Common::base64url_encode(hash('sha256', random_bytes(57)));
|
||||
|
||||
DB::persist($app = OAuth2Client::create([
|
||||
'identifier' => $identifier,
|
||||
'secret' => $secret,
|
||||
'redirect_uris' => $args['redirect_uris'],
|
||||
'grants' => 'client_credentials authorization_code',
|
||||
'scopes' => $args['scopes'],
|
||||
'active' => true,
|
||||
'allow_plain_text_pkce' => false,
|
||||
'client_name' => $args['client_name'],
|
||||
'website' => $args['website'],
|
||||
]));
|
||||
|
||||
Log::debug('OAuth2 Apps: Created App: ', [$app]);
|
||||
|
||||
DB::flush();
|
||||
|
||||
// Success
|
||||
return new JsonResponse([
|
||||
'name' => $app->getClientName(),
|
||||
'website' => $app->getWebsite(),
|
||||
'redirect_uri' => $app->getRedirectUris()[0],
|
||||
'client_id' => $app->getIdentifier(),
|
||||
'client_secret' => $app->getSecret(),
|
||||
], status: 200, headers: ['content_type' => 'application/json; charset=utf-8']);
|
||||
}
|
||||
}
|
70
plugins/IndieAuth/Controller/OAuth2.php
Normal file
70
plugins/IndieAuth/Controller/OAuth2.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* ActivityPub implementation for GNU social
|
||||
*
|
||||
* @package OAuth2
|
||||
* @category API
|
||||
*
|
||||
* @author Diogo Peralta Cordeiro <@diogo.site>
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Plugin\IndieAuth\Controller;
|
||||
|
||||
use App\Core\Controller;
|
||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||
use Plugin\IndieAuth\IndieAuth;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* App Management Endpoint
|
||||
*
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class OAuth2 extends Controller
|
||||
{
|
||||
private ServerRequestInterface $psrRequest;
|
||||
|
||||
public function __construct(RequestStack $requestStack)
|
||||
{
|
||||
parent::__construct($requestStack);
|
||||
$psr17Factory = new Psr17Factory();
|
||||
$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
|
||||
$this->psrRequest = $psrHttpFactory->createRequest($this->request);
|
||||
}
|
||||
|
||||
public function handleAuthorizationEndpointRequest(): ResponseInterface
|
||||
{
|
||||
return IndieAuth::$server->handleAuthorizationEndpointRequest($this->psrRequest);
|
||||
}
|
||||
|
||||
public function handleTokenEndpointRequest(): ResponseInterface
|
||||
{
|
||||
return IndieAuth::$server->handleTokenEndpointRequest($this->psrRequest);
|
||||
}
|
||||
}
|
225
plugins/IndieAuth/Entity/OAuth2Client.php
Normal file
225
plugins/IndieAuth/Entity/OAuth2Client.php
Normal file
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* ActivityPub implementation for GNU social
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @category OAuth2
|
||||
*
|
||||
* @author Diogo Peralta Cordeiro <@diogo.site>
|
||||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Plugin\IndieAuth\Entity;
|
||||
|
||||
use App\Core\Entity;
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* OAuth application registration record
|
||||
*
|
||||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class OAuth2Client extends Entity
|
||||
{
|
||||
// {{{ Autocode
|
||||
// @codeCoverageIgnoreStart
|
||||
private string $identifier;
|
||||
private ?string $secret;
|
||||
private string $redirect_uris = '';
|
||||
private string $grants = '';
|
||||
private string $scopes = '';
|
||||
private bool $active = true;
|
||||
private bool $allow_plain_text_pkce = false;
|
||||
private ?string $client_name = null;
|
||||
private ?string $website = null;
|
||||
private DateTimeInterface $created;
|
||||
private DateTimeInterface $modified;
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getIdentifier();
|
||||
}
|
||||
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
public function getSecret(): ?string
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
public function setSecret(?string $secret): self
|
||||
{
|
||||
$this->secret = $secret;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRedirectUris(): array
|
||||
{
|
||||
return explode(' ', $this->redirect_uris);
|
||||
}
|
||||
|
||||
public function setRedirectUris(string ...$redirect_uris): self
|
||||
{
|
||||
$this->redirect_uris = implode(' ', $redirect_uris);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGrants(): array
|
||||
{
|
||||
return explode(' ', $this->grants);
|
||||
}
|
||||
|
||||
public function setGrants(string ...$grants): self
|
||||
{
|
||||
$this->grants = implode(' ', $grants);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getScopes(): array
|
||||
{
|
||||
return explode(' ', $this->scopes);
|
||||
}
|
||||
|
||||
public function setScopes(string ...$scopes): self
|
||||
{
|
||||
$this->scopes = implode(' ', $scopes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
public function setActive(bool $active): self
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isConfidential(): bool
|
||||
{
|
||||
return !empty($this->secret);
|
||||
}
|
||||
|
||||
public function isPlainTextPkceAllowed(): bool
|
||||
{
|
||||
return $this->allow_plain_text_pkce;
|
||||
}
|
||||
|
||||
public function setAllowPlainTextPkce(bool $allow_plain_text_pkce): self
|
||||
{
|
||||
$this->allow_plain_text_pkce = $allow_plain_text_pkce;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setIdentifier(string $identifier): self
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClientName(): string
|
||||
{
|
||||
return $this->client_name;
|
||||
}
|
||||
|
||||
public function setClientName(string $client_name): self
|
||||
{
|
||||
$this->client_name = $client_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWebsite(): ?string
|
||||
{
|
||||
return $this->website;
|
||||
}
|
||||
|
||||
public function setWebsite(?string $website): self
|
||||
{
|
||||
$this->website = $website;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCreated(DateTimeInterface $created): self
|
||||
{
|
||||
$this->created = $created;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreated(): DateTimeInterface
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
public function setModified(DateTimeInterface $modified): self
|
||||
{
|
||||
$this->modified = $modified;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getModified(): DateTimeInterface
|
||||
{
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
// }}} Autocode
|
||||
|
||||
/**
|
||||
* Return table definition for Schema setup and Entity usage.
|
||||
*
|
||||
* @return array array of column definitions
|
||||
*/
|
||||
public static function schemaDef(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'oauth2_client',
|
||||
'fields' => [
|
||||
'identifier' => ['type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'foreign key to oauth2_client->identifier'],
|
||||
'secret' => ['type' => 'varchar', 'length' => 128, 'not null' => false, 'description' => 'foreign key to oauth2_client->identifier'],
|
||||
'client_name' => ['type' => 'varchar', 'length' => 191, 'not null' => false, 'description' => 'name of the application'],
|
||||
'redirect_uris' => ['type' => 'text', 'not null' => false, 'description' => 'application homepage - used for source link'],
|
||||
'grants' => ['type' => 'text', 'not null' => true, 'default' => '', 'description' => 'application homepage - used for source link'],
|
||||
'scopes' => ['type' => 'text', 'not null' => true, 'default' => '', 'description' => 'application homepage - used for source link'],
|
||||
'active' => ['type' => 'bool', 'not null' => true, 'description' => 'was this note generated by a local actor'],
|
||||
'allow_plain_text_pkce' => ['type' => 'bool', 'not null' => true, 'default' => false, 'description' => 'was this note generated by a local actor'],
|
||||
'website' => ['type' => 'text', 'not null' => false, 'description' => 'application homepage - used for source link'],
|
||||
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
|
||||
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
|
||||
],
|
||||
'primary key' => ['identifier'],
|
||||
];
|
||||
}
|
||||
}
|
@ -30,21 +30,19 @@ declare(strict_types = 1);
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Plugin\OAuth2;
|
||||
namespace Plugin\IndieAuth;
|
||||
|
||||
use App\Core\Event;
|
||||
use App\Core\Log;
|
||||
use App\Core\Modules\Plugin;
|
||||
use App\Core\Router\RouteLoader;
|
||||
use App\Core\Router\Router;
|
||||
use App\Util\Common;
|
||||
use App\Util\Exception\NoLoggedInUser;
|
||||
use Nyholm\Psr7\Response;
|
||||
use Plugin\OAuth2\Controller\Apps;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEvent;
|
||||
use Trikoder\Bundle\OAuth2Bundle\Event\UserResolveEvent;
|
||||
use Trikoder\Bundle\OAuth2Bundle\Model\Grant;
|
||||
use Trikoder\Bundle\OAuth2Bundle\OAuth2Events;
|
||||
use Plugin\IndieAuth\Controller\Apps;
|
||||
use Plugin\IndieAuth\Controller\OAuth2;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Taproot\IndieAuth\Server;
|
||||
use XML_XRD_Element_Link;
|
||||
|
||||
/**
|
||||
@ -53,12 +51,39 @@ use XML_XRD_Element_Link;
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class OAuth2 extends Plugin implements EventSubscriberInterface
|
||||
class IndieAuth extends Plugin
|
||||
{
|
||||
public const OAUTH_ACCESS_TOKEN_REL = 'http://apinamespace.org/oauth/access_token';
|
||||
public const OAUTH_REQUEST_TOKEN_REL = 'http://apinamespace.org/oauth/request_token';
|
||||
public const OAUTH_AUTHORIZE_REL = 'http://apinamespace.org/oauth/authorize';
|
||||
|
||||
public static Server $server;
|
||||
|
||||
public function onInitializePlugin()
|
||||
{
|
||||
self::$server = new Server([
|
||||
'secret' => 'YOUR_APP_INDIEAUTH_SECRET$config["secret"] must be a string with a minimum length of 64 characters.yeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||
'logger' => Log::getLogger(),
|
||||
'requirePKCE' => false,
|
||||
// A path to store token data, or an object implementing TokenStorageInterface.
|
||||
'tokenStorage' => '/../data/auth_tokens/',
|
||||
|
||||
// An authentication callback function, which either returns data about the current user,
|
||||
// or redirects to/implements an authentication flow.
|
||||
'authenticationHandler' => function (ServerRequestInterface $request, string $authenticationRedirect, ?string $normalizedMeUrl) {
|
||||
// If the request is authenticated, return an array with a `me` key containing the
|
||||
// canonical URL of the currently logged-in user.
|
||||
if ($actor = Common::actor()) {
|
||||
return ['me' => $actor->getUri(Router::ABSOLUTE_URL)];
|
||||
}
|
||||
|
||||
// Otherwise, redirect the user to a login page, ensuring that they will be redirected
|
||||
// back to the IndieAuth flow with query parameters intact once logged in.
|
||||
return new Response(302, ['Location' => Router::url('security_login') . '?returnUrl=' . urlencode($authenticationRedirect)]);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
public function version(): string
|
||||
{
|
||||
return '3.0.0';
|
||||
@ -78,6 +103,19 @@ class OAuth2 extends Plugin implements EventSubscriberInterface
|
||||
Apps::class,
|
||||
['http-methods' => ['POST']],
|
||||
);
|
||||
|
||||
$r->connect(
|
||||
'oauth2_authorization_code',
|
||||
'/oauth/authorize',
|
||||
[OAuth2::class, 'handleAuthorizationEndpointRequest'],
|
||||
);
|
||||
|
||||
$r->connect(
|
||||
'oauth2_token',
|
||||
'/oauth/token',
|
||||
[OAuth2::class, 'handleTokenEndpointRequest'],
|
||||
);
|
||||
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
@ -88,40 +126,4 @@ class OAuth2 extends Plugin implements EventSubscriberInterface
|
||||
$links[] = new XML_XRD_Element_link(self::OAUTH_ACCESS_TOKEN_REL, Router::url('oauth2_token', type: Router::ABSOLUTE_URL));
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
public function userResolve(UserResolveEvent $event): void
|
||||
{
|
||||
$user = Common::user();
|
||||
|
||||
if (\is_null($user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event->setUser($user);
|
||||
}
|
||||
|
||||
public function authorizeRequestResolve(AuthorizationRequestResolveEvent $event): void
|
||||
{
|
||||
$request = Common::getRequest();
|
||||
try {
|
||||
$user = Common::ensureLoggedIn();
|
||||
$event->setUser($user);
|
||||
$event->resolveAuthorization(AuthorizationRequestResolveEvent::AUTHORIZATION_APPROVED);
|
||||
$event->getClient()->setGrants(new Grant('client_credentials'), new Grant('authorization_code'));
|
||||
} catch (NoLoggedInUser) {
|
||||
$event->setResponse(new Response(302, [
|
||||
'Location' => Router::url('security_login', [
|
||||
'returnUrl' => $request->getUri(),
|
||||
]),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
OAuth2Events::USER_RESOLVE => 'userResolve',
|
||||
OAuth2Events::AUTHORIZATION_REQUEST_RESOLVE => 'authorizeRequestResolve',
|
||||
];
|
||||
}
|
||||
}
|
7
plugins/IndieAuth/composer.json
Normal file
7
plugins/IndieAuth/composer.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"require": {
|
||||
"nyholm/psr7": "^1.4",
|
||||
"symfony/psr-http-message-bridge": "^2.1",
|
||||
"taproot/indieauth": "^0.1.0"
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* ActivityPub implementation for GNU social
|
||||
*
|
||||
* @package OAuth2
|
||||
* @category API
|
||||
*
|
||||
* @author Diogo Peralta Cordeiro <@diogo.site>
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Plugin\OAuth2\Controller;
|
||||
|
||||
use App\Core\Controller;
|
||||
use App\Core\DB\DB;
|
||||
use App\Core\Log;
|
||||
use App\Util\Common;
|
||||
use Plugin\OAuth2\Entity\OAuth2ClientMeta;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Trikoder\Bundle\OAuth2Bundle\Model\Client;
|
||||
use Trikoder\Bundle\OAuth2Bundle\Model\Grant;
|
||||
use Trikoder\Bundle\OAuth2Bundle\Model\RedirectUri;
|
||||
use Trikoder\Bundle\OAuth2Bundle\Model\Scope;
|
||||
|
||||
/**
|
||||
* App Management Endpoint
|
||||
*
|
||||
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class Apps extends Controller
|
||||
{
|
||||
public function onPost(): JsonResponse
|
||||
{
|
||||
Log::debug('OAuth2 Apps: Received a POST request.');
|
||||
Log::debug('OAuth2 Apps: Request content: ', [$body = $this->request->getContent()]);
|
||||
$args = json_decode($body, true);
|
||||
|
||||
$identifier = hash('md5', random_bytes(16)); // Random string Length should be between 43 and 128
|
||||
$secret = Common::base64url_encode(hash('sha256', random_bytes(57)));
|
||||
|
||||
$client = new Client($identifier, $secret);
|
||||
$client->setActive(true);
|
||||
$client->setAllowPlainTextPkce(false);
|
||||
|
||||
$redirectUris = array_map(
|
||||
static fn (string $redirectUri): RedirectUri => new RedirectUri($redirectUri),
|
||||
explode(' ', $args['redirect_uris']),
|
||||
);
|
||||
$client->setRedirectUris(...$redirectUris);
|
||||
|
||||
$client->setGrants(new Grant('client_credentials'));
|
||||
|
||||
$scopes = array_map(
|
||||
static fn (string $scope): Scope => new Scope($scope),
|
||||
explode(' ', $args['scopes']),
|
||||
);
|
||||
$client->setScopes(...$scopes);
|
||||
|
||||
DB::persist($client);
|
||||
|
||||
DB::persist($additional_meta = OAuth2ClientMeta::create([
|
||||
'identifier' => $client->getIdentifier(),
|
||||
'client_name' => $args['client_name'],
|
||||
'website' => $args['website'],
|
||||
]));
|
||||
|
||||
Log::debug('OAuth2 Apps: Created App: ', [$client, $additional_meta]);
|
||||
$app_meta = [
|
||||
'id' => (string) $additional_meta->getId(),
|
||||
'name' => $additional_meta->getClientName(),
|
||||
'website' => $additional_meta->getWebsite(),
|
||||
'redirect_uri' => (string) $client->getRedirectUris()[0],
|
||||
'client_id' => $client->getIdentifier(),
|
||||
'client_secret' => $client->getSecret(),
|
||||
];
|
||||
|
||||
Log::debug('OAuth2 Apps: Create App Meta: ', [$app_meta]);
|
||||
|
||||
DB::flush();
|
||||
|
||||
// Success
|
||||
return new JsonResponse($app_meta, status: 200, headers: ['content_type' => 'application/json; charset=utf-8']);
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
// {{{ License
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
// }}}
|
||||
|
||||
/**
|
||||
* ActivityPub implementation for GNU social
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @category OAuth2
|
||||
*
|
||||
* @author Diogo Peralta Cordeiro <@diogo.site>
|
||||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Plugin\OAuth2\Entity;
|
||||
|
||||
use App\Core\Entity;
|
||||
use DateTimeInterface;
|
||||
|
||||
/**
|
||||
* OAuth application registration record
|
||||
*
|
||||
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class OAuth2ClientMeta extends Entity
|
||||
{
|
||||
// {{{ Autocode
|
||||
// @codeCoverageIgnoreStart
|
||||
private int $id;
|
||||
private string $identifier;
|
||||
private string $client_name;
|
||||
private ?string $website = null;
|
||||
private DateTimeInterface $created;
|
||||
private DateTimeInterface $modified;
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
public function setIdentifier(string $identifier): self
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClientName(): string
|
||||
{
|
||||
return $this->client_name;
|
||||
}
|
||||
|
||||
public function setClientName(string $client_name): self
|
||||
{
|
||||
$this->client_name = $client_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWebsite(): ?string
|
||||
{
|
||||
return $this->website;
|
||||
}
|
||||
|
||||
public function setWebsite(?string $website): self
|
||||
{
|
||||
$this->website = $website;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCreated(DateTimeInterface $created): self
|
||||
{
|
||||
$this->created = $created;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreated(): DateTimeInterface
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
public function setModified(DateTimeInterface $modified): self
|
||||
{
|
||||
$this->modified = $modified;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getModified(): DateTimeInterface
|
||||
{
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
// }}} Autocode
|
||||
|
||||
/**
|
||||
* Return table definition for Schema setup and Entity usage.
|
||||
*
|
||||
* @return array array of column definitions
|
||||
*/
|
||||
public static function schemaDef(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'oauth2_client_meta',
|
||||
'fields' => [
|
||||
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'],
|
||||
'identifier' => ['type' => 'varchar', 'length' => 32, 'description' => 'foreign key to oauth2_client->identifier'],
|
||||
'client_name' => ['type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the application'],
|
||||
'website' => ['type' => 'text', 'not null' => false, 'description' => 'application homepage - used for source link'],
|
||||
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
|
||||
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
|
||||
],
|
||||
'primary key' => ['id'],
|
||||
];
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"require": {
|
||||
"nyholm/psr7": "*",
|
||||
"symfony-bundles/json-request-bundle": "^4.1",
|
||||
"trikoder/oauth2-bundle": "v3.x-dev"
|
||||
}
|
||||
}
|
@ -58,6 +58,11 @@ abstract class Log
|
||||
self::$logger = $l;
|
||||
}
|
||||
|
||||
public static function getLogger(): LoggerInterface
|
||||
{
|
||||
return self::$logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a critical error when a really unexpected exception occured. This indicates a bug in the software
|
||||
*
|
||||
|
62
symfony.lock
62
symfony.lock
@ -1,10 +1,10 @@
|
||||
{
|
||||
"ajgarlag/psr-http-message-bundle": {
|
||||
"version": "1.2.1"
|
||||
},
|
||||
"alchemy/binary-driver": {
|
||||
"version": "v5.2.0"
|
||||
},
|
||||
"barnabywalters/mf-cleaner": {
|
||||
"version": "v0.1.4"
|
||||
},
|
||||
"behat/gherkin": {
|
||||
"version": "v4.9.0"
|
||||
},
|
||||
@ -68,8 +68,8 @@
|
||||
"composer/xdebug-handler": {
|
||||
"version": "1.4.6"
|
||||
},
|
||||
"defuse/php-encryption": {
|
||||
"version": "v2.3.1"
|
||||
"dflydev/fig-cookies": {
|
||||
"version": "v3.0.0"
|
||||
},
|
||||
"doctrine/annotations": {
|
||||
"version": "1.0",
|
||||
@ -208,6 +208,15 @@
|
||||
"guzzlehttp/psr7": {
|
||||
"version": "2.1.0"
|
||||
},
|
||||
"indieauth/client": {
|
||||
"version": "1.1.5"
|
||||
},
|
||||
"indieweb/link-rel-parser": {
|
||||
"version": "0.1.3"
|
||||
},
|
||||
"indieweb/representative-h-card": {
|
||||
"version": "0.1.2"
|
||||
},
|
||||
"jchook/phpunit-assert-throws": {
|
||||
"version": "v1.0.3"
|
||||
},
|
||||
@ -229,18 +238,6 @@
|
||||
"landrok/activitypub": {
|
||||
"version": "0.5.6"
|
||||
},
|
||||
"lcobucci/clock": {
|
||||
"version": "2.1.0"
|
||||
},
|
||||
"lcobucci/jwt": {
|
||||
"version": "4.1.5"
|
||||
},
|
||||
"league/event": {
|
||||
"version": "2.2.0"
|
||||
},
|
||||
"league/oauth2-server": {
|
||||
"version": "8.3.3"
|
||||
},
|
||||
"league/uri-parser": {
|
||||
"version": "1.4.1"
|
||||
},
|
||||
@ -301,6 +298,9 @@
|
||||
"oscarotero/html-parser": {
|
||||
"version": "v0.1.6"
|
||||
},
|
||||
"p3k/http": {
|
||||
"version": "0.1.12"
|
||||
},
|
||||
"paragonie/constant_time_encoding": {
|
||||
"version": "v2.4.0"
|
||||
},
|
||||
@ -390,6 +390,12 @@
|
||||
"psr/http-message": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"psr/http-server-handler": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"psr/http-server-middleware": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"psr/link": {
|
||||
"version": "1.1.1"
|
||||
},
|
||||
@ -468,9 +474,6 @@
|
||||
"someonewithpc/redis-polyfill": {
|
||||
"version": "dev-master"
|
||||
},
|
||||
"symfony-bundles/json-request-bundle": {
|
||||
"version": "4.1.1"
|
||||
},
|
||||
"symfony/amqp-messenger": {
|
||||
"version": "v5.4.0"
|
||||
},
|
||||
@ -868,6 +871,9 @@
|
||||
"symfonycasts/verify-email-bundle": {
|
||||
"version": "v1.3.0"
|
||||
},
|
||||
"taproot/indieauth": {
|
||||
"version": "v0.1.0"
|
||||
},
|
||||
"tgalopin/html-sanitizer": {
|
||||
"version": "1.4.0"
|
||||
},
|
||||
@ -886,19 +892,6 @@
|
||||
"theseer/tokenizer": {
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"trikoder/oauth2-bundle": {
|
||||
"version": "3.2",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes-contrib",
|
||||
"branch": "master",
|
||||
"version": "3.0",
|
||||
"ref": "43774de114904e86d18de0cea92f368d8e3c7499"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/trikoder_oauth2.yaml",
|
||||
"config/routes/trikoder_oauth2.yaml"
|
||||
]
|
||||
},
|
||||
"twig/extra-bundle": {
|
||||
"version": "v3.3.0"
|
||||
},
|
||||
@ -923,6 +916,9 @@
|
||||
"webmozart/assert": {
|
||||
"version": "1.10.0"
|
||||
},
|
||||
"webmozart/path-util": {
|
||||
"version": "2.3.0"
|
||||
},
|
||||
"wikimedia/composer-merge-plugin": {
|
||||
"version": "v2.0.1"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user