Skip to content
Snippets Groups Projects
Commit 31955522 authored by Peter Wolanin's avatar Peter Wolanin
Browse files

Issue #3427911: Add several minutes of default leeway to reduce issues with time mis-alignment

parent d5fe2966
No related branches found
No related tags found
1 merge request!25Issue #3427911: Add several minutes of default leeway to reduce issues with time mis-alignment
Pipeline #421274 passed
......@@ -74,6 +74,9 @@ class UsersJwtAuth implements AuthenticationProviderInterface {
if (!$jwt_class) {
$jwt_class = JWT::class;
}
if (property_exists($jwt_class, 'leeway')) {
$jwt_class::$leeway = 300;
}
$this->transcoder = new $jwt_class();
}
......
......@@ -92,6 +92,9 @@ class JwtTranscoder implements JwtTranscoderInterface {
if (!$jwt_class) {
$jwt_class = JWT::class;
}
if (property_exists($jwt_class, 'leeway')) {
$jwt_class::$leeway = 300;
}
$this->transcoder = new $jwt_class();
if ($key) {
$this->setKey($key);
......
services:
jwt_test_auth_issuer.subscriber:
class: Drupal\jwt_test\EventSubscriber\JwtTestAuthIssuerSubscriber
tags:
- { name: event_subscriber }
<?php
namespace Drupal\jwt_test\EventSubscriber;
use Drupal\jwt\Authentication\Event\JwtAuthEvents;
use Drupal\jwt\Authentication\Event\JwtAuthGenerateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Modify claims on a JWT being issued for testing.
*/
class JwtTestAuthIssuerSubscriber implements EventSubscriberInterface {
/**
* Modifications to make to the claims.
*
* @var array
*/
public static array $modifications = [];
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events = [];
$events[JwtAuthEvents::GENERATE][] = ['modifyStandardClaims', 20];
return $events;
}
/**
* Modify the standard claims set for a JWT.
*
* @param \Drupal\jwt\Authentication\Event\JwtAuthGenerateEvent $event
* The event.
*/
public function modifyStandardClaims(JwtAuthGenerateEvent $event) {
foreach (static::$modifications as $claim => $value) {
$event->addClaim($claim, $value);
}
}
}
......@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Drupal\Tests\jwt\Functional;
use Drupal\Core\Url;
use Drupal\jwt_test\EventSubscriber\JwtTestAuthIssuerSubscriber;
use Drupal\Tests\BrowserTestBase;
/**
......@@ -64,7 +65,7 @@ class JwtAuthTest extends BrowserTestBase {
$this->drupalGet($url, [], $headers);
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->pageTextContains($account->getAccountName());
self::assertNull($this->getSession()->getResponseHeader('X-Drupal-Cache'));
self::assertEquals('UNCACHEABLE (request policy)', $this->getSession()->getResponseHeader('X-Drupal-Cache'));
self::assertStringNotContainsString('public', $this->getSession()->getResponseHeader('Cache-Control'), 'Cache-Control is not set to public');
$account->block()->save();
$this->drupalGet($url, [], $headers);
......@@ -83,6 +84,32 @@ class JwtAuthTest extends BrowserTestBase {
$this->mink->resetSessions();
}
}
// Test the 300 seconds of default leeway on nbf, iat, and exp values.
$url = Url::fromRoute('jwt_test.11.2');
$time = time();
$test_cases = [
['claims' => ['iat' => $time + 250], 'code' => 200],
['claims' => ['nbf' => $time + 250], 'code' => 200],
['claims' => ['exp' => $time - 250], 'code' => 200],
['claims' => ['iat' => $time + 350], 'code' => 403],
['claims' => ['nbf' => $time + 350], 'code' => 403],
['claims' => ['iat' => $time, 'nbf' => $time + 350], 'code' => 403],
['claims' => ['exp' => $time - 350], 'code' => 403],
];
foreach ($test_cases as $case) {
JwtTestAuthIssuerSubscriber::$modifications = $case['claims'];
$token = $auth->generateToken();
$headers = [
'Authorization' => 'Bearer ' . $token,
];
$this->drupalGet($url, [], $headers);
$this->assertSession()->statusCodeEquals($case['code']);
if ($case['code'] === 200) {
$this->assertSession()->pageTextContains($account->getAccountName());
}
$this->mink->resetSessions();
}
JwtTestAuthIssuerSubscriber::$modifications = [];
// The front page should return a 200 even for an invalid JWT.
foreach (['Authorization', 'JWT-Authorization'] as $header_name) {
$headers = [
......@@ -101,13 +128,14 @@ class JwtAuthTest extends BrowserTestBase {
$this->assertEquals($this->getSession()->getResponseHeader('X-Drupal-Cache'), 'MISS');
$this->drupalGet($url);
$this->assertEquals($this->getSession()->getResponseHeader('X-Drupal-Cache'), 'HIT');
$token = $auth->generateToken();
foreach (['Authorization', 'JWT-Authorization'] as $header_name) {
$headers = [
$header_name => 'Bearer ' . $token,
];
$this->drupalGet($url, [], $headers);
$this->assertSession()->statusCodeEquals(200);
$this->assertNull($this->getSession()->getResponseHeader('X-Drupal-Cache'));
self::assertEquals('UNCACHEABLE (request policy)', $this->getSession()->getResponseHeader('X-Drupal-Cache'));
$this->assertStringNotContainsString('public', $this->getSession()->getResponseHeader('Cache-Control'), 'No page cache response when requesting a cached page with jwt credentials.');
// This is needed to prevent the Authorization header from the last loop
// being sent again by the mink session.
......@@ -134,6 +162,7 @@ class JwtAuthTest extends BrowserTestBase {
$code = (int) $this->getSession()->getStatusCode();
$this->assertTrue(in_array($code, [401, 403], TRUE), 'Access is not granted.');
$this->mink->resetSessions();
$token = $auth->generateToken();
$headers += ['JWT-Authorization' => 'Bearer ' . $token];
$this->drupalGet($url, [], $headers);
$this->assertSession()->statusCodeEquals(200);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment