Search code examples
phpsymfony1authenticationdoctrinefunctional-testing

Can't access secured pages after login on symfony functional test


I currently trying to test a symfony app that has secured pages, using functional tests.

Scenario

  1. Log in as a user that is a superadmin (thus bypassing any credential check)
  2. Browse to a secured page (here displaying a list of documents)
  3. Make some various tests to check various requirements.

Problem

When I browse the secured page, instead of a 200 HTTP code, I get a 401 "Unauthorized" HTTP code, meaning I'm trying to access a page without being authenticated/without having the right credentials.

Even if I log as a normal user, that have the proper symfony credentials, I still get a 401 error.

Code used

//CapWebndfTestFunctional.class.php

class CapWebndfTestFunctional extends sfTestFunctional
{
  /**
* Login as a user
* @param string $username User's username
*/
  public function signInAs($username)
  {
    $user = Doctrine_Core::getTable('sfGuardUser')->findOneByUsername($username);

    //force the context to be created
    $this->browser->getContext(true)->getUser()->signIn($user);

    $this->info(sprintf('Signin user using username "%s"', $username));

    if ($user->getIsSuperAdmin())
    {
      $this->info('Beware, you are logged as a superadmin!');
    }

    return $this;
  }

}

Test suite:

<?php

$browser = new CapWebndfTestFunctional(new sfBrowser());

$browser->
  signInAs('superadmin')->
  with('user')->begin()->
    isAuthenticated()-> //ensure that I'm well authenticated
  end()->

  get('/document')-> //a secured page
  with('request')->begin()->
    isParameter('module', 'document')->
    isParameter('action', 'index')->
  end()->

  with('response')->begin()->
    isStatusCode(200)-> //as superadmin is a sfGuard superadmin, this should be 200;
  end()->
  // Here some other tests...

/* Outputs :
clem@ubuntu:/var/www/cap_webndf/trunk$ php symfony test:functional backend documentActions
> Signin user using username "superadmin"
> Beware, you are logged as a superadmin!
ok 1 - user is authenticated
# get /document
ok 2 - request parameter module is document
ok 3 - request parameter action is index
not ok 4 - status code is 200
# Failed test (./lib/vendor/symfony/lib/test/sfTesterResponse.class.php at line 412)
# got: 401
# expected: 200
*/

I'm really stuck on this one, so thank you for any help.

Edit: If you prefer, here is the used code on a gist

EDIT: What is the difference between going to the login page and sending a (fake) post request, and directly signin in using the dedicated sfGuard method?


Solution

  • I don't think you can use SignIn() like that as it would not set the cookie within the browser so on the next page you would be logged out again.

    Whenever I have done functional testing with users I have gone to the login page and entered the username/password of the user and logged in as them.

    I haven't tested this but something like this should work, I normally use test users and know their password

    //CapWebndfTestFunctionnal.class.php

    class CapWebndfTestFunctionnal extends sfTestFunctional
    {
      /**
    * Login as a user
    * @param string $username User's username
    */
      public function signInAs($username)
      {
        $tempPassword = rand(1000, 9999999);
    
        $user = Doctrine_Core::getTable('sfGuardUser')->findOneByUsername($username);
        $oldPassword = $user->getPassword();
    
        $user->setPassword($tempPassword);
        $user->save();
    
        $this->info(sprintf('Signin user using username "%s"', $username));
    
        $this->post('/login', array('username' => $user->getUsername(), 'password' => $tempPassword))->isRedirected();
    
        if ($user->getIsSuperAdmin())
        {
          $this->info('Beware, you are logged as a superadmin!');
        }
    
        $user->setPasswordHash($oldPassword);
        $user->save();
    
        return $this;
      }
    }