mirror of
https://github.com/elyby/accounts.git
synced 2025-05-31 14:11:46 +05:30
Restore full functionality of OAuth2 server [skip ci]
This commit is contained in:
@@ -81,10 +81,10 @@ class AccessTokenCest {
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'redirect_uri' => 'http://some-other.domain',
|
||||
]);
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseCodeIs(401);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_client',
|
||||
'message' => 'Client authentication failed.',
|
||||
'message' => 'Client authentication failed',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ class AuthCodeCest {
|
||||
'redirect_uri' => 'http://ely.by',
|
||||
'response_type' => 'code',
|
||||
'scope' => 'minecraft_server_session block_account',
|
||||
]));
|
||||
]), ['accept' => true]); // TODO: maybe remove?
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
|
||||
@@ -1,120 +1,87 @@
|
||||
<?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 ClientCredentialsCest {
|
||||
|
||||
/**
|
||||
* @var OauthRoute
|
||||
*/
|
||||
private $route;
|
||||
|
||||
public function _before(FunctionalTester $I) {
|
||||
$this->route = new OauthRoute($I);
|
||||
public function issueTokenWithPublicScopes(FunctionalTester $I) {
|
||||
$I->wantTo('issue token as not trusted client and require only public scopes');
|
||||
// We don't have any public scopes yet for this grant, so the test runs with an empty set
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'scope' => '',
|
||||
]);
|
||||
$this->assertSuccessResponse($I);
|
||||
}
|
||||
|
||||
public function testIssueTokenWithWrongArgs(FunctionalTester $I) {
|
||||
$I->wantTo('check behavior on on request without any credentials');
|
||||
$this->route->issueToken($this->buildParams());
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_request',
|
||||
public function issueTokenWithInternalScopesAsNotTrustedClient(FunctionalTester $I) {
|
||||
$I->wantTo('issue token as not trusted client and require some internal scope');
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'scope' => 'block_account',
|
||||
]);
|
||||
|
||||
$I->wantTo('check behavior on passing invalid client_id');
|
||||
$this->route->issueToken($this->buildParams(
|
||||
'invalid-client',
|
||||
'invalid-secret',
|
||||
['invalid-scope']
|
||||
));
|
||||
$I->canSeeResponseCodeIs(401);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_client',
|
||||
]);
|
||||
|
||||
$I->wantTo('check behavior on passing invalid client_secret');
|
||||
$this->route->issueToken($this->buildParams(
|
||||
'ely',
|
||||
'invalid-secret',
|
||||
['invalid-scope']
|
||||
));
|
||||
$I->canSeeResponseCodeIs(401);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_client',
|
||||
]);
|
||||
|
||||
$I->wantTo('check behavior on passing invalid client_secret');
|
||||
$this->route->issueToken($this->buildParams(
|
||||
'ely',
|
||||
'invalid-secret',
|
||||
['invalid-scope']
|
||||
));
|
||||
$I->canSeeResponseCodeIs(401);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_client',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testIssueTokenWithPublicScopes(OauthSteps $I) {
|
||||
// TODO: we don't have any public scopes yet for this grant, so the test runs with an empty set
|
||||
$this->route->issueToken($this->buildParams(
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
[]
|
||||
));
|
||||
$I->canSeeResponseCodeIs(200);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'token_type' => 'Bearer',
|
||||
]);
|
||||
$I->canSeeResponseJsonMatchesJsonPath('$.access_token');
|
||||
$I->canSeeResponseJsonMatchesJsonPath('$.expires_in');
|
||||
}
|
||||
|
||||
public function testIssueTokenWithInternalScopes(OauthSteps $I) {
|
||||
$this->route->issueToken($this->buildParams(
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
['account_block']
|
||||
));
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_scope',
|
||||
]);
|
||||
}
|
||||
|
||||
$this->route->issueToken($this->buildParams(
|
||||
'trusted-client',
|
||||
'tXBbyvMcyaOgHMOAXBpN2EC7uFoJAaL9',
|
||||
['account_block']
|
||||
));
|
||||
public function issueTokenWithInternalScopesAsTrustedClient(OauthSteps $I) {
|
||||
$I->wantTo('issue token as trusted client and require some internal scope');
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => 'trusted-client',
|
||||
'client_secret' => 'tXBbyvMcyaOgHMOAXBpN2EC7uFoJAaL9',
|
||||
'scope' => 'block_account',
|
||||
]);
|
||||
$this->assertSuccessResponse($I);
|
||||
}
|
||||
|
||||
public function issueTokenByPassingInvalidClientId(FunctionalTester $I) {
|
||||
$I->wantToTest('behavior on passing invalid client_id');
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => 'invalid-client',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'scope' => 'block_account',
|
||||
]);
|
||||
$I->canSeeResponseCodeIs(401);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_client',
|
||||
]);
|
||||
}
|
||||
|
||||
public function issueTokenByPassingInvalidClientSecret(FunctionalTester $I) {
|
||||
$I->wantTo('check behavior on passing invalid client_secret');
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'client_credentials',
|
||||
'client_id' => 'trusted-client',
|
||||
'client_secret' => 'invalid-secret',
|
||||
'scope' => 'block_account',
|
||||
]);
|
||||
$I->canSeeResponseCodeIs(401);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_client',
|
||||
]);
|
||||
}
|
||||
|
||||
private function assertSuccessResponse(FunctionalTester $I): void {
|
||||
$I->canSeeResponseCodeIs(200);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'token_type' => 'Bearer',
|
||||
]);
|
||||
$I->canSeeResponseJsonMatchesJsonPath('$.access_token');
|
||||
$I->canSeeResponseJsonMatchesJsonPath('$.expires_in');
|
||||
}
|
||||
|
||||
private function buildParams($clientId = null, $clientSecret = null, array $scopes = null) {
|
||||
$params = ['grant_type' => 'client_credentials'];
|
||||
if ($clientId !== null) {
|
||||
$params['client_id'] = $clientId;
|
||||
}
|
||||
|
||||
if ($clientSecret !== null) {
|
||||
$params['client_secret'] = $clientSecret;
|
||||
}
|
||||
|
||||
if ($scopes !== null) {
|
||||
$params['scope'] = implode(',', $scopes);
|
||||
}
|
||||
|
||||
return $params;
|
||||
$I->cantSeeResponseJsonMatchesJsonPath('$.refresh_token');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace api\tests\functional\oauth;
|
||||
|
||||
use api\components\OAuth2\Repositories\ScopeStorage as S;
|
||||
use api\rbac\Permissions as P;
|
||||
use api\tests\_pages\OauthRoute;
|
||||
use api\tests\functional\_steps\OauthSteps;
|
||||
use api\tests\FunctionalTester;
|
||||
|
||||
class RefreshTokenCest {
|
||||
|
||||
/**
|
||||
* @var OauthRoute
|
||||
*/
|
||||
private $route;
|
||||
|
||||
public function _before(FunctionalTester $I) {
|
||||
$this->route = new OauthRoute($I);
|
||||
public function refreshToken(OauthSteps $I) {
|
||||
$I->wantTo('refresh token without passing the desired scopes');
|
||||
$refreshToken = $I->getRefreshToken();
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
]);
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
}
|
||||
|
||||
public function testInvalidRefreshToken(OauthSteps $I) {
|
||||
$this->route->issueToken($this->buildParams(
|
||||
'some-invalid-refresh-token',
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM'
|
||||
));
|
||||
public function refreshTokenWithSameScopes(OauthSteps $I) {
|
||||
$refreshToken = $I->getRefreshToken(['minecraft_server_session']);
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'scope' => 'minecraft_server_session offline_access',
|
||||
]);
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
}
|
||||
|
||||
public function refreshTokenTwice(OauthSteps $I) {
|
||||
$I->wantTo('refresh token two times in a row and ensure, that token isn\'t rotating');
|
||||
$refreshToken = $I->getRefreshToken(['minecraft_server_session']);
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'scope' => 'minecraft_server_session',
|
||||
]);
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'scope' => 'minecraft_server_session',
|
||||
]);
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
}
|
||||
|
||||
public function passInvalidRefreshToken(OauthSteps $I) {
|
||||
$I->wantToTest('behaviour of the server when invalid refresh token passed');
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => 'some-invalid-refresh-token',
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
]);
|
||||
$I->canSeeResponseCodeIs(401);
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'invalid_request',
|
||||
'message' => 'The refresh token is invalid.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testRefreshToken(OauthSteps $I) {
|
||||
$refreshToken = $I->getRefreshToken();
|
||||
$this->route->issueToken($this->buildParams(
|
||||
$refreshToken,
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM'
|
||||
));
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
}
|
||||
|
||||
public function testRefreshTokenWithSameScopes(OauthSteps $I) {
|
||||
$refreshToken = $I->getRefreshToken([P::MINECRAFT_SERVER_SESSION]);
|
||||
$this->route->issueToken($this->buildParams(
|
||||
$refreshToken,
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
[P::MINECRAFT_SERVER_SESSION, S::OFFLINE_ACCESS]
|
||||
));
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
}
|
||||
|
||||
public function testRefreshTokenTwice(OauthSteps $I) {
|
||||
$refreshToken = $I->getRefreshToken([P::MINECRAFT_SERVER_SESSION]);
|
||||
$this->route->issueToken($this->buildParams(
|
||||
$refreshToken,
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
[P::MINECRAFT_SERVER_SESSION, S::OFFLINE_ACCESS]
|
||||
));
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
|
||||
$this->route->issueToken($this->buildParams(
|
||||
$refreshToken,
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
[P::MINECRAFT_SERVER_SESSION, S::OFFLINE_ACCESS]
|
||||
));
|
||||
$this->canSeeRefreshTokenSuccess($I);
|
||||
}
|
||||
|
||||
public function testRefreshTokenWithNewScopes(OauthSteps $I) {
|
||||
$refreshToken = $I->getRefreshToken([P::MINECRAFT_SERVER_SESSION]);
|
||||
$this->route->issueToken($this->buildParams(
|
||||
$refreshToken,
|
||||
'ely',
|
||||
'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
[P::MINECRAFT_SERVER_SESSION, S::OFFLINE_ACCESS, 'account_email']
|
||||
));
|
||||
public function requireNewScopes(OauthSteps $I) {
|
||||
$I->wantToTest('behavior when required the new scope that was not issued with original token');
|
||||
$refreshToken = $I->getRefreshToken(['minecraft_server_session']);
|
||||
$I->sendPOST('/api/oauth2/v1/token', [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => 'ely',
|
||||
'client_secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
|
||||
'scope' => 'minecraft_server_session account_email',
|
||||
]);
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
@@ -85,34 +85,8 @@ class RefreshTokenCest {
|
||||
]);
|
||||
}
|
||||
|
||||
private function buildParams($refreshToken = null, $clientId = null, $clientSecret = null, $scopes = []) {
|
||||
$params = ['grant_type' => 'refresh_token'];
|
||||
if ($refreshToken !== null) {
|
||||
$params['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
if ($clientId !== null) {
|
||||
$params['client_id'] = $clientId;
|
||||
}
|
||||
|
||||
if ($clientSecret !== null) {
|
||||
$params['client_secret'] = $clientSecret;
|
||||
}
|
||||
|
||||
if (!empty($scopes)) {
|
||||
if (is_array($scopes)) {
|
||||
$scopes = implode(',', $scopes);
|
||||
}
|
||||
|
||||
$params['scope'] = $scopes;
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
private function canSeeRefreshTokenSuccess(OauthSteps $I) {
|
||||
$I->canSeeResponseCodeIs(200);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'token_type' => 'Bearer',
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user