-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
numelion
committed
Oct 19, 2022
1 parent
ab5d7e0
commit 11eaeee
Showing
12 changed files
with
1,038 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Ignore all test and documentation for archive | ||
/.gitattributes export-ignore | ||
/.gitignore export-ignore | ||
/.travis.yml export-ignore | ||
/phpunit.xml.dist export-ignore | ||
/tests export-ignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# phpstorm project files | ||
.idea | ||
|
||
# netbeans project files | ||
nbproject | ||
|
||
# zend studio for eclipse project files | ||
.buildpath | ||
.project | ||
.settings | ||
|
||
# windows thumbnail cache | ||
Thumbs.db | ||
|
||
# composer vendor dir | ||
/vendor | ||
|
||
/composer.lock | ||
|
||
# composer itself is not needed | ||
composer.phar | ||
|
||
# Mac DS_Store Files | ||
.DS_Store | ||
|
||
# phpunit itself is not needed | ||
phpunit.phar | ||
# local phpunit config | ||
/phpunit.xml | ||
|
||
# local tests configuration | ||
/tests/data/config.local.php | ||
|
||
# runtime cache | ||
/tests/runtime |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
language: php | ||
|
||
php: | ||
- 5.6 | ||
- 7.0 | ||
- 7.1 | ||
- 7.2 | ||
- 8.0 | ||
- 8.1 | ||
|
||
# faster builds on new travis setup not using sudo | ||
sudo: false | ||
|
||
install: | ||
# - composer global require "fxp/composer-asset-plugin:~1.4.4" | ||
- export PATH="$HOME/.composer/vendor/bin:$PATH" | ||
- composer install --prefer-dist --no-interaction | ||
|
||
#script: | ||
# - phpunit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
<?php | ||
|
||
namespace numelion\jwt; | ||
|
||
use Lcobucci\JWT\Builder; | ||
use Lcobucci\JWT\Claim\Factory as ClaimFactory; | ||
use Lcobucci\JWT\Parser; | ||
use Lcobucci\JWT\Parsing\Decoder; | ||
use Lcobucci\JWT\Parsing\Encoder; | ||
use Lcobucci\JWT\Signer; | ||
use Lcobucci\JWT\Signer\Key; | ||
use Lcobucci\JWT\Token; | ||
use Lcobucci\JWT\ValidationData; | ||
use Yii; | ||
use yii\base\Component; | ||
use yii\base\InvalidArgumentException; | ||
|
||
/** | ||
* JSON Web Token implementation, based on this library: | ||
* https://github.com/lcobucci/jwt | ||
* | ||
* @author Dmitriy Demin <[email protected]> | ||
* @since 1.0.0-a | ||
*/ | ||
class Jwt extends Component | ||
{ | ||
|
||
/** | ||
* @var array Supported algorithms | ||
*/ | ||
public $supportedAlgs = [ | ||
'HS256' => \Lcobucci\JWT\Signer\Hmac\Sha256::class, | ||
'HS384' => \Lcobucci\JWT\Signer\Hmac\Sha384::class, | ||
'HS512' => \Lcobucci\JWT\Signer\Hmac\Sha512::class, | ||
'ES256' => \Lcobucci\JWT\Signer\Ecdsa\Sha256::class, | ||
'ES384' => \Lcobucci\JWT\Signer\Ecdsa\Sha384::class, | ||
'ES512' => \Lcobucci\JWT\Signer\Ecdsa\Sha512::class, | ||
'RS256' => \Lcobucci\JWT\Signer\Rsa\Sha256::class, | ||
'RS384' => \Lcobucci\JWT\Signer\Rsa\Sha384::class, | ||
'RS512' => \Lcobucci\JWT\Signer\Rsa\Sha512::class, | ||
]; | ||
|
||
/** | ||
* @var Key|string $key The key | ||
*/ | ||
public $key; | ||
|
||
/** | ||
* @var string|array|callable \numelion\jwtJwtValidationData | ||
* @see [[Yii::createObject()]] | ||
*/ | ||
public $jwtValidationData = JwtValidationData::class; | ||
|
||
/** | ||
* @see [[Lcobucci\JWT\Builder::__construct()]] | ||
* @param Encoder|null $encoder | ||
* @param ClaimFactory|null $claimFactory | ||
* @return Builder | ||
*/ | ||
public function getBuilder(Encoder $encoder = null, ClaimFactory $claimFactory = null) | ||
{ | ||
return new Builder($encoder, $claimFactory); | ||
} | ||
|
||
/** | ||
* @see [[Lcobucci\JWT\Parser::__construct()]] | ||
* @param Decoder|null $decoder | ||
* @param ClaimFactory|null $claimFactory | ||
* @return Parser | ||
*/ | ||
public function getParser(Decoder $decoder = null, ClaimFactory $claimFactory = null) | ||
{ | ||
return new Parser($decoder, $claimFactory); | ||
} | ||
|
||
/** | ||
* @see [[Lcobucci\JWT\ValidationData::__construct()]] | ||
* @return ValidationData | ||
*/ | ||
public function getValidationData() | ||
{ | ||
return Yii::createObject($this->jwtValidationData)->getValidationData(); | ||
} | ||
|
||
/** | ||
* @param string $alg | ||
* @return Signer | ||
*/ | ||
public function getSigner($alg) | ||
{ | ||
$class = $this->supportedAlgs[$alg]; | ||
|
||
return new $class(); | ||
} | ||
|
||
/** | ||
* @param strng $content | ||
* @param string|null $passphrase | ||
* @return Key | ||
*/ | ||
public function getKey($content = null, $passphrase = null) | ||
{ | ||
$content = $content ?: $this->key; | ||
|
||
if ($content instanceof Key) { | ||
return $content; | ||
} | ||
|
||
return new Key($content, $passphrase); | ||
} | ||
|
||
/** | ||
* Parses the JWT and returns a token class | ||
* @param string $token JWT | ||
* @param bool $validate | ||
* @param bool $verify | ||
* @return Token|null | ||
* @throws \Throwable | ||
*/ | ||
public function loadToken($token, $validate = true, $verify = true) | ||
{ | ||
try { | ||
$token = $this->getParser()->parse((string) $token); | ||
} catch (\RuntimeException $e) { | ||
Yii::warning('Invalid JWT provided: ' . $e->getMessage(), 'jwt'); | ||
return null; | ||
} catch (\InvalidArgumentException $e) { | ||
Yii::warning('Invalid JWT provided: ' . $e->getMessage(), 'jwt'); | ||
return null; | ||
} | ||
|
||
if ($validate && !$this->validateToken($token)) { | ||
return null; | ||
} | ||
|
||
if ($verify && !$this->verifyToken($token)) { | ||
return null; | ||
} | ||
|
||
return $token; | ||
} | ||
|
||
/** | ||
* Validate token | ||
* @param Token $token token object | ||
* @param int|null $currentTime | ||
* @return bool | ||
*/ | ||
public function validateToken(Token $token, $currentTime = null) | ||
{ | ||
$validationData = $this->getValidationData(); | ||
if ($currentTime !== null) { | ||
$validationData->setCurrentTime($currentTime); | ||
} | ||
return $token->validate($validationData); | ||
} | ||
|
||
/** | ||
* Validate token | ||
* @param Token $token token object | ||
* @return bool | ||
* @throws \Throwable | ||
*/ | ||
public function verifyToken(Token $token) | ||
{ | ||
$alg = $token->getHeader('alg'); | ||
|
||
if (empty($this->supportedAlgs[$alg])) { | ||
throw new InvalidArgumentException('Algorithm not supported'); | ||
} | ||
|
||
/** @var Signer $signer */ | ||
$signer = Yii::createObject($this->supportedAlgs[$alg]); | ||
|
||
return $token->verify($signer, $this->key); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<?php | ||
|
||
namespace numelion\jwt; | ||
|
||
use yii\di\Instance; | ||
use yii\filters\auth\AuthMethod; | ||
|
||
/** | ||
* JwtHttpBearerAuth is an action filter that supports the authentication method based on JSON Web Token. | ||
* | ||
* You may use JwtHttpBearerAuth by attaching it as a behavior to a controller or module, like the following: | ||
* | ||
* ```php | ||
* public function behaviors() | ||
* { | ||
* return [ | ||
* 'bearerAuth' => [ | ||
* 'class' => \numelion\jwt\JwtHttpBearerAuth::className(), | ||
* ], | ||
* ]; | ||
* } | ||
* ``` | ||
* | ||
* @author Dmitriy Demin <[email protected]> | ||
* @since 1.0.0-a | ||
*/ | ||
class JwtHttpBearerAuth extends AuthMethod | ||
{ | ||
|
||
/** | ||
* @var Jwt|string|array the [[Jwt]] object or the application component ID of the [[Jwt]]. | ||
*/ | ||
public $jwt = 'jwt'; | ||
|
||
/** | ||
* @var string A "realm" attribute MAY be included to indicate the scope | ||
* of protection in the manner described in HTTP/1.1 [RFC2617]. The "realm" | ||
* attribute MUST NOT appear more than once. | ||
*/ | ||
public $realm = 'api'; | ||
|
||
/** | ||
* @var string Authorization header schema, default 'Bearer' | ||
*/ | ||
public $schema = 'Bearer'; | ||
|
||
/** | ||
* @var callable a PHP callable that will authenticate the user with the JWT payload information | ||
* | ||
* ```php | ||
* function ($token, $authMethod) { | ||
* return \app\models\User::findOne($token->getClaim('id')); | ||
* } | ||
* ``` | ||
* | ||
* If this property is not set, the username information will be considered as an access token | ||
* while the password information will be ignored. The [[\yii\web\User::loginByAccessToken()]] | ||
* method will be called to authenticate and login the user. | ||
*/ | ||
public $auth; | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
public function init() | ||
{ | ||
parent::init(); | ||
$this->jwt = Instance::ensure($this->jwt, Jwt::className()); | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
public function authenticate($user, $request, $response) | ||
{ | ||
$authHeader = $request->getHeaders()->get('Authorization'); | ||
if ($authHeader !== null && preg_match('/^' . $this->schema . '\s+(.*?)$/', $authHeader, $matches)) { | ||
$token = $this->loadToken($matches[1]); | ||
if ($token === null) { | ||
return null; | ||
} | ||
|
||
if ($this->auth) { | ||
$identity = call_user_func($this->auth, $token, get_class($this)); | ||
} else { | ||
$identity = $user->loginByAccessToken($token, get_class($this)); | ||
} | ||
|
||
return $identity; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
public function challenge($response) | ||
{ | ||
$response->getHeaders()->set( | ||
'WWW-Authenticate', | ||
"{$this->schema} realm=\"{$this->realm}\", error=\"invalid_token\", error_description=\"The access token invalid or expired\"" | ||
); | ||
} | ||
|
||
/** | ||
* Parses the JWT and returns a token class | ||
* @param string $token JWT | ||
* @return Token|null | ||
*/ | ||
public function loadToken($token) | ||
{ | ||
return $this->jwt->loadToken($token); | ||
} | ||
} |
Oops, something went wrong.