diff --git a/src/Authenticator/BearerUserProvider.php b/src/Authenticator/BearerUserProvider.php index 1a7cf750ba3fcd4f705a9baf214fc4d39ab1459a..c0656f1aae2c7ee24cc76b365e86cea840483419 100644 --- a/src/Authenticator/BearerUserProvider.php +++ b/src/Authenticator/BearerUserProvider.php @@ -31,6 +31,13 @@ class BearerUserProvider implements BearerUserProviderInterface, LoggerAwareInte $this->config = $config; } + public function getValidationLeewaySeconds(): int + { + $config = $this->config; + + return $config['local_validation_leeway']; + } + public function loadUserByToken(string $accessToken): UserInterface { $config = $this->config; diff --git a/src/OIDC/OIDProvider.php b/src/OIDC/OIDProvider.php index 052b1a0282d6c31001b63891fb14c96bc97bb355..fd961f8d209a0fca76d66b23fc0f90f661569a3d 100644 --- a/src/OIDC/OIDProvider.php +++ b/src/OIDC/OIDProvider.php @@ -52,7 +52,7 @@ class OIDProvider implements LoggerAwareInterface $this->clientHandler = $handler; } - private function getClient(): Client + private function getClient(bool $noCache = false): Client { $stack = HandlerStack::create($this->clientHandler); if ($this->logger !== null) { @@ -67,7 +67,7 @@ class OIDProvider implements LoggerAwareInterface $client = new Client($options); - if ($this->cachePool !== null) { + if ($this->cachePool !== null && !$noCache) { $cacheMiddleWare = new CacheMiddleware( new GreedyCacheStrategy( new Psr6CacheStorage($this->cachePool), @@ -80,6 +80,17 @@ class OIDProvider implements LoggerAwareInterface return $client; } + public function getProviderDateTime(): \DateTimeInterface + { + $serverUrl = $this->config['server_url'] ?? ''; + $client = $this->getClient(true); + $response = $client->request('GET', $serverUrl); + $date = new \DateTimeImmutable($response->getHeader('Date')[0]); + $date = $date->setTimezone(new \DateTimeZone('UTC')); + + return $date; + } + /** * @throws OIDError */ diff --git a/src/Service/HealthCheck.php b/src/Service/HealthCheck.php index 29e6c395216f8486faf32dbe4f250d6f2db54d2a..23093681aaa16334e3eb6240b6b547902f96032e 100644 --- a/src/Service/HealthCheck.php +++ b/src/Service/HealthCheck.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Dbp\Relay\AuthBundle\Service; +use Dbp\Relay\AuthBundle\Authenticator\BearerUserProvider; use Dbp\Relay\AuthBundle\OIDC\OIDProvider; use Dbp\Relay\CoreBundle\HealthCheck\CheckInterface; use Dbp\Relay\CoreBundle\HealthCheck\CheckOptions; @@ -11,11 +12,13 @@ use Dbp\Relay\CoreBundle\HealthCheck\CheckResult; class HealthCheck implements CheckInterface { - private $provider; + private $oidcProvider; + private $userProvider; - public function __construct(OIDProvider $provider) + public function __construct(OIDProvider $oidcProvider, BearerUserProvider $userProvider) { - $this->provider = $provider; + $this->oidcProvider = $oidcProvider; + $this->userProvider = $userProvider; } public function getName(): string @@ -40,12 +43,23 @@ class HealthCheck implements CheckInterface public function checkConfig() { - $this->provider->getProviderConfig(); + $this->oidcProvider->getProviderConfig(); } public function checkPublicKey() { - $this->provider->getJWKs(); + $this->oidcProvider->getJWKs(); + } + + public function checkTimeSync() + { + $providerTime = $this->oidcProvider->getProviderDateTime(); + $systemTime = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); + $leeway = $this->userProvider->getValidationLeewaySeconds(); + $difference = abs($providerTime->getTimestamp() - $systemTime->getTimestamp()); + if ($difference > $leeway) { + throw new \RuntimeException("The system time and the OIDC server time is out of sync ($difference > $leeway seconds)"); + } } public function check(CheckOptions $options): array @@ -53,6 +67,7 @@ class HealthCheck implements CheckInterface $results = []; $results[] = $this->checkMethod('Check if the OIDC config can be fetched', [$this, 'checkConfig']); $results[] = $this->checkMethod('Check if the OIDC public key can be fetched', [$this, 'checkPublicKey']); + $results[] = $this->checkMethod('Check if the OIDC server time is in sync', [$this, 'checkTimeSync']); return $results; }