-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IBX-8323: Reworked RepositoryAuthenticationProvider and moved its log…
…ic to a dedicated subscriber
- Loading branch information
1 parent
232ee8a
commit 0c1a674
Showing
6 changed files
with
112 additions
and
504 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
...ymfony/Security/Authentication/EventSubscriber/RepositoryUserAuthenticationSubscriber.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
* @license For full copyright and license information view LICENSE file distributed with this source code. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Ibexa\Core\MVC\Symfony\Security\Authentication\EventSubscriber; | ||
|
||
use Exception; | ||
use Ibexa\Contracts\Core\Repository\Exceptions\PasswordInUnsupportedFormatException; | ||
use Ibexa\Contracts\Core\Repository\UserService; | ||
use Ibexa\Core\MVC\Symfony\Security\UserInterface as IbexaUserInterface; | ||
use Ibexa\Core\Repository\User\Exception\UnsupportedPasswordHashType; | ||
use Psr\Log\LoggerAwareTrait; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\HttpFoundation\RequestStack; | ||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; | ||
use Symfony\Component\Security\Http\Event\CheckPassportEvent; | ||
|
||
final class RepositoryUserAuthenticationSubscriber implements EventSubscriberInterface | ||
{ | ||
use LoggerAwareTrait; | ||
|
||
// Constant authentication execution time in seconds (float). Blocks timing attacks. | ||
// Must be larger than expected real execution time, with a good margin. | ||
// If set to zero, constant time authentication is disabled. Do not do this on production environments. | ||
public const float CONSTANT_AUTH_TIME_DEFAULT = 1.0; | ||
|
||
public const string CONSTANT_AUTH_TIME_SETTING = 'ibexa.security.authentication.constant_auth_time'; | ||
|
||
private const int USLEEP_MULTIPLIER = 1000000; | ||
|
||
public function __construct( | ||
private readonly RequestStack $requestStack, | ||
private readonly UserService $userService, | ||
) { | ||
} | ||
|
||
public static function getSubscribedEvents(): array | ||
{ | ||
return [ | ||
CheckPassportEvent::class => ['validateRepositoryUser'], | ||
]; | ||
} | ||
|
||
public function validateRepositoryUser(CheckPassportEvent $event): void | ||
{ | ||
$request = $this->requestStack->getCurrentRequest(); | ||
if ($request === null) { | ||
return; | ||
} | ||
|
||
$badge = $event->getPassport()->getBadge(UserBadge::class); | ||
if (!$badge instanceof UserBadge) { | ||
return; | ||
} | ||
|
||
$user = $badge->getUser(); | ||
if (!$user instanceof IbexaUserInterface) { | ||
return; | ||
} | ||
|
||
$startTime = $this->startConstantTimer(); | ||
try { | ||
$this->userService->checkUserCredentials( | ||
$user->getAPIUser(), | ||
$user->getPassword() ?? '' | ||
); | ||
|
||
$event->getAuthenticator()->authenticate($request); | ||
} catch (UnsupportedPasswordHashType $exception) { | ||
$this->sleepUsingConstantTimer($startTime); | ||
|
||
throw new PasswordInUnsupportedFormatException($exception); | ||
} catch (Exception $e) { | ||
$this->sleepUsingConstantTimer($startTime); | ||
|
||
throw $e; | ||
} | ||
|
||
$this->sleepUsingConstantTimer($startTime); | ||
} | ||
|
||
private function startConstantTimer(): float | ||
{ | ||
return microtime(true); | ||
} | ||
|
||
private function sleepUsingConstantTimer(float $startTime): void | ||
{ | ||
$remainingTime = self::CONSTANT_AUTH_TIME_DEFAULT - (microtime(true) - $startTime); | ||
if ($remainingTime > 0) { | ||
$microseconds = $remainingTime * self::USLEEP_MULTIPLIER; | ||
|
||
usleep((int)$microseconds); | ||
} elseif ($this->logger) { | ||
$this->logger->warning( | ||
sprintf( | ||
'Authentication took longer than the configured constant time. Consider increasing the value of %s', | ||
self::CONSTANT_AUTH_TIME_SETTING | ||
), | ||
[__CLASS__] | ||
); | ||
} | ||
} | ||
} |
133 changes: 0 additions & 133 deletions
133
src/lib/MVC/Symfony/Security/Authentication/RepositoryAuthenticationProvider.php
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.