. */ namespace vierbergenlars\AuthserverOAuthAccountBundle\Security\Core\User; use App\Entity\User; use App\Security\User\UserProvider; use Doctrine\Common\Persistence\ManagerRegistry; use Symfony\Component\Security\Core\User\UserInterface; use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface; use HWI\Bundle\OAuthBundle\Connect\AccountConnectorInterface; use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException; use vierbergenlars\AuthserverExternalAccountBundle\Entity\ExternalUser; use vierbergenlars\AuthserverOAuthAccountBundle\Entity\TemporaryUser; class OAuthUserProvider extends UserProvider implements OAuthAwareUserProviderInterface, AccountConnectorInterface { /** * * @var ManagerRegistry */ private $registry; public function __construct(ManagerRegistry $registry) { parent::__construct($registry); $this->registry = $registry; } /** * Loads the user by a given UserResponseInterface object. * * @param UserResponseInterface $response * * @return UserInterface * * @throws AccountNotLinkedException if the provider is not linked to an account */ public function loadUserByOAuthUserResponse(UserResponseInterface $response) { try { return $this->getExternalAccount($response)->getUser(); } catch (AccountNotLinkedException $ex) { $user = new TemporaryUser(); $externalUser = $this->createExternalUser($response); $user->setExternalUser($externalUser); if ($response->getEmail()) $user->setEmail($response->getEmail()); return $user; } } private function createExternalUser(UserResponseInterface $response) { $externalUser = new ExternalUser(); $externalUser->setProvider('oauth_' . $response->getResourceOwner() ->getName()); $externalUser->setProviderRef($response->getUsername()); $externalUser->setProviderFriendlyName($response->getRealName()); return $externalUser; } public function connect(UserInterface $user, UserResponseInterface $response) { if (!$user instanceof User) throw new \UnexpectedValueException('User must be instance of ' . User::class . ', got ' . get_class($user)); try { $externalUser = $this->getExternalAccount($response); $this->disconnect($externalUser); } catch (AccountNotLinkedException $ex) { // do nothing } $externalUser = $this->createExternalUser($response); $externalUser->setUser($user); $this->getManager()->persist($externalUser); $this->getManager()->flush(); } public function disconnect(ExternalUser $externalUser) { $this->getManager()->remove($externalUser); $this->getManager()->flush(); } /** * * @return \Doctrine\Common\Persistence\ObjectRepository */ private function getRepo() { return $this->getManager()->getRepository('AuthserverExternalAccountBundle:ExternalUser'); } /** * * @return \Doctrine\Common\Persistence\ObjectManager|null */ private function getManager() { return $this->registry->getManagerForClass('AuthserverExternalAccountBundle:ExternalUser'); } /** * * @param UserResponseInterface $response * @return ExternalUser */ private function getExternalAccount(UserResponseInterface $response) { $repo = $this->getRepo(); $externalAccount = $repo->findOneBy([ 'provider' => 'oauth_' . $response->getResourceOwner() ->getName(), 'provider_ref' => $response->getUsername() ]); if (!$externalAccount) { throw new AccountNotLinkedException(sprintf('No external account registered for provider "%s", ref: "%s"', $response->getResourceOwner()->getName(), $response->getUsername())); } return $externalAccount; } }