tuupola / slim-basic-auth

PSR-7 and PSR-15 HTTP Basic Authentication Middleware
MIT License
440 stars 66 forks source link

Authenticator misinterpretation of "authorization" header #105

Closed Mo0812 closed 3 years ago

Mo0812 commented 3 years ago

Hey, I work with Slim 4.7 and slim-basic-auth 3.3 and realize a Basic Auth Authentification with a custom authenticator:

middleware.php

...
$app->add(new \Tuupola\Middleware\HttpBasicAuthentication([
        "authenticator" => $app->getContainer()->get(BasicAuthMiddleware::class),
        "secure" => false,
        "error" => function (Response $response, array $arguments) {
            $data = [];
            $data["status"] = "AuthError";
            $data["message"] = $arguments["message"];
            $response->getBody()->write(json_encode($arguments, JSON_PRETTY_PRINT));
            $response->withHeader('Content-Type', 'application/json')
                ->withStatus(403);
            return $response;
        }
    ]));

authenticator.php

...
class BasicAuthMiddleware implements AuthenticatorInterface
{

    private $db_handler;

    public function __construct(DatabaseConnectionHandler $db_handler)
    {
        $this->db_handler = $db_handler;
    }

    public function __invoke(array $arguments): bool
    {
        $username = $arguments["user"];
        $pw = $arguments["password"];
        try {
            $result = $this->db_handler->query("SELECT * FROM user WHERE username = ? AND pw = ?;", array($username, $pw));

            if ($result->getSelectedRows() > 0) {
                return true;
            }
            return false;
        } catch (\Exception $e) {
            throw new DomainUnauthenticatedException("Unauthenticated login");
        }
    }
}

I have the following problem:

When I request a secured endpoint with the HTTP Header "Authentication: Basic ..." the arguments "user" and "password" in the $arguments variable of the Authenticator __invoke method are interpreted and used correctly.

When I access the endpoint from a JS frontend with fetch, which converts the custom HTTP Headers to lowercase, like "authentication: Basic ...", the request get rejected all the time.

I logged the $arguments input in the __invoke method and see a difference:

Even without fetch and JS the problem can easily reproduced with CURL by changing the spelling of "Authentication" to "authentication" as the HTTP Header field.

I am not using multiple users in authentication.

Has anyone an idea where this behavior is coming from or how I can workaround/fix it?

Regards

tuupola commented 3 years ago

It seems this code is somehow failing. Header names are case insensitive. Changing the header to lowercase should not affect anything. I will setup a test case and see what is happening.

tuupola commented 3 years ago

This seems to be an issue with slim/psr-7 which creates two Authorization headers when request has a lowercase header. When using some other PSR-7 implementation such as nyholm/psr7 and nyholm/psr7-server problem does not exist.

In other words quick workaround at the moment is:

$ composer remove slim/psr7
$ composer require nyholm/psr7
$ composer require nyholm/psr7-server
Mo0812 commented 3 years ago

Thanks for your research, the workaround fixes my problem for now. Do you already have created an issue for this in the slim/psr-7 repo?

tuupola commented 3 years ago

I did. It is the https://github.com/slimphp/Slim-Psr7/issues/188.

tuupola commented 3 years ago

This has been fixed in https://github.com/slimphp/Slim-Psr7/pull/195