3
votes

I am writing a REST API endpoint in PHP / Symfony 4.0 and I want to use basic authentication, with an in-memory user whose password is blank. When I try to call the endpoint with these credentials, I get a BadCredentialsException saying 'The presented password cannot be empty'.

It appears that the exception is being thrown by the DaoAuthenticationProvider.

How can I configure basic authentication in Symfony to allow an empty password?

Context: I'm setting up basic authentication for a simple endpoint that will be used as a Prismic custom API for an integration field (see https://user-guides.prismic.io/en/articles/1401183-connect-to-a-custom-api). Prismic supports basic authentication for this, where you enter a key which will be used as the username, and the password will be left blank.

I am writing this in PHP / Symfony 4.0, and I have been following the docs at https://symfony.com/doc/current/security.html .

My config/packages/security.yaml file is:

security:
    firewalls:
        secured_area:
            pattern: ^/api/my-endpoint
            http_basic: ~
            security: true
        main:
            security: false

    providers:
        in_memory:
            memory:
                users:
                    test:
                        password: ''

    encoders:
        Symfony\Component\Security\Core\User\User: plaintext

The full error message in my logs is:

Basic authentication failed for user. {"username":"test","exception":"[object] (Symfony\Component\Security\Core\Exception\BadCredentialsException(code: 0): Bad credentials. at my-project\vendor\symfony\security\Core\Authentication\Provider\UserAuthenticationProvider.php:84, Symfony\Component\Security\Core\Exception\BadCredentialsException(code: 0): The presented password cannot be empty. at my-project\vendor\symfony\security\Core\Authentication\Provider\DaoAuthenticationProvider.php:54)"} []

1
Just for clarification: which Symfony version do you use? Have you tried updating it to the most recent version of 4.3?Nico Haase
Symfony 4.0. I have tried updating to Symfony 4.3 and I get the same exception.dans

1 Answers

2
votes

If you really don't want to have a proper authentication, and then authenticated user will do a call to a remote endpoint with the API key, and resolve the task in a more "dirty" way, then what you can do is:

  • create your own AuthenticationProvider, which will extend the original https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php

  • overwrite the checkAuthentication method where you will have same code as original, but without check on empty password (and perhaps everything else related in that else statement)

  • overwrite the service definition to point to your own created AuthenticationProvider

     <service id="security.authentication.provider.dao" class="XXXX Your class here XXXX" abstract="true">
         <argument /> <!-- User Provider -->
         <argument /> <!-- User Checker -->
         <argument /> <!-- Provider-shared Key -->
         <argument type="service" id="security.encoder_factory" />
         <argument>%security.authentication.hide_user_not_found%</argument>
     </service>
    
  • clear the cache and try

Overwrite the service:

services:
  ...
  ...
  security.authentication.provider.dao:
    alias: MyProject\Service\Security\OverriddenDaoAuthenticationProvider
    public: true

In your OverriddenDaoAuthenticationProvider class remember to call the original constructor to pass through the parameters:

public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, string $providerKey, EncoderFactoryInterface $encoderFactory, bool $hideUserNotFoundExceptions = true)
{
    parent::__construct($userProvider, $userChecker, $providerKey, $encoderFactory, $hideUserNotFoundExceptions);
}