Подделка аутентификации в тестах Symfony2 — get('security.context')->getToken() на контроллере возвращает токен, отличный от установленного в TestCase

Я пишу функциональные тесты Symfony для приложения Symfony 2.0, которое использует FOSFacebookBundle (v2.0). Контроллеры, которые я тестирую, проверяют подлинность следующим образом:

if($this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')){...}

Поэтому мне нужно, чтобы тест $client (типа Symfony\Bundle\FrameworkBundle\Client) был аутентифицирован.

Предположительно, мне нужно создать действительный токен и установить его на security.context, session и cookieJar $client для аутентификации $client, верно?

Проблема в том, что security.context в контроллерах возвращает токен, отличный от действительного, который я установил в тестовом $client.

Кто-нибудь знает, почему токен сбрасывается после выполнения запроса?

Вот как я настраиваю это в классе тестового примера:

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()));

После этой настройки в тестовом примере это возвращает true:

if($client->getContainer()->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')){...}

Но на контроллерах он возвращает false

if($this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')){...}

Я неправильно настраиваю что-то в security.context или в сеансе?

Вот конфигурация безопасности приложения:

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

Сервис facebook.id — это класс, реализующий интерфейс Symfony\Component\Security\Core\User\UserProviderInterface.

Этот класс использует php api facebook (класс BaseFacebook) для вызова API-интерфейса facebook (BaseFacebook->api('/me')), но этого никогда не происходит, так как я не могу пройти мимо безопасности Symfony.

Любые комментарии, указатели или ссылки на ресурсы приветствуются. Спасибо!


person gtb    schedule 03.09.2014    source источник


Ответы (2)


Возможно, самый простой способ — открыть учетную запись разработчика на Facebook, а затем перейти на сайт разработчика. Кроме того, вы найдете инструменты. Одним из них является «отладчик токенов». Он может создать токен для вас. Вы также можете скопировать и вставить один из токенов, полученных при вызове, и инструмент отобразит содержимое токена.

Полезно понять, что происходит, и посмотреть, имеет ли токен, который вы получаете, ту ценность, которую вы думаете.

person Peter    schedule 03.09.2014
comment
Спасибо за ваш комментарий, но это не токен FB. Проблема в том, что я не прошел уровень безопасности Symfony. Я проверил отладчик токенов FB, приятно знать об этом :) - person gtb; 05.09.2014

Проблема связана с ошибкой в ​​Symfony 2.0.

Я заметил, что $this->contextKey равно 'primary_auth' внутри метода: \Symfony\Component\Security\Http\Firewall\ContextListener::handle(GetResponseEvent $event)

поэтому в моем тестовом наборе я делаю:

$client->getContainer()->get('session')->set('_security_primary_auth', serialize($authenticatedToken));

вместо

$client->getContainer()->get('session')->set('_security_public', serialize($authenticatedToken));

(эта проблема задокументирована здесь: https://github.com/symfony/symfony/issues/5228 (прочитать полностью))

person gtb    schedule 05.09.2014