oauth2-bundle icon indicating copy to clipboard operation
oauth2-bundle copied to clipboard

Support for new AuthenticatorManager feature introduced with symfony 5.1+

Open pixelfantasy opened this issue 4 years ago • 2 comments

Hello folks,

actually I am integrating your bundle in my symfony 5.1+ application and stumbled over an incompatibilty. When combining your bundle with a bundle which already depends on the new AuthenticatorManager feature and enabled that feature in the security.yaml an error occurs.

Cannot configure AuthenticatorManager as "oauth2" authentication does not support it, set "security.enable_authenticator_manager" to `false`.

More informations about that feature and configuration example: https://symfony.com/doc/current/security/experimental_authenticators.html

Are there any plans to support that feature in the near future?

pixelfantasy avatar Dec 03 '20 16:12 pixelfantasy

Hi there, while working on the current branch, I can get an implementation working with this authenticator:

<?php

namespace App\Security;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\CustomCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\UserPassportInterface;
use Trikoder\Bundle\OAuth2Bundle\Security\Guard\Authenticator\OAuth2Authenticator as TrikoderOAuth2Authenticator;

class OAuth2Authenticator implements AuthenticatorInterface
{
    private TrikoderOAuth2Authenticator $decorated;
    private UserProviderInterface $userProvider;

    public function __construct(TrikoderOAuth2Authenticator $decorated, UserProviderInterface $userProvider)
    {
        $this->decorated = $decorated;
        $this->userProvider = $userProvider;
    }

    public function supports(Request $request): ?bool
    {
        return $this->decorated->supports($request);
    }

    public function authenticate(Request $request): PassportInterface
    {

        return new Passport(
            new UserBadge(
                $this->decorated->getCredentials($request),
                fn ($id) => $this->decorated->getUser($id, $this->userProvider)
            ),
            new CustomCredentials(
                fn ($credentials, $user) => $this->decorated->checkCredentials($credentials, $user),
                $this->decorated->getCredentials($request)
            )
        );
    }

    public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
    {
        if (!$passport instanceof UserPassportInterface) {
            throw new \RuntimeException('Must be supplied with a UserPassport');
        }
        return $this->decorated->createAuthenticatedToken($passport->getUser(), $firewallName);
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return $this->decorated->onAuthenticationSuccess($request, $token, $firewallName);
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        return $this->decorated->onAuthenticationFailure($request, $exception);
    }
}

And adding this to the firewall (instead of oauth2: true):

      custom_authenticators:
        - App\Security\OAuth2Authenticator

And then this to the services.yml file. You may need different parameters depending on your firewall setup:

  App\Security\OAuth2Authenticator:
    arguments:
      $decorated: '@Trikoder\Bundle\OAuth2Bundle\Security\Guard\Authenticator\OAuth2Authenticator'
      $userProvider: '@security.user.provider.concrete.any_user'

Works well enough for the client_credentials grant type. Haven't tested any others.

nathansalter avatar Jan 13 '21 14:01 nathansalter

Worked on a PR for this issue https://github.com/trikoder/oauth2-bundle/issues/289

ricohumme avatar Sep 07 '21 07:09 ricohumme