diff --git a/config/packages/trikoder_oauth2.yaml b/config/packages/trikoder_oauth2.yaml index 6b576083a8..9ba8c70db3 100644 --- a/config/packages/trikoder_oauth2.yaml +++ b/config/packages/trikoder_oauth2.yaml @@ -6,6 +6,10 @@ trikoder_oauth2: encryption_key: '%env(string:OAUTH2_ENCRYPTION_KEY)%' # (Optional) Change this + grant_types: + authorization_code: + enable: true + resource_server: public_key: '%kernel.project_dir%/var/oauth/public.key' diff --git a/src/Core/GNUsocial.php b/src/Core/GNUsocial.php index d0c689d288..eef0965419 100644 --- a/src/Core/GNUsocial.php +++ b/src/Core/GNUsocial.php @@ -48,7 +48,6 @@ use App\Core\DB\DB; use App\Core\I18n\I18n; use App\Core\Queue\Queue; use App\Core\Router\Router; -use App\Entity\LocalUser; use App\Kernel; use App\Security\EmailVerifier; use App\Util\Common; @@ -57,6 +56,7 @@ use App\Util\Formatting; use App\Util\HTML; use Doctrine\ORM\EntityManagerInterface; use HtmlSanitizer\SanitizerInterface; +use Nyholm\Psr7\Response; use Psr\Log\LoggerInterface; use Symfony\Component\Config\Loader\LoaderInterface; 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\UserResolveEvent; use Trikoder\Bundle\OAuth2Bundle\OAuth2Events; +use Trikoder\Bundle\OAuth2Bundle\OAuth2Grants; use Twig\Environment; /** @@ -277,7 +278,7 @@ class GNUsocial implements EventSubscriberInterface Log::debug('cenas: ', [$event, $userProvider, $userPasswordEncoder]); $user = $userProvider->loadUserByUsername($event->getUsername()); - if (null === $user) { + if (\is_null($user)) { return; } @@ -290,9 +291,51 @@ class GNUsocial implements EventSubscriberInterface public function authRequestResolve(AuthorizationRequestResolveEvent $event): void { - // TODO: if using 3rd party clients, make sure the user approves access - $event->resolveAuthorization(true); - $event->setUser(LocalUser::getById(1)); + $request = $this->request; + + // 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); } /** diff --git a/src/Security/Authenticator.php b/src/Security/Authenticator.php index 0c819b6085..0daf9df958 100644 --- a/src/Security/Authenticator.php +++ b/src/Security/Authenticator.php @@ -157,7 +157,10 @@ class Authenticator extends AbstractFormLoginAuthenticator implements Authentica $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); } @@ -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); } } diff --git a/templates/security/grant.html.twig b/templates/security/grant.html.twig new file mode 100644 index 0000000000..91228aaca2 --- /dev/null +++ b/templates/security/grant.html.twig @@ -0,0 +1,33 @@ +
+ {% if app.user %} +
+ You are logged in as {{ app.user.username }}, Logout +
+ {% endif %} + +

Grant Permissions

+ + + + +

Grant the following permissions:

+ + + + + +
\ No newline at end of file