Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix support for lcobucci/jwt v3.4 and 4.0 #797

Merged
merged 2 commits into from
Nov 28, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 46 additions & 16 deletions Services/JWSProvider/LcobucciJWSProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@

use Lcobucci\Clock\SystemClock;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Encoding\MicrosecondBasedDateConversion;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Token\Parser as JWTParser;
use Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint\PermittedFor;
use Lcobucci\JWT\Token\Builder as JWTBuilder;
use Lcobucci\JWT\Token\Plain;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
use Lcobucci\JWT\Validation\Constraint\ValidAt;
use Lcobucci\JWT\Validation\Validator;
Expand Down Expand Up @@ -78,15 +83,19 @@ public function __construct(KeyLoaderInterface $keyLoader, $cryptoEngine, $signa
$this->signer = $this->getSignerForAlgorithm($signatureAlgorithm);
$this->ttl = $ttl;
$this->clockSkew = $clockSkew;
$this->legacyJWTApi = !method_exists(Builder::class, 'with');
$this->legacyJWTApi = !method_exists(Builder::class, 'withHeader');
}

/**
* {@inheritdoc}
*/
public function create(array $payload, array $header = [])
{
$jws = new Builder();
if (class_exists(JWTBuilder::class)) {
$jws = new JWTBuilder(new JoseEncoder(), new MicrosecondBasedDateConversion());
} else {
$jws = new Builder();
}

foreach ($header as $k => $v) {
$jws->{$this->legacyJWTApi ? 'setHeader' : 'withHeader'}($k, $v);
Expand Down Expand Up @@ -117,10 +126,14 @@ public function create(array $payload, array $header = [])
}

foreach ($payload as $name => $value) {
$jws->{$this->legacyJWTApi ? 'set' : 'with'}($name, $value);
if ($this->legacyJWTApi) {
$jws->set($name, $value);
} else {
$jws->{method_exists($jws,'with') ? 'with' : 'withClaim'}($name, $value);
}
}

$e = null;
$e = $token = null;

try {
$token = $this->getSignedToken($jws);
Expand All @@ -135,7 +148,12 @@ public function create(array $payload, array $header = [])
*/
public function load($token)
{
$jws = (new Parser())->parse((string) $token);
if (class_exists(JWTParser::class)) {
$jws = (new JWTParser(new JoseEncoder()))->parse((string) $token);
} else {
$jws = (new Parser())->parse((string) $token);
}

$payload = [];

if ($this->legacyJWTApi) {
Expand Down Expand Up @@ -189,19 +207,25 @@ private function getSignerForAlgorithm($signatureAlgorithm)

private function getSignedToken(Builder $jws)
{
if (class_exists(InMemory::class)) {
$key = InMemory::plainText($this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE), $this->signer instanceof Hmac ? '' : $this->keyLoader->getPassphrase());
} else {
new Key($this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE), $this->signer instanceof Hmac ? '' : $this->keyLoader->getPassphrase());
}

if ($this->legacyJWTApi) {
$jws->sign(
$this->signer,
new Key($this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE), $this->signer instanceof Hmac ? '' : $this->keyLoader->getPassphrase())
);
$jws->sign($key, $this->signer);

return $jws->getToken();
}

return $jws->getToken(
$this->signer,
new Key($this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE), $this->signer instanceof Hmac ? '' : $this->keyLoader->getPassphrase())
);
$token = $jws->getToken($this->signer, $key);

if (!$token instanceof Plain) {
return (string) $token;
}

return $token->toString();
}

private function verify(Token $jwt)
Expand All @@ -217,13 +241,19 @@ private function verify(Token $jwt)
);
}

$clock = SystemClock::fromSystemTimezone();
if (class_exists(InMemory::class)) {
$key = InMemory::plainText($this->signer instanceof Hmac ? $this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE) : $this->keyLoader->loadKey(RawKeyLoader::TYPE_PUBLIC));
} else {
$key = new Key($this->signer instanceof Hmac ? $this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE) : $this->keyLoader->loadKey(RawKeyLoader::TYPE_PUBLIC));
}

$clock = SystemClock::fromUTC();
$validator = new Validator();

return $validator->validate(
$jwt,
new ValidAt($clock, new \DateInterval("PT{$this->clockSkew}S")),
new SignedWith($this->signer, new Key($this->signer instanceof Hmac ? $this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE) : $this->keyLoader->loadKey(RawKeyLoader::TYPE_PUBLIC)))
new SignedWith($this->signer, $key)
);
}
}
3 changes: 1 addition & 2 deletions Signature/LoadedJWS.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,10 @@ private function checkExpiration()
return;
}

if (!isset($this->payload['exp'])) {
if (!isset($this->payload['exp']) || !is_numeric($this->payload['exp'])) {
return $this->state = self::INVALID;
}


if ($this->clockSkew <= time() - $this->payload['exp']) {
$this->state = self::EXPIRED;
}
Expand Down
12 changes: 10 additions & 2 deletions Tests/Functional/GetTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Lexik\Bundle\JWTAuthenticationBundle\Tests\Functional;

use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Token\Parser as JWTParser;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTAuthenticatedEvent;
Expand Down Expand Up @@ -68,8 +70,14 @@ public function testGetTokenWithCustomClaim()
$this->assertArrayHasKey('custom', $payload, 'The payload should contains a "custom" claim.');
$this->assertSame('dummy', $payload['custom'], 'The "custom" claim should be equal to "dummy".');

$jws = (new Parser())->parse($token);
$this->assertArrayHasKey('foo', $jws->getHeaders(), 'The payload should contains a custom "foo" header.');
if (class_exists(JWTParser::class)) {
$parser = new JWTParser(new JoseEncoder());
} else {
$parser = new Parser();
}
$jws = $parser->parse($token);

$this->assertArrayHasKey('foo', method_exists($jws, 'headers') ? $jws->headers()->all() : $jws->getHeaders(), 'The payload should contains a custom "foo" header.');
}

public function testGetTokenFromInvalidCredentials()
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"require": {
"php": ">=5.6",
"ext-openssl": "*",
"lcobucci/jwt": "^3.2",
"lcobucci/jwt": "^3.2|^4.0",
chalasr marked this conversation as resolved.
Show resolved Hide resolved
"namshi/jose": "^7.2",
"symfony/framework-bundle": "^3.4|^4.0|^5.0",
"symfony/security-bundle": "^3.4|^4.0|^5.0"
Expand Down