Reputation: 2869
I came up with a briliant idea of using Basic Auth in my small script since I thought it's gonna be faster than using jwt ... well I was wrong. I cannot test my endpoint now because I constantly get 401.
Source code from below is also available here: https://github.com/tarach/blog-api/tree/feature/posts-resource-test
public function testShouldCreatePost(): void
{
$client = static::createClient();
$headers = [
'Content-Type' => 'application/json',
'Authorization' => 'Basic ' . base64_encode('test:qwe123'),
];
dump($headers);
$client->request('POST', '/api/posts', [
'headers' => $headers,
'json' => [],
]);
dump([
'response' => [
'status' => $client->getResponse()->getStatusCode(),
'body' => $client->getResponse()->getContent(),
],
]);
}
security.yaml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
encoders:
App\Infrastructure\Symfony\User\EnvironmentUser:
algorithm: plaintext
providers:
environment_user_provider:
id: App\Infrastructure\Symfony\User\EnvironmentUserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/api
stateless: true
anonymous: true
provider: environment_user_provider
http_basic:
realm: Protected
access_control:
- { path: ^/api/posts, methods: ["GET"], roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
EnvironmentUserProvider uses two env. variables USER_NAME and USER_PASSWORD.
via Postman it works correctly:
Solution:
public function testShouldCreatePost(): void
{
// Method A)
$client = static::createClient([], [
'PHP_AUTH_USER' => 'test',
'PHP_AUTH_PW' => 'qwe123',
]);
// Method B)
$client->setServerParameter('HTTP_AUTHORIZATION', 'Basic ' . base64_encode('test:qwe123'));
$content = json_encode([
'title' => 'Some title',
'body' => '<strong>Some Body</strong>'
]);
$client->request(
'POST',
'/api/posts',
[],
[],
[
'CONTENT_TYPE' => 'application/json',
],
$content
);
$this->assertEquals(201, $client->getResponse()->getStatusCode());
}
Upvotes: 0
Views: 1771
Reputation: 17166
If you use a recent Symfony version (5.1 or higher) there is a neat helper on client that you can use:
$client = static::createClient();
$userRepository = static::$container->get(UserRepository::class);
// retrieve the test user
$testUser = $userRepository->findOneByEmail('[email protected]');
// simulate $testUser being logged in
$client->loginUser($testUser);
// test e.g. the profile page
$client->request('GET', '/profile');
Example taken from the docs for Logging in Users in Tests.
If you use basic auth, you can pass in the credentials for the auth dialog like this:
$client = static::createClient([], [
'PHP_AUTH_USER' => 'username',
'PHP_AUTH_PW' => 'pa$$word',
]);
As seen in the old docs for How to Simulate HTTP Authentication in a Functional Test.
If you want to submit the headers from your example, things are a bit tricky because you will need to pass in the internal representation as can be seen in the BrowserKit Browser.
In your case the headers should probably change like this:
$headers = [
'CONTENT_TYPE' => 'application/json',
'HTTP_AUTHORIZATION' => 'Basic ' . base64_encode('test:qwe123'),
];
You can see the which internal representation Symfony uses in the code for the HttpFoundation ServerBag.
Upvotes: 3