I just wanted to write a quick post illustrating how to use the http basic authentication mechanism to test secured pages. Since the testing framework does not support sessions at the moment, it is not possible to write tests using the form login mechanism. Because of this, we have to use http basic authentication to test our secure pages.
First, we must make changes to the application’s test environment. The config_test.yml file located in the app/config directory is where we put all of our test environment specific configuration. We need to override the security configuration we set up in the previous tutorial to use the http basic authentication mechanism. Open up the config_test.yml file and add the following.
## Security Configuration
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
providers:
main:
users:
john.doe: { password: admin, roles: ROLE_ADMIN }
firewalls:
main:
pattern: /.*
http_basic: true
logout: true
security: true
anonymous: true
Here we have declared that we want to use http_basic authentication in the test environment firewall. We have also told symfony that we want to use a plaintext password encoder for our user. This allows us to specify the user’s password in plain text. Under the providers entry we have declared an in-memory user with a username of john.doe, a password of admin and having the role ROLE_ADMIN. We will supply these credentials in our request using server parameters.
Now open up the AdminControllerTest.php file located in the src/Company/BlogBundle/Tests/Controller folder. Here is the code for the test.
namespace Company\BlogBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class AdminControllerTest extends WebTestCase { public function testIndex() { $client = $this->createClient(); $client->followRedirects(true); // request the index action with invalid credentials $crawler = $client->request('GET', '/admin/', array(), array(), array('PHP_AUTH_USER' => 'john.doe', 'PHP_AUTH_PW' => 'wrong_pass')); $this->assertEquals(200, $client->getResponse()->getStatusCode()); // we should be redirected to the login page $this->assertTrue($crawler->filter('title:contains("Login")')->count() > 0); // request the index action with valid credentials $crawler = $client->request('GET', '/admin/', array(), array(), array('PHP_AUTH_USER' => 'john.doe', 'PHP_AUTH_PW' => 'admin')); $this->assertEquals(200, $client->getResponse()->getStatusCode()); // check the title of the page matches the admin home page $this->assertTrue($crawler->filter('title:contains("Admin | Home")')->count() > 0); // check that the logout link exists $this->assertTrue($crawler->filter('a:contains("Logout")')->count() > 0); } } |
The code is fairly straightforward. You should be able to follow along with the comments and know what is going on. Two special server parameters are used to pass the user’s credentials to the application PHP_AUTH_USER and PHP_AUTH_PW.
You should now be setup to test all of your secured pages. I am still not sure what I will be posting about next. I have been out of town, so I have not had time to even think about it. I am hesitant to do a Form tutorial because of the proposed changes. I was thinking about maybe going over the container and writing a custom service. Let me know what you guys want. Until next time…
If possible, I want to know more on forms. Thanks
Thanks Dustin,
I’ll very appreciate if next topic would be either form or custom service.
Good luck!
Hi there, please by all means you can expand on the ground you have already work on the blogbundle tutorial. Sometimes we want to gain more confidence on changes and expanding features, not necessarily boarding into new specific grande features. Please remember the newbies!
Hi. This is by far the best Symfony2 tutorials. I learned all I know about security here. So thank you very much.
I would like to see some service implementation. I want to move forward learning services, right know I can’t come up with any idea but mailing (but of course that is already there hehe).
Congratulations and great work!!!
Yeah, helped a lot, thanks!
How do you get the “routing” to invoke testIndex()? There is no documentation on making a URL that invokes DefaultControllerTest to run this test in the first place.
Hi, great tutorials here.
Do you know if there’s some way to test the ROLE after the login?
In a twig template you can use the is_granted twig function provided by the SecurityBundle to check if the current user has a certain role. For example, {% if is_granted(‘ROLE_ADMIN’) %} would check to see that the user has the ROLE_ADMIN role.
If you are in a Controller class then you can get the security.context service to check.
// in a class that extends Symfony\Bundle\FrameworkBundle\Controller\Controller
if ($this->get(‘security.context’)->isGranted(‘ROLE_ADMIN’)) { ..
You could also inject the security.context service into any class you have configured as a service in the DIC and use it as needed.
I misunderstood your question with my earlier reply. I see you are asking how to do it in a test. Something like this:
$security = $this->getContainer()->get(‘security.context’);
$this->assertTrue($security->isGranted(‘ROLE_ADMIN’));
EXCELLENT!!!! Very very work.
This tutorial maybe outdated, cause for security settings mostly secuirty.yml is used.
And it is not possible to overwrite security settings in config_test.yml also on my system a security_test.yml is ignored. Hope to find a solution for that soon.
As i found out config environment was misconfigured, the load of security.yml was hard coded thats why security_test.yml was not loaded