mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Completely restored authorization_code grant for user side.
Reworked oauth_sessions table. Added extension to use MariaDB's JSON columns. Rewritten tests for authorization_code grant for client side. Deprecate some old shit. [skip ci]
This commit is contained in:
		| @@ -9,31 +9,30 @@ use api\tests\FunctionalTester; | ||||
|  | ||||
| class OauthSteps extends FunctionalTester { | ||||
|  | ||||
|     public function getAuthCode(array $permissions = []): string { | ||||
|     public function obtainAuthCode(array $permissions = []): string { | ||||
|         $this->amAuthenticated(); | ||||
|         $route = new OauthRoute($this); | ||||
|         $route->complete([ | ||||
|         $this->sendPOST('/api/oauth2/v1/complete?' . http_build_query([ | ||||
|             'client_id' => 'ely', | ||||
|             'redirect_uri' => 'http://ely.by', | ||||
|             'response_type' => 'code', | ||||
|             'scope' => implode(',', $permissions), | ||||
|         ], ['accept' => true]); | ||||
|             'scope' => implode(' ', $permissions), | ||||
|         ]), ['accept' => true]); | ||||
|         $this->canSeeResponseJsonMatchesJsonPath('$.redirectUri'); | ||||
|         $response = json_decode($this->grabResponse(), true); | ||||
|         preg_match('/code=([\w-]+)/', $response['redirectUri'], $matches); | ||||
|         [$redirectUri] = $this->grabDataFromResponseByJsonPath('$.redirectUri'); | ||||
|         preg_match('/code=([\w-]+)/', $redirectUri, $matches); | ||||
|  | ||||
|         return $matches[1]; | ||||
|     } | ||||
|  | ||||
|     public function getAccessToken(array $permissions = []): string { | ||||
|         $authCode = $this->getAuthCode($permissions); | ||||
|         $authCode = $this->obtainAuthCode($permissions); | ||||
|         $response = $this->issueToken($authCode); | ||||
|  | ||||
|         return $response['access_token']; | ||||
|     } | ||||
|  | ||||
|     public function getRefreshToken(array $permissions = []): string { | ||||
|         $authCode = $this->getAuthCode(array_merge([S::OFFLINE_ACCESS], $permissions)); | ||||
|         $authCode = $this->obtainAuthCode(array_merge([S::OFFLINE_ACCESS], $permissions)); | ||||
|         $response = $this->issueToken($authCode); | ||||
|  | ||||
|         return $response['refresh_token']; | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| <?php | ||||
| namespace api\tests\functional\oauth; | ||||
| declare(strict_types=1); | ||||
| 
 | ||||
| namespace api\tests\functional\dev\applications; | ||||
| 
 | ||||
| use api\tests\_pages\OauthRoute; | ||||
| use api\tests\FunctionalTester; | ||||
| @@ -1,5 +1,7 @@ | ||||
| <?php | ||||
| namespace api\tests\functional\oauth; | ||||
| declare(strict_types=1); | ||||
| 
 | ||||
| namespace api\tests\functional\dev\applications; | ||||
| 
 | ||||
| use api\tests\_pages\OauthRoute; | ||||
| use api\tests\FunctionalTester; | ||||
| @@ -1,5 +1,7 @@ | ||||
| <?php | ||||
| namespace api\tests\functional\oauth; | ||||
| declare(strict_types=1); | ||||
| 
 | ||||
| namespace api\tests\functional\dev\applications; | ||||
| 
 | ||||
| use api\tests\_pages\OauthRoute; | ||||
| use api\tests\FunctionalTester; | ||||
| @@ -1,5 +1,7 @@ | ||||
| <?php | ||||
| namespace api\tests\functional\oauth; | ||||
| declare(strict_types=1); | ||||
| 
 | ||||
| namespace api\tests\functional\dev\applications; | ||||
| 
 | ||||
| use api\tests\_pages\IdentityInfoRoute; | ||||
| use api\tests\functional\_steps\OauthSteps; | ||||
| @@ -1,5 +1,7 @@ | ||||
| <?php | ||||
| namespace api\tests\functional\oauth; | ||||
| declare(strict_types=1); | ||||
| 
 | ||||
| namespace api\tests\functional\dev\applications; | ||||
| 
 | ||||
| use api\tests\_pages\OauthRoute; | ||||
| use api\tests\FunctionalTester; | ||||
| @@ -1,5 +1,7 @@ | ||||
| <?php | ||||
| namespace api\tests\functional\oauth; | ||||
| declare(strict_types=1); | ||||
| 
 | ||||
| namespace api\tests\functional\dev\applications; | ||||
| 
 | ||||
| use api\tests\_pages\OauthRoute; | ||||
| use api\tests\FunctionalTester; | ||||
| @@ -1,113 +1,91 @@ | ||||
| <?php | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace api\tests\functional\oauth; | ||||
|  | ||||
| use api\tests\_pages\OauthRoute; | ||||
| use api\tests\functional\_steps\OauthSteps; | ||||
| use api\tests\FunctionalTester; | ||||
|  | ||||
| class AccessTokenCest { | ||||
|  | ||||
|     /** | ||||
|      * @var OauthRoute | ||||
|      */ | ||||
|     private $route; | ||||
|  | ||||
|     public function _before(FunctionalTester $I) { | ||||
|         $this->route = new OauthRoute($I); | ||||
|     public function successfullyIssueToken(OauthSteps $I) { | ||||
|         $I->wantTo('complete oauth flow and obtain access_token'); | ||||
|         $authCode = $I->obtainAuthCode(); | ||||
|         $I->sendPOST('/api/oauth2/v1/token', [ | ||||
|             'grant_type' => 'authorization_code', | ||||
|             'code' => $authCode, | ||||
|             'client_id' => 'ely', | ||||
|             'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'redirect_uri' => 'http://ely.by', | ||||
|         ]); | ||||
|         $I->canSeeResponseCodeIs(200); | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'token_type' => 'Bearer', | ||||
|         ]); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.access_token'); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.expires_in'); | ||||
|         $I->cantSeeResponseJsonMatchesJsonPath('$.refresh_token'); | ||||
|     } | ||||
|  | ||||
|     public function testIssueTokenWithWrongArgs(OauthSteps $I) { | ||||
|         $I->wantTo('check behavior on on request without any credentials'); | ||||
|         $this->route->issueToken(); | ||||
|     public function successfullyIssueOfflineToken(OauthSteps $I) { | ||||
|         $I->wantTo('complete oauth flow with offline_access scope and obtain access_token and refresh_token'); | ||||
|         $authCode = $I->obtainAuthCode(['offline_access']); | ||||
|         $I->sendPOST('/api/oauth2/v1/token', [ | ||||
|             'grant_type' => 'authorization_code', | ||||
|             'code' => $authCode, | ||||
|             'client_id' => 'ely', | ||||
|             'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'redirect_uri' => 'http://ely.by', | ||||
|         ]); | ||||
|         $I->canSeeResponseCodeIs(200); | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'token_type' => 'Bearer', | ||||
|         ]); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.access_token'); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.expires_in'); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.refresh_token'); | ||||
|     } | ||||
|  | ||||
|     public function callEndpointWithByEmptyRequest(OauthSteps $I) { | ||||
|         $I->wantTo('check behavior on on request without any params'); | ||||
|         $I->sendPOST('/api/oauth2/v1/token'); | ||||
|         $I->canSeeResponseCodeIs(400); | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'error' => 'invalid_request', | ||||
|             'message' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "grant_type" parameter.', | ||||
|             'error' => 'unsupported_grant_type', | ||||
|             'message' => 'The authorization grant type is not supported by the authorization server.', | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function issueTokenByPassingInvalidAuthCode(OauthSteps $I) { | ||||
|         $I->wantTo('check behavior on passing invalid auth code'); | ||||
|         $this->route->issueToken($this->buildParams( | ||||
|             'wrong-auth-code', | ||||
|             'ely', | ||||
|             'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'http://ely.by' | ||||
|         )); | ||||
|         $I->sendPOST('/api/oauth2/v1/token', [ | ||||
|             'grant_type' => 'authorization_code', | ||||
|             'code' => 'wrong-auth-code', | ||||
|             'client_id' => 'ely', | ||||
|             'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'redirect_uri' => 'http://ely.by', | ||||
|         ]); | ||||
|         $I->canSeeResponseCodeIs(400); | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'error' => 'invalid_request', | ||||
|             'message' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "code" parameter.', | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|         $authCode = $I->getAuthCode(); | ||||
|     public function issueTokenByPassingInvalidRedirectUri(OauthSteps $I) { | ||||
|         $I->wantTo('check behavior on passing invalid redirect_uri'); | ||||
|         $this->route->issueToken($this->buildParams( | ||||
|             $authCode, | ||||
|             'ely', | ||||
|             'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'http://some-other.domain' | ||||
|         )); | ||||
|         $I->canSeeResponseCodeIs(401); | ||||
|         $authCode = $I->obtainAuthCode(); | ||||
|         $I->sendPOST('/api/oauth2/v1/token', [ | ||||
|             'grant_type' => 'authorization_code', | ||||
|             'code' => $authCode, | ||||
|             'client_id' => 'ely', | ||||
|             'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'redirect_uri' => 'http://some-other.domain', | ||||
|         ]); | ||||
|         $I->canSeeResponseCodeIs(400); | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'error' => 'invalid_client', | ||||
|             'message' => 'Client authentication failed.', | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function testIssueToken(OauthSteps $I) { | ||||
|         $authCode = $I->getAuthCode(); | ||||
|         $this->route->issueToken($this->buildParams( | ||||
|             $authCode, | ||||
|             'ely', | ||||
|             'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'http://ely.by' | ||||
|         )); | ||||
|         $I->canSeeResponseCodeIs(200); | ||||
|         $I->canSeeResponseIsJson(); | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'token_type' => 'Bearer', | ||||
|         ]); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.access_token'); | ||||
|         $I->cantSeeResponseJsonMatchesJsonPath('$.refresh_token'); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.expires_in'); | ||||
|     } | ||||
|  | ||||
|     public function testIssueTokenWithRefreshToken(OauthSteps $I) { | ||||
|         $authCode = $I->getAuthCode(['offline_access']); | ||||
|         $this->route->issueToken($this->buildParams( | ||||
|             $authCode, | ||||
|             'ely', | ||||
|             'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM', | ||||
|             'http://ely.by' | ||||
|         )); | ||||
|         $I->canSeeResponseCodeIs(200); | ||||
|         $I->canSeeResponseIsJson(); | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'token_type' => 'Bearer', | ||||
|         ]); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.access_token'); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.refresh_token'); | ||||
|         $I->canSeeResponseJsonMatchesJsonPath('$.expires_in'); | ||||
|     } | ||||
|  | ||||
|     private function buildParams($code = null, $clientId = null, $clientSecret = null, $redirectUri = null) { | ||||
|         $params = ['grant_type' => 'authorization_code']; | ||||
|         if ($code !== null) { | ||||
|             $params['code'] = $code; | ||||
|         } | ||||
|  | ||||
|         if ($clientId !== null) { | ||||
|             $params['client_id'] = $clientId; | ||||
|         } | ||||
|  | ||||
|         if ($clientSecret !== null) { | ||||
|             $params['client_secret'] = $clientSecret; | ||||
|         } | ||||
|  | ||||
|         if ($redirectUri !== null) { | ||||
|             $params['redirect_uri'] = $redirectUri; | ||||
|         } | ||||
|  | ||||
|         return $params; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -72,7 +72,7 @@ class AuthCodeCest { | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'success' => false, | ||||
|             'error' => 'accept_required', | ||||
|             'parameter' => '', | ||||
|             'parameter' => null, | ||||
|             'statusCode' => 401, | ||||
|         ]); | ||||
|     } | ||||
| @@ -90,7 +90,7 @@ class AuthCodeCest { | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'success' => false, | ||||
|             'error' => 'accept_required', | ||||
|             'parameter' => '', | ||||
|             'parameter' => null, | ||||
|             'statusCode' => 401, | ||||
|         ]); | ||||
|     } | ||||
| @@ -114,7 +114,7 @@ class AuthCodeCest { | ||||
|         $I->canSeeResponseContainsJson([ | ||||
|             'success' => false, | ||||
|             'error' => 'accept_required', | ||||
|             'parameter' => '', | ||||
|             'parameter' => null, | ||||
|             'statusCode' => 401, | ||||
|         ]); | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user