I'm using an SF2.8 API based on this tutorial https://gist.github.com/tjamps/11d617a4b318d65ca583 except i'm using MongoDB.
When a FOSUser (created on my DB A with oAuth tables) is connected to my API, i don't have all infos what i need because there are an other database.
I found a SF doc which explain how to custom symfony default authentication by replacing the default FOS User provider with a custom user provider.
So I decided to create the same architecture on this doc : http://symfony.com/doc/2.8/security/custom_provider.html
Before asking my oAuth token in /oauth/v2/token by HTTP Post request, my overrided loadUserByUsername method call an external API and instanciate a WebserviceUser which contain a user companies's collection in addition to having basic fields like username, password, salt etc. needed to connect.
After loadUserByUsername call, oAuth try to flush the generated accesstoken to the connected user into DB, but an exception is thrown because the User document to persist in AccessToken document is a AppBundle\Security\User\WebserviceUser instead of AppBundle\Document\User (child of FOSUser Document) so the mapping fail while persisting.
I got this :
The class 'AppBundle\Security\User\WebserviceUser' was not found in the chain configured namespaces AppBundle\Document, FOS\UserBundle\Document, FOS\OAuthServerBundle\Document (500 Internal Server Error)
Did I do something wrong ?
EDIT : My new loadUserByUsername method :
public function loadUserByUsername($username)
{
$apiUser = $this->manager->getRepository('AppBundle:User')->findOneByUsername($username);
if (is_null($apiUser)) {
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
$userData = $this->client->httpGetList("user", ['filter_usrMail' => $apiUser->getEmail()]);
$userData = $userData[array_keys($userData)[0]];
$companies = isset($userData['usrCompany']) ? $userData['usrCompany'] : [];
if ($userData) {
$role = isset($userData['usrRole']) ? [$userData['usrRole']] : ['ROLE_USER'];
$user = new WebserviceUser($apiUser->getUsername(), $apiUser->getPassword(), $apiUser->getSalt(), $apiUser->getRoles());
$user->setCompanies($companies);
$user->setApiUsername($apiUser->getUsername());
return $user;
}
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
fos_oauth_server yml conf :
db_driver: mongodb
client_class: AppBundle\Document\Client
access_token_class: AppBundle\Document\AccessToken
refresh_token_class: AppBundle\Document\RefreshToken
auth_code_class: AppBundle\Document\AuthCode
service:
user_provider: app.webservice_user_provider
services.yml conf :
app.webservice_user_provider:
class: AppBundle\Security\User\WebserviceUserProvider
arguments: ['@my_communicator.client', '@session', '@doctrine.odm.mongodb.document_manager', '%session_refresh_ttl%']
security.yml conf :
encoders:
AppBundle\Security\User\WebserviceUser: bcrypt
FOS\UserBundle\Model\UserInterface: bcrypt
providers:
webservice:
id: app.webservice_user_provider
#in_memory:
# memory: ~
fos_userbundle:
id: fos_user.user_provider.username
role_hierarchy:
ROLE_ADMIN: ROLE_USER
firewalls:
oauth_token: # Everyone can access the access token URL.
pattern: ^/oauth/v2/token
security: false
api:
pattern: ^\/api(?!\/doc|\/v[0-9][\.0-9]*\/core(\/createaccount|\/clients)) # All URLs are protected (except api doc and api create account)
fos_oauth: true # OAuth2 protected resource
stateless: true # Do no set session cookies
anonymous: false # Anonymous access is not allowed
access_denied_handler: app.listener.access_denied.handler
apidoc:
pattern: ^\/api\/doc
anonymous: false
security: false
access_control:
- { path: ^\/api\/v[0-9][\.0-9]*\/(?!(admin|core)), roles: ROLE_USER }
- { path: ^\/api\/v[0-9][\.0-9]*\/(admin|core)(?!(\/createaccount|\/clients)), roles: ROLE_ADMIN }
- { path: ^\/api\/v[0-9][\.0-9]*\/core(\/createaccount|\/clients), roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1, localhost, ::1] }
- { path: ^\/api\/v[0-9][\.0-9]*\/core(\/createaccount|\/clients), roles: ROLE_NO_ACCESS }
access_decision_manager:
strategy: unanimous