Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[13.x] Fix determining revoked records #1751

Merged
merged 2 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Bridge/AuthCodeRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ public function revokeAuthCode(string $codeId): void
*/
public function isAuthCodeRevoked(string $codeId): bool
{
return Passport::authCode()->where('id', $codeId)->where('revoked', 1)->exists();
return Passport::authCode()->where('id', $codeId)->where('revoked', 0)->doesntExist();
}
}
6 changes: 1 addition & 5 deletions src/RefreshTokenRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ public function revokeRefreshTokensByAccessTokenId($tokenId)
*/
public function isRefreshTokenRevoked($id)
{
if ($token = $this->find($id)) {
return $token->revoked;
}

return true;
return Passport::refreshToken()->where('id', $id)->where('revoked', 0)->doesntExist();
}
}
6 changes: 1 addition & 5 deletions src/TokenRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,7 @@ public function revokeAccessToken($id)
*/
public function isAccessTokenRevoked($id)
{
if ($token = $this->find($id)) {
return $token->revoked;
}

return true;
return Passport::token()->where('id', $id)->where('revoked', 0)->doesntExist();
}

/**
Expand Down
149 changes: 149 additions & 0 deletions tests/Feature/RevokedTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

use Carbon\CarbonImmutable;
use Laravel\Passport\Bridge\AccessToken;
use Laravel\Passport\Bridge\AccessTokenRepository as BridgeAccessTokenRepository;
use Laravel\Passport\Bridge\AuthCode;
use Laravel\Passport\Bridge\AuthCodeRepository as BridgeAuthCodeRepository;
use Laravel\Passport\Bridge\RefreshToken;
use Laravel\Passport\Bridge\RefreshTokenRepository as BridgeRefreshTokenRepository;
use Laravel\Passport\RefreshTokenRepository;
use Laravel\Passport\Tests\Feature\PassportTestCase;
use Laravel\Passport\TokenRepository;
use Mockery as m;
use Orchestra\Testbench\Concerns\WithLaravelMigrations;

class RevokedTest extends PassportTestCase
{
use WithLaravelMigrations;

public function test_it_can_determine_if_a_access_token_is_revoked()
{
$repository = $this->accessTokenRepository();
$this->persistNewAccessToken($repository, 'tokenId');

$repository->revokeAccessToken('tokenId');

$this->assertTrue($repository->isAccessTokenRevoked('tokenId'));
}

public function test_a_access_token_is_also_revoked_if_it_cannot_be_found()
{
$repository = $this->accessTokenRepository();

$this->assertTrue($repository->isAccessTokenRevoked('notExistingTokenId'));
}

public function test_it_can_determine_if_a_access_token_is_not_revoked()
{
$repository = $this->accessTokenRepository();
$this->persistNewAccessToken($repository, 'tokenId');

$this->assertFalse($repository->isAccessTokenRevoked('tokenId'));
}

public function test_it_can_determine_if_a_auth_code_is_revoked()
{
$repository = $this->authCodeRepository();
$this->persistNewAuthCode($repository, 'tokenId');

$repository->revokeAuthCode('tokenId');

$this->assertTrue($repository->isAuthCodeRevoked('tokenId'));
}

public function test_a_auth_code_is_also_revoked_if_it_cannot_be_found()
{
$repository = $this->authCodeRepository();

$this->assertTrue($repository->isAuthCodeRevoked('notExistingTokenId'));
}

public function test_it_can_determine_if_a_auth_code_is_not_revoked()
{
$repository = $this->authCodeRepository();
$this->persistNewAuthCode($repository, 'tokenId');

$this->assertFalse($repository->isAuthCodeRevoked('tokenId'));
}

public function test_it_can_determine_if_a_refresh_token_is_revoked()
{
$repository = $this->refreshTokenRepository();
$this->persistNewRefreshToken($repository, 'tokenId');

$repository->revokeRefreshToken('tokenId');

$this->assertTrue($repository->isRefreshTokenRevoked('tokenId'));
}

public function test_a_refresh_token_is_also_revoked_if_it_cannot_be_found()
{
$repository = $this->refreshTokenRepository();

$this->assertTrue($repository->isRefreshTokenRevoked('notExistingTokenId'));
}

public function test_it_can_determine_if_a_refresh_token_is_not_revoked()
{
$repository = $this->refreshTokenRepository();
$this->persistNewRefreshToken($repository, 'tokenId');

$this->assertFalse($repository->isRefreshTokenRevoked('tokenId'));
}

private function accessTokenRepository(): BridgeAccessTokenRepository
{
$events = m::mock('Illuminate\Contracts\Events\Dispatcher');
$events->shouldReceive('dispatch');

return new BridgeAccessTokenRepository(new TokenRepository, $events);
}

private function persistNewAccessToken(BridgeAccessTokenRepository $repository, string $id): void
{
$accessToken = m::mock(AccessToken::class);
$accessToken->shouldReceive('getIdentifier')->andReturn($id);
$accessToken->shouldReceive('getUserIdentifier')->andReturn('1');
$accessToken->shouldReceive('getClient->getIdentifier')->andReturn('clientId');
$accessToken->shouldReceive('getScopes')->andReturn([]);
$accessToken->shouldReceive('getExpiryDateTime')->andReturn(CarbonImmutable::now());

$repository->persistNewAccessToken($accessToken);
}

private function authCodeRepository(): BridgeAuthCodeRepository
{
return new BridgeAuthCodeRepository;
}

private function persistNewAuthCode(BridgeAuthCodeRepository $repository, string $id): void
{
$authCode = m::mock(AuthCode::class);
$authCode->shouldReceive('getIdentifier')->andReturn($id);
$authCode->shouldReceive('getUserIdentifier')->andReturn('1');
$authCode->shouldReceive('getClient->getIdentifier')->andReturn('clientId');
$authCode->shouldReceive('getExpiryDateTime')->andReturn(CarbonImmutable::now());
$authCode->shouldReceive('getScopes')->andReturn([]);

$repository->persistNewAuthCode($authCode);
}

private function refreshTokenRepository(): BridgeRefreshTokenRepository
{
$events = m::mock('Illuminate\Contracts\Events\Dispatcher');
$events->shouldReceive('dispatch');

return new BridgeRefreshTokenRepository(new RefreshTokenRepository, $events);
}

private function persistNewRefreshToken(BridgeRefreshTokenRepository $repository, string $id): void
{
$refreshToken = m::mock(RefreshToken::class);
$refreshToken->shouldReceive('getIdentifier')->andReturn($id);
$refreshToken->shouldReceive('getAccessToken->getIdentifier')->andReturn('accessTokenId');
$refreshToken->shouldReceive('getExpiryDateTime')->andReturn(CarbonImmutable::now());

$repository->persistNewRefreshToken($refreshToken);
}
}
65 changes: 32 additions & 33 deletions tests/Unit/BridgeRefreshTokenRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

namespace Laravel\Passport\Tests\Unit;

use Carbon\CarbonImmutable;
use Illuminate\Contracts\Events\Dispatcher;
use Laravel\Passport\Bridge\AccessToken;
use Laravel\Passport\Bridge\Client;
use Laravel\Passport\Bridge\RefreshToken;
use Laravel\Passport\Bridge\RefreshTokenRepository as BridgeRefreshTokenRepository;
use Laravel\Passport\RefreshTokenRepository;
use Mockery as m;
Expand All @@ -14,49 +19,43 @@ protected function tearDown(): void
m::close();
}

public function test_it_can_determine_if_a_refresh_token_is_revoked()
public function test_access_tokens_can_be_persisted()
{
$refreshToken = new RevokedRefreshToken;
$repository = $this->repository($refreshToken);
$expiration = CarbonImmutable::now();

$this->assertTrue($repository->isRefreshTokenRevoked('tokenId'));
}
$refreshTokenRepository = m::mock(RefreshTokenRepository::class);
$events = m::mock(Dispatcher::class);

public function test_a_refresh_token_is_also_revoked_if_it_cannot_be_found()
{
$refreshToken = null;
$repository = $this->repository($refreshToken);
$refreshTokenRepository->shouldReceive('create')->once()->andReturnUsing(function ($array) use ($expiration) {
$this->assertEquals('1', $array['id']);
$this->assertEquals('2', $array['access_token_id']);
$this->assertFalse($array['revoked']);
$this->assertEquals($expiration, $array['expires_at']);
});

$this->assertTrue($repository->isRefreshTokenRevoked('tokenId'));
}
$events->shouldReceive('dispatch')->once();

public function test_it_can_determine_if_a_refresh_token_is_not_revoked()
{
$refreshToken = new ActiveRefreshToken;
$repository = $this->repository($refreshToken);
$accessToken = new AccessToken('3', [], m::mock(Client::class));
$accessToken->setIdentifier('2');

$refreshToken = new RefreshToken;
$refreshToken->setIdentifier('1');
$refreshToken->setExpiryDateTime($expiration);
$refreshToken->setAccessToken($accessToken);

$repository = new BridgeRefreshTokenRepository($refreshTokenRepository, $events);

$this->assertFalse($repository->isRefreshTokenRevoked('tokenId'));
$repository->persistNewRefreshToken($refreshToken);
}

private function repository($refreshToken): BridgeRefreshTokenRepository
public function test_can_get_new_refresh_token()
{
$refreshTokenRepository = m::mock(RefreshTokenRepository::class)->makePartial();
$refreshTokenRepository->shouldReceive('find')
->with('tokenId')
->andReturn($refreshToken);
$refreshTokenRepository = m::mock(RefreshTokenRepository::class);
$events = m::mock(Dispatcher::class);
$repository = new BridgeRefreshTokenRepository($refreshTokenRepository, $events);

$events = m::mock('Illuminate\Contracts\Events\Dispatcher');
$token = $repository->getNewRefreshToken();

return new BridgeRefreshTokenRepository($refreshTokenRepository, $events);
$this->assertInstanceOf(RefreshToken::class, $token);
}
}

class ActiveRefreshToken
{
public $revoked = false;
}

class RevokedRefreshToken
{
public $revoked = true;
}