1

How is it possible to implement an OAuth server based on FOSOAuthServerBundle without using FOSUserBundle?

My user class starts like his:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;

/**
*
* @ORM\Entity
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository")
*/
class User implements UserInterface

My user repository class starts with this:

<?php

namespace AppBundle\Entity;

use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;

class UserRepository extends EntityRepository implements UserLoaderInterface, UserProviderInterface

In my security.yml I included the following:

    providers:
        user_db:
            entity:
                class: AppBundle\Entity\User
                property: username

And finally the config.yml:

fos_oauth_server:
    db_driver: orm
    client_class: AppBundle\Entity\OAuthClient
    access_token_class: AppBundle\Entity\OAuthAccessToken
    refresh_token_class: AppBundle\Entity\OAuthRefreshToken
    auth_code_class: AppBundle\Entity\OAuthAuthCode
    service:
        options:
            access_token_lifetime: 3600

        user_provider: user_db
        #user_provider: AppBundle\Entity\UserRepository
        #user_provider: AppBundle\Entity\User

Right now it throws an exception:

[1] Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function loadUserByUsername() on null
    at n/a
        in /home/wanderson/api/vendor/friendsofsymfony/oauth-server-bundle/Storage/OAuthStorage.php line 161

    at FOS\OAuthServerBundle\Storage\OAuthStorage->checkUserCredentials(object(OAuthClient), 'admin', 'admin')
        in /home/wanderson/api/vendor/friendsofsymfony/oauth2-php/lib/OAuth2.php line 929

    at OAuth2\OAuth2->grantAccessTokenUserCredentials(object(OAuthClient), array('grant_type' => 'password', 'scope' => null, 'code' => null, 'redirect_uri' => null, 'username' => 'admin', 'password' => 'admin', 'refresh_token' => null))
        in /home/wanderson/api/vendor/friendsofsymfony/oauth2-php/lib/OAuth2.php line 815

    at OAuth2\OAuth2->grantAccessToken(object(Request))
        in /home/wanderson/api/vendor/friendsofsymfony/oauth-server-bundle/Controller/TokenController.php line 42

    at FOS\OAuthServerBundle\Controller\TokenController->tokenAction(object(Request))
        in  line 

    at call_user_func_array(array(object(TokenController), 'tokenAction'), array(object(Request)))
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php line 153

    at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), '1')
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php line 68

    at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true)
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php line 169

    at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
        in /home/wanderson/api/web/app_dev.php line 30

    at require('/home/wanderson/api/web/app_dev.php')
        in /home/wanderson/api/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php line 40

1 Answer 1

4

Create a user provider, or if you want to use your repository class for it read 'how define repository like service' (i don't know working if it at newest version or not):

https://stackoverflow.com/a/17230333/6848076 https://stackoverflow.com/a/31807608/6848076

But i not recommended this way

<?php 

namespace AppBundle\Security\Provider\UserProvider;

use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\ORM\NoResultException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Serializer\Exception\UnsupportedException;
use Doctrine\ORM\EntityManager;

class UserProvider implements UserProviderInterface
{
    protected $class;

    protected $userRepository;

    public function __construct(EntityManager $entityManager, $class)
    {
        $this->class = $class;
        $this->userRepository = $entityManager->getRepository($class);
    }

    public function loadUserByUsername($username)
    {
        $user = $this->userRepository->findOneBy(array('username' => $username));
        if (null === $user) {
            $message = sprintf(
                'Unable to find an active User object identified by "%s"',
                $username
            );
            throw new UsernameNotFoundException($message, 0, $failed);
        }
        return $user;
    }

    public function refreshUser(UserInterface $user)
    {
        $class = get_class($user);
        if (false == $this->supportsClass($class)) {
            throw new UnsupportedException(
                sprintf(
                    'Instances of "%s" are not supported',
                    $class
                )
            );
        }
        return $this->userRepository->find($user->getId());
    }

    public function supportsClass($class)
    {
        return $this->class === $class
            || is_subclass_of($class, $this->class);

    }
}

About services you can read: http://symfony.com/doc/current/service_container.html Define a provider service at {project_directory}/src/AppBundle/Resources/config/service.yml

parameters:
    user.class: AppBundle\Entity\User
    user.provider.class: AppBundle\Security\Provider\UserProvider
services:
    user.provider:
      class: %user.provider.class%
      arguments: [@doctrine.orm.entity_manager, %user.class%]

Change fosoauth configuration at config.yml:

fos_oauth_server:
    db_driver: orm
    client_class: AppBundle\Entity\OAuthClient
    access_token_class: AppBundle\Entity\OAuthAccessToken
    refresh_token_class: AppBundle\Entity\OAuthRefreshToken
    auth_code_class: AppBundle\Entity\OAuthAuthCode
    service:
        options:
            access_token_lifetime: 3600
        user_provider: user.provider

About security.yml you can read: http://symfony.com/doc/current/security.html

Sign up to request clarification or add additional context in comments.

1 Comment

Sorry, I am a newbie with Symfony, I'm not sure where do place this provider service configuration. I tried to put it under security.providers (security.yml) exactly as in your example and I get Symfony to tell me this file does not contain valid YAML. PS: the UserProvider class is, except for the constructor, pretty much identical to my UserRepository class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.