Fixed almost everything, but all functional tests are broken at the last minute :(

This commit is contained in:
ErickSkrauch
2019-08-02 03:29:20 +03:00
parent 6bd054e743
commit f2ab7346aa
45 changed files with 504 additions and 377 deletions

View File

@@ -3,8 +3,8 @@ namespace api\components\OAuth2\Storage;
use api\components\OAuth2\Entities\ClientEntity;
use api\components\OAuth2\Entities\ScopeEntity;
use api\rbac\Permissions as P;
use Assert\Assert;
use common\rbac\Permissions as P;
use League\OAuth2\Server\Storage\AbstractStorage;
use League\OAuth2\Server\Storage\ScopeInterface;

View File

@@ -3,6 +3,7 @@ declare(strict_types=1);
namespace api\components\Tokens;
use Carbon\Carbon;
use Exception;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
@@ -11,8 +12,6 @@ use yii\base\Component as BaseComponent;
class Component extends BaseComponent {
private const EXPIRATION_TIMEOUT = 3600; // 1h
private const PREFERRED_ALGORITHM = 'ES256';
/**
@@ -41,10 +40,10 @@ class Component extends BaseComponent {
private $algorithmManager;
public function create(array $payloads = [], array $headers = []): Token {
$time = time();
$now = Carbon::now();
$builder = (new Builder())
->issuedAt($time)
->expiresAt($time + self::EXPIRATION_TIMEOUT);
->issuedAt($now->getTimestamp())
->expiresAt($now->addHour()->getTimestamp());
foreach ($payloads as $claim => $value) {
$builder->withClaim($claim, $value);
}

View File

@@ -3,6 +3,7 @@ declare(strict_types=1);
namespace api\components\Tokens;
use Carbon\Carbon;
use common\models\Account;
use common\models\AccountSession;
use Lcobucci\JWT\Token;
@@ -20,7 +21,7 @@ class TokensFactory {
if ($session === null) {
// If we don't remember a session, the token should live longer
// so that the session doesn't end while working with the account
$payloads['exp'] = time() + 60 * 60 * 24 * 7; // 7d
$payloads['exp'] = Carbon::now()->addDays(7)->getTimestamp();
} else {
$payloads['jti'] = $session->id;
}

View File

@@ -5,10 +5,6 @@ namespace api\components\User;
use common\models\Account;
use common\models\AccountSession;
use Exception;
use InvalidArgumentException;
use Yii;
use yii\web\UnauthorizedHttpException;
use yii\web\User as YiiUserComponent;
/**
@@ -38,29 +34,11 @@ class Component extends YiiUserComponent {
*/
public $identityClass = IdentityFactory::class;
public function findIdentityByAccessToken($accessToken): ?IdentityInterface {
if (empty($accessToken)) {
return null;
}
try {
return IdentityFactory::findIdentityByAccessToken($accessToken);
} catch (UnauthorizedHttpException $e) {
// TODO: if this exception is catched there, how it forms "Token expired" exception?
// Do nothing. It's okay to catch this.
} catch (Exception $e) {
Yii::error($e);
}
return null;
}
/**
* The method searches AccountSession model, which one has been used to create current JWT token.
* null will be returned in case when any of the following situations occurred:
* - The user isn't authorized
* - There is no header with a token
* - Token validation isn't passed and some exception has been thrown
* - The user isn't authorized via JWT token
* - No session key found in the token. This is possible if the user chose not to remember me
* or just some old tokens, without the support of saving the used session
*
@@ -71,18 +49,13 @@ class Component extends YiiUserComponent {
return null;
}
$bearer = $this->getBearerToken();
if ($bearer === null) {
/** @var IdentityInterface $identity */
$identity = $this->getIdentity();
if (!$identity instanceof JwtIdentity) {
return null;
}
try {
$token = Yii::$app->tokens->parse($bearer);
} catch (InvalidArgumentException $e) {
return null;
}
$sessionId = $token->getClaim('jti', false);
$sessionId = $identity->getToken()->getClaim('jti', false);
if ($sessionId === false) {
return null;
}
@@ -111,13 +84,4 @@ class Component extends YiiUserComponent {
}
}
private function getBearerToken(): ?string {
$authHeader = Yii::$app->request->getHeaders()->get('Authorization');
if ($authHeader === null || !preg_match('/^Bearer\s+(.*?)$/', $authHeader, $matches)) {
return null;
}
return $matches[1];
}
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace api\components\User;
use api\components\Tokens\TokensFactory;
use Carbon\Carbon;
use common\models\Account;
use Exception;
use Lcobucci\JWT\Token;
@@ -36,22 +37,27 @@ class JwtIdentity implements IdentityInterface {
throw new UnauthorizedHttpException('Incorrect token');
}
if ($token->isExpired()) {
$now = Carbon::now();
if ($token->isExpired($now)) {
throw new UnauthorizedHttpException('Token expired');
}
if (!$token->validate(new ValidationData())) {
if (!$token->validate(new ValidationData($now->getTimestamp()))) {
throw new UnauthorizedHttpException('Incorrect token');
}
$sub = $token->getClaim('sub', false);
if ($sub !== false && strpos($sub, TokensFactory::SUB_ACCOUNT_PREFIX) !== 0) {
if ($sub !== false && strpos((string)$sub, TokensFactory::SUB_ACCOUNT_PREFIX) !== 0) {
throw new UnauthorizedHttpException('Incorrect token');
}
return new self($token);
}
public function getToken(): Token {
return $this->token;
}
public function getAccount(): ?Account {
$subject = $this->token->getClaim('sub', false);
if ($subject === false) {
@@ -77,6 +83,7 @@ class JwtIdentity implements IdentityInterface {
return (string)$this->token;
}
// @codeCoverageIgnoreStart
public function getAuthKey() {
throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
}
@@ -89,4 +96,6 @@ class JwtIdentity implements IdentityInterface {
throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
}
// @codeCoverageIgnoreEnd
}