I'm writing symfony functional tests for a Symfony 2.0 application that uses the FOSFacebookBundle (v2.0). The controllers I'm testing check for authentication like so:
if($this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')){...}
So I need the test's $client
(of type Symfony\Bundle\FrameworkBundle\Client
) to be authenticated.
Supposedly I need to create a valid token and set it on the $client
's security.context
, session
, and cookieJar
for $client
to be authenticated, right?
The issue is that the security.context
in the controllers return a different token from the valid one I set up on the test's $client
.
Does anyone know why the token gets reset after making the request?
Here's how I'm setting this up in the test case class:
use FOS\FacebookBundle\Security\Authentication\Provider\FacebookProvider;
use FOS\FacebookBundle\Security\Authentication\Token\FacebookUserToken;
use Symfony\Component\BrowserKit\Cookie;
$providerKey = 'public';
$facebookMock = $this->getMockBuilder('\Facebook')
->disableOriginalConstructor()
->getMock();
$facebookMock->expects($this->once())
->method('getUser')
->will($this->returnValue('DevTestUsername'));
$facebookProvider = new FacebookProvider($providerKey, $facebookMock);
$tokenMock = new FacebookUserToken(
'public',
'DevTestUsername',
array('ROLE_MEMBER', 'ROLE_MANAGER', 'ROLE_USER')
);
$authenticatedToken = $facebookProvider->authenticate($tokenMock);
$client->getContainer()->get('security.context')->setToken($authenticatedToken);
$client->getContainer()->get('session')->set('_security_public', serialize($authenticatedToken));
$client->getContainer()->get('session')->save();
$client->getCookieJar()->set(new Cookie(session_name(), $client->getContainer()->get('session')->getId()));
After this setup, on the test case this returns true
:
if($client->getContainer()->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')){...}
But on the controllers, it returns false
if($this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')){...}
Am I setting up things wrong in the security.context or in the session?
Here's the application's security config:
security:
factories:
- "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]
ROLE_SUPER_ADMIN: [ROLE_ADMIN]
providers:
chain_provider:
providers: [fos_userbundle, facebook_provider]
fos_userbundle:
id: fos_user.user_manager
facebook_provider:
id: facebook.user
firewalls:
public:
pattern: ^/.*
fos_facebook:
provider: facebook_provider
app_url: "http://apps.facebook.com/myapp"
server_url: "http://myapp.local/"
login_path: /login
check_path: /login_check
default_target_path: /target
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
check_path: /login_check
anonymous: true
switch_user: { role: ROLE_ADMIN }
logout:
target: http://myapp.com
handlers: ["fos_facebook.logout_handler"]
context: primary_auth
The facebook.id service is a class that implements the Symfony\Component\Security\Core\User\UserProviderInterface
This class uses facebook's php api (BaseFacebook class) to make a call to the facebook graph api (BaseFacebook->api('/me')), but this never happens, as I don't get past Symfony's security.
Any comments, pointers or links to resources greatly appreciated. Thanks!
The issue is a bug in Symfony 2.0
I noticed that $this->contextKey
equals 'primary_auth'
inside method: \Symfony\Component\Security\Http\Firewall\ContextListener::handle(GetResponseEvent $event)
so in my test suite I do:
$client->getContainer()->get('session')->set('_security_primary_auth', serialize($authenticatedToken));
instead of
$client->getContainer()->get('session')->set('_security_public', serialize($authenticatedToken));
(this issue is documented here: https://github.com/symfony/symfony/issues/5228 (read the whole thing))