diff --git a/api/components/OAuth2/Entities/RefreshTokenEntity.php b/api/components/OAuth2/Entities/RefreshTokenEntity.php index 5ef3fc7..372f003 100644 --- a/api/components/OAuth2/Entities/RefreshTokenEntity.php +++ b/api/components/OAuth2/Entities/RefreshTokenEntity.php @@ -1,9 +1,11 @@ session; } + /** @var SessionStorage $sessionStorage */ $sessionStorage = $this->server->getSessionStorage(); - if (!$sessionStorage instanceof SessionStorage) { - throw new ErrorException('SessionStorage must be instance of ' . SessionStorage::class); - } + Assert::isInstanceOf($sessionStorage, SessionStorage::class); return $sessionStorage->getById($this->sessionId); } @@ -32,7 +33,7 @@ class RefreshTokenEntity extends \League\OAuth2\Server\Entity\RefreshTokenEntity public function setSession(OriginalSessionEntity $session): self { parent::setSession($session); - $this->setSessionId($session->getId()); + $this->setSessionId((int)$session->getId()); return $this; } diff --git a/api/components/User/IdentityFactory.php b/api/components/User/IdentityFactory.php index f38f47e..2b59630 100644 --- a/api/components/User/IdentityFactory.php +++ b/api/components/User/IdentityFactory.php @@ -20,7 +20,7 @@ class IdentityFactory { return JwtIdentity::findIdentityByAccessToken($token, $type); } - return Oauth2Identity::findIdentityByAccessToken($token, $type); + return OAuth2Identity::findIdentityByAccessToken($token, $type); } } diff --git a/api/components/User/Oauth2Identity.php b/api/components/User/OAuth2Identity.php similarity index 90% rename from api/components/User/Oauth2Identity.php rename to api/components/User/OAuth2Identity.php index 8a9001a..bbb06cf 100644 --- a/api/components/User/Oauth2Identity.php +++ b/api/components/User/OAuth2Identity.php @@ -10,7 +10,7 @@ use Yii; use yii\base\NotSupportedException; use yii\web\UnauthorizedHttpException; -class Oauth2Identity implements IdentityInterface { +class OAuth2Identity implements IdentityInterface { /** * @var AccessTokenEntity @@ -55,6 +55,7 @@ class Oauth2Identity implements IdentityInterface { return $this->_accessToken->getId(); } + // @codeCoverageIgnoreStart public function getAuthKey() { throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth'); } @@ -67,8 +68,10 @@ class Oauth2Identity implements IdentityInterface { throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth'); } + // @codeCoverageIgnoreEnd + private function getSession(): OauthSession { - return OauthSession::findOne($this->_accessToken->getSessionId()); + return OauthSession::findOne(['id' => $this->_accessToken->getSessionId()]); } } diff --git a/api/tests/unit/components/Tokens/ComponentTest.php b/api/tests/unit/components/Tokens/ComponentTest.php index 9cd9c36..d8a7018 100644 --- a/api/tests/unit/components/Tokens/ComponentTest.php +++ b/api/tests/unit/components/Tokens/ComponentTest.php @@ -73,6 +73,10 @@ class ComponentTest extends TestCase { (new Parser())->parse('eyJhbGciOiJFUzI1NiJ9.eyJlbHktc2NvcGVzIjoiYWNjb3VudHNfd2ViX3VzZXIiLCJpYXQiOjE1NjQ1Mjc0NzYsImV4cCI6MTU2NDUzMTA3Niwic3ViIjoiZWx5fDEiLCJqdGkiOjMwNjk1OTJ9.xxx'), false, ]; + yield 'RS256 (unsupported)' => [ + (new Parser())->parse('eyJhbGciOiJSUzI1NiJ9.eyJlbHktc2NvcGVzIjoiYWNjb3VudHNfd2ViX3VzZXIiLCJpYXQiOjE1NjQ1Mjc0NzYsImV4cCI6MTU2NDUzMTA3Niwic3ViIjoiZWx5fDEiLCJqdGkiOjMwNjk1OTJ9.t3c68OMaoWWXxNFuz6SW-RfNmCOwAagyPSedbzJ1K3gR3bY5C8PRP6IEyE-OQvAcSFQcake0brsa4caXAmVlU0c3jQxpjk0bl4fBMd-InpGCoo42G89lgAY-dqWeJqokRORCpUL5Mzptbm5fNDlCrnNhI_6EmQygL3WXh1uorCbcxxO-Lb2Nr7Sge7GV0t24-I61I7ErrFL2ZC9ybSi6V8pdhFZlfO6MSUM0ASyRN994sVmcQEZHDiQFP7zj79zoAFamfYe8JBFAGtC-p4LeVYjrw052VahNXyRuGLxW7y1gX-znpyx0T-7lgKSWVxhJ6k3qt5qT33utdC76w1vihEdYinpEE3VbTMN01bxAFpyDbK11R49FCwCKStPjw_wdoLZChx_zob95yVU6IUCJwPYVc4SBtrAPV0uVe3mL3Gzgtr6MkhJAF3diFevTLGfnOOCAWwhdjVs10VWqcajBwvfFlm_Yw5MYZnetEECqumqFEr_u6CdRxtx0gCiPReDG8XwYHt0EqEw-LoRqxGWp5zqfud7f0DWv6cXlLbnKsB8XQh8EqnKblvNCFilXJIgfknCZ34PAob1pUkXO1geMLw4b8NUnKta1D3ad3AxGW5CEmOjWzEhzMOxIgnouU2ZVtWFDrPVs12Q4494BxTvGKXrG2cT6TK18-XY26DllglY'), + false, + ]; } protected function _setUp() { diff --git a/api/tests/unit/components/User/ComponentTest.php b/api/tests/unit/components/User/ComponentTest.php index 1d9ac6e..e9ca1cc 100644 --- a/api/tests/unit/components/User/ComponentTest.php +++ b/api/tests/unit/components/User/ComponentTest.php @@ -5,7 +5,7 @@ namespace codeception\api\unit\components\User; use api\components\User\Component; use api\components\User\JwtIdentity; -use api\components\User\Oauth2Identity; +use api\components\User\OAuth2Identity; use api\tests\unit\TestCase; use common\models\Account; use common\models\AccountSession; @@ -41,7 +41,7 @@ class ComponentTest extends TestCase { $this->assertNull($component->getActiveSession()); // Identity is a Oauth2Identity - $component->setIdentity(mock(Oauth2Identity::class)); + $component->setIdentity(mock(OAuth2Identity::class)); $this->assertNull($component->getActiveSession()); // Identity is correct, but have no jti claim diff --git a/api/tests/unit/components/User/IdentityFactoryTest.php b/api/tests/unit/components/User/IdentityFactoryTest.php new file mode 100644 index 0000000..b3d6851 --- /dev/null +++ b/api/tests/unit/components/User/IdentityFactoryTest.php @@ -0,0 +1,59 @@ +assertInstanceOf(JwtIdentity::class, $identity); + + // Find identity by oauth2 token + $accessToken = new AccessTokenEntity(mock(AbstractServer::class)); + $accessToken->setExpireTime(time() + 3600); + $accessToken->setId('mock-token'); + + /** @var AccessTokenInterface|\Mockery\MockInterface $accessTokensStorage */ + $accessTokensStorage = mock(AccessTokenInterface::class); + $accessTokensStorage->shouldReceive('get')->with('mock-token')->andReturn($accessToken); + + /** @var Component|\Mockery\MockInterface $component */ + $component = mock(Component::class); + $component->shouldReceive('getAccessTokenStorage')->andReturn($accessTokensStorage); + Yii::$app->set('oauth', $component); + + $identity = IdentityFactory::findIdentityByAccessToken('mock-token'); + $this->assertInstanceOf(OAuth2Identity::class, $identity); + } + + public function testFindIdentityByAccessTokenWithEmptyValue() { + $this->expectException(UnauthorizedHttpException::class); + $this->expectExceptionMessage('Incorrect token'); + IdentityFactory::findIdentityByAccessToken(''); + } + + protected function _setUp() { + parent::_setUp(); + Carbon::setTestNow(Carbon::create(2019, 8, 1, 1, 2, 22, 'Europe/Minsk')); + } + + protected function _tearDown() { + parent::_tearDown(); + Carbon::setTestNow(); + } + +} diff --git a/api/tests/unit/components/User/OAuth2IdentityTest.php b/api/tests/unit/components/User/OAuth2IdentityTest.php new file mode 100644 index 0000000..790f139 --- /dev/null +++ b/api/tests/unit/components/User/OAuth2IdentityTest.php @@ -0,0 +1,56 @@ +setExpireTime(time() + 3600); + $accessToken->setId('mock-token'); + $this->mockFoundedAccessToken($accessToken); + + $identity = OAuth2Identity::findIdentityByAccessToken('mock-token'); + $this->assertSame('mock-token', $identity->getId()); + } + + public function testFindIdentityByAccessTokenWithNonExistsToken() { + $this->expectException(UnauthorizedHttpException::class); + $this->expectExceptionMessage('Incorrect token'); + + OAuth2Identity::findIdentityByAccessToken('not exists token'); + } + + public function testFindIdentityByAccessTokenWithExpiredToken() { + $this->expectException(UnauthorizedHttpException::class); + $this->expectExceptionMessage('Token expired'); + + $accessToken = new AccessTokenEntity(mock(AbstractServer::class)); + $accessToken->setExpireTime(time() - 3600); + $this->mockFoundedAccessToken($accessToken); + + OAuth2Identity::findIdentityByAccessToken('mock-token'); + } + + private function mockFoundedAccessToken(AccessTokenEntity $accessToken) { + /** @var AccessTokenInterface|\Mockery\MockInterface $accessTokensStorage */ + $accessTokensStorage = mock(AccessTokenInterface::class); + $accessTokensStorage->shouldReceive('get')->with('mock-token')->andReturn($accessToken); + + /** @var Component|\Mockery\MockInterface $component */ + $component = mock(Component::class); + $component->shouldReceive('getAccessTokenStorage')->andReturn($accessTokensStorage); + Yii::$app->set('oauth', $component); + } + +}