primo commit

This commit is contained in:
2024-12-17 17:34:10 +01:00
commit e650f8df99
16435 changed files with 2451012 additions and 0 deletions

View File

@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace Jose\Component\NestedToken;
use InvalidArgumentException;
use Jose\Component\Core\JWK;
use Jose\Component\Encryption\JWEBuilder;
use Jose\Component\Encryption\Serializer\JWESerializerManager;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use function array_key_exists;
use function is_array;
class NestedTokenBuilder
{
public function __construct(
private readonly JWEBuilder $jweBuilder,
private readonly JWESerializerManager $jweSerializerManager,
private readonly JWSBuilder $jwsBuilder,
private readonly JWSSerializerManager $jwsSerializerManager
) {
}
/**
* Creates a nested token.
*
* @param array{array{key: JWK, protected_header?: array<string, mixed>, header?: array<string, mixed>}} $signatures
* @param array{alg?: string, string?: mixed} $jweSharedProtectedHeader
* @param array{alg?: string, string?: mixed} $jweSharedHeader
* @param array{array{key: JWK, header?: array<string, mixed>}} $recipients
*/
public function create(
string $payload,
array $signatures,
string $jws_serialization_mode,
array $jweSharedProtectedHeader,
array $jweSharedHeader,
array $recipients,
string $jwe_serialization_mode,
?string $aad = null
): string {
$jws = $this->jwsBuilder->create()
->withPayload($payload);
foreach ($signatures as $signature) {
if (! is_array($signature) || ! array_key_exists('key', $signature)) {
throw new InvalidArgumentException(
'The signatures must be an array of arrays containing a key, a protected header and a header'
);
}
$signature['protected_header'] = array_key_exists(
'protected_header',
$signature
) ? $signature['protected_header'] : [];
$signature['header'] = array_key_exists('header', $signature) ? $signature['header'] : [];
$jws = $jws->addSignature($signature['key'], $signature['protected_header'], $signature['header']);
}
$jws = $jws->build();
$token = $this->jwsSerializerManager->serialize($jws_serialization_mode, $jws);
$jweSharedProtectedHeader['cty'] = 'JWT';
$jwe = $this->jweBuilder
->create()
->withPayload($token)
->withSharedProtectedHeader($jweSharedProtectedHeader)
->withSharedHeader($jweSharedHeader)
->withAAD($aad);
foreach ($recipients as $recipient) {
if (! is_array($recipient) || ! array_key_exists('key', $recipient)) {
throw new InvalidArgumentException(
'The recipients must be an array of arrays containing a key and a header'
);
}
$recipient['header'] = array_key_exists('header', $recipient) ? $recipient['header'] : [];
$jwe = $jwe->addRecipient($recipient['key'], $recipient['header']);
}
$jwe = $jwe->build();
return $this->jweSerializerManager->serialize($jwe_serialization_mode, $jwe);
}
}

View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Jose\Component\NestedToken;
use Jose\Component\Encryption\JWEBuilderFactory;
use Jose\Component\Encryption\Serializer\JWESerializerManagerFactory;
use Jose\Component\Signature\JWSBuilderFactory;
use Jose\Component\Signature\Serializer\JWSSerializerManagerFactory;
class NestedTokenBuilderFactory
{
public function __construct(
private readonly JWEBuilderFactory $jweBuilderFactory,
private readonly JWESerializerManagerFactory $jweSerializerManagerFactory,
private readonly JWSBuilderFactory $jwsBuilderFactory,
private readonly JWSSerializerManagerFactory $jwsSerializerManagerFactory
) {
}
/**
* This method creates a Nested Token Builder with the given encryption/signature algorithms, serializers and
* compression methods.
*
* @param array<string> $jwe_serializers
* @param array<string> $encryptionAlgorithms
* @param null|array<string> $contentEncryptionAlgorithms
* @param null|array<string> $compressionMethods
* @param array<string> $jws_serializers
* @param array<string> $signatureAlgorithms
*/
public function create(
array $jwe_serializers,
array $encryptionAlgorithms,
null|array $contentEncryptionAlgorithms,
null|array $compressionMethods,
array $jws_serializers,
array $signatureAlgorithms
): NestedTokenBuilder {
if ($contentEncryptionAlgorithms !== null) {
$encryptionAlgorithms = array_merge($encryptionAlgorithms, $contentEncryptionAlgorithms);
}
$jweBuilder = $this->jweBuilderFactory->create($encryptionAlgorithms, null, $compressionMethods);
$jweSerializerManager = $this->jweSerializerManagerFactory->create($jwe_serializers);
$jwsBuilder = $this->jwsBuilderFactory->create($signatureAlgorithms);
$jwsSerializerManager = $this->jwsSerializerManagerFactory->create($jws_serializers);
return new NestedTokenBuilder($jweBuilder, $jweSerializerManager, $jwsBuilder, $jwsSerializerManager);
}
}

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Jose\Component\NestedToken;
use InvalidArgumentException;
use Jose\Component\Core\JWKSet;
use Jose\Component\Encryption\JWE;
use Jose\Component\Encryption\JWELoader;
use Jose\Component\Signature\JWS;
use Jose\Component\Signature\JWSLoader;
use function is_string;
class NestedTokenLoader
{
public function __construct(
private readonly JWELoader $jweLoader,
private readonly JWSLoader $jwsLoader
) {
}
/**
* This method will try to load, decrypt and verify the token. In case of failure, an exception is thrown, otherwise
* returns the JWS and populates the $signature variable.
*/
public function load(string $token, JWKSet $encryptionKeySet, JWKSet $signatureKeySet, ?int &$signature = null): JWS
{
$recipient = null;
$jwe = $this->jweLoader->loadAndDecryptWithKeySet($token, $encryptionKeySet, $recipient);
$this->checkContentTypeHeader($jwe, $recipient);
if ($jwe->getPayload() === null) {
throw new InvalidArgumentException('The token has no payload.');
}
return $this->jwsLoader->loadAndVerifyWithKeySet($jwe->getPayload(), $signatureKeySet, $signature);
}
private function checkContentTypeHeader(JWE $jwe, int $recipient): void
{
$cty = match (true) {
$jwe->hasSharedProtectedHeaderParameter('cty') => $jwe->getSharedProtectedHeaderParameter('cty'),
$jwe->hasSharedHeaderParameter('cty') => $jwe->getSharedHeaderParameter('cty'),
$jwe->getRecipient($recipient)
->hasHeaderParameter('cty') => $jwe->getRecipient($recipient)
->getHeaderParameter('cty'),
default => throw new InvalidArgumentException('The token is not a nested token.'),
};
if (! is_string($cty)) {
throw new InvalidArgumentException('Invalid "cty" header parameter.');
}
if (strcasecmp($cty, 'jwt') !== 0) {
throw new InvalidArgumentException('The token is not a nested token.');
}
}
}

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Jose\Component\NestedToken;
use Jose\Component\Encryption\JWELoaderFactory;
use Jose\Component\Signature\JWSLoaderFactory;
class NestedTokenLoaderFactory
{
public function __construct(
private readonly JWELoaderFactory $jweLoaderFactory,
private readonly JWSLoaderFactory $jwsLoaderFactory
) {
}
/**
* This method creates a Nested Token Loader with the given encryption/signature algorithms, serializers,
* compression methods and header checkers.
*
* @param array<string> $jweSerializers
* @param array<string> $keyEncryptionAlgorithms
* @param array<string> $contentEncryptionAlgorithms
* @param null|array<string> $compressionMethods
* @param array<string> $jweHeaderCheckers
* @param array<string> $jwsSerializers
* @param array<string> $signatureAlgorithms
* @param array<string> $jwsHeaderCheckers
*/
public function create(
array $jweSerializers,
array $keyEncryptionAlgorithms,
null|array $contentEncryptionAlgorithms,
null|array $compressionMethods,
array $jweHeaderCheckers,
array $jwsSerializers,
array $signatureAlgorithms,
array $jwsHeaderCheckers
): NestedTokenLoader {
$jweLoader = $this->jweLoaderFactory->create(
$jweSerializers,
$keyEncryptionAlgorithms,
$contentEncryptionAlgorithms,
$compressionMethods,
$jweHeaderCheckers
);
$jwsLoader = $this->jwsLoaderFactory->create($jwsSerializers, $signatureAlgorithms, $jwsHeaderCheckers);
return new NestedTokenLoader($jweLoader, $jwsLoader);
}
}