welcome back to dyb-tech

This commit is contained in:
Daniel Guzman
2024-05-18 02:28:01 +02:00
parent 9513cdba09
commit 9f30bc98c7
6149 changed files with 668407 additions and 0 deletions
@@ -0,0 +1,131 @@
<?php
namespace Lexik\Bundle\JWTAuthenticationBundle\Services\JWSProvider;
@trigger_error(sprintf('The "%s" class is deprecated since version 2.5 and will be removed in 3.0. Use "%s" or create your own "%s" implementation instead.', DefaultJWSProvider::class, LcobucciJWSProvider::class, JWSProviderInterface::class), E_USER_DEPRECATED);
use Lexik\Bundle\JWTAuthenticationBundle\Services\KeyLoader\KeyLoaderInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Signature\CreatedJWS;
use Lexik\Bundle\JWTAuthenticationBundle\Signature\LoadedJWS;
use Namshi\JOSE\JWS;
/**
* JWS Provider, Namshi\JOSE library integration.
* Supports OpenSSL and phpseclib crypto engines.
*
* @final
*
* @author Robin Chalas <robin.chalas@gmail.com>
*
* @deprecated since version 2.5, to be removed in 3.0
*/
class DefaultJWSProvider implements JWSProviderInterface
{
/**
* @var KeyLoaderInterface
*/
private $keyLoader;
/**
* @var string
*/
private $cryptoEngine;
/**
* @var string
*/
private $signatureAlgorithm;
/**
* @var int
*/
private $ttl;
/**
* @var int
*/
private $clockSkew;
/**
* @param string $cryptoEngine
* @param string $signatureAlgorithm
* @param int $ttl
* @param int $clockSkew
*
* @throws \InvalidArgumentException If the given algorithm is not supported
*/
public function __construct(KeyLoaderInterface $keyLoader, $cryptoEngine, $signatureAlgorithm, $ttl, $clockSkew)
{
if (null !== $ttl && !is_numeric($ttl)) {
throw new \InvalidArgumentException(sprintf('The TTL should be a numeric value, got %s instead.', $ttl));
}
if (null !== $clockSkew && !is_numeric($clockSkew)) {
throw new \InvalidArgumentException(sprintf('The clock skew should be a numeric value, got %s instead.', $clockSkew));
}
$cryptoEngine = 'openssl' == $cryptoEngine ? 'OpenSSL' : 'SecLib';
if (!$this->isAlgorithmSupportedForEngine($cryptoEngine, $signatureAlgorithm)) {
throw new \InvalidArgumentException(sprintf('The algorithm "%s" is not supported for %s', $signatureAlgorithm, $cryptoEngine));
}
$this->keyLoader = $keyLoader;
$this->cryptoEngine = $cryptoEngine;
$this->signatureAlgorithm = $signatureAlgorithm;
$this->ttl = $ttl;
$this->clockSkew = $clockSkew;
}
/**
* {@inheritdoc}
*/
public function create(array $payload, array $header = [])
{
$header['alg'] = $this->signatureAlgorithm;
$jws = new JWS($header, $this->cryptoEngine);
$claims = ['iat' => time()];
if (null !== $this->ttl && !isset($payload['exp'])) {
$claims['exp'] = time() + $this->ttl;
}
$jws->setPayload($payload + $claims);
$jws->sign(
$this->keyLoader->loadKey('private'),
$this->keyLoader->getPassphrase()
);
return new CreatedJWS($jws->getTokenString(), $jws->isSigned());
}
/**
* {@inheritdoc}
*/
public function load($token)
{
$jws = JWS::load($token, false, null, $this->cryptoEngine);
return new LoadedJWS(
$jws->getPayload(),
$jws->verify($this->keyLoader->loadKey('public'), $this->signatureAlgorithm),
null !== $this->ttl,
$jws->getHeader(),
$this->clockSkew
);
}
/**
* @param string $cryptoEngine
* @param string $signatureAlgorithm
*
* @return bool
*/
private function isAlgorithmSupportedForEngine($cryptoEngine, $signatureAlgorithm)
{
$signerClass = sprintf('Namshi\\JOSE\\Signer\\%s\\%s', $cryptoEngine, $signatureAlgorithm);
return class_exists($signerClass);
}
}
@@ -0,0 +1,30 @@
<?php
namespace Lexik\Bundle\JWTAuthenticationBundle\Services\JWSProvider;
use Lexik\Bundle\JWTAuthenticationBundle\Signature\CreatedJWS;
use Lexik\Bundle\JWTAuthenticationBundle\Signature\LoadedJWS;
/**
* Interface for classes that are able to create and load JSON web signatures (JWS).
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
interface JWSProviderInterface
{
/**
* Creates a new JWS signature from a given payload.
*
* @return CreatedJWS
*/
public function create(array $payload, array $header = []);
/**
* Loads an existing JWS signature from a given JWT token.
*
* @param string $token
*
* @return LoadedJWS
*/
public function load($token);
}
@@ -0,0 +1,283 @@
<?php
namespace Lexik\Bundle\JWTAuthenticationBundle\Services\JWSProvider;
use Lcobucci\Clock\Clock;
use Lcobucci\Clock\SystemClock;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Encoding\ChainedFormatter;
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Hmac\Sha384;
use Lcobucci\JWT\Signer\Hmac\Sha512;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Token\Builder as JWTBuilder;
use Lcobucci\JWT\Token\Parser as JWTParser;
use Lcobucci\JWT\Token\Plain;
use Lcobucci\JWT\Token\RegisteredClaims;
use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
use Lcobucci\JWT\Validation\Constraint\ValidAt;
use Lcobucci\JWT\Validation\Validator;
use Lcobucci\JWT\ValidationData;
use Lexik\Bundle\JWTAuthenticationBundle\Services\KeyLoader\KeyLoaderInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\KeyLoader\RawKeyLoader;
use Lexik\Bundle\JWTAuthenticationBundle\Signature\CreatedJWS;
use Lexik\Bundle\JWTAuthenticationBundle\Signature\LoadedJWS;
/**
* @final
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class LcobucciJWSProvider implements JWSProviderInterface
{
/**
* @var KeyLoaderInterface
*/
private $keyLoader;
/**
* @var Clock
*/
private $clock;
/**
* @var Signer
*/
private $signer;
/**
* @var int|null
*/
private $ttl;
/**
* @var int|null
*/
private $clockSkew;
/**
* @var bool
*/
private $allowNoExpiration;
/**
* @throws \InvalidArgumentException If the given crypto engine is not supported
*/
public function __construct(KeyLoaderInterface $keyLoader, string $cryptoEngine, string $signatureAlgorithm, ?int $ttl, ?int $clockSkew, bool $allowNoExpiration = false, Clock $clock = null)
{
if ('openssl' !== $cryptoEngine) {
throw new \InvalidArgumentException(sprintf('The %s provider supports only "openssl" as crypto engine.', self::class));
}
if (null === $clock) {
$clock = new SystemClock(new \DateTimeZone('UTC'));
}
$this->keyLoader = $keyLoader;
$this->clock = $clock;
$this->signer = $this->getSignerForAlgorithm($signatureAlgorithm);
$this->ttl = $ttl;
$this->clockSkew = $clockSkew;
$this->allowNoExpiration = $allowNoExpiration;
}
/**
* {@inheritdoc}
*/
public function create(array $payload, array $header = [])
{
if (class_exists(JWTBuilder::class)) {
$jws = new JWTBuilder(new JoseEncoder(), ChainedFormatter::default());
} else {
$jws = new Builder();
}
foreach ($header as $k => $v) {
$jws = $jws->withHeader($k, $v);
}
$now = time();
$issuedAt = $payload['iat'] ?? $now;
unset($payload['iat']);
$jws = $jws->issuedAt(!$issuedAt instanceof \DateTimeImmutable ? new \DateTimeImmutable("@{$issuedAt}") : $issuedAt);
if (null !== $this->ttl || isset($payload['exp'])) {
$exp = $payload['exp'] ?? $now + $this->ttl;
unset($payload['exp']);
if ($exp) {
$jws = $jws->expiresAt(!$exp instanceof \DateTimeImmutable ? new \DateTimeImmutable("@{$exp}") : $exp);
}
}
if (isset($payload['sub'])) {
$jws = $jws->relatedTo($payload['sub']);
unset($payload['sub']);
}
if (interface_exists(RegisteredClaims::class)) {
$jws = $this->addStandardClaims($jws, $payload);
}
foreach ($payload as $name => $value) {
$jws = $jws->withClaim($name, $value);
}
$e = $token = null;
try {
$token = $this->getSignedToken($jws);
} catch (\InvalidArgumentException $e) {
}
return new CreatedJWS((string) $token, null === $e);
}
/**
* {@inheritdoc}
*/
public function load($token)
{
if (class_exists(JWTParser::class)) {
$jws = (new JWTParser(new JoseEncoder()))->parse((string) $token);
} else {
$jws = (new Parser())->parse((string) $token);
}
$payload = [];
foreach ($jws->claims()->all() as $name => $value) {
if ($value instanceof \DateTimeInterface) {
$value = $value->getTimestamp();
}
$payload[$name] = $value;
}
$jws = new LoadedJWS(
$payload,
$this->verify($jws),
false == $this->allowNoExpiration,
$jws->headers()->all(),
$this->clockSkew
);
return $jws;
}
private function getSignerForAlgorithm($signatureAlgorithm)
{
$signerMap = [
'HS256' => Sha256::class,
'HS384' => Sha384::class,
'HS512' => Sha512::class,
'RS256' => Signer\Rsa\Sha256::class,
'RS384' => Signer\Rsa\Sha384::class,
'RS512' => Signer\Rsa\Sha512::class,
'ES256' => Signer\Ecdsa\Sha256::class,
'ES384' => Signer\Ecdsa\Sha384::class,
'ES512' => Signer\Ecdsa\Sha512::class,
];
if (!isset($signerMap[$signatureAlgorithm])) {
throw new \InvalidArgumentException(sprintf('The algorithm "%s" is not supported by %s', $signatureAlgorithm, self::class));
}
$signerClass = $signerMap[$signatureAlgorithm];
if (is_subclass_of($signerClass, Ecdsa::class) && method_exists($signerClass, 'create')) {
return $signerClass::create();
}
return new $signerClass();
}
private function getSignedToken(Builder $jws)
{
if (class_exists(InMemory::class)) {
$key = InMemory::plainText($this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE), $this->signer instanceof Hmac ? '' : (string) $this->keyLoader->getPassphrase());
} else {
$key = new Key($this->keyLoader->loadKey(RawKeyLoader::TYPE_PRIVATE), $this->signer instanceof Hmac ? '' : (string) $this->keyLoader->getPassphrase());
}
$token = $jws->getToken($this->signer, $key);
if (!$token instanceof Plain) {
return (string) $token;
}
return $token->toString();
}
private function verify(Token $jwt)
{
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));
}
$validator = new Validator();
$classValidator = class_exists(LooseValidAt::class) ? LooseValidAt::class : ValidAt::class;
$isValid = $validator->validate(
$jwt,
new $classValidator($this->clock, new \DateInterval("PT{$this->clockSkew}S")),
new SignedWith($this->signer, $key)
);
$publicKeys = $this->keyLoader->getAdditionalPublicKeys();
if ($isValid || $this->signer instanceof Hmac || empty($publicKeys)) {
return $isValid;
}
// If the key used to verify the token is invalid, and it's not Hmac algorithm, try with additional public keys
foreach ($publicKeys as $key) {
$isValid = $validator->validate(
$jwt,
new $classValidator($this->clock, new \DateInterval("PT{$this->clockSkew}S")),
new SignedWith($this->signer, InMemory::plainText($key))
);
if ($isValid) {
return true;
}
}
return false;
}
private function addStandardClaims(Builder $builder, array &$payload): Builder
{
$mutatorMap = [
RegisteredClaims::AUDIENCE => 'permittedFor',
RegisteredClaims::ID => 'identifiedBy',
RegisteredClaims::ISSUER => 'issuedBy',
RegisteredClaims::NOT_BEFORE => 'canOnlyBeUsedAfter',
];
foreach ($payload as $claim => $value) {
if (!isset($mutatorMap[$claim])) {
continue;
}
$mutator = $mutatorMap[$claim];
unset($payload[$claim]);
if (\is_array($value)) {
$builder = \call_user_func_array([$builder, $mutator], $value);
continue;
}
$builder = $builder->{$mutator}($value);
}
return $builder;
}
}