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] Support OAuth2 Server v9 #1734

Merged
merged 22 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 1 addition & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ jobs:
strategy:
fail-fast: true
matrix:
php: ['8.0', 8.1, 8.2, 8.3]
php: [8.1, 8.2, 8.3]
laravel: [9, 10, 11]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a next PR we may drop Laravel v9 and v10 support as well as PHP 8.1

exclude:
- php: '8.0'
laravel: 10
- php: '8.0'
laravel: 11
- php: 8.1
laravel: 11
- php: 8.3
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
composer.lock
/phpunit.xml
.phpunit.result.cache
/.idea
/.vscode
/.rnd
hafezdivandari marked this conversation as resolved.
Show resolved Hide resolved
15 changes: 8 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
}
],
"require": {
"php": "^8.0",
"php": "^8.1",
"ext-json": "*",
"ext-openssl": "*",
"firebase/php-jwt": "^6.4",
"illuminate/auth": "^9.21|^10.0|^11.0",
"illuminate/console": "^9.21|^10.0|^11.0",
Expand All @@ -26,18 +27,18 @@
"illuminate/encryption": "^9.21|^10.0|^11.0",
"illuminate/http": "^9.21|^10.0|^11.0",
"illuminate/support": "^9.21|^10.0|^11.0",
"lcobucci/jwt": "^4.3|^5.0",
"league/oauth2-server": "^8.5.3",
"lcobucci/jwt": "^5.0",
"league/oauth2-server": "^9.0-rc1",
"nyholm/psr7": "^1.5",
"phpseclib/phpseclib": "^2.0|^3.0",
"phpseclib/phpseclib": "^3.0",
"symfony/console": "^6.0|^7.0",
"symfony/psr-http-message-bridge": "^2.1|^6.0|^7.0"
"symfony/psr-http-message-bridge": "^6.0|^7.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^7.35|^8.14|^9.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.3|^10.5"
"phpunit/phpunit": "^9.3|^10.5|^11.0"
},
"autoload": {
"psr-4": {
Expand Down Expand Up @@ -66,6 +67,6 @@
"post-autoload-dump": "@prepare",
"prepare": "@php vendor/bin/testbench package:discover --ansi"
},
"minimum-stability": "dev",
"minimum-stability": "stable",
"prefer-stable": true
}
8 changes: 3 additions & 5 deletions src/Bridge/AccessToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
Expand All @@ -15,12 +16,9 @@ class AccessToken implements AccessTokenEntityInterface
/**
* Create a new token instance.
*
* @param string $userIdentifier
* @param array $scopes
* @param \League\OAuth2\Server\Entities\ClientEntityInterface $client
* @return void
* @param ScopeEntityInterface[] $scopes
*/
public function __construct($userIdentifier, array $scopes, ClientEntityInterface $client)
public function __construct(string|int $userIdentifier, array $scopes, ClientEntityInterface $client)
{
$this->setUserIdentifier($userIdentifier);

Expand Down
25 changes: 10 additions & 15 deletions src/Bridge/AccessTokenRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,16 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface

/**
* The token repository instance.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokenRepository;
protected TokenRepository $tokenRepository;

/**
* The event dispatcher instance.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected $events;
protected Dispatcher $events;

/**
* Create a new repository instance.
*
* @param \Laravel\Passport\TokenRepository $tokenRepository
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function __construct(TokenRepository $tokenRepository, Dispatcher $events)
{
Expand All @@ -45,15 +37,18 @@ public function __construct(TokenRepository $tokenRepository, Dispatcher $events
/**
* {@inheritdoc}
*/
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
{
public function getNewToken(
ClientEntityInterface $clientEntity,
array $scopes,
mixed $userIdentifier = null
): AccessTokenEntityInterface {
return new Passport::$accessTokenEntity($userIdentifier, $scopes, $clientEntity);
}

/**
* {@inheritdoc}
*/
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity): void
{
$this->tokenRepository->create([
'id' => $accessTokenEntity->getIdentifier(),
Expand All @@ -76,15 +71,15 @@ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEnt
/**
* {@inheritdoc}
*/
public function revokeAccessToken($tokenId)
public function revokeAccessToken(string $tokenId): void
{
$this->tokenRepository->revokeAccessToken($tokenId);
}

/**
* {@inheritdoc}
*/
public function isAccessTokenRevoked($tokenId)
public function isAccessTokenRevoked(string $tokenId): bool
{
return $this->tokenRepository->isAccessTokenRevoked($tokenId);
}
Expand Down
8 changes: 4 additions & 4 deletions src/Bridge/AuthCodeRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ class AuthCodeRepository implements AuthCodeRepositoryInterface
/**
* {@inheritdoc}
*/
public function getNewAuthCode()
public function getNewAuthCode(): AuthCodeEntityInterface
{
return new AuthCode;
}

/**
* {@inheritdoc}
*/
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity): void
{
$attributes = [
'id' => $authCodeEntity->getIdentifier(),
Expand All @@ -38,15 +38,15 @@ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
/**
* {@inheritdoc}
*/
public function revokeAuthCode($codeId)
public function revokeAuthCode(string $codeId): void
{
Passport::authCode()->where('id', $codeId)->update(['revoked' => true]);
}

/**
* {@inheritdoc}
*/
public function isAuthCodeRevoked($codeId)
public function isAuthCodeRevoked(string $codeId): bool
{
return Passport::authCode()->where('id', $codeId)->where('revoked', 1)->exists();
}
Expand Down
53 changes: 11 additions & 42 deletions src/Bridge/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,32 @@

use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\Traits\ClientTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;

class Client implements ClientEntityInterface
{
use ClientTrait;

/**
* The client identifier.
*
* @var string
*/
protected $identifier;
use ClientTrait, EntityTrait;

/**
* The client's provider.
*
* @var string
*/
public $provider;
public ?string $provider;

/**
* Create a new client instance.
*
* @param string $identifier
* @param string $name
* @param string $redirectUri
* @param bool $isConfidential
* @param string|null $provider
* @return void
*/
public function __construct($identifier, $name, $redirectUri, $isConfidential = false, $provider = null)
{
$this->setIdentifier((string) $identifier);
public function __construct(
string|int $identifier,
string $name,
string $redirectUri,
bool $isConfidential = false,
?string $provider = null
) {
$this->setIdentifier($identifier);

$this->name = $name;
$this->isConfidential = $isConfidential;
$this->redirectUri = explode(',', $redirectUri);
$this->provider = $provider;
}

/**
* Get the client's identifier.
*
* @return string
*/
public function getIdentifier()
{
return (string) $this->identifier;
}

/**
* Set the client's identifier.
*
* @param string $identifier
* @return void
*/
public function setIdentifier($identifier)
{
$this->identifier = $identifier;
}
}
46 changes: 15 additions & 31 deletions src/Bridge/ClientRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@

namespace Laravel\Passport\Bridge;

use Laravel\Passport\Client as ClientModel;
use Laravel\Passport\ClientRepository as ClientModelRepository;
use Laravel\Passport\Passport;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;

class ClientRepository implements ClientRepositoryInterface
{
/**
* The client model repository.
*
* @var \Laravel\Passport\ClientRepository
*/
protected $clients;
protected ClientModelRepository $clients;

/**
* Create a new repository instance.
*
* @param \Laravel\Passport\ClientRepository $clients
* @return void
*/
public function __construct(ClientModelRepository $clients)
{
Expand All @@ -29,12 +26,12 @@ public function __construct(ClientModelRepository $clients)
/**
* {@inheritdoc}
*/
public function getClientEntity($clientIdentifier)
public function getClientEntity(string $clientIdentifier): ?ClientEntityInterface
{
$record = $this->clients->findActive($clientIdentifier);

if (! $record) {
return;
return null;
}

return new Client(
Expand All @@ -49,7 +46,7 @@ public function getClientEntity($clientIdentifier)
/**
* {@inheritdoc}
*/
public function validateClient($clientIdentifier, $clientSecret, $grantType)
public function validateClient(string $clientIdentifier, ?string $clientSecret, ?string $grantType): bool
{
// First, we will verify that the client exists and is authorized to create personal
// access tokens. Generally personal access tokens are only generated by the user
Expand All @@ -65,39 +62,26 @@ public function validateClient($clientIdentifier, $clientSecret, $grantType)

/**
* Determine if the given client can handle the given grant type.
*
* @param \Laravel\Passport\Client $record
* @param string $grantType
* @return bool
*/
protected function handlesGrant($record, $grantType)
protected function handlesGrant(ClientModel $record, string $grantType): bool
{
if (! $record->hasGrantType($grantType)) {
return false;
}

switch ($grantType) {
case 'authorization_code':
return ! $record->firstParty();
case 'personal_access':
return $record->personal_access_client && $record->confidential();
case 'password':
return $record->password_client;
case 'client_credentials':
return $record->confidential();
default:
return true;
}
return match ($grantType) {
'authorization_code' => ! $record->firstParty(),
'personal_access' => $record->personal_access_client && $record->confidential(),
'password' => $record->password_client,
'client_credentials' => $record->confidential(),
default => true,
};
}

/**
* Verify the client secret is valid.
*
* @param string $clientSecret
* @param string $storedHash
* @return bool
*/
protected function verifySecret($clientSecret, $storedHash)
protected function verifySecret(string $clientSecret, string $storedHash): bool
{
return Passport::$hashesClientSecrets
? password_verify($clientSecret, $storedHash)
Expand Down
Loading
Loading