package and depencies

This commit is contained in:
RafficMohammed
2023-01-08 02:57:24 +05:30
parent d5332eb421
commit 1d54b8bc7f
4309 changed files with 193331 additions and 172289 deletions

View File

@@ -1,472 +1,77 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT;
use Lcobucci\JWT\Claim\Factory as ClaimFactory;
use Lcobucci\JWT\Parsing\Encoder;
use DateTimeImmutable;
use Lcobucci\JWT\Encoding\CannotEncodeContent;
use Lcobucci\JWT\Signer\CannotSignPayload;
use Lcobucci\JWT\Signer\Ecdsa\ConversionFailed;
use Lcobucci\JWT\Signer\InvalidKeyProvided;
use Lcobucci\JWT\Signer\Key;
use function implode;
use Lcobucci\JWT\Token\Plain;
use Lcobucci\JWT\Token\RegisteredClaimGiven;
/**
* This class makes easier the token creation process
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Builder
interface Builder
{
/**
* The token header
*
* @var array
* Appends new items to audience
*/
private $headers = ['typ'=> 'JWT', 'alg' => 'none'];
/**
* The token claim set
*
* @var array
*/
private $claims = [];
/**
* The data encoder
*
* @var Encoder
*/
private $encoder;
/**
* The factory of claims
*
* @var ClaimFactory
*/
private $claimFactory;
/**
* @var Signer|null
*/
private $signer;
/**
* @var Key|null
*/
private $key;
/**
* Initializes a new builder
*
* @param Encoder $encoder
* @param ClaimFactory $claimFactory
*/
public function __construct(
Encoder $encoder = null,
ClaimFactory $claimFactory = null
) {
$this->encoder = $encoder ?: new Encoder();
$this->claimFactory = $claimFactory ?: new ClaimFactory();
}
/**
* Configures the audience
*
* @deprecated This method has been wrongly added and doesn't exist on v4
* @see Builder::permittedFor()
*
* @param string $audience
* @param bool $replicateAsHeader
*
* @return Builder
*/
public function canOnlyBeUsedBy($audience, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('aud', (string) $audience, $replicateAsHeader);
}
/**
* Configures the audience
*
* @param string $audience
* @param bool $replicateAsHeader
*
* @return Builder
*/
public function permittedFor($audience, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('aud', (string) $audience, $replicateAsHeader);
}
/**
* Configures the audience
*
* @deprecated This method will be removed on v4
* @see Builder::permittedFor()
*
* @param string $audience
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setAudience($audience, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('aud', (string) $audience, $replicateAsHeader);
}
public function permittedFor(string ...$audiences): Builder;
/**
* Configures the expiration time
*
* @param int $expiration
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function expiresAt($expiration, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('exp', (int) $expiration, $replicateAsHeader);
}
/**
* Configures the expiration time
*
* @deprecated This method will be removed on v4
* @see Builder::expiresAt()
*
* @param int $expiration
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setExpiration($expiration, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('exp', (int) $expiration, $replicateAsHeader);
}
public function expiresAt(DateTimeImmutable $expiration): Builder;
/**
* Configures the token id
*
* @param string $id
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function identifiedBy($id, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('jti', (string) $id, $replicateAsHeader);
}
/**
* Configures the token id
*
* @deprecated This method will be removed on v4
* @see Builder::identifiedBy()
*
* @param string $id
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setId($id, $replicateAsHeader = false)
{
return $this->identifiedBy($id, $replicateAsHeader);
}
public function identifiedBy(string $id): Builder;
/**
* Configures the time that the token was issued
*
* @param int $issuedAt
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function issuedAt($issuedAt, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('iat', (int) $issuedAt, $replicateAsHeader);
}
/**
* Configures the time that the token was issued
*
* @deprecated This method will be removed on v4
* @see Builder::issuedAt()
*
* @param int $issuedAt
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setIssuedAt($issuedAt, $replicateAsHeader = false)
{
return $this->issuedAt($issuedAt, $replicateAsHeader);
}
public function issuedAt(DateTimeImmutable $issuedAt): Builder;
/**
* Configures the issuer
*
* @param string $issuer
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function issuedBy($issuer, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('iss', (string) $issuer, $replicateAsHeader);
}
/**
* Configures the issuer
*
* @deprecated This method will be removed on v4
* @see Builder::issuedBy()
*
* @param string $issuer
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setIssuer($issuer, $replicateAsHeader = false)
{
return $this->issuedBy($issuer, $replicateAsHeader);
}
public function issuedBy(string $issuer): Builder;
/**
* Configures the time before which the token cannot be accepted
*
* @param int $notBefore
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function canOnlyBeUsedAfter($notBefore, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('nbf', (int) $notBefore, $replicateAsHeader);
}
/**
* Configures the time before which the token cannot be accepted
*
* @deprecated This method will be removed on v4
* @see Builder::canOnlyBeUsedAfter()
*
* @param int $notBefore
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setNotBefore($notBefore, $replicateAsHeader = false)
{
return $this->canOnlyBeUsedAfter($notBefore, $replicateAsHeader);
}
public function canOnlyBeUsedAfter(DateTimeImmutable $notBefore): Builder;
/**
* Configures the subject
*
* @param string $subject
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function relatedTo($subject, $replicateAsHeader = false)
{
return $this->setRegisteredClaim('sub', (string) $subject, $replicateAsHeader);
}
/**
* Configures the subject
*
* @deprecated This method will be removed on v4
* @see Builder::relatedTo()
*
* @param string $subject
* @param boolean $replicateAsHeader
*
* @return Builder
*/
public function setSubject($subject, $replicateAsHeader = false)
{
return $this->relatedTo($subject, $replicateAsHeader);
}
/**
* Configures a registered claim
*
* @param string $name
* @param mixed $value
* @param boolean $replicate
*
* @return Builder
*/
protected function setRegisteredClaim($name, $value, $replicate)
{
$this->withClaim($name, $value);
if ($replicate) {
$this->headers[$name] = $this->claims[$name];
}
return $this;
}
public function relatedTo(string $subject): Builder;
/**
* Configures a header item
*
* @param string $name
* @param mixed $value
*
* @return Builder
*/
public function withHeader($name, $value)
{
$this->headers[(string) $name] = $this->claimFactory->create($name, $value);
return $this;
}
/**
* Configures a header item
*
* @deprecated This method will be removed on v4
* @see Builder::withHeader()
*
* @param string $name
* @param mixed $value
*
* @return Builder
*/
public function setHeader($name, $value)
{
return $this->withHeader($name, $value);
}
public function withHeader(string $name, $value): Builder;
/**
* Configures a claim item
*
* @deprecated This method has been wrongly added and doesn't exist on v4
* @see Builder::withClaim()
*
* @param string $name
* @param mixed $value
*
* @return Builder
* @throws RegisteredClaimGiven When trying to set a registered claim.
*/
public function with($name, $value)
{
return $this->withClaim($name, $value);
}
public function withClaim(string $name, $value): Builder;
/**
* Configures a claim item
* Returns a signed token to be used
*
* @param string $name
* @param mixed $value
*
* @return Builder
* @throws CannotEncodeContent When data cannot be converted to JSON.
* @throws CannotSignPayload When payload signing fails.
* @throws InvalidKeyProvided When issue key is invalid/incompatible.
* @throws ConversionFailed When signature could not be converted.
*/
public function withClaim($name, $value)
{
$this->claims[(string) $name] = $this->claimFactory->create($name, $value);
return $this;
}
/**
* Configures a claim item
*
* @deprecated This method will be removed on v4
* @see Builder::withClaim()
*
* @param string $name
* @param mixed $value
*
* @return Builder
*/
public function set($name, $value)
{
return $this->withClaim($name, $value);
}
/**
* Signs the data
*
* @deprecated This method will be removed on v4
* @see Builder::getToken()
*
* @param Signer $signer
* @param Key|string $key
*
* @return Builder
*/
public function sign(Signer $signer, $key)
{
if (! $key instanceof Key) {
$key = new Key($key);
}
$this->signer = $signer;
$this->key = $key;
return $this;
}
/**
* Removes the signature from the builder
*
* @deprecated This method will be removed on v4
* @see Builder::getToken()
*
* @return Builder
*/
public function unsign()
{
$this->signer = null;
$this->key = null;
return $this;
}
/**
* Returns the resultant token
*
* @return Token
*/
public function getToken(Signer $signer = null, Key $key = null)
{
$signer = $signer ?: $this->signer;
$key = $key ?: $this->key;
if ($signer instanceof Signer) {
$signer->modifyHeader($this->headers);
}
$payload = [
$this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->headers)),
$this->encoder->base64UrlEncode($this->encoder->jsonEncode($this->claims))
];
$signature = $this->createSignature($payload, $signer, $key);
if ($signature !== null) {
$payload[] = $this->encoder->base64UrlEncode($signature);
}
return new Token($this->headers, $this->claims, $signature, $payload);
}
/**
* @param string[] $payload
*
* @return Signature|null
*/
private function createSignature(array $payload, Signer $signer = null, Key $key = null)
{
if ($signer === null || $key === null) {
return null;
}
return $signer->sign(implode('.', $payload), $key);
}
public function getToken(Signer $signer, Key $key): Plain;
}

View File

@@ -1,40 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use JsonSerializable;
/**
* Basic interface for token claims
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
interface Claim extends JsonSerializable
{
/**
* Returns the claim name
*
* @return string
*/
public function getName();
/**
* Returns the claim value
*
* @return mixed
*/
public function getValue();
/**
* Returns the string representation of the claim
*
* @return string
*/
public function __toString();
}

View File

@@ -1,75 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
/**
* The default claim
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class Basic implements Claim
{
/**
* @var string
*/
private $name;
/**
* @var mixed
*/
private $value;
/**
* Initializes the claim
*
* @param string $name
* @param mixed $value
*/
public function __construct($name, $value)
{
$this->name = $name;
$this->value = $value;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getValue()
{
return $this->value;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
return $this->value;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return (string) $this->value;
}
}

View File

@@ -1,34 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Validatable claim that checks if value is strictly equals to the given data
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class EqualsTo extends Basic implements Claim, Validatable
{
/**
* {@inheritdoc}
*/
public function validate(ValidationData $data)
{
if ($data->has($this->getName())) {
return $this->getValue() === $data->get($this->getName());
}
return true;
}
}

View File

@@ -1,118 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
/**
* Class that create claims
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class Factory
{
/**
* The list of claim callbacks
*
* @var array
*/
private $callbacks;
/**
* Initializes the factory, registering the default callbacks
*
* @param array $callbacks
*/
public function __construct(array $callbacks = [])
{
$this->callbacks = array_merge(
[
'iat' => [$this, 'createLesserOrEqualsTo'],
'nbf' => [$this, 'createLesserOrEqualsTo'],
'exp' => [$this, 'createGreaterOrEqualsTo'],
'iss' => [$this, 'createEqualsTo'],
'aud' => [$this, 'createEqualsTo'],
'sub' => [$this, 'createEqualsTo'],
'jti' => [$this, 'createEqualsTo']
],
$callbacks
);
}
/**
* Create a new claim
*
* @param string $name
* @param mixed $value
*
* @return Claim
*/
public function create($name, $value)
{
if (!empty($this->callbacks[$name])) {
return call_user_func($this->callbacks[$name], $name, $value);
}
return $this->createBasic($name, $value);
}
/**
* Creates a claim that can be compared (greator or equals)
*
* @param string $name
* @param mixed $value
*
* @return GreaterOrEqualsTo
*/
private function createGreaterOrEqualsTo($name, $value)
{
return new GreaterOrEqualsTo($name, $value);
}
/**
* Creates a claim that can be compared (greator or equals)
*
* @param string $name
* @param mixed $value
*
* @return LesserOrEqualsTo
*/
private function createLesserOrEqualsTo($name, $value)
{
return new LesserOrEqualsTo($name, $value);
}
/**
* Creates a claim that can be compared (equals)
*
* @param string $name
* @param mixed $value
*
* @return EqualsTo
*/
private function createEqualsTo($name, $value)
{
return new EqualsTo($name, $value);
}
/**
* Creates a basic claim
*
* @param string $name
* @param mixed $value
*
* @return Basic
*/
private function createBasic($name, $value)
{
return new Basic($name, $value);
}
}

View File

@@ -1,34 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Validatable claim that checks if value is greater or equals the given data
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class GreaterOrEqualsTo extends Basic implements Claim, Validatable
{
/**
* {@inheritdoc}
*/
public function validate(ValidationData $data)
{
if ($data->has($this->getName())) {
return $this->getValue() >= $data->get($this->getName());
}
return true;
}
}

View File

@@ -1,34 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Validatable claim that checks if value is lesser or equals to the given data
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class LesserOrEqualsTo extends Basic implements Claim, Validatable
{
/**
* {@inheritdoc}
*/
public function validate(ValidationData $data)
{
if ($data->has($this->getName())) {
return $this->getValue() <= $data->get($this->getName());
}
return true;
}
}

View File

@@ -1,30 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Claim;
use Lcobucci\JWT\ValidationData;
/**
* Basic interface for validatable token claims
*
* @deprecated This interface will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
interface Validatable
{
/**
* Returns if claim is valid according with given data
*
* @param ValidationData $data
*
* @return boolean
*/
public function validate(ValidationData $data);
}

View File

@@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
interface ClaimsFormatter
{
/**
* @param array<string, mixed> $claims
*
* @return array<string, mixed>
*/
public function formatClaims(array $claims): array;
}

View File

@@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Closure;
use Lcobucci\JWT\Encoding\ChainedFormatter;
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Signer\None;
use Lcobucci\JWT\Validation\Constraint;
/**
* Configuration container for the JWT Builder and Parser
*
* Serves like a small DI container to simplify the creation and usage
* of the objects.
*/
final class Configuration
{
private Parser $parser;
private Signer $signer;
private Key $signingKey;
private Key $verificationKey;
private Validator $validator;
/** @var Closure(ClaimsFormatter $claimFormatter): Builder */
private Closure $builderFactory;
/** @var Constraint[] */
private array $validationConstraints = [];
private function __construct(
Signer $signer,
Key $signingKey,
Key $verificationKey,
?Encoder $encoder = null,
?Decoder $decoder = null
) {
$this->signer = $signer;
$this->signingKey = $signingKey;
$this->verificationKey = $verificationKey;
$this->parser = new Token\Parser($decoder ?? new JoseEncoder());
$this->validator = new Validation\Validator();
$this->builderFactory = static function (ClaimsFormatter $claimFormatter) use ($encoder): Builder {
return new Token\Builder($encoder ?? new JoseEncoder(), $claimFormatter);
};
}
public static function forAsymmetricSigner(
Signer $signer,
Key $signingKey,
Key $verificationKey,
?Encoder $encoder = null,
?Decoder $decoder = null
): self {
return new self(
$signer,
$signingKey,
$verificationKey,
$encoder,
$decoder
);
}
public static function forSymmetricSigner(
Signer $signer,
Key $key,
?Encoder $encoder = null,
?Decoder $decoder = null
): self {
return new self(
$signer,
$key,
$key,
$encoder,
$decoder
);
}
/** @deprecated Deprecated since v4.3 */
public static function forUnsecuredSigner(
?Encoder $encoder = null,
?Decoder $decoder = null
): self {
$key = InMemory::empty();
return new self(
new None(),
$key,
$key,
$encoder,
$decoder
);
}
/** @param callable(ClaimsFormatter): Builder $builderFactory */
public function setBuilderFactory(callable $builderFactory): void
{
$this->builderFactory = Closure::fromCallable($builderFactory);
}
public function builder(?ClaimsFormatter $claimFormatter = null): Builder
{
return ($this->builderFactory)($claimFormatter ?? ChainedFormatter::default());
}
public function parser(): Parser
{
return $this->parser;
}
public function setParser(Parser $parser): void
{
$this->parser = $parser;
}
public function signer(): Signer
{
return $this->signer;
}
public function signingKey(): Key
{
return $this->signingKey;
}
public function verificationKey(): Key
{
return $this->verificationKey;
}
public function validator(): Validator
{
return $this->validator;
}
public function setValidator(Validator $validator): void
{
$this->validator = $validator;
}
/** @return Constraint[] */
public function validationConstraints(): array
{
return $this->validationConstraints;
}
public function setValidationConstraints(Constraint ...$validationConstraints): void
{
$this->validationConstraints = $validationConstraints;
}
}

27
vendor/lcobucci/jwt/src/Decoder.php vendored Normal file
View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Lcobucci\JWT\Encoding\CannotDecodeContent;
interface Decoder
{
/**
* Decodes from JSON, validating the errors
*
* @return mixed
*
* @throws CannotDecodeContent When something goes wrong while decoding.
*/
public function jsonDecode(string $json);
/**
* Decodes from Base64URL
*
* @link http://tools.ietf.org/html/rfc4648#section-5
*
* @throws CannotDecodeContent When something goes wrong while decoding.
*/
public function base64UrlDecode(string $data): string;
}

25
vendor/lcobucci/jwt/src/Encoder.php vendored Normal file
View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Lcobucci\JWT\Encoding\CannotEncodeContent;
interface Encoder
{
/**
* Encodes to JSON, validating the errors
*
* @param mixed $data
*
* @throws CannotEncodeContent When something goes wrong while encoding.
*/
public function jsonEncode($data): string;
/**
* Encodes to base64url
*
* @link http://tools.ietf.org/html/rfc4648#section-5
*/
public function base64UrlEncode(string $data): string;
}

View File

@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Encoding;
use JsonException;
use Lcobucci\JWT\Exception;
use RuntimeException;
final class CannotDecodeContent extends RuntimeException implements Exception
{
public static function jsonIssues(JsonException $previous): self
{
return new self('Error while decoding from JSON', 0, $previous);
}
public static function invalidBase64String(): self
{
return new self('Error while decoding from Base64Url, invalid base64 characters detected');
}
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Encoding;
use JsonException;
use Lcobucci\JWT\Exception;
use RuntimeException;
final class CannotEncodeContent extends RuntimeException implements Exception
{
public static function jsonIssues(JsonException $previous): self
{
return new self('Error while encoding to JSON', 0, $previous);
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Encoding;
use Lcobucci\JWT\ClaimsFormatter;
final class ChainedFormatter implements ClaimsFormatter
{
/** @var list<ClaimsFormatter> */
private array $formatters;
public function __construct(ClaimsFormatter ...$formatters)
{
$this->formatters = $formatters;
}
public static function default(): self
{
return new self(new UnifyAudience(), new MicrosecondBasedDateConversion());
}
public static function withUnixTimestampDates(): self
{
return new self(new UnifyAudience(), new UnixTimestampDates());
}
/** @inheritdoc */
public function formatClaims(array $claims): array
{
foreach ($this->formatters as $formatter) {
$claims = $formatter->formatClaims($claims);
}
return $claims;
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Encoding;
use JsonException;
use Lcobucci\JWT\Decoder;
use Lcobucci\JWT\Encoder;
use Lcobucci\JWT\SodiumBase64Polyfill;
use function json_decode;
use function json_encode;
use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;
use const JSON_UNESCAPED_UNICODE;
/**
* A utilitarian class that encodes and decodes data according with JOSE specifications
*/
final class JoseEncoder implements Encoder, Decoder
{
private const JSON_DEFAULT_DEPTH = 512;
/** @inheritdoc */
public function jsonEncode($data): string
{
try {
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw CannotEncodeContent::jsonIssues($exception);
}
}
/** @inheritdoc */
public function jsonDecode(string $json)
{
try {
return json_decode($json, true, self::JSON_DEFAULT_DEPTH, JSON_THROW_ON_ERROR);
} catch (JsonException $exception) {
throw CannotDecodeContent::jsonIssues($exception);
}
}
public function base64UrlEncode(string $data): string
{
return SodiumBase64Polyfill::bin2base64(
$data,
SodiumBase64Polyfill::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
);
}
public function base64UrlDecode(string $data): string
{
return SodiumBase64Polyfill::base642bin(
$data,
SodiumBase64Polyfill::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
);
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Encoding;
use DateTimeImmutable;
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Token\RegisteredClaims;
use function array_key_exists;
final class MicrosecondBasedDateConversion implements ClaimsFormatter
{
/** @inheritdoc */
public function formatClaims(array $claims): array
{
foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
if (! array_key_exists($claim, $claims)) {
continue;
}
$claims[$claim] = $this->convertDate($claims[$claim]);
}
return $claims;
}
/** @return int|float */
private function convertDate(DateTimeImmutable $date)
{
if ($date->format('u') === '000000') {
return (int) $date->format('U');
}
return (float) $date->format('U.u');
}
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Encoding;
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Token\RegisteredClaims;
use function array_key_exists;
use function count;
use function current;
final class UnifyAudience implements ClaimsFormatter
{
/** @inheritdoc */
public function formatClaims(array $claims): array
{
if (
! array_key_exists(RegisteredClaims::AUDIENCE, $claims)
|| count($claims[RegisteredClaims::AUDIENCE]) !== 1
) {
return $claims;
}
$claims[RegisteredClaims::AUDIENCE] = current($claims[RegisteredClaims::AUDIENCE]);
return $claims;
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Encoding;
use DateTimeImmutable;
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Token\RegisteredClaims;
use function array_key_exists;
final class UnixTimestampDates implements ClaimsFormatter
{
/** @inheritdoc */
public function formatClaims(array $claims): array
{
foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
if (! array_key_exists($claim, $claims)) {
continue;
}
$claims[$claim] = $this->convertDate($claims[$claim]);
}
return $claims;
}
private function convertDate(DateTimeImmutable $date): int
{
return $date->getTimestamp();
}
}

10
vendor/lcobucci/jwt/src/Exception.php vendored Normal file
View File

@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Throwable;
interface Exception extends Throwable
{
}

66
vendor/lcobucci/jwt/src/JwtFacade.php vendored Normal file
View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Closure;
use DateTimeImmutable;
use Lcobucci\Clock\Clock;
use Lcobucci\Clock\SystemClock;
use Lcobucci\JWT\Encoding\ChainedFormatter;
use Lcobucci\JWT\Encoding\JoseEncoder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\SignedWith;
use Lcobucci\JWT\Validation\ValidAt;
use Lcobucci\JWT\Validation\Validator;
use function assert;
final class JwtFacade
{
private Parser $parser;
private Clock $clock;
public function __construct(?Parser $parser = null, ?Clock $clock = null)
{
$this->parser = $parser ?? new Token\Parser(new JoseEncoder());
$this->clock = $clock ?? SystemClock::fromSystemTimezone();
}
/** @param Closure(Builder, DateTimeImmutable):Builder $customiseBuilder */
public function issue(
Signer $signer,
Key $signingKey,
Closure $customiseBuilder
): UnencryptedToken {
$builder = new Token\Builder(new JoseEncoder(), ChainedFormatter::withUnixTimestampDates());
$now = $this->clock->now();
$builder
->issuedAt($now)
->canOnlyBeUsedAfter($now)
->expiresAt($now->modify('+5 minutes'));
return $customiseBuilder($builder, $now)->getToken($signer, $signingKey);
}
public function parse(
string $jwt,
SignedWith $signedWith,
ValidAt $validAt,
Constraint ...$constraints
): UnencryptedToken {
$token = $this->parser->parse($jwt);
assert($token instanceof UnencryptedToken);
(new Validator())->assert(
$token,
$signedWith,
$validAt,
...$constraints
);
return $token;
}
}

View File

@@ -1,157 +1,20 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT;
use InvalidArgumentException;
use Lcobucci\JWT\Claim\Factory as ClaimFactory;
use Lcobucci\JWT\Parsing\Decoder;
use Lcobucci\JWT\Encoding\CannotDecodeContent;
use Lcobucci\JWT\Token\InvalidTokenStructure;
use Lcobucci\JWT\Token\UnsupportedHeaderFound;
/**
* This class parses the JWT strings and convert them into tokens
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Parser
interface Parser
{
/**
* The data decoder
*
* @var Decoder
*/
private $decoder;
/**
* The claims factory
*
* @var ClaimFactory
*/
private $claimFactory;
/**
* Initializes the object
*
* @param Decoder $decoder
* @param ClaimFactory $claimFactory
*/
public function __construct(
Decoder $decoder = null,
ClaimFactory $claimFactory = null
) {
$this->decoder = $decoder ?: new Decoder();
$this->claimFactory = $claimFactory ?: new ClaimFactory();
}
/**
* Parses the JWT and returns a token
*
* @param string $jwt
*
* @return Token
* @throws CannotDecodeContent When something goes wrong while decoding.
* @throws InvalidTokenStructure When token string structure is invalid.
* @throws UnsupportedHeaderFound When parsed token has an unsupported header.
*/
public function parse($jwt)
{
$data = $this->splitJwt($jwt);
$header = $this->parseHeader($data[0]);
$claims = $this->parseClaims($data[1]);
$signature = $this->parseSignature($header, $data[2]);
foreach ($claims as $name => $value) {
if (isset($header[$name])) {
$header[$name] = $value;
}
}
if ($signature === null) {
unset($data[2]);
}
return new Token($header, $claims, $signature, $data);
}
/**
* Splits the JWT string into an array
*
* @param string $jwt
*
* @return array
*
* @throws InvalidArgumentException When JWT is not a string or is invalid
*/
protected function splitJwt($jwt)
{
if (!is_string($jwt)) {
throw new InvalidArgumentException('The JWT string must have two dots');
}
$data = explode('.', $jwt);
if (count($data) != 3) {
throw new InvalidArgumentException('The JWT string must have two dots');
}
return $data;
}
/**
* Parses the header from a string
*
* @param string $data
*
* @return array
*
* @throws InvalidArgumentException When an invalid header is informed
*/
protected function parseHeader($data)
{
$header = (array) $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
if (isset($header['enc'])) {
throw new InvalidArgumentException('Encryption is not supported yet');
}
return $header;
}
/**
* Parses the claim set from a string
*
* @param string $data
*
* @return array
*/
protected function parseClaims($data)
{
$claims = (array) $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
foreach ($claims as $name => &$value) {
$value = $this->claimFactory->create($name, $value);
}
return $claims;
}
/**
* Returns the signature from given data
*
* @param array $header
* @param string $data
*
* @return Signature
*/
protected function parseSignature(array $header, $data)
{
if ($data == '' || !isset($header['alg']) || $header['alg'] == 'none') {
return null;
}
$hash = $this->decoder->base64UrlDecode($data);
return new Signature($hash);
}
public function parse(string $jwt): Token;
}

View File

@@ -1,56 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Parsing;
use RuntimeException;
/**
* Class that decodes data according with the specs of RFC-4648
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*
* @link http://tools.ietf.org/html/rfc4648#section-5
*/
class Decoder
{
/**
* Decodes from JSON, validating the errors (will return an associative array
* instead of objects)
*
* @param string $json
* @return mixed
*
* @throws RuntimeException When something goes wrong while decoding
*/
public function jsonDecode($json)
{
$data = json_decode($json);
if (json_last_error() != JSON_ERROR_NONE) {
throw new RuntimeException('Error while decoding to JSON: ' . json_last_error_msg());
}
return $data;
}
/**
* Decodes from base64url
*
* @param string $data
* @return string
*/
public function base64UrlDecode($data)
{
if ($remainder = strlen($data) % 4) {
$data .= str_repeat('=', 4 - $remainder);
}
return base64_decode(strtr($data, '-_', '+/'));
}
}

View File

@@ -1,51 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Parsing;
use RuntimeException;
/**
* Class that encodes data according with the specs of RFC-4648
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*
* @link http://tools.ietf.org/html/rfc4648#section-5
*/
class Encoder
{
/**
* Encodes to JSON, validating the errors
*
* @param mixed $data
* @return string
*
* @throws RuntimeException When something goes wrong while encoding
*/
public function jsonEncode($data)
{
$json = json_encode($data);
if (json_last_error() != JSON_ERROR_NONE) {
throw new RuntimeException('Error while encoding to JSON: ' . json_last_error_msg());
}
return $json;
}
/**
* Encodes to base64url
*
* @param string $data
* @return string
*/
public function base64UrlEncode($data)
{
return str_replace('=', '', strtr(base64_encode($data), '+/', '-_'));
}
}

View File

@@ -1,61 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
use Lcobucci\JWT\Signer\Key;
/**
* This class represents a token signature
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Signature
{
/**
* The resultant hash
*
* @var string
*/
protected $hash;
/**
* Initializes the object
*
* @param string $hash
*/
public function __construct($hash)
{
$this->hash = $hash;
}
/**
* Verifies if the current hash matches with with the result of the creation of
* a new signature with given data
*
* @param Signer $signer
* @param string $payload
* @param Key|string $key
*
* @return boolean
*/
public function verify(Signer $signer, $payload, $key)
{
return $signer->verify($this->hash, $payload, $key);
}
/**
* Returns the current hash as a string representation of the signature
*
* @return string
*/
public function __toString()
{
return $this->hash;
}
}

View File

@@ -1,59 +1,34 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT;
use InvalidArgumentException;
use Lcobucci\JWT\Signer\CannotSignPayload;
use Lcobucci\JWT\Signer\Ecdsa\ConversionFailed;
use Lcobucci\JWT\Signer\InvalidKeyProvided;
use Lcobucci\JWT\Signer\Key;
/**
* Basic interface for token signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
interface Signer
{
/**
* Returns the algorithm id
*
* @return string
*/
public function getAlgorithmId();
public function algorithmId(): string;
/**
* Apply changes on headers according with algorithm
* Creates a hash for the given payload
*
* @param array $headers
* @throws CannotSignPayload When payload signing fails.
* @throws InvalidKeyProvided When issue key is invalid/incompatible.
* @throws ConversionFailed When signature could not be converted.
*/
public function modifyHeader(array &$headers);
/**
* Returns a signature for given data
*
* @param string $payload
* @param Key|string $key
*
* @return Signature
*
* @throws InvalidArgumentException When given key is invalid
*/
public function sign($payload, $key);
public function sign(string $payload, Key $key): string;
/**
* Returns if the expected hash matches with the data and key
*
* @param string $expected
* @param string $payload
* @param Key|string $key
*
* @return boolean
*
* @throws InvalidArgumentException When given key is invalid
* @throws InvalidKeyProvided When issue key is invalid/incompatible.
* @throws ConversionFailed When signature could not be converted.
*/
public function verify($expected, $payload, $key);
public function verify(string $expected, string $payload, Key $key): bool;
}

View File

@@ -1,85 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signature;
use Lcobucci\JWT\Signer;
/**
* Base class for signers
*
* @deprecated This class will be removed on v4
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
abstract class BaseSigner implements Signer
{
/**
* {@inheritdoc}
*/
public function modifyHeader(array &$headers)
{
$headers['alg'] = $this->getAlgorithmId();
}
/**
* {@inheritdoc}
*/
public function sign($payload, $key)
{
return new Signature($this->createHash($payload, $this->getKey($key)));
}
/**
* {@inheritdoc}
*/
public function verify($expected, $payload, $key)
{
return $this->doVerify($expected, $payload, $this->getKey($key));
}
/**
* @param Key|string $key
*
* @return Key
*/
private function getKey($key)
{
if (is_string($key)) {
$key = new Key($key);
}
return $key;
}
/**
* Creates a hash with the given data
*
* @internal
*
* @param string $payload
* @param Key $key
*
* @return string
*/
abstract public function createHash($payload, Key $key);
/**
* Performs the signature verification
*
* @internal
*
* @param string $expected
* @param string $payload
* @param Key $key
*
* @return boolean
*/
abstract public function doVerify($expected, $payload, Key $key);
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer;
use function hash_equals;
use function sodium_crypto_generichash;
use function strlen;
final class Blake2b implements Signer
{
private const MINIMUM_KEY_LENGTH_IN_BITS = 256;
public function algorithmId(): string
{
return 'BLAKE2B';
}
public function sign(string $payload, Key $key): string
{
$actualKeyLength = 8 * strlen($key->contents());
if ($actualKeyLength < self::MINIMUM_KEY_LENGTH_IN_BITS) {
throw InvalidKeyProvided::tooShort(self::MINIMUM_KEY_LENGTH_IN_BITS, $actualKeyLength);
}
return sodium_crypto_generichash($payload, $key->contents());
}
public function verify(string $expected, string $payload, Key $key): bool
{
return hash_equals($expected, $this->sign($payload, $key));
}
}

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class CannotSignPayload extends InvalidArgumentException implements Exception
{
public static function errorHappened(string $error): self
{
return new self('There was an error while creating the signature:' . $error);
}
}

View File

@@ -1,69 +1,69 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter;
use Lcobucci\JWT\Signer\Ecdsa\SignatureConverter;
use const OPENSSL_KEYTYPE_EC;
/**
* Base class for ECDSA signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
abstract class Ecdsa extends OpenSSL
{
/**
* @var SignatureConverter
*/
private $converter;
private SignatureConverter $converter;
public function __construct(SignatureConverter $converter = null)
public function __construct(?SignatureConverter $converter = null)
{
$this->converter = $converter ?: new MultibyteStringConverter();
$this->converter = $converter ?? new MultibyteStringConverter();
}
/**
* {@inheritdoc}
*/
public function createHash($payload, Key $key)
/** @deprecated */
public static function create(): Ecdsa
{
return new static(); // @phpstan-ignore-line
}
final public function sign(string $payload, Key $key): string
{
return $this->converter->fromAsn1(
parent::createHash($payload, $key),
$this->getKeyLength()
$this->createSignature($key->contents(), $key->passphrase(), $payload),
$this->pointLength()
);
}
/**
* {@inheritdoc}
*/
public function doVerify($expected, $payload, Key $key)
final public function verify(string $expected, string $payload, Key $key): bool
{
return parent::doVerify(
$this->converter->toAsn1($expected, $this->getKeyLength()),
return $this->verifySignature(
$this->converter->toAsn1($expected, $this->pointLength()),
$payload,
$key
$key->contents()
);
}
/** {@inheritdoc} */
final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void
{
if ($type !== OPENSSL_KEYTYPE_EC) {
throw InvalidKeyProvided::incompatibleKeyType(
self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_EC],
self::KEY_TYPE_MAP[$type],
);
}
$expectedKeyLength = $this->expectedKeyLength();
if ($lengthInBits !== $expectedKeyLength) {
throw InvalidKeyProvided::incompatibleKeyLength($expectedKeyLength, $lengthInBits);
}
}
/** @internal */
abstract public function expectedKeyLength(): int;
/**
* Returns the length of each point in the signature, so that we can calculate and verify R and S points properly
*
* @internal
*/
abstract public function getKeyLength();
/**
* {@inheritdoc}
*/
final public function getKeyType()
{
return OPENSSL_KEYTYPE_EC;
}
abstract public function pointLength(): int;
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class ConversionFailed extends InvalidArgumentException implements Exception
{
public static function invalidLength(): self
{
return new self('Invalid signature length.');
}
public static function incorrectStartSequence(): self
{
return new self('Invalid data. Should start with a sequence.');
}
public static function integerExpected(): self
{
return new self('Invalid data. Should contain an integer.');
}
}

View File

@@ -1,4 +1,6 @@
<?php
declare(strict_types=1);
/*
* The MIT License (MIT)
*
@@ -9,16 +11,19 @@
*
* @link https://github.com/web-token/jwt-framework/blob/v1.2/src/Component/Core/Util/ECSignature.php
*/
namespace Lcobucci\JWT\Signer\Ecdsa;
use InvalidArgumentException;
use function assert;
use function bin2hex;
use function dechex;
use function hex2bin;
use function hexdec;
use function is_string;
use function mb_strlen;
use function mb_substr;
use function str_pad;
use const STR_PAD_LEFT;
/**
@@ -28,24 +33,24 @@ use const STR_PAD_LEFT;
*/
final class MultibyteStringConverter implements SignatureConverter
{
const ASN1_SEQUENCE = '30';
const ASN1_INTEGER = '02';
const ASN1_MAX_SINGLE_BYTE = 128;
const ASN1_LENGTH_2BYTES = '81';
const ASN1_BIG_INTEGER_LIMIT = '7f';
const ASN1_NEGATIVE_INTEGER = '00';
const BYTE_SIZE = 2;
private const ASN1_SEQUENCE = '30';
private const ASN1_INTEGER = '02';
private const ASN1_MAX_SINGLE_BYTE = 128;
private const ASN1_LENGTH_2BYTES = '81';
private const ASN1_BIG_INTEGER_LIMIT = '7f';
private const ASN1_NEGATIVE_INTEGER = '00';
private const BYTE_SIZE = 2;
public function toAsn1($signature, $length)
public function toAsn1(string $points, int $length): string
{
$signature = bin2hex($signature);
$points = bin2hex($points);
if (self::octetLength($signature) !== $length) {
throw new InvalidArgumentException('Invalid signature length.');
if (self::octetLength($points) !== $length) {
throw ConversionFailed::invalidLength();
}
$pointR = self::preparePositiveInteger(mb_substr($signature, 0, $length, '8bit'));
$pointS = self::preparePositiveInteger(mb_substr($signature, $length, null, '8bit'));
$pointR = self::preparePositiveInteger(mb_substr($points, 0, $length, '8bit'));
$pointS = self::preparePositiveInteger(mb_substr($points, $length, null, '8bit'));
$lengthR = self::octetLength($pointR);
$lengthS = self::octetLength($pointS);
@@ -59,38 +64,42 @@ final class MultibyteStringConverter implements SignatureConverter
. self::ASN1_INTEGER . dechex($lengthR) . $pointR
. self::ASN1_INTEGER . dechex($lengthS) . $pointS
);
assert(is_string($asn1));
return $asn1;
}
private static function octetLength($data)
private static function octetLength(string $data): int
{
return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE);
}
private static function preparePositiveInteger($data)
private static function preparePositiveInteger(string $data): string
{
if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
return self::ASN1_NEGATIVE_INTEGER . $data;
}
while (mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT) {
while (
mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT
) {
$data = mb_substr($data, 2, null, '8bit');
}
return $data;
}
public function fromAsn1($signature, $length)
public function fromAsn1(string $signature, int $length): string
{
$message = bin2hex($signature);
$position = 0;
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) {
throw new InvalidArgumentException('Invalid data. Should start with a sequence.');
throw ConversionFailed::incorrectStartSequence();
}
// @phpstan-ignore-next-line
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) {
$position += self::BYTE_SIZE;
}
@@ -99,11 +108,12 @@ final class MultibyteStringConverter implements SignatureConverter
$pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
$points = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT));
assert(is_string($points));
return $points;
}
private static function readAsn1Content($message, &$position, $length)
private static function readAsn1Content(string $message, int &$position, int $length): string
{
$content = mb_substr($message, $position, $length, '8bit');
$position += $length;
@@ -111,10 +121,10 @@ final class MultibyteStringConverter implements SignatureConverter
return $content;
}
private static function readAsn1Integer($message, &$position)
private static function readAsn1Integer(string $message, int &$position): string
{
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_INTEGER) {
throw new InvalidArgumentException('Invalid data. Should contain an integer.');
throw ConversionFailed::integerExpected();
}
$length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE));
@@ -122,10 +132,12 @@ final class MultibyteStringConverter implements SignatureConverter
return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE);
}
private static function retrievePositiveInteger($data)
private static function retrievePositiveInteger(string $data): string
{
while (mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
while (
mb_substr($data, 0, self::BYTE_SIZE, '8bit') === self::ASN1_NEGATIVE_INTEGER
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT
) {
$data = mb_substr($data, 2, null, '8bit');
}

View File

@@ -1,43 +1,31 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa;
/**
* Signer for ECDSA SHA-256
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha256 extends Ecdsa
use const OPENSSL_ALGO_SHA256;
final class Sha256 extends Ecdsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'ES256';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): int
{
return 'sha256';
return OPENSSL_ALGO_SHA256;
}
/**
* {@inheritdoc}
*/
public function getKeyLength()
public function pointLength(): int
{
return 64;
}
public function expectedKeyLength(): int
{
return 256;
}
}

View File

@@ -1,43 +1,31 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa;
/**
* Signer for ECDSA SHA-384
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha384 extends Ecdsa
use const OPENSSL_ALGO_SHA384;
final class Sha384 extends Ecdsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'ES384';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): int
{
return 'sha384';
return OPENSSL_ALGO_SHA384;
}
/**
* {@inheritdoc}
*/
public function getKeyLength()
public function pointLength(): int
{
return 96;
}
public function expectedKeyLength(): int
{
return 384;
}
}

View File

@@ -1,43 +1,31 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa;
/**
* Signer for ECDSA SHA-512
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha512 extends Ecdsa
use const OPENSSL_ALGO_SHA512;
final class Sha512 extends Ecdsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'ES512';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): int
{
return 'sha512';
return OPENSSL_ALGO_SHA512;
}
/**
* {@inheritdoc}
*/
public function getKeyLength()
public function pointLength(): int
{
return 132;
}
public function expectedKeyLength(): int
{
return 521;
}
}

View File

@@ -1,4 +1,6 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
/**
@@ -19,20 +21,14 @@ interface SignatureConverter
/**
* Converts the signature generated by OpenSSL into what JWA defines
*
* @param string $signature
* @param int $length
*
* @return string
* @throws ConversionFailed When there was an issue during the format conversion.
*/
public function fromAsn1($signature, $length);
public function fromAsn1(string $signature, int $length): string;
/**
* Converts the JWA signature into something OpenSSL understands
*
* @param string $points
* @param int $length
*
* @return string
* @throws ConversionFailed When there was an issue during the format conversion.
*/
public function toAsn1($points, $length);
public function toAsn1(string $points, int $length): string;
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\UnsafeEcdsa;
use const OPENSSL_ALGO_SHA256;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha256 extends UnsafeEcdsa
{
public function algorithmId(): string
{
return 'ES256';
}
public function algorithm(): int
{
return OPENSSL_ALGO_SHA256;
}
public function pointLength(): int
{
return 64;
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\UnsafeEcdsa;
use const OPENSSL_ALGO_SHA384;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha384 extends UnsafeEcdsa
{
public function algorithmId(): string
{
return 'ES384';
}
public function algorithm(): int
{
return OPENSSL_ALGO_SHA384;
}
public function pointLength(): int
{
return 96;
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\UnsafeEcdsa;
use const OPENSSL_ALGO_SHA512;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha512 extends UnsafeEcdsa
{
public function algorithmId(): string
{
return 'ES512';
}
public function algorithm(): int
{
return OPENSSL_ALGO_SHA512;
}
public function pointLength(): int
{
return 132;
}
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer;
use SodiumException;
use function sodium_crypto_sign_detached;
use function sodium_crypto_sign_verify_detached;
final class Eddsa implements Signer
{
public function algorithmId(): string
{
return 'EdDSA';
}
public function sign(string $payload, Key $key): string
{
try {
return sodium_crypto_sign_detached($payload, $key->contents());
} catch (SodiumException $sodiumException) {
throw new InvalidKeyProvided($sodiumException->getMessage(), 0, $sodiumException);
}
}
public function verify(string $expected, string $payload, Key $key): bool
{
try {
return sodium_crypto_sign_verify_detached($expected, $payload, $key->contents());
} catch (SodiumException $sodiumException) {
throw new InvalidKeyProvided($sodiumException->getMessage(), 0, $sodiumException);
}
}
}

View File

@@ -1,75 +1,34 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
/**
* Base class for hmac signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
abstract class Hmac extends BaseSigner
use Lcobucci\JWT\Signer;
use function hash_equals;
use function hash_hmac;
use function strlen;
abstract class Hmac implements Signer
{
/**
* {@inheritdoc}
*/
public function createHash($payload, Key $key)
final public function sign(string $payload, Key $key): string
{
return hash_hmac($this->getAlgorithm(), $payload, $key->getContent(), true);
}
/**
* {@inheritdoc}
*/
public function doVerify($expected, $payload, Key $key)
{
if (!is_string($expected)) {
return false;
$actualKeyLength = 8 * strlen($key->contents());
$expectedKeyLength = $this->minimumBitsLengthForKey();
if ($actualKeyLength < $expectedKeyLength) {
throw InvalidKeyProvided::tooShort($expectedKeyLength, $actualKeyLength);
}
$callback = function_exists('hash_equals') ? 'hash_equals' : [$this, 'hashEquals'];
return call_user_func($callback, $expected, $this->createHash($payload, $key));
return hash_hmac($this->algorithm(), $payload, $key->contents(), true);
}
/**
* PHP < 5.6 timing attack safe hash comparison
*
* @internal
*
* @param string $expected
* @param string $generated
*
* @return boolean
*/
public function hashEquals($expected, $generated)
final public function verify(string $expected, string $payload, Key $key): bool
{
$expectedLength = strlen($expected);
if ($expectedLength !== strlen($generated)) {
return false;
}
$res = 0;
for ($i = 0; $i < $expectedLength; ++$i) {
$res |= ord($expected[$i]) ^ ord($generated[$i]);
}
return $res === 0;
return hash_equals($expected, $this->sign($payload, $key));
}
/**
* Returns the algorithm name
*
* @internal
*
* @return string
*/
abstract public function getAlgorithm();
abstract public function algorithm(): string;
/** @return positive-int */
abstract public function minimumBitsLengthForKey(): int;
}

View File

@@ -1,35 +1,24 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/**
* Signer for HMAC SHA-256
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Sha256 extends Hmac
final class Sha256 extends Hmac
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'HS256';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): string
{
return 'sha256';
}
public function minimumBitsLengthForKey(): int
{
return 256;
}
}

View File

@@ -1,35 +1,24 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/**
* Signer for HMAC SHA-384
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Sha384 extends Hmac
final class Sha384 extends Hmac
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'HS384';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): string
{
return 'sha384';
}
public function minimumBitsLengthForKey(): int
{
return 384;
}
}

View File

@@ -1,35 +1,24 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/**
* Signer for HMAC SHA-512
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Sha512 extends Hmac
final class Sha512 extends Hmac
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'HS512';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): string
{
return 'sha512';
}
public function minimumBitsLengthForKey(): int
{
return 512;
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha256 extends Hmac
{
public function algorithmId(): string
{
return 'HS256';
}
public function algorithm(): string
{
return 'sha256';
}
public function minimumBitsLengthForKey(): int
{
return 1;
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha384 extends Hmac
{
public function algorithmId(): string
{
return 'HS384';
}
public function algorithm(): string
{
return 'sha384';
}
public function minimumBitsLengthForKey(): int
{
return 1;
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Hmac;
use Lcobucci\JWT\Signer\Hmac;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha512 extends Hmac
{
public function algorithmId(): string
{
return 'HS512';
}
public function algorithm(): string
{
return 'sha512';
}
public function minimumBitsLengthForKey(): int
{
return 1;
}
}

View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class InvalidKeyProvided extends InvalidArgumentException implements Exception
{
public static function cannotBeParsed(string $details): self
{
return new self('It was not possible to parse your key, reason:' . $details);
}
public static function incompatibleKeyType(string $expectedType, string $actualType): self
{
return new self(
'The type of the provided key is not "' . $expectedType
. '", "' . $actualType . '" provided'
);
}
public static function incompatibleKeyLength(int $expectedLength, int $actualLength): self
{
return new self(
'The length of the provided key is different than ' . $expectedLength . ' bits, '
. $actualLength . ' bits provided'
);
}
public static function cannotBeEmpty(): self
{
return new self('Key cannot be empty');
}
public static function tooShort(int $expectedLength, int $actualLength): self
{
return new self('Key provided is shorter than ' . $expectedLength . ' bits,'
. ' only ' . $actualLength . ' bits provided');
}
}

View File

@@ -1,92 +1,11 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use Exception;
use InvalidArgumentException;
use SplFileObject;
/**
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 3.0.4
*/
final class Key
interface Key
{
/**
* @var string
*/
private $content;
public function contents(): string;
/**
* @var string
*/
private $passphrase;
/**
* @param string $content
* @param string $passphrase
*/
public function __construct($content, $passphrase = null)
{
$this->setContent($content);
$this->passphrase = $passphrase;
}
/**
* @param string $content
*
* @throws InvalidArgumentException
*/
private function setContent($content)
{
if (strpos($content, 'file://') === 0) {
$content = $this->readFile($content);
}
$this->content = $content;
}
/**
* @param string $content
*
* @return string
*
* @throws InvalidArgumentException
*/
private function readFile($content)
{
try {
$file = new SplFileObject(substr($content, 7));
$content = '';
while (! $file->eof()) {
$content .= $file->fgets();
}
return $content;
} catch (Exception $exception) {
throw new InvalidArgumentException('You must provide a valid key file', 0, $exception);
}
}
/**
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* @return string
*/
public function getPassphrase()
{
return $this->passphrase;
}
public function passphrase(): string;
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Key;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
use Throwable;
final class FileCouldNotBeRead extends InvalidArgumentException implements Exception
{
public static function onPath(string $path, ?Throwable $cause = null): self
{
return new self(
'The path "' . $path . '" does not contain a valid key file',
0,
$cause
);
}
}

View File

@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\InvalidKeyProvided;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\SodiumBase64Polyfill;
use SplFileObject;
use Throwable;
use function assert;
use function is_string;
final class InMemory implements Key
{
private string $contents;
private string $passphrase;
/** @param non-empty-string $contents */
private function __construct(string $contents, string $passphrase)
{
// @phpstan-ignore-next-line
if ($contents === '') {
throw InvalidKeyProvided::cannotBeEmpty();
}
$this->contents = $contents;
$this->passphrase = $passphrase;
}
/** @deprecated Deprecated since v4.3 */
public static function empty(): self
{
$emptyKey = new self('empty', 'empty');
$emptyKey->contents = '';
$emptyKey->passphrase = '';
return $emptyKey;
}
/** @param non-empty-string $contents */
public static function plainText(string $contents, string $passphrase = ''): self
{
return new self($contents, $passphrase);
}
/** @param non-empty-string $contents */
public static function base64Encoded(string $contents, string $passphrase = ''): self
{
$decoded = SodiumBase64Polyfill::base642bin(
$contents,
SodiumBase64Polyfill::SODIUM_BASE64_VARIANT_ORIGINAL
);
// @phpstan-ignore-next-line
return new self($decoded, $passphrase);
}
/** @throws FileCouldNotBeRead */
public static function file(string $path, string $passphrase = ''): self
{
try {
$file = new SplFileObject($path);
} catch (Throwable $exception) {
throw FileCouldNotBeRead::onPath($path, $exception);
}
$contents = $file->fread($file->getSize());
assert(is_string($contents));
assert($contents !== '');
return new self($contents, $passphrase);
}
public function contents(): string
{
return $this->contents;
}
public function passphrase(): string
{
return $this->passphrase;
}
}

View File

@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Key;
use function file_exists;
use function strpos;
use function substr;
/** @deprecated please use {@see InMemory} instead */
final class LocalFileReference implements Key
{
private const PATH_PREFIX = 'file://';
private string $path;
private string $passphrase;
private string $contents;
private function __construct(string $path, string $passphrase)
{
$this->path = $path;
$this->passphrase = $passphrase;
}
/** @throws FileCouldNotBeRead */
public static function file(string $path, string $passphrase = ''): self
{
if (strpos($path, self::PATH_PREFIX) === 0) {
$path = substr($path, 7);
}
if (! file_exists($path)) {
throw FileCouldNotBeRead::onPath($path);
}
return new self($path, $passphrase);
}
public function contents(): string
{
if (! isset($this->contents)) {
$this->contents = InMemory::file($this->path)->contents();
}
return $this->contents;
}
public function passphrase(): string
{
return $this->passphrase;
}
}

View File

@@ -1,44 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT\Signer;
/**
* A utilitarian class that encapsulates the retrieval of public and private keys
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*
* @deprecated Since we've removed OpenSSL from ECDSA there's no reason to use this class
*/
class Keychain
{
/**
* Returns a private key from file path or content
*
* @param string $key
* @param string $passphrase
*
* @return Key
*/
public function getPrivateKey($key, $passphrase = null)
{
return new Key($key, $passphrase);
}
/**
* Returns a public key from file path or content
*
* @param string $certificate
*
* @return Key
*/
public function getPublicKey($certificate)
{
return new Key($certificate);
}
}

27
vendor/lcobucci/jwt/src/Signer/None.php vendored Normal file
View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer;
/** @deprecated Deprecated since v4.3 */
final class None implements Signer
{
public function algorithmId(): string
{
return 'none';
}
// @phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
public function sign(string $payload, Key $key): string
{
return '';
}
// @phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
public function verify(string $expected, string $payload, Key $key): bool
{
return $expected === '';
}
}

View File

@@ -1,11 +1,16 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use InvalidArgumentException;
use Lcobucci\JWT\Signer;
use OpenSSLAsymmetricKey;
use function array_key_exists;
use function assert;
use function is_array;
use function is_resource;
use function is_bool;
use function is_int;
use function openssl_error_string;
use function openssl_free_key;
use function openssl_pkey_get_details;
@@ -14,34 +19,51 @@ use function openssl_pkey_get_public;
use function openssl_sign;
use function openssl_verify;
abstract class OpenSSL extends BaseSigner
use const OPENSSL_KEYTYPE_DH;
use const OPENSSL_KEYTYPE_DSA;
use const OPENSSL_KEYTYPE_EC;
use const OPENSSL_KEYTYPE_RSA;
use const PHP_EOL;
abstract class OpenSSL implements Signer
{
public function createHash($payload, Key $key)
{
$privateKey = $this->getPrivateKey($key->getContent(), $key->getPassphrase());
protected const KEY_TYPE_MAP = [
OPENSSL_KEYTYPE_RSA => 'RSA',
OPENSSL_KEYTYPE_DSA => 'DSA',
OPENSSL_KEYTYPE_DH => 'DH',
OPENSSL_KEYTYPE_EC => 'EC',
];
/**
* @throws CannotSignPayload
* @throws InvalidKeyProvided
*/
final protected function createSignature(
string $pem,
string $passphrase,
string $payload
): string {
$key = $this->getPrivateKey($pem, $passphrase);
try {
$signature = '';
if (! openssl_sign($payload, $signature, $privateKey, $this->getAlgorithm())) {
throw new InvalidArgumentException(
'There was an error while creating the signature: ' . openssl_error_string()
);
if (! openssl_sign($payload, $signature, $key, $this->algorithm())) {
throw CannotSignPayload::errorHappened($this->fullOpenSSLErrorString());
}
return $signature;
} finally {
openssl_free_key($privateKey);
$this->freeKey($key);
}
}
/**
* @param string $pem
* @param string $passphrase
* @return resource|OpenSSLAsymmetricKey
*
* @return resource
* @throws CannotSignPayload
*/
private function getPrivateKey($pem, $passphrase)
private function getPrivateKey(string $pem, string $passphrase)
{
$privateKey = openssl_pkey_get_private($pem, $passphrase);
$this->validateKey($privateKey);
@@ -49,27 +71,25 @@ abstract class OpenSSL extends BaseSigner
return $privateKey;
}
/**
* @param $expected
* @param $payload
* @param $pem
* @return bool
*/
public function doVerify($expected, $payload, Key $key)
{
$publicKey = $this->getPublicKey($key->getContent());
$result = openssl_verify($payload, $expected, $publicKey, $this->getAlgorithm());
openssl_free_key($publicKey);
/** @throws InvalidKeyProvided */
final protected function verifySignature(
string $expected,
string $payload,
string $pem
): bool {
$key = $this->getPublicKey($pem);
$result = openssl_verify($payload, $expected, $key, $this->algorithm());
$this->freeKey($key);
return $result === 1;
}
/**
* @param string $pem
* @return resource|OpenSSLAsymmetricKey
*
* @return resource
* @throws InvalidKeyProvided
*/
private function getPublicKey($pem)
private function getPublicKey(string $pem)
{
$publicKey = openssl_pkey_get_public($pem);
$this->validateKey($publicKey);
@@ -80,36 +100,55 @@ abstract class OpenSSL extends BaseSigner
/**
* Raises an exception when the key type is not the expected type
*
* @param resource|bool $key
* @param resource|OpenSSLAsymmetricKey|bool $key
*
* @throws InvalidArgumentException
* @throws InvalidKeyProvided
*/
private function validateKey($key)
private function validateKey($key): void
{
if (! is_resource($key)) {
throw new InvalidArgumentException(
'It was not possible to parse your key, reason: ' . openssl_error_string()
);
if (is_bool($key)) {
throw InvalidKeyProvided::cannotBeParsed($this->fullOpenSSLErrorString());
}
$details = openssl_pkey_get_details($key);
assert(is_array($details));
if (! isset($details['key']) || $details['type'] !== $this->getKeyType()) {
throw new InvalidArgumentException('This key is not compatible with this signer');
}
assert(array_key_exists('bits', $details));
assert(is_int($details['bits']));
assert(array_key_exists('type', $details));
assert(is_int($details['type']));
$this->guardAgainstIncompatibleKey($details['type'], $details['bits']);
}
/**
* Returns the type of key to be used to create/verify the signature (using OpenSSL constants)
*
* @internal
*/
abstract public function getKeyType();
private function fullOpenSSLErrorString(): string
{
$error = '';
while ($msg = openssl_error_string()) {
$error .= PHP_EOL . '* ' . $msg;
}
return $error;
}
/** @throws InvalidKeyProvided */
abstract protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void;
/** @param resource|OpenSSLAsymmetricKey $key */
private function freeKey($key): void
{
if ($key instanceof OpenSSLAsymmetricKey) {
return;
}
openssl_free_key($key); // Deprecated and no longer necessary as of PHP >= 8.0
}
/**
* Returns which algorithm to be used to create/verify the signature (using OpenSSL constants)
*
* @internal
*/
abstract public function getAlgorithm();
abstract public function algorithm(): int;
}

View File

@@ -1,24 +1,35 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use const OPENSSL_KEYTYPE_RSA;
/**
* Base class for RSASSA-PKCS1 signers
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
abstract class Rsa extends OpenSSL
{
final public function getKeyType()
private const MINIMUM_KEY_LENGTH = 2048;
final public function sign(string $payload, Key $key): string
{
return OPENSSL_KEYTYPE_RSA;
return $this->createSignature($key->contents(), $key->passphrase(), $payload);
}
final public function verify(string $expected, string $payload, Key $key): bool
{
return $this->verifySignature($expected, $payload, $key->contents());
}
final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void
{
if ($type !== OPENSSL_KEYTYPE_RSA) {
throw InvalidKeyProvided::incompatibleKeyType(
self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_RSA],
self::KEY_TYPE_MAP[$type],
);
}
if ($lengthInBits < self::MINIMUM_KEY_LENGTH) {
throw InvalidKeyProvided::tooShort(self::MINIMUM_KEY_LENGTH, $lengthInBits);
}
}
}

View File

@@ -1,34 +1,20 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\Rsa;
/**
* Signer for RSA SHA-256
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha256 extends Rsa
use const OPENSSL_ALGO_SHA256;
final class Sha256 extends Rsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'RS256';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): int
{
return OPENSSL_ALGO_SHA256;
}

View File

@@ -1,34 +1,20 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\Rsa;
/**
* Signer for RSA SHA-384
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha384 extends Rsa
use const OPENSSL_ALGO_SHA384;
final class Sha384 extends Rsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'RS384';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): int
{
return OPENSSL_ALGO_SHA384;
}

View File

@@ -1,34 +1,20 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\Rsa;
/**
* Signer for RSA SHA-512
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.1.0
*/
class Sha512 extends Rsa
use const OPENSSL_ALGO_SHA512;
final class Sha512 extends Rsa
{
/**
* {@inheritdoc}
*/
public function getAlgorithmId()
public function algorithmId(): string
{
return 'RS512';
}
/**
* {@inheritdoc}
*/
public function getAlgorithm()
public function algorithm(): int
{
return OPENSSL_ALGO_SHA512;
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\UnsafeRsa;
use const OPENSSL_ALGO_SHA256;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha256 extends UnsafeRsa
{
public function algorithmId(): string
{
return 'RS256';
}
public function algorithm(): int
{
return OPENSSL_ALGO_SHA256;
}
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\UnsafeRsa;
use const OPENSSL_ALGO_SHA384;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha384 extends UnsafeRsa
{
public function algorithmId(): string
{
return 'RS384';
}
public function algorithm(): int
{
return OPENSSL_ALGO_SHA384;
}
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer\Rsa;
use Lcobucci\JWT\Signer\UnsafeRsa;
use const OPENSSL_ALGO_SHA512;
/** @deprecated Deprecated since v4.2 */
final class UnsafeSha512 extends UnsafeRsa
{
public function algorithmId(): string
{
return 'RS512';
}
public function algorithm(): int
{
return OPENSSL_ALGO_SHA512;
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter;
use Lcobucci\JWT\Signer\Ecdsa\SignatureConverter;
use const OPENSSL_KEYTYPE_EC;
/** @deprecated Deprecated since v4.2 */
abstract class UnsafeEcdsa extends OpenSSL
{
private SignatureConverter $converter;
public function __construct(SignatureConverter $converter)
{
$this->converter = $converter;
}
public static function create(): UnsafeEcdsa
{
return new static(new MultibyteStringConverter()); // @phpstan-ignore-line
}
final public function sign(string $payload, Key $key): string
{
return $this->converter->fromAsn1(
$this->createSignature($key->contents(), $key->passphrase(), $payload),
$this->pointLength()
);
}
final public function verify(string $expected, string $payload, Key $key): bool
{
return $this->verifySignature(
$this->converter->toAsn1($expected, $this->pointLength()),
$payload,
$key->contents()
);
}
// phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void
{
if ($type !== OPENSSL_KEYTYPE_EC) {
throw InvalidKeyProvided::incompatibleKeyType(
self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_EC],
self::KEY_TYPE_MAP[$type],
);
}
}
/**
* Returns the length of each point in the signature, so that we can calculate and verify R and S points properly
*
* @internal
*/
abstract public function pointLength(): int;
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Signer;
use const OPENSSL_KEYTYPE_RSA;
/** @deprecated Deprecated since v4.2 */
abstract class UnsafeRsa extends OpenSSL
{
final public function sign(string $payload, Key $key): string
{
return $this->createSignature($key->contents(), $key->passphrase(), $payload);
}
final public function verify(string $expected, string $payload, Key $key): bool
{
return $this->verifySignature($expected, $payload, $key->contents());
}
// phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
final protected function guardAgainstIncompatibleKey(int $type, int $lengthInBits): void
{
if ($type !== OPENSSL_KEYTYPE_RSA) {
throw InvalidKeyProvided::incompatibleKeyType(
self::KEY_TYPE_MAP[OPENSSL_KEYTYPE_RSA],
self::KEY_TYPE_MAP[$type],
);
}
}
}

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Lcobucci\JWT\Encoding\CannotDecodeContent;
use SodiumException;
use function base64_decode;
use function base64_encode;
use function function_exists;
use function is_string;
use function rtrim;
use function sodium_base642bin;
use function sodium_bin2base64;
use function strtr;
/** @internal */
final class SodiumBase64Polyfill
{
public const SODIUM_BASE64_VARIANT_ORIGINAL = 1;
public const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
public const SODIUM_BASE64_VARIANT_URLSAFE = 5;
public const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
public static function bin2base64(string $decoded, int $variant): string
{
if (! function_exists('sodium_bin2base64')) {
return self::bin2base64Fallback($decoded, $variant); // @codeCoverageIgnore
}
return sodium_bin2base64($decoded, $variant);
}
public static function bin2base64Fallback(string $decoded, int $variant): string
{
$encoded = base64_encode($decoded);
if (
$variant === self::SODIUM_BASE64_VARIANT_URLSAFE
|| $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
) {
$encoded = strtr($encoded, '+/', '-_');
}
if (
$variant === self::SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING
|| $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
) {
$encoded = rtrim($encoded, '=');
}
return $encoded;
}
/** @throws CannotDecodeContent */
public static function base642bin(string $encoded, int $variant): string
{
if (! function_exists('sodium_base642bin')) {
return self::base642binFallback($encoded, $variant); // @codeCoverageIgnore
}
try {
return sodium_base642bin($encoded, $variant, '');
} catch (SodiumException $sodiumException) {
throw CannotDecodeContent::invalidBase64String();
}
}
/** @throws CannotDecodeContent */
public static function base642binFallback(string $encoded, int $variant): string
{
if (
$variant === self::SODIUM_BASE64_VARIANT_URLSAFE
|| $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
) {
$encoded = strtr($encoded, '-_', '+/');
}
$decoded = base64_decode($encoded, true);
if (! is_string($decoded)) {
throw CannotDecodeContent::invalidBase64String();
}
return $decoded;
}
}

View File

@@ -1,285 +1,55 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
declare(strict_types=1);
namespace Lcobucci\JWT;
use BadMethodCallException;
use DateTime;
use DateTimeInterface;
use Generator;
use Lcobucci\JWT\Claim\Validatable;
use Lcobucci\JWT\Signer\Key;
use OutOfBoundsException;
use Lcobucci\JWT\Token\DataSet;
/**
* Basic structure of the JWT
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 0.1.0
*/
class Token
interface Token
{
/**
* The token headers
*
* @var array
*/
private $headers;
/**
* The token claim set
*
* @var array
*/
private $claims;
/**
* The token signature
*
* @var Signature
*/
private $signature;
/**
* The encoded data
*
* @var array
*/
private $payload;
/**
* Initializes the object
*
* @param array $headers
* @param array $claims
* @param array $payload
* @param Signature $signature
*/
public function __construct(
array $headers = ['alg' => 'none'],
array $claims = [],
Signature $signature = null,
array $payload = ['', '']
) {
$this->headers = $headers;
$this->claims = $claims;
$this->signature = $signature;
$this->payload = $payload;
}
/**
* Returns the token headers
*
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
public function headers(): DataSet;
/**
* Returns if the header is configured
*
* @param string $name
*
* @return boolean
* Returns if the token is allowed to be used by the audience
*/
public function hasHeader($name)
{
return array_key_exists($name, $this->headers);
}
public function isPermittedFor(string $audience): bool;
/**
* Returns the value of a token header
*
* @param string $name
* @param mixed $default
*
* @return mixed
*
* @throws OutOfBoundsException
* Returns if the token has the given id
*/
public function getHeader($name, $default = null)
{
if ($this->hasHeader($name)) {
return $this->getHeaderValue($name);
}
if ($default === null) {
throw new OutOfBoundsException('Requested header is not configured');
}
return $default;
}
public function isIdentifiedBy(string $id): bool;
/**
* Returns the value stored in header
*
* @param string $name
*
* @return mixed
* Returns if the token has the given subject
*/
private function getHeaderValue($name)
{
$header = $this->headers[$name];
if ($header instanceof Claim) {
return $header->getValue();
}
return $header;
}
public function isRelatedTo(string $subject): bool;
/**
* Returns the token claim set
*
* @return array
* Returns if the token was issued by any of given issuers
*/
public function getClaims()
{
return $this->claims;
}
public function hasBeenIssuedBy(string ...$issuers): bool;
/**
* Returns if the claim is configured
*
* @param string $name
*
* @return boolean
* Returns if the token was issued before of given time
*/
public function hasClaim($name)
{
return array_key_exists($name, $this->claims);
}
public function hasBeenIssuedBefore(DateTimeInterface $now): bool;
/**
* Returns the value of a token claim
*
* @param string $name
* @param mixed $default
*
* @return mixed
*
* @throws OutOfBoundsException
* Returns if the token minimum time is before than given time
*/
public function getClaim($name, $default = null)
{
if ($this->hasClaim($name)) {
return $this->claims[$name]->getValue();
}
if ($default === null) {
throw new OutOfBoundsException('Requested claim is not configured');
}
return $default;
}
public function isMinimumTimeBefore(DateTimeInterface $now): bool;
/**
* Verify if the key matches with the one that created the signature
*
* @param Signer $signer
* @param Key|string $key
*
* @return boolean
*
* @throws BadMethodCallException When token is not signed
* Returns if the token is expired
*/
public function verify(Signer $signer, $key)
{
if ($this->signature === null) {
throw new BadMethodCallException('This token is not signed');
}
if ($this->headers['alg'] !== $signer->getAlgorithmId()) {
return false;
}
return $this->signature->verify($signer, $this->getPayload(), $key);
}
/**
* Validates if the token is valid
*
* @param ValidationData $data
*
* @return boolean
*/
public function validate(ValidationData $data)
{
foreach ($this->getValidatableClaims() as $claim) {
if (!$claim->validate($data)) {
return false;
}
}
return true;
}
/**
* Determine if the token is expired.
*
* @param DateTimeInterface $now Defaults to the current time.
*
* @return bool
*/
public function isExpired(DateTimeInterface $now = null)
{
$exp = $this->getClaim('exp', false);
if ($exp === false) {
return false;
}
$now = $now ?: new DateTime();
$expiresAt = new DateTime();
$expiresAt->setTimestamp($exp);
return $now > $expiresAt;
}
/**
* Yields the validatable claims
*
* @return Generator
*/
private function getValidatableClaims()
{
foreach ($this->claims as $claim) {
if ($claim instanceof Validatable) {
yield $claim;
}
}
}
/**
* Returns the token payload
*
* @return string
*/
public function getPayload()
{
return $this->payload[0] . '.' . $this->payload[1];
}
public function isExpired(DateTimeInterface $now): bool;
/**
* Returns an encoded representation of the token
*
* @return string
*/
public function __toString()
{
$data = implode('.', $this->payload);
if ($this->signature === null) {
$data .= '.';
}
return $data;
}
public function toString(): string;
}

View File

@@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
use DateTimeImmutable;
use Lcobucci\JWT\Builder as BuilderInterface;
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Encoder;
use Lcobucci\JWT\Encoding\CannotEncodeContent;
use Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Key;
use function array_diff;
use function array_merge;
use function in_array;
final class Builder implements BuilderInterface
{
/** @var array<string, mixed> */
private array $headers = ['typ' => 'JWT', 'alg' => null];
/** @var array<string, mixed> */
private array $claims = [];
private Encoder $encoder;
private ClaimsFormatter $claimFormatter;
public function __construct(Encoder $encoder, ClaimsFormatter $claimFormatter)
{
$this->encoder = $encoder;
$this->claimFormatter = $claimFormatter;
}
public function permittedFor(string ...$audiences): BuilderInterface
{
$configured = $this->claims[RegisteredClaims::AUDIENCE] ?? [];
$toAppend = array_diff($audiences, $configured);
return $this->setClaim(RegisteredClaims::AUDIENCE, array_merge($configured, $toAppend));
}
public function expiresAt(DateTimeImmutable $expiration): BuilderInterface
{
return $this->setClaim(RegisteredClaims::EXPIRATION_TIME, $expiration);
}
public function identifiedBy(string $id): BuilderInterface
{
return $this->setClaim(RegisteredClaims::ID, $id);
}
public function issuedAt(DateTimeImmutable $issuedAt): BuilderInterface
{
return $this->setClaim(RegisteredClaims::ISSUED_AT, $issuedAt);
}
public function issuedBy(string $issuer): BuilderInterface
{
return $this->setClaim(RegisteredClaims::ISSUER, $issuer);
}
public function canOnlyBeUsedAfter(DateTimeImmutable $notBefore): BuilderInterface
{
return $this->setClaim(RegisteredClaims::NOT_BEFORE, $notBefore);
}
public function relatedTo(string $subject): BuilderInterface
{
return $this->setClaim(RegisteredClaims::SUBJECT, $subject);
}
/** @inheritdoc */
public function withHeader(string $name, $value): BuilderInterface
{
$this->headers[$name] = $value;
return $this;
}
/** @inheritdoc */
public function withClaim(string $name, $value): BuilderInterface
{
if (in_array($name, RegisteredClaims::ALL, true)) {
throw RegisteredClaimGiven::forClaim($name);
}
return $this->setClaim($name, $value);
}
/** @param mixed $value */
private function setClaim(string $name, $value): BuilderInterface
{
$this->claims[$name] = $value;
return $this;
}
/**
* @param array<string, mixed> $items
*
* @throws CannotEncodeContent When data cannot be converted to JSON.
*/
private function encode(array $items): string
{
return $this->encoder->base64UrlEncode(
$this->encoder->jsonEncode($items)
);
}
public function getToken(Signer $signer, Key $key): Plain
{
$headers = $this->headers;
$headers['alg'] = $signer->algorithmId();
$encodedHeaders = $this->encode($headers);
$encodedClaims = $this->encode($this->claimFormatter->formatClaims($this->claims));
$signature = $signer->sign($encodedHeaders . '.' . $encodedClaims, $key);
$encodedSignature = $this->encoder->base64UrlEncode($signature);
return new Plain(
new DataSet($headers, $encodedHeaders),
new DataSet($this->claims, $encodedClaims),
new Signature($signature, $encodedSignature)
);
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
use function array_key_exists;
final class DataSet
{
/** @var array<string, mixed> */
private array $data;
private string $encoded;
/** @param array<string, mixed> $data */
public function __construct(array $data, string $encoded)
{
$this->data = $data;
$this->encoded = $encoded;
}
/**
* @param mixed|null $default
*
* @return mixed|null
*/
public function get(string $name, $default = null)
{
return $this->data[$name] ?? $default;
}
public function has(string $name): bool
{
return array_key_exists($name, $this->data);
}
/** @return array<string, mixed> */
public function all(): array
{
return $this->data;
}
public function toString(): string
{
return $this->encoded;
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class InvalidTokenStructure extends InvalidArgumentException implements Exception
{
public static function missingOrNotEnoughSeparators(): self
{
return new self('The JWT string must have two dots');
}
public static function arrayExpected(string $part): self
{
return new self($part . ' must be an array');
}
public static function dateIsNotParseable(string $value): self
{
return new self('Value is not in the allowed date format: ' . $value);
}
}

154
vendor/lcobucci/jwt/src/Token/Parser.php vendored Normal file
View File

@@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
use DateTimeImmutable;
use Lcobucci\JWT\Decoder;
use Lcobucci\JWT\Parser as ParserInterface;
use Lcobucci\JWT\Token as TokenInterface;
use function array_key_exists;
use function count;
use function explode;
use function is_array;
use function is_numeric;
use function number_format;
final class Parser implements ParserInterface
{
private const MICROSECOND_PRECISION = 6;
private Decoder $decoder;
public function __construct(Decoder $decoder)
{
$this->decoder = $decoder;
}
public function parse(string $jwt): TokenInterface
{
[$encodedHeaders, $encodedClaims, $encodedSignature] = $this->splitJwt($jwt);
$header = $this->parseHeader($encodedHeaders);
return new Plain(
new DataSet($header, $encodedHeaders),
new DataSet($this->parseClaims($encodedClaims), $encodedClaims),
$this->parseSignature($header, $encodedSignature)
);
}
/**
* Splits the JWT string into an array
*
* @return string[]
*
* @throws InvalidTokenStructure When JWT doesn't have all parts.
*/
private function splitJwt(string $jwt): array
{
$data = explode('.', $jwt);
if (count($data) !== 3) {
throw InvalidTokenStructure::missingOrNotEnoughSeparators();
}
return $data;
}
/**
* Parses the header from a string
*
* @return mixed[]
*
* @throws UnsupportedHeaderFound When an invalid header is informed.
* @throws InvalidTokenStructure When parsed content isn't an array.
*/
private function parseHeader(string $data): array
{
$header = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
if (! is_array($header)) {
throw InvalidTokenStructure::arrayExpected('headers');
}
if (array_key_exists('enc', $header)) {
throw UnsupportedHeaderFound::encryption();
}
if (! array_key_exists('typ', $header)) {
$header['typ'] = 'JWT';
}
return $header;
}
/**
* Parses the claim set from a string
*
* @return mixed[]
*
* @throws InvalidTokenStructure When parsed content isn't an array or contains non-parseable dates.
*/
private function parseClaims(string $data): array
{
$claims = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data));
if (! is_array($claims)) {
throw InvalidTokenStructure::arrayExpected('claims');
}
if (array_key_exists(RegisteredClaims::AUDIENCE, $claims)) {
$claims[RegisteredClaims::AUDIENCE] = (array) $claims[RegisteredClaims::AUDIENCE];
}
foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
if (! array_key_exists($claim, $claims)) {
continue;
}
$claims[$claim] = $this->convertDate($claims[$claim]);
}
return $claims;
}
/**
* @param int|float|string $timestamp
*
* @throws InvalidTokenStructure
*/
private function convertDate($timestamp): DateTimeImmutable
{
if (! is_numeric($timestamp)) {
throw InvalidTokenStructure::dateIsNotParseable($timestamp);
}
$normalizedTimestamp = number_format((float) $timestamp, self::MICROSECOND_PRECISION, '.', '');
$date = DateTimeImmutable::createFromFormat('U.u', $normalizedTimestamp);
if ($date === false) {
throw InvalidTokenStructure::dateIsNotParseable($normalizedTimestamp);
}
return $date;
}
/**
* Returns the signature from given data
*
* @param mixed[] $header
*/
private function parseSignature(array $header, string $data): Signature
{
if ($data === '' || ! array_key_exists('alg', $header) || $header['alg'] === 'none') {
return Signature::fromEmptyData();
}
$hash = $this->decoder->base64UrlDecode($data);
return new Signature($hash, $data);
}
}

92
vendor/lcobucci/jwt/src/Token/Plain.php vendored Normal file
View File

@@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
use DateTimeInterface;
use Lcobucci\JWT\UnencryptedToken;
use function in_array;
final class Plain implements UnencryptedToken
{
private DataSet $headers;
private DataSet $claims;
private Signature $signature;
public function __construct(
DataSet $headers,
DataSet $claims,
Signature $signature
) {
$this->headers = $headers;
$this->claims = $claims;
$this->signature = $signature;
}
public function headers(): DataSet
{
return $this->headers;
}
public function claims(): DataSet
{
return $this->claims;
}
public function signature(): Signature
{
return $this->signature;
}
public function payload(): string
{
return $this->headers->toString() . '.' . $this->claims->toString();
}
public function isPermittedFor(string $audience): bool
{
return in_array($audience, $this->claims->get(RegisteredClaims::AUDIENCE, []), true);
}
public function isIdentifiedBy(string $id): bool
{
return $this->claims->get(RegisteredClaims::ID) === $id;
}
public function isRelatedTo(string $subject): bool
{
return $this->claims->get(RegisteredClaims::SUBJECT) === $subject;
}
public function hasBeenIssuedBy(string ...$issuers): bool
{
return in_array($this->claims->get(RegisteredClaims::ISSUER), $issuers, true);
}
public function hasBeenIssuedBefore(DateTimeInterface $now): bool
{
return $now >= $this->claims->get(RegisteredClaims::ISSUED_AT);
}
public function isMinimumTimeBefore(DateTimeInterface $now): bool
{
return $now >= $this->claims->get(RegisteredClaims::NOT_BEFORE);
}
public function isExpired(DateTimeInterface $now): bool
{
if (! $this->claims->has(RegisteredClaims::EXPIRATION_TIME)) {
return false;
}
return $now >= $this->claims->get(RegisteredClaims::EXPIRATION_TIME);
}
public function toString(): string
{
return $this->headers->toString() . '.'
. $this->claims->toString() . '.'
. $this->signature->toString();
}
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
use function sprintf;
final class RegisteredClaimGiven extends InvalidArgumentException implements Exception
{
private const DEFAULT_MESSAGE = 'Builder#withClaim() is meant to be used for non-registered claims, '
. 'check the documentation on how to set claim "%s"';
public static function forClaim(string $name): self
{
return new self(sprintf(self::DEFAULT_MESSAGE, $name));
}
}

View File

@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
/**
* Defines the list of claims that are registered in the IANA "JSON Web Token Claims" registry
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1
*/
interface RegisteredClaims
{
public const ALL = [
self::AUDIENCE,
self::EXPIRATION_TIME,
self::ID,
self::ISSUED_AT,
self::ISSUER,
self::NOT_BEFORE,
self::SUBJECT,
];
public const DATE_CLAIMS = [
self::ISSUED_AT,
self::NOT_BEFORE,
self::EXPIRATION_TIME,
];
/**
* Identifies the recipients that the JWT is intended for
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.3
*/
public const AUDIENCE = 'aud';
/**
* Identifies the expiration time on or after which the JWT MUST NOT be accepted for processing
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.4
*/
public const EXPIRATION_TIME = 'exp';
/**
* Provides a unique identifier for the JWT
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.7
*/
public const ID = 'jti';
/**
* Identifies the time at which the JWT was issued
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.6
*/
public const ISSUED_AT = 'iat';
/**
* Identifies the principal that issued the JWT
*
* @see https://tools.ietf.org/html/rfc7519#section-4.1.1
*/
public const ISSUER = 'iss';
/**
* Identifies the time before which the JWT MUST NOT be accepted for processing
*
* https://tools.ietf.org/html/rfc7519#section-4.1.5
*/
public const NOT_BEFORE = 'nbf';
/**
* Identifies the principal that is the subject of the JWT.
*
* https://tools.ietf.org/html/rfc7519#section-4.1.2
*/
public const SUBJECT = 'sub';
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
final class Signature
{
private string $hash;
private string $encoded;
public function __construct(string $hash, string $encoded)
{
$this->hash = $hash;
$this->encoded = $encoded;
}
/** @deprecated Deprecated since v4.3 */
public static function fromEmptyData(): self
{
return new self('', '');
}
public function hash(): string
{
return $this->hash;
}
/**
* Returns the encoded version of the signature
*/
public function toString(): string
{
return $this->encoded;
}
}

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Token;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class UnsupportedHeaderFound extends InvalidArgumentException implements Exception
{
public static function encryption(): self
{
return new self('Encryption is not supported yet');
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Lcobucci\JWT\Token\DataSet;
use Lcobucci\JWT\Token\Signature;
interface UnencryptedToken extends Token
{
/**
* Returns the token claims
*/
public function claims(): DataSet;
/**
* Returns the token signature
*/
public function signature(): Signature;
/**
* Returns the token payload
*/
public function payload(): string;
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation;
use Lcobucci\JWT\Token;
interface Constraint
{
/** @throws ConstraintViolation */
public function assert(Token $token): void;
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class CannotValidateARegisteredClaim extends InvalidArgumentException implements Exception
{
public static function create(string $claim): self
{
return new self(
'The claim "' . $claim . '" is a registered claim, another constraint must be used to validate its value'
);
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\UnencryptedToken;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
use function in_array;
final class HasClaimWithValue implements Constraint
{
private string $claim;
/** @var mixed */
private $expectedValue;
/** @param mixed $expectedValue */
public function __construct(string $claim, $expectedValue)
{
if (in_array($claim, Token\RegisteredClaims::ALL, true)) {
throw CannotValidateARegisteredClaim::create($claim);
}
$this->claim = $claim;
$this->expectedValue = $expectedValue;
}
public function assert(Token $token): void
{
if (! $token instanceof UnencryptedToken) {
throw ConstraintViolation::error('You should pass a plain token', $this);
}
$claims = $token->claims();
if (! $claims->has($this->claim)) {
throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this);
}
if ($claims->get($this->claim) !== $this->expectedValue) {
throw ConstraintViolation::error(
'The claim "' . $this->claim . '" does not have the expected value',
$this
);
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
final class IdentifiedBy implements Constraint
{
private string $id;
public function __construct(string $id)
{
$this->id = $id;
}
public function assert(Token $token): void
{
if (! $token->isIdentifiedBy($this->id)) {
throw ConstraintViolation::error(
'The token is not identified with the expected ID',
$this
);
}
}
}

View File

@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
final class IssuedBy implements Constraint
{
/** @var string[] */
private array $issuers;
public function __construct(string ...$issuers)
{
$this->issuers = $issuers;
}
public function assert(Token $token): void
{
if (! $token->hasBeenIssuedBy(...$this->issuers)) {
throw ConstraintViolation::error(
'The token was not issued by the given issuers',
$this
);
}
}
}

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use InvalidArgumentException;
use Lcobucci\JWT\Exception;
final class LeewayCannotBeNegative extends InvalidArgumentException implements Exception
{
public static function create(): self
{
return new self('Leeway cannot be negative');
}
}

View File

@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use DateInterval;
use DateTimeInterface;
use Lcobucci\Clock\Clock;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\ConstraintViolation;
use Lcobucci\JWT\Validation\ValidAt as ValidAtInterface;
final class LooseValidAt implements ValidAtInterface
{
private Clock $clock;
private DateInterval $leeway;
public function __construct(Clock $clock, ?DateInterval $leeway = null)
{
$this->clock = $clock;
$this->leeway = $this->guardLeeway($leeway);
}
private function guardLeeway(?DateInterval $leeway): DateInterval
{
if ($leeway === null) {
return new DateInterval('PT0S');
}
if ($leeway->invert === 1) {
throw LeewayCannotBeNegative::create();
}
return $leeway;
}
public function assert(Token $token): void
{
$now = $this->clock->now();
$this->assertIssueTime($token, $now->add($this->leeway));
$this->assertMinimumTime($token, $now->add($this->leeway));
$this->assertExpiration($token, $now->sub($this->leeway));
}
/** @throws ConstraintViolation */
private function assertExpiration(Token $token, DateTimeInterface $now): void
{
if ($token->isExpired($now)) {
throw ConstraintViolation::error('The token is expired', $this);
}
}
/** @throws ConstraintViolation */
private function assertMinimumTime(Token $token, DateTimeInterface $now): void
{
if (! $token->isMinimumTimeBefore($now)) {
throw ConstraintViolation::error('The token cannot be used yet', $this);
}
}
/** @throws ConstraintViolation */
private function assertIssueTime(Token $token, DateTimeInterface $now): void
{
if (! $token->hasBeenIssuedBefore($now)) {
throw ConstraintViolation::error('The token was issued in the future', $this);
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
final class PermittedFor implements Constraint
{
private string $audience;
public function __construct(string $audience)
{
$this->audience = $audience;
}
public function assert(Token $token): void
{
if (! $token->isPermittedFor($this->audience)) {
throw ConstraintViolation::error(
'The token is not allowed to be used by this audience',
$this
);
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
final class RelatedTo implements Constraint
{
private string $subject;
public function __construct(string $subject)
{
$this->subject = $subject;
}
public function assert(Token $token): void
{
if (! $token->isRelatedTo($this->subject)) {
throw ConstraintViolation::error(
'The token is not related to the expected subject',
$this
);
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Signer;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\UnencryptedToken;
use Lcobucci\JWT\Validation\ConstraintViolation;
use Lcobucci\JWT\Validation\SignedWith as SignedWithInterface;
final class SignedWith implements SignedWithInterface
{
private Signer $signer;
private Signer\Key $key;
public function __construct(Signer $signer, Signer\Key $key)
{
$this->signer = $signer;
$this->key = $key;
}
public function assert(Token $token): void
{
if (! $token instanceof UnencryptedToken) {
throw ConstraintViolation::error('You should pass a plain token', $this);
}
if ($token->headers()->get('alg') !== $this->signer->algorithmId()) {
throw ConstraintViolation::error('Token signer mismatch', $this);
}
if (! $this->signer->verify($token->signature()->hash(), $token->payload(), $this->key)) {
throw ConstraintViolation::error('Token signature mismatch', $this);
}
}
}

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use DateInterval;
use DateTimeInterface;
use Lcobucci\Clock\Clock;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\UnencryptedToken;
use Lcobucci\JWT\Validation\ConstraintViolation;
use Lcobucci\JWT\Validation\ValidAt as ValidAtInterface;
final class StrictValidAt implements ValidAtInterface
{
private Clock $clock;
private DateInterval $leeway;
public function __construct(Clock $clock, ?DateInterval $leeway = null)
{
$this->clock = $clock;
$this->leeway = $this->guardLeeway($leeway);
}
private function guardLeeway(?DateInterval $leeway): DateInterval
{
if ($leeway === null) {
return new DateInterval('PT0S');
}
if ($leeway->invert === 1) {
throw LeewayCannotBeNegative::create();
}
return $leeway;
}
public function assert(Token $token): void
{
if (! $token instanceof UnencryptedToken) {
throw ConstraintViolation::error('You should pass a plain token', $this);
}
$now = $this->clock->now();
$this->assertIssueTime($token, $now->add($this->leeway));
$this->assertMinimumTime($token, $now->add($this->leeway));
$this->assertExpiration($token, $now->sub($this->leeway));
}
/** @throws ConstraintViolation */
private function assertExpiration(UnencryptedToken $token, DateTimeInterface $now): void
{
if (! $token->claims()->has(Token\RegisteredClaims::EXPIRATION_TIME)) {
throw ConstraintViolation::error('"Expiration Time" claim missing', $this);
}
if ($token->isExpired($now)) {
throw ConstraintViolation::error('The token is expired', $this);
}
}
/** @throws ConstraintViolation */
private function assertMinimumTime(UnencryptedToken $token, DateTimeInterface $now): void
{
if (! $token->claims()->has(Token\RegisteredClaims::NOT_BEFORE)) {
throw ConstraintViolation::error('"Not Before" claim missing', $this);
}
if (! $token->isMinimumTimeBefore($now)) {
throw ConstraintViolation::error('The token cannot be used yet', $this);
}
}
/** @throws ConstraintViolation */
private function assertIssueTime(UnencryptedToken $token, DateTimeInterface $now): void
{
if (! $token->claims()->has(Token\RegisteredClaims::ISSUED_AT)) {
throw ConstraintViolation::error('"Issued At" claim missing', $this);
}
if (! $token->hasBeenIssuedBefore($now)) {
throw ConstraintViolation::error('The token was issued in the future', $this);
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use DateInterval;
use Lcobucci\Clock\Clock;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\Validation\Constraint;
/** @deprecated Use \Lcobucci\JWT\Validation\Constraint\LooseValidAt */
final class ValidAt implements Constraint
{
private LooseValidAt $constraint;
public function __construct(Clock $clock, ?DateInterval $leeway = null)
{
$this->constraint = new LooseValidAt($clock, $leeway);
}
public function assert(Token $token): void
{
$this->constraint->assert($token);
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation;
use Lcobucci\JWT\Exception;
use RuntimeException;
use function get_class;
final class ConstraintViolation extends RuntimeException implements Exception
{
/**
* @readonly
* @var class-string<Constraint>|null
*/
public ?string $constraint = null;
public static function error(string $message, Constraint $constraint): self
{
$exception = new self($message);
$exception->constraint = get_class($constraint);
return $exception;
}
}

View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation;
use Lcobucci\JWT\Exception;
use RuntimeException;
final class NoConstraintsGiven extends RuntimeException implements Exception
{
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation;
use Lcobucci\JWT\Exception;
use RuntimeException;
use function array_map;
use function implode;
final class RequiredConstraintsViolated extends RuntimeException implements Exception
{
/** @var ConstraintViolation[] */
private array $violations = [];
public static function fromViolations(ConstraintViolation ...$violations): self
{
$exception = new self(self::buildMessage($violations));
$exception->violations = $violations;
return $exception;
}
/** @param ConstraintViolation[] $violations */
private static function buildMessage(array $violations): string
{
$violations = array_map(
static function (ConstraintViolation $violation): string {
return '- ' . $violation->getMessage();
},
$violations
);
$message = "The token violates some mandatory constraints, details:\n";
$message .= implode("\n", $violations);
return $message;
}
/** @return ConstraintViolation[] */
public function violations(): array
{
return $this->violations;
}
}

View File

@@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation;
interface SignedWith extends Constraint
{
}

View File

@@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation;
interface ValidAt extends Constraint
{
}

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation;
use Lcobucci\JWT\Token;
final class Validator implements \Lcobucci\JWT\Validator
{
public function assert(Token $token, Constraint ...$constraints): void
{
if ($constraints === []) {
throw new NoConstraintsGiven('No constraint given.');
}
$violations = [];
foreach ($constraints as $constraint) {
$this->checkConstraint($constraint, $token, $violations);
}
if ($violations) {
throw RequiredConstraintsViolated::fromViolations(...$violations);
}
}
/** @param ConstraintViolation[] $violations */
private function checkConstraint(
Constraint $constraint,
Token $token,
array &$violations
): void {
try {
$constraint->assert($token);
} catch (ConstraintViolation $e) {
$violations[] = $e;
}
}
public function validate(Token $token, Constraint ...$constraints): bool
{
if ($constraints === []) {
throw new NoConstraintsGiven('No constraint given.');
}
try {
foreach ($constraints as $constraint) {
$constraint->assert($token);
}
return true;
} catch (ConstraintViolation $e) {
return false;
}
}
}

View File

@@ -1,129 +0,0 @@
<?php
/**
* This file is part of Lcobucci\JWT, a simple library to handle JWT and JWS
*
* @license http://opensource.org/licenses/BSD-3-Clause BSD-3-Clause
*/
namespace Lcobucci\JWT;
/**
* Class that wraps validation values
*
* @author Luís Otávio Cobucci Oblonczyk <lcobucci@gmail.com>
* @since 2.0.0
*/
class ValidationData
{
/**
* The list of things to be validated
*
* @var array
*/
private $items;
/**
* The leeway (in seconds) to use when validating time claims
* @var int
*/
private $leeway;
/**
* Initializes the object
*
* @param int $currentTime
* @param int $leeway
*/
public function __construct($currentTime = null, $leeway = 0)
{
$currentTime = $currentTime ?: time();
$this->leeway = (int) $leeway;
$this->items = [
'jti' => null,
'iss' => null,
'aud' => null,
'sub' => null
];
$this->setCurrentTime($currentTime);
}
/**
* Configures the id
*
* @param string $id
*/
public function setId($id)
{
$this->items['jti'] = (string) $id;
}
/**
* Configures the issuer
*
* @param string $issuer
*/
public function setIssuer($issuer)
{
$this->items['iss'] = (string) $issuer;
}
/**
* Configures the audience
*
* @param string $audience
*/
public function setAudience($audience)
{
$this->items['aud'] = (string) $audience;
}
/**
* Configures the subject
*
* @param string $subject
*/
public function setSubject($subject)
{
$this->items['sub'] = (string) $subject;
}
/**
* Configures the time that "iat", "nbf" and "exp" should be based on
*
* @param int $currentTime
*/
public function setCurrentTime($currentTime)
{
$currentTime = (int) $currentTime;
$this->items['iat'] = $currentTime + $this->leeway;
$this->items['nbf'] = $currentTime + $this->leeway;
$this->items['exp'] = $currentTime - $this->leeway;
}
/**
* Returns the requested item
*
* @param string $name
*
* @return mixed
*/
public function get($name)
{
return isset($this->items[$name]) ? $this->items[$name] : null;
}
/**
* Returns if the item is present
*
* @param string $name
*
* @return boolean
*/
public function has($name)
{
return !empty($this->items[$name]);
}
}

20
vendor/lcobucci/jwt/src/Validator.php vendored Normal file
View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Lcobucci\JWT;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\NoConstraintsGiven;
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
interface Validator
{
/**
* @throws RequiredConstraintsViolated
* @throws NoConstraintsGiven
*/
public function assert(Token $token, Constraint ...$constraints): void;
/** @throws NoConstraintsGiven */
public function validate(Token $token, Constraint ...$constraints): bool;
}