Skip to content

JsonLoginAuthenticator::getCredentials() should not allow blank username or password #46100

Closed
@rimas-kudelis

Description

@rimas-kudelis

Symfony version(s) affected

All currently supported versions

Description

When JsonLoginAuthenticator does its job, among other things, it checks that the username passed in the request is a string and that it is not longer than 4096 characters:

try {
$credentials['username'] = $this->propertyAccessor->getValue($data, $this->options['username_path']);
if (!\is_string($credentials['username'])) {
throw new BadRequestHttpException(sprintf('The key "%s" must be a string.', $this->options['username_path']));
}
if (\strlen($credentials['username']) > Security::MAX_USERNAME_LENGTH) {
throw new BadCredentialsException('Invalid username.');
}
} catch (AccessException $e) {
throw new BadRequestHttpException(sprintf('The key "%s" must be provided.', $this->options['username_path']), $e);
}

Further down below it makes sure that the supplied password is also a string:

try {
$credentials['password'] = $this->propertyAccessor->getValue($data, $this->options['password_path']);
if (!\is_string($credentials['password'])) {
throw new BadRequestHttpException(sprintf('The key "%s" must be a string.', $this->options['password_path']));
}
} catch (AccessException $e) {
throw new BadRequestHttpException(sprintf('The key "%s" must be provided.', $this->options['password_path']), $e);
}
return $credentials;

I propose to additionally check that both username and password consist of at least one character each, so that attempts to login with an empty username or password are refused without making attempts to load the user.

How to reproduce

Enable debugging, add a breakpoint in

$credentials = $this->getCredentials($request);
and attempt to trigger a JSON login with blank username and password. You will see that no BadRequestHttpException will be caught here and that the logic will proceed creating a Passport object with two useless badges, one for blank username and another for blank password:
public function authenticate(Request $request): Passport
{
try {
$credentials = $this->getCredentials($request);
} catch (BadRequestHttpException $e) {
$request->setRequestFormat('json');
throw $e;
}
$passport = new Passport(
new UserBadge($credentials['username'], $this->userProvider->loadUserByIdentifier(...)),
new PasswordCredentials($credentials['password'])
);
if ($this->userProvider instanceof PasswordUpgraderInterface) {
$passport->addBadge(new PasswordUpgradeBadge($credentials['password'], $this->userProvider));
}
return $passport;
}

Possible Solution

No response

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions