Skip to content

Split encoder and normalizer to fix Symfony 6.1 compatibility #347

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

Merged
merged 3 commits into from
May 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Jose\Bundle\JoseFramework\DependencyInjection\Compiler;

use Jose\Bundle\JoseFramework\Serializer\JWEEncoder;
use Jose\Bundle\JoseFramework\Serializer\JWESerializer;
use Jose\Bundle\JoseFramework\Serializer\JWSEncoder;
use Jose\Bundle\JoseFramework\Serializer\JWSSerializer;
use Jose\Component\Encryption\Serializer\JWESerializerManagerFactory;
use Jose\Component\Signature\Serializer\JWSSerializerManagerFactory;
Expand All @@ -15,22 +17,34 @@ class SymfonySerializerCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
if (! class_exists('Symfony\Component\Serializer\Serializer')) {
if (! class_exists('Symfony\\Component\\Serializer\\Serializer')) {
return;
}
if ($container->hasDefinition(JWSSerializerManagerFactory::class)) {
$container->autowire(JWSSerializer::class, JWSSerializer::class)
$container
->autowire(JWSSerializer::class, JWSSerializer::class)
->setPublic(false)
->addTag('serializer.encoder')
->addTag('serializer.normalizer')
;

$container
->autowire(JWSEncoder::class, JWSEncoder::class)
->setPublic(false)
->addTag('serializer.encoder')
;
}
if ($container->hasDefinition(JWESerializerManagerFactory::class)) {
$container->autowire(JWESerializer::class, JWESerializer::class)
$container
->autowire(JWESerializer::class, JWESerializer::class)
->setPublic(false)
->addTag('serializer.encoder')
->addTag('serializer.normalizer')
;

$container
->autowire(JWEEncoder::class, JWEEncoder::class)
->setPublic(false)
->addTag('serializer.encoder')
;
}
}
}
91 changes: 91 additions & 0 deletions src/Bundle/JoseFramework/Serializer/JWEEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

declare(strict_types=1);

namespace Jose\Bundle\JoseFramework\Serializer;

use Exception;
use function in_array;
use function is_int;
use Jose\Component\Encryption\JWE;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Component\Encryption\Serializer\JWESerializerManagerFactory;
use LogicException;
use function mb_strtolower;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\NormalizationAwareInterface;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
use Throwable;

final class JWEEncoder implements EncoderInterface, DecoderInterface, NormalizationAwareInterface
{
private JWESerializerManager $serializerManager;

public function __construct(
JWESerializerManagerFactory $serializerManagerFactory,
?JWESerializerManager $serializerManager = null
) {
if ($serializerManager === null) {
$serializerManager = $serializerManagerFactory->create($serializerManagerFactory->names());
}
$this->serializerManager = $serializerManager;
}

public function supportsEncoding(string $format): bool
{
return class_exists(JWESerializerManager::class) && $this->formatSupported($format);
}

public function supportsDecoding(string $format): bool
{
return class_exists(JWESerializerManager::class) && $this->formatSupported($format);
}

public function encode(mixed $data, string $format, array $context = []): string
{
if ($data instanceof JWE === false) {
throw new LogicException('Expected data to be a JWE.');
}

try {
return $this->serializerManager->serialize(
mb_strtolower($format),
$data,
$this->getRecipientIndex($context)
);
} catch (Throwable $ex) {
throw new NotEncodableValueException(sprintf('Cannot encode JWE to %s format.', $format), 0, $ex);
}
}

public function decode(string $data, string $format, array $context = []): JWE
{
try {
return $this->serializerManager->unserialize($data);
} catch (Exception $ex) {
throw new NotEncodableValueException(sprintf('Cannot decode JWE from %s format.', $format), 0, $ex);
}
}

/**
* Get JWE recipient index from context.
*/
private function getRecipientIndex(array $context): int
{
if (isset($context['recipient_index']) && is_int($context['recipient_index'])) {
return $context['recipient_index'];
}

return 0;
}

/**
* Check if format is supported.
*/
private function formatSupported(?string $format): bool
{
return $format !== null
&& in_array(mb_strtolower($format), $this->serializerManager->names(), true);
}
}
67 changes: 2 additions & 65 deletions src/Bundle/JoseFramework/Serializer/JWESerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,15 @@

namespace Jose\Bundle\JoseFramework\Serializer;

use Exception;
use function in_array;
use function is_int;
use Jose\Component\Encryption\JWE;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Component\Encryption\Serializer\JWESerializerManagerFactory;
use LogicException;
use function mb_strtolower;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\NormalizationAwareInterface;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Throwable;

final class JWESerializer implements DenormalizerInterface, EncoderInterface, DecoderInterface, NormalizationAwareInterface
final class JWESerializer implements DenormalizerInterface
{
private JWESerializerManager $serializerManager;

Expand All @@ -33,49 +26,13 @@ public function __construct(
$this->serializerManager = $serializerManager;
}

public function supportsEncoding(string $format): bool
{
return $this->formatSupported($format);
}

public function supportsDecoding(string $format): bool
{
return $this->formatSupported($format);
}

public function supportsDenormalization(mixed $data, string $type, string $format = null): bool
{
return $type === JWE::class
&& $this->componentInstalled()
&& class_exists(JWESerializerManager::class)
&& $this->formatSupported($format);
}

public function encode(mixed $data, string $format, array $context = []): string
{
if ($data instanceof JWE === false) {
throw new LogicException('Expected data to be a JWE.');
}

try {
return $this->serializerManager->serialize(
mb_strtolower($format),
$data,
$this->getRecipientIndex($context)
);
} catch (Throwable $ex) {
throw new NotEncodableValueException(sprintf('Cannot encode JWE to %s format.', $format), 0, $ex);
}
}

public function decode(string $data, string $format, array $context = []): JWE
{
try {
return $this->serializerManager->unserialize($data);
} catch (Exception $ex) {
throw new NotEncodableValueException(sprintf('Cannot decode JWE from %s format.', $format), 0, $ex);
}
}

public function denormalize(mixed $data, string $type, string $format = null, array $context = []): JWE
{
if ($data instanceof JWE === false) {
Expand All @@ -85,26 +42,6 @@ public function denormalize(mixed $data, string $type, string $format = null, ar
return $data;
}

/**
* Get JWE recipient index from context.
*/
private function getRecipientIndex(array $context): int
{
if (isset($context['recipient_index']) && is_int($context['recipient_index'])) {
return $context['recipient_index'];
}

return 0;
}

/**
* Check if encryption component is installed.
*/
private function componentInstalled(): bool
{
return class_exists(JWESerializerManager::class);
}

/**
* Check if format is supported.
*/
Expand Down
90 changes: 90 additions & 0 deletions src/Bundle/JoseFramework/Serializer/JWSEncoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace Jose\Bundle\JoseFramework\Serializer;

use Exception;
use function in_array;
use function is_int;
use Jose\Component\Signature\JWS;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Jose\Component\Signature\Serializer\JWSSerializerManagerFactory;
use LogicException;
use function mb_strtolower;
use Symfony\Component\Serializer\Encoder\DecoderInterface;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\NormalizationAwareInterface;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;

final class JWSEncoder implements EncoderInterface, DecoderInterface, NormalizationAwareInterface
{
private JWSSerializerManager $serializerManager;

public function __construct(
JWSSerializerManagerFactory $serializerManagerFactory,
?JWSSerializerManager $serializerManager = null
) {
if ($serializerManager === null) {
$serializerManager = $serializerManagerFactory->create($serializerManagerFactory->names());
}
$this->serializerManager = $serializerManager;
}

public function supportsEncoding(string $format): bool
{
return class_exists(JWSSerializerManager::class) && $this->formatSupported($format);
}

public function supportsDecoding(string $format): bool
{
return class_exists(JWSSerializerManager::class) && $this->formatSupported($format);
}

public function encode($data, $format, array $context = []): string
{
if ($data instanceof JWS === false) {
throw new LogicException('Expected data to be a JWS.');
}

try {
return $this->serializerManager->serialize(
mb_strtolower($format),
$data,
$this->getSignatureIndex($context)
);
} catch (Exception $ex) {
throw new NotEncodableValueException(sprintf('Cannot encode JWS to %s format.', $format), 0, $ex);
}
}

public function decode($data, $format, array $context = []): JWS
{
try {
return $this->serializerManager->unserialize($data);
} catch (Exception $ex) {
throw new NotEncodableValueException(sprintf('Cannot decode JWS from %s format.', $format), 0, $ex);
}
}

/**
* Get JWS signature index from context.
*/
private function getSignatureIndex(array $context): int
{
if (isset($context['signature_index']) && is_int($context['signature_index'])) {
return $context['signature_index'];
}

return 0;
}

/**
* Check if format is supported.
*/
private function formatSupported(?string $format): bool
{
return $format !== null
&& in_array(mb_strtolower($format), $this->serializerManager->list(), true);
}
}
Loading