mirror of
https://github.com/elyby/accounts.git
synced 2025-02-20 17:27:56 +05:30
Added jwt public and private key path params to user component
This commit is contained in:
parent
3f9ee42539
commit
445c234360
@ -7,8 +7,8 @@ EMAILS_RENDERER_HOST=http://emails-renderer:3000
|
|||||||
|
|
||||||
## Security params
|
## Security params
|
||||||
JWT_USER_SECRET=
|
JWT_USER_SECRET=
|
||||||
JWT_PUBLIC_KEY=
|
JWT_PUBLIC_KEY_PATH=
|
||||||
JWT_PRIVATE_KEY=
|
JWT_PRIVATE_KEY_PATH=
|
||||||
|
|
||||||
## External services
|
## External services
|
||||||
RECAPTCHA_PUBLIC=
|
RECAPTCHA_PUBLIC=
|
||||||
|
@ -11,6 +11,7 @@ use Emarref\Jwt\Algorithm\AlgorithmInterface;
|
|||||||
use Emarref\Jwt\Algorithm\Hs256;
|
use Emarref\Jwt\Algorithm\Hs256;
|
||||||
use Emarref\Jwt\Algorithm\Rs256;
|
use Emarref\Jwt\Algorithm\Rs256;
|
||||||
use Emarref\Jwt\Claim;
|
use Emarref\Jwt\Claim;
|
||||||
|
use Emarref\Jwt\Encryption\EncryptionInterface;
|
||||||
use Emarref\Jwt\Encryption\Factory as EncryptionFactory;
|
use Emarref\Jwt\Encryption\Factory as EncryptionFactory;
|
||||||
use Emarref\Jwt\Exception\VerificationException;
|
use Emarref\Jwt\Exception\VerificationException;
|
||||||
use Emarref\Jwt\HeaderParameter\Custom;
|
use Emarref\Jwt\HeaderParameter\Custom;
|
||||||
@ -46,14 +47,18 @@ class Component extends YiiUserComponent {
|
|||||||
|
|
||||||
public $secret;
|
public $secret;
|
||||||
|
|
||||||
public $publicKey;
|
public $publicKeyPath;
|
||||||
|
|
||||||
public $privateKey;
|
public $privateKeyPath;
|
||||||
|
|
||||||
public $expirationTimeout = 'PT1H';
|
public $expirationTimeout = 'PT1H';
|
||||||
|
|
||||||
public $sessionTimeout = 'P7D';
|
public $sessionTimeout = 'P7D';
|
||||||
|
|
||||||
|
private $publicKey;
|
||||||
|
|
||||||
|
private $privateKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Token[]
|
* @var Token[]
|
||||||
*/
|
*/
|
||||||
@ -62,16 +67,28 @@ class Component extends YiiUserComponent {
|
|||||||
public function init() {
|
public function init() {
|
||||||
parent::init();
|
parent::init();
|
||||||
Assert::notEmpty($this->secret, 'secret must be specified');
|
Assert::notEmpty($this->secret, 'secret must be specified');
|
||||||
Assert::notEmpty($this->publicKey, 'public key must be specified');
|
Assert::notEmpty($this->publicKeyPath, 'public key path must be specified');
|
||||||
Assert::notEmpty($this->privateKey, 'private key must be specified');
|
Assert::notEmpty($this->privateKeyPath, 'private key path must be specified');
|
||||||
|
}
|
||||||
|
|
||||||
if (!($this->publicKey = file_get_contents($this->publicKey))) {
|
public function getPublicKey() {
|
||||||
throw new InvalidConfigException('invalid public key');
|
if (empty($this->publicKey)) {
|
||||||
|
if (!($this->publicKey = file_get_contents($this->publicKeyPath))) {
|
||||||
|
throw new InvalidConfigException('invalid public key path');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!($this->privateKey = file_get_contents($this->privateKey))) {
|
return $this->publicKey;
|
||||||
throw new InvalidConfigException('invalid private key');
|
}
|
||||||
|
|
||||||
|
public function getPrivateKey() {
|
||||||
|
if (empty($this->privateKey)) {
|
||||||
|
if (!($this->privateKey = file_get_contents($this->privateKeyPath))) {
|
||||||
|
throw new InvalidConfigException('invalid private key path');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findIdentityByAccessToken($accessToken): ?IdentityInterface {
|
public function findIdentityByAccessToken($accessToken): ?IdentityInterface {
|
||||||
@ -153,16 +170,9 @@ class Component extends YiiUserComponent {
|
|||||||
throw new VerificationException('Incorrect token encoding', 0, $e);
|
throw new VerificationException('Incorrect token encoding', 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$algorithm = $this->getAlgorithm();
|
|
||||||
$version = $notVerifiedToken->getHeader()->findParameterByName('v');
|
$version = $notVerifiedToken->getHeader()->findParameterByName('v');
|
||||||
if ($version === null) {
|
$version = $version ? $version->getValue() : null;
|
||||||
$algorithm = new Hs256($this->secret);
|
$encryption = $this->getEncryption($version);
|
||||||
}
|
|
||||||
|
|
||||||
$encryption = EncryptionFactory::create($algorithm);
|
|
||||||
if ($version !== null) {
|
|
||||||
$encryption->setPublicKey($this->publicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
$context = new VerificationContext($encryption);
|
$context = new VerificationContext($encryption);
|
||||||
$context->setSubject(self::JWT_SUBJECT_PREFIX);
|
$context->setSubject(self::JWT_SUBJECT_PREFIX);
|
||||||
@ -234,8 +244,19 @@ class Component extends YiiUserComponent {
|
|||||||
return new Rs256();
|
return new Rs256();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEncryption(?int $version): EncryptionInterface {
|
||||||
|
$algorithm = $version ? new Rs256() : new Hs256($this->secret);
|
||||||
|
$encryption = EncryptionFactory::create($algorithm);
|
||||||
|
|
||||||
|
if ($version) {
|
||||||
|
$encryption->setPublicKey($this->getPublicKey())->setPrivateKey($this->getPrivateKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $encryption;
|
||||||
|
}
|
||||||
|
|
||||||
protected function serializeToken(Token $token): string {
|
protected function serializeToken(Token $token): string {
|
||||||
$encryption = EncryptionFactory::create($this->getAlgorithm())->setPrivateKey($this->privateKey);
|
$encryption = $this->getEncryption(1);
|
||||||
|
|
||||||
return (new Jwt())->serialize($token, $encryption);
|
return (new Jwt())->serialize($token, $encryption);
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@ return [
|
|||||||
'user' => [
|
'user' => [
|
||||||
'class' => api\components\User\Component::class,
|
'class' => api\components\User\Component::class,
|
||||||
'secret' => getenv('JWT_USER_SECRET'),
|
'secret' => getenv('JWT_USER_SECRET'),
|
||||||
'publicKey' => getenv('JWT_PUBLIC_KEY') ?: '/data/certs/public.crt',
|
'publicKeyPath' => getenv('JWT_PUBLIC_KEY') ?: 'data/certs/public.crt',
|
||||||
'privateKey' => getenv('JWT_PRIVATE_KEY') ?: '/data/certs/private.key',
|
'privateKeyPath' => getenv('JWT_PRIVATE_KEY') ?: 'data/certs/private.key',
|
||||||
],
|
],
|
||||||
'log' => [
|
'log' => [
|
||||||
'traceLevel' => YII_DEBUG ? 3 : 0,
|
'traceLevel' => YII_DEBUG ? 3 : 0,
|
||||||
|
@ -189,8 +189,8 @@ class ComponentTest extends TestCase {
|
|||||||
'enableSession' => false,
|
'enableSession' => false,
|
||||||
'loginUrl' => null,
|
'loginUrl' => null,
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,8 +63,8 @@ class LogoutFormTest extends TestCase {
|
|||||||
'enableSession' => false,
|
'enableSession' => false,
|
||||||
'loginUrl' => null,
|
'loginUrl' => null,
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +61,8 @@ class ChangePasswordFormTest extends TestCase {
|
|||||||
'enableSession' => false,
|
'enableSession' => false,
|
||||||
'loginUrl' => null,
|
'loginUrl' => null,
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
]]);
|
]]);
|
||||||
$component->shouldNotReceive('terminateSessions');
|
$component->shouldNotReceive('terminateSessions');
|
||||||
|
|
||||||
@ -123,8 +123,8 @@ class ChangePasswordFormTest extends TestCase {
|
|||||||
'enableSession' => false,
|
'enableSession' => false,
|
||||||
'loginUrl' => null,
|
'loginUrl' => null,
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
]]);
|
]]);
|
||||||
$component->shouldReceive('terminateSessions')->once()->withArgs([$account, Component::KEEP_CURRENT_SESSION]);
|
$component->shouldReceive('terminateSessions')->once()->withArgs([$account, Component::KEEP_CURRENT_SESSION]);
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ class EnableTwoFactorAuthFormTest extends TestCase {
|
|||||||
'enableSession' => false,
|
'enableSession' => false,
|
||||||
'loginUrl' => null,
|
'loginUrl' => null,
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
]]);
|
]]);
|
||||||
$component->shouldReceive('terminateSessions')->withArgs([$account, Component::KEEP_CURRENT_SESSION]);
|
$component->shouldReceive('terminateSessions')->withArgs([$account, Component::KEEP_CURRENT_SESSION]);
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ class AccountOwnerTest extends TestCase {
|
|||||||
public function testIdentityIsNull() {
|
public function testIdentityIsNull() {
|
||||||
$component = mock(Component::class . '[findIdentityByAccessToken]', [[
|
$component = mock(Component::class . '[findIdentityByAccessToken]', [[
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
]]);
|
]]);
|
||||||
$component->shouldDeferMissing();
|
$component->shouldDeferMissing();
|
||||||
$component->shouldReceive('findIdentityByAccessToken')->andReturn(null);
|
$component->shouldReceive('findIdentityByAccessToken')->andReturn(null);
|
||||||
@ -40,8 +40,8 @@ class AccountOwnerTest extends TestCase {
|
|||||||
|
|
||||||
$component = mock(Component::class . '[findIdentityByAccessToken]', [[
|
$component = mock(Component::class . '[findIdentityByAccessToken]', [[
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
]]);
|
]]);
|
||||||
$component->shouldDeferMissing();
|
$component->shouldDeferMissing();
|
||||||
$component->shouldReceive('findIdentityByAccessToken')->withArgs(['token'])->andReturn($identity);
|
$component->shouldReceive('findIdentityByAccessToken')->withArgs(['token'])->andReturn($identity);
|
||||||
|
@ -36,8 +36,8 @@ class OauthClientOwnerTest extends TestCase {
|
|||||||
/** @var Component|\Mockery\MockInterface $component */
|
/** @var Component|\Mockery\MockInterface $component */
|
||||||
$component = mock(Component::class . '[findIdentityByAccessToken]', [[
|
$component = mock(Component::class . '[findIdentityByAccessToken]', [[
|
||||||
'secret' => 'secret',
|
'secret' => 'secret',
|
||||||
'publicKey' => 'data/certs/public.crt',
|
'publicKeyPath' => 'data/certs/public.crt',
|
||||||
'privateKey' => 'data/certs/private.key',
|
'privateKeyPath' => 'data/certs/private.key',
|
||||||
]]);
|
]]);
|
||||||
$component->shouldDeferMissing();
|
$component->shouldDeferMissing();
|
||||||
$component->shouldReceive('findIdentityByAccessToken')->withArgs(['token'])->andReturn($identity);
|
$component->shouldReceive('findIdentityByAccessToken')->withArgs(['token'])->andReturn($identity);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user