This commit is contained in:
Diogo Peralta Cordeiro 2022-01-16 04:31:04 +00:00
parent cb16b627b4
commit 29f53bb698
Signed by: diogo
GPG Key ID: 18D2D35001FBFAB0
4 changed files with 91 additions and 8 deletions

View File

@ -6,6 +6,10 @@ trikoder_oauth2:
encryption_key: '%env(string:OAUTH2_ENCRYPTION_KEY)%' # (Optional) Change this encryption_key: '%env(string:OAUTH2_ENCRYPTION_KEY)%' # (Optional) Change this
grant_types:
authorization_code:
enable: true
resource_server: resource_server:
public_key: '%kernel.project_dir%/var/oauth/public.key' public_key: '%kernel.project_dir%/var/oauth/public.key'

View File

@ -48,7 +48,6 @@ use App\Core\DB\DB;
use App\Core\I18n\I18n; use App\Core\I18n\I18n;
use App\Core\Queue\Queue; use App\Core\Queue\Queue;
use App\Core\Router\Router; use App\Core\Router\Router;
use App\Entity\LocalUser;
use App\Kernel; use App\Kernel;
use App\Security\EmailVerifier; use App\Security\EmailVerifier;
use App\Util\Common; use App\Util\Common;
@ -57,6 +56,7 @@ use App\Util\Formatting;
use App\Util\HTML; use App\Util\HTML;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use HtmlSanitizer\SanitizerInterface; use HtmlSanitizer\SanitizerInterface;
use Nyholm\Psr7\Response;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Event\ConsoleCommandEvent;
@ -84,6 +84,7 @@ use SymfonyCasts\Bundle\VerifyEmail\VerifyEmailHelperInterface;
use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEvent; use Trikoder\Bundle\OAuth2Bundle\Event\AuthorizationRequestResolveEvent;
use Trikoder\Bundle\OAuth2Bundle\Event\UserResolveEvent; use Trikoder\Bundle\OAuth2Bundle\Event\UserResolveEvent;
use Trikoder\Bundle\OAuth2Bundle\OAuth2Events; use Trikoder\Bundle\OAuth2Bundle\OAuth2Events;
use Trikoder\Bundle\OAuth2Bundle\OAuth2Grants;
use Twig\Environment; use Twig\Environment;
/** /**
@ -277,7 +278,7 @@ class GNUsocial implements EventSubscriberInterface
Log::debug('cenas: ', [$event, $userProvider, $userPasswordEncoder]); Log::debug('cenas: ', [$event, $userProvider, $userPasswordEncoder]);
$user = $userProvider->loadUserByUsername($event->getUsername()); $user = $userProvider->loadUserByUsername($event->getUsername());
if (null === $user) { if (\is_null($user)) {
return; return;
} }
@ -290,9 +291,51 @@ class GNUsocial implements EventSubscriberInterface
public function authRequestResolve(AuthorizationRequestResolveEvent $event): void public function authRequestResolve(AuthorizationRequestResolveEvent $event): void
{ {
// TODO: if using 3rd party clients, make sure the user approves access $request = $this->request;
$event->resolveAuthorization(true);
$event->setUser(LocalUser::getById(1)); // only handle post requests for logged-in users:
// get requests will be intercepted and shown the login form
// other verbs we will handle as an authorization denied
// and this implementation ensures a user is set at this point already
if ($request->getMethod() !== 'POST' && \is_null($event->getUser())) {
$event->resolveAuthorization(AuthorizationRequestResolveEvent::AUTHORIZATION_DENIED);
return;
}
if (!$request->request->has('action')) {
// 1. successful login, goes to grant page
$content = $this->twig->render('security/grant.html.twig', [
'scopes' => $event->getScopes(),
'client' => $event->getClient(),
'grant' => OAuth2Grants::AUTHORIZATION_CODE,
// very simple way to ensure user gets to this point in the
// flow when granting or denying is to pre-add their credentials
'email' => $request->request->get('email'),
'password' => $request->request->get('password'),
]);
$response = new Response(200, [], $content);
$event->setResponse($response);
} else {
// 2. grant operation, either grants or denies
if ($request->request->get('action') == OAuth2Grants::AUTHORIZATION_CODE) {
$event->resolveAuthorization(AuthorizationRequestResolveEvent::AUTHORIZATION_APPROVED);
} else {
$event->resolveAuthorization(AuthorizationRequestResolveEvent::AUTHORIZATION_DENIED);
}
}
if (\is_null($event->getUser())) {
$event->setResponse(new Response(302, [
'Location' => Router::url('security_login', [
'returnUrl' => $request->getUri(),
]),
]));
return;
}
$event->resolveAuthorization(AuthorizationRequestResolveEvent::AUTHORIZATION_APPROVED);
} }
/** /**

View File

@ -157,7 +157,10 @@ class Authenticator extends AbstractFormLoginAuthenticator implements Authentica
$nickname, $nickname,
); );
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) { // TODO: Fix the Open Redirect security flaw here.
$targetPath = $request->request->get('returnUrl');
if ($targetPath ??= $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath); return new RedirectResponse($targetPath);
} }
@ -178,8 +181,8 @@ class Authenticator extends AbstractFormLoginAuthenticator implements Authentica
); );
} }
protected function getLoginUrl() protected function getLoginUrl(int $type = Router::ABSOLUTE_PATH): string
{ {
return Router::url(self::LOGIN_ROUTE); return Router::url(self::LOGIN_ROUTE, type: $type);
} }
} }

View File

@ -0,0 +1,33 @@
<form method="post">
{% if app.user %}
<div class="mb-3">
You are logged in as {{ app.user.username }}, <a href="{{ path('api_logout') }}">Logout</a>
</div>
{% endif %}
<h1 class="h3 mb-3 font-weight-normal">Grant Permissions</h1>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
<input type="hidden" name="email"
value="{{ email }}"
>
<input type="hidden" name="password"
value="{{ password }}"
>
<p>Grant the following permissions:</p>
<ul>
{% for scope in scopes %}
<li>{{ scope }}: {{ scope }}</li>
{% endfor %}
</ul>
<button class="btn btn-lg btn-primary" type="submit" name="action" value="{{ grant }}">
Grant
</button>
<button class="btn btn-lg btn-primary" type="submit" name="action" value="Deny">
Deny
</button>
</form>