142 lines
4.3 KiB
PHP
142 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace Lexik\Bundle\JWTAuthenticationBundle\Services\WebToken;
|
|
|
|
use Jose\Bundle\JoseFramework\Services\JWEBuilder;
|
|
use Jose\Bundle\JoseFramework\Services\JWEBuilderFactory;
|
|
use Jose\Bundle\JoseFramework\Services\JWSBuilder;
|
|
use Jose\Bundle\JoseFramework\Services\JWSBuilderFactory;
|
|
use Jose\Component\Core\JWK;
|
|
use Jose\Component\Encryption\Serializer\CompactSerializer as JweCompactSerializer;
|
|
use Jose\Component\Signature\Serializer\CompactSerializer as JwsCompactSerializer;
|
|
use Lexik\Bundle\JWTAuthenticationBundle\Event\BeforeJWEComputationEvent;
|
|
use Lexik\Bundle\JWTAuthenticationBundle\Events;
|
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
|
|
|
final class AccessTokenBuilder
|
|
{
|
|
/**
|
|
* @var JWSBuilder
|
|
*/
|
|
private $jwsBuilder;
|
|
|
|
/**
|
|
* @var null|JWEBuilder
|
|
*/
|
|
private $jweBuilder = null;
|
|
|
|
/**
|
|
* @var JWK
|
|
*/
|
|
private $signatureKey;
|
|
|
|
/**
|
|
* @var JWK|null
|
|
*/
|
|
private $encryptionKey;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $signatureAlgorithm;
|
|
|
|
/**
|
|
* @var string|null
|
|
*/
|
|
private $keyEncryptionAlgorithm;
|
|
|
|
/**
|
|
* @var string|null
|
|
*/
|
|
private $contentEncryptionAlgorithm;
|
|
|
|
/**
|
|
* @var EventDispatcherInterface
|
|
*/
|
|
private $dispatcher;
|
|
|
|
public function __construct(
|
|
EventDispatcherInterface $dispatcher,
|
|
JWSBuilderFactory $jwsBuilderFactory,
|
|
?JWEBuilderFactory $jweBuilderFactory,
|
|
string $signatureAlgorithm,
|
|
string $signatureKey,
|
|
?string $keyEncryptionAlgorithm,
|
|
?string $contentEncryptionAlgorithm,
|
|
?string $encryptionKey
|
|
) {
|
|
$this->jwsBuilder = $jwsBuilderFactory->create([$signatureAlgorithm]);
|
|
if ($jweBuilderFactory !== null && $keyEncryptionAlgorithm !== null && $contentEncryptionAlgorithm !== null) {
|
|
$this->jweBuilder = $jweBuilderFactory->create([$keyEncryptionAlgorithm, $contentEncryptionAlgorithm]);
|
|
}
|
|
$this->signatureKey = JWK::createFromJson($signatureKey);
|
|
$this->encryptionKey = $encryptionKey ? JWK::createFromJson($encryptionKey) : null;
|
|
$this->signatureAlgorithm = $signatureAlgorithm;
|
|
$this->keyEncryptionAlgorithm = $keyEncryptionAlgorithm;
|
|
$this->contentEncryptionAlgorithm = $contentEncryptionAlgorithm;
|
|
$this->dispatcher = $dispatcher;
|
|
}
|
|
|
|
public function build(array $header, array $claims): string
|
|
{
|
|
$token = $this->buildJWS($header, $claims);
|
|
|
|
if ($this->jweBuilder !== null) {
|
|
$token = $this->buildJWE($claims, $token);
|
|
}
|
|
|
|
return $token;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $header
|
|
* @param array<string, mixed> $claims
|
|
*/
|
|
private function buildJWS(array $header, array $claims): string
|
|
{
|
|
$header['alg'] = $this->signatureAlgorithm;
|
|
if ($this->signatureKey->has('kid')) {
|
|
$header['kid'] = $this->signatureKey->get('kid');
|
|
}
|
|
$jws = $this->jwsBuilder
|
|
->create()
|
|
->withPayload(json_encode($claims, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE))
|
|
->addSignature($this->signatureKey, $header)
|
|
->build()
|
|
;
|
|
$token = (new JwsCompactSerializer())->serialize($jws);
|
|
|
|
return $token;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $header
|
|
*/
|
|
private function buildJWE(array $claims, string $payload): string
|
|
{
|
|
$header = [
|
|
'alg' => $this->keyEncryptionAlgorithm,
|
|
'enc' => $this->contentEncryptionAlgorithm,
|
|
'cty' => 'JWT',
|
|
'typ' => 'JWT',
|
|
];
|
|
if ($this->encryptionKey->has('kid')) {
|
|
$header['kid'] = $this->encryptionKey->get('kid');
|
|
}
|
|
foreach (['exp', 'iat', 'nbf'] as $claim) {
|
|
if (array_key_exists($claim, $claims)) {
|
|
$header[$claim] = $claims[$claim];
|
|
}
|
|
}
|
|
$event = $this->dispatcher->dispatch(new BeforeJWEComputationEvent($header), Events::BEFORE_JWE_COMPUTATION);
|
|
$jwe = $this->jweBuilder
|
|
->create()
|
|
->withPayload($payload)
|
|
->withSharedProtectedHeader($event->getHeader())
|
|
->addRecipient($this->encryptionKey)
|
|
->build()
|
|
;
|
|
return (new JweCompactSerializer())->serialize($jwe);
|
|
}
|
|
}
|