| Current Path : /var/www/clients/client3/web2/web/vendor/magento/module-jwt-framework-adapter/Model/ |
| Current File : /var/www/clients/client3/web2/web/vendor/magento/module-jwt-framework-adapter/Model/JweManager.php |
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\JwtFrameworkAdapter\Model;
use Jose\Component\Encryption\JWEBuilder;
use Jose\Component\Encryption\JWELoader;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Magento\Framework\Jwt\EncryptionSettingsInterface;
use Magento\Framework\Jwt\Exception\EncryptionException;
use Magento\Framework\Jwt\Exception\JwtException;
use Magento\Framework\Jwt\Exception\MalformedTokenException;
use Magento\Framework\Jwt\HeaderInterface;
use Magento\Framework\Jwt\Jwe\JweEncryptionJwks;
use Magento\Framework\Jwt\Jwe\JweHeader;
use Magento\Framework\Jwt\Jwe\JweInterface;
use Jose\Component\Core\JWK as AdapterJwk;
use Jose\Component\Core\JWKSet as AdapterJwkSet;
use Magento\Framework\Jwt\Jwk;
use Magento\Framework\Jwt\Jws\JwsHeader;
use Magento\Framework\Jwt\Payload\ClaimsPayloadInterface;
use Magento\JwtFrameworkAdapter\Model\Data\Header;
/**
* Works with JWE
*/
class JweManager
{
/**
* @var JWEBuilder
*/
private $builder;
/**
* @var JWESerializerManager
*/
private $serializer;
/**
* @var JWELoader
*/
private $loader;
/**
* @var JweFactory
*/
private $jweFactory;
public function __construct(
JweBuilderFactory $jweBuilderFactory,
JweSerializerPoolFactory $serializerPoolFactory,
JweLoaderFactory $jweLoaderFactory,
JweFactory $jweFactory
) {
$this->builder = $jweBuilderFactory->create();
$this->serializer = $serializerPoolFactory->create();
$this->loader = $jweLoaderFactory->create();
$this->jweFactory = $jweFactory;
}
/**
* Generate JWE token.
*
* @param JweInterface $jwe
* @param EncryptionSettingsInterface|JweEncryptionJwks $encryptionSettings
* @return string
*/
public function build(JweInterface $jwe, EncryptionSettingsInterface $encryptionSettings): string
{
$this->validateJweSettings($jwe, $encryptionSettings);
$builder = $this->builder->create();
$payload = $jwe->getPayload();
$builder = $builder->withPayload($payload->getContent());
$sharedProtected = $this->extractHeaderData($jwe->getProtectedHeader());
$sharedProtected['enc'] = $encryptionSettings->getContentEncryptionAlgorithm();
if ($payload->getContentType()) {
$sharedProtected['cty'] = $payload->getContentType();
}
if (!$jwe->getPerRecipientUnprotectedHeaders()) {
$sharedProtected['alg'] = $encryptionSettings->getAlgorithmName();
}
if ($payload instanceof ClaimsPayloadInterface) {
foreach ($payload->getClaims() as $claim) {
if ($claim->isHeaderDuplicated()) {
$sharedProtected[$claim->getName()] = $claim->getValue();
}
}
}
$builder = $builder->withSharedProtectedHeader($sharedProtected);
$sharedUnprotected = [];
if ($jwe->getSharedUnprotectedHeader()) {
$sharedUnprotected = array_merge(
$this->extractHeaderData($jwe->getSharedUnprotectedHeader()),
$sharedUnprotected
);
}
if ($sharedUnprotected) {
$builder = $builder->withSharedHeader($sharedUnprotected);
}
if (!$jwe->getPerRecipientUnprotectedHeaders()) {
$builder = $builder->addRecipient(
new AdapterJwk($encryptionSettings->getJwkSet()->getKeys()[0]->getJsonData())
);
} else {
foreach ($jwe->getPerRecipientUnprotectedHeaders() as $i => $header) {
$jwk = $encryptionSettings->getJwkSet()->getKeys()[$i];
$headerData = $this->extractHeaderData($header);
$headerData['alg'] = $jwk->getAlgorithm();
$builder = $builder->addRecipient(new AdapterJwk($jwk->getJsonData()), $headerData);
}
}
$built = $builder->build();
if ($jwe->getPerRecipientUnprotectedHeaders()
&& count($jwe->getPerRecipientUnprotectedHeaders()) === 1
|| (!$jwe->getPerRecipientUnprotectedHeaders() && $jwe->getSharedUnprotectedHeader())
) {
return $this->serializer->serialize('jwe_json_flattened', $built);
}
if ($jwe->getPerRecipientUnprotectedHeaders()) {
return $this->serializer->serialize('jwe_json_general', $built);
}
return $this->serializer->serialize('jwe_compact', $built);
}
/**
* Read JWE token.
*
* @param string $token
* @param EncryptionSettingsInterface|JweEncryptionJwks $encryptionSettings
* @return JweInterface
*/
public function read(string $token, EncryptionSettingsInterface $encryptionSettings): JweInterface
{
if (!$encryptionSettings instanceof JweEncryptionJwks) {
throw new JwtException('Can only work with JWK encryption settings for JWE tokens');
}
$jwkSet = new AdapterJwkSet(
array_map(
function (Jwk $jwk) {
return new AdapterJwk($jwk->getJsonData());
},
$encryptionSettings->getJwkSet()->getKeys()
)
);
try {
/** @var int|null $recipientId */
$jwe = $this->loader->loadAndDecryptWithKeySet($token, $jwkSet, $recipientId);
} catch (\Throwable $exception) {
throw new EncryptionException('Failed to decrypt JWE token.', 0, $exception);
}
if ($recipientId) {
throw new EncryptionException('Failed to decrypt JWE token.');
}
$recipientHeader = $jwe->getRecipient($recipientId)->getHeader();
return $this->jweFactory->create(
$jwe->getSharedProtectedHeader(),
$jwe->getPayload() ?? '',
$jwe->getSharedHeader() ? $jwe->getSharedHeader() : null,
$recipientHeader ? $recipientHeader : null
);
}
/**
* Read JWS headers.
*
* @param string $token
* @return HeaderInterface[]
*/
public function readHeaders(string $token): array
{
try {
$jwe = $this->serializer->unserialize($token);
} catch (\Throwable $exception) {
throw new JwtException('Failed to read JWE headers');
}
$headers = [];
$headersValues = [];
if ($jwe->getSharedHeader()) {
$headersValues[] = $jwe->getSharedHeader();
}
if ($jwe->getSharedProtectedHeader()) {
$headersValues[] = $jwe->getSharedProtectedHeader();
}
foreach ($jwe->getRecipients() as $recipient) {
if ($recipient->getHeader()) {
$headersValues[] = $recipient->getHeader();
}
}
foreach ($headersValues as $headerValues) {
$params = [];
foreach ($headerValues as $header => $value) {
$params[] = new Header($header, $value, null);
}
if ($params) {
$headers[] = new JweHeader($params);
}
}
return $headers;
}
private function validateJweSettings(JweInterface $jwe, EncryptionSettingsInterface $encryptionSettings): void
{
if (!$encryptionSettings instanceof JweEncryptionJwks) {
throw new JwtException('Can only work with JWK encryption settings for JWE tokens');
}
if ($jwe->getPerRecipientUnprotectedHeaders()
&& count($encryptionSettings->getJwkSet()->getKeys()) !== count($jwe->getPerRecipientUnprotectedHeaders())
) {
throw new EncryptionException('Not enough JWKs to encrypt all headers');
}
if (count($encryptionSettings->getJwkSet()->getKeys()) > 1 && !$jwe->getPerRecipientUnprotectedHeaders()) {
throw new MalformedTokenException('Need more per-recipient headers for the amount of keys');
}
}
/**
* Extract JOSE header data.
*
* @param HeaderInterface $header
* @return array
*/
private function extractHeaderData(HeaderInterface $header): array
{
$data = [];
foreach ($header->getParameters() as $parameter) {
$data[$parameter->getName()] = $parameter->getValue();
}
return $data;
}
}