From b182a80e4dcc93e48a2e8833348706e4a6f6786c Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 8 Sep 2020 17:30:36 +0200 Subject: [PATCH 01/73] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80c7f05..8a63030 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v10.0.0...10.x) +## [Unreleased](https://github.com/laravel/passport/compare/v10.0.0...master) ## [v10.0.0 (2020-09-08)](https://github.com/laravel/passport/compare/v9.3.2...v10.0.0) From ce7f5ab7e15f11446de77a94c50fc2faf2ac283e Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 8 Sep 2020 17:30:52 +0200 Subject: [PATCH 02/73] update branch alias --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9d3d1cd..990652e 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ }, "extra": { "branch-alias": { - "dev-master": "10.x-dev" + "dev-master": "11.x-dev" }, "laravel": { "providers": [ From fb950814a5bf86473a53f98c14312b761e1b0a39 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 22 Feb 2021 15:13:46 +0100 Subject: [PATCH 03/73] Revert model DB connection customization (#1412) --- config/passport.php | 17 ---------- ...1_000001_create_oauth_auth_codes_table.php | 31 ++----------------- ...00002_create_oauth_access_tokens_table.php | 31 ++----------------- ...0003_create_oauth_refresh_tokens_table.php | 31 ++----------------- ...6_01_000004_create_oauth_clients_table.php | 31 ++----------------- ...te_oauth_personal_access_clients_table.php | 31 ++----------------- src/AuthCode.php | 10 ------ src/Client.php | 10 ------ src/PersonalAccessClient.php | 10 ------ src/RefreshToken.php | 10 ------ src/Token.php | 10 ------ tests/Feature/PassportTestCase.php | 2 -- 12 files changed, 10 insertions(+), 214 deletions(-) diff --git a/config/passport.php b/config/passport.php index 162f1f8..79c59ac 100644 --- a/config/passport.php +++ b/config/passport.php @@ -46,21 +46,4 @@ 'secret' => env('PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET'), ], - /* - |-------------------------------------------------------------------------- - | Passport Storage Driver - |-------------------------------------------------------------------------- - | - | This configuration value allows you to customize the storage options - | for Passport, such as the database connection that should be used - | by Passport's internal database models which store tokens, etc. - | - */ - - 'storage' => [ - 'database' => [ - 'connection' => env('DB_CONNECTION', 'mysql'), - ], - ], - ]; diff --git a/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php b/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php index 0eabf05..6c47d24 100644 --- a/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php +++ b/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php @@ -6,23 +6,6 @@ class CreateOauthAuthCodesTable extends Migration { - /** - * The database schema. - * - * @var \Illuminate\Database\Schema\Builder - */ - protected $schema; - - /** - * Create a new migration instance. - * - * @return void - */ - public function __construct() - { - $this->schema = Schema::connection($this->getConnection()); - } - /** * Run the migrations. * @@ -30,7 +13,7 @@ public function __construct() */ public function up() { - $this->schema->create('oauth_auth_codes', function (Blueprint $table) { + Schema::create('oauth_auth_codes', function (Blueprint $table) { $table->string('id', 100)->primary(); $table->unsignedBigInteger('user_id')->index(); $table->unsignedBigInteger('client_id'); @@ -47,16 +30,6 @@ public function up() */ public function down() { - $this->schema->dropIfExists('oauth_auth_codes'); - } - - /** - * Get the migration connection name. - * - * @return string|null - */ - public function getConnection() - { - return config('passport.storage.database.connection'); + Schema::dropIfExists('oauth_auth_codes'); } } diff --git a/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php b/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php index 67c682d..00f0063 100644 --- a/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php +++ b/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php @@ -6,23 +6,6 @@ class CreateOauthAccessTokensTable extends Migration { - /** - * The database schema. - * - * @var \Illuminate\Database\Schema\Builder - */ - protected $schema; - - /** - * Create a new migration instance. - * - * @return void - */ - public function __construct() - { - $this->schema = Schema::connection($this->getConnection()); - } - /** * Run the migrations. * @@ -30,7 +13,7 @@ public function __construct() */ public function up() { - $this->schema->create('oauth_access_tokens', function (Blueprint $table) { + Schema::create('oauth_access_tokens', function (Blueprint $table) { $table->string('id', 100)->primary(); $table->unsignedBigInteger('user_id')->nullable()->index(); $table->unsignedBigInteger('client_id'); @@ -49,16 +32,6 @@ public function up() */ public function down() { - $this->schema->dropIfExists('oauth_access_tokens'); - } - - /** - * Get the migration connection name. - * - * @return string|null - */ - public function getConnection() - { - return config('passport.storage.database.connection'); + Schema::dropIfExists('oauth_access_tokens'); } } diff --git a/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php b/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php index b4ac095..60c5234 100644 --- a/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php +++ b/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php @@ -6,23 +6,6 @@ class CreateOauthRefreshTokensTable extends Migration { - /** - * The database schema. - * - * @var \Illuminate\Database\Schema\Builder - */ - protected $schema; - - /** - * Create a new migration instance. - * - * @return void - */ - public function __construct() - { - $this->schema = Schema::connection($this->getConnection()); - } - /** * Run the migrations. * @@ -30,7 +13,7 @@ public function __construct() */ public function up() { - $this->schema->create('oauth_refresh_tokens', function (Blueprint $table) { + Schema::create('oauth_refresh_tokens', function (Blueprint $table) { $table->string('id', 100)->primary(); $table->string('access_token_id', 100)->index(); $table->boolean('revoked'); @@ -45,16 +28,6 @@ public function up() */ public function down() { - $this->schema->dropIfExists('oauth_refresh_tokens'); - } - - /** - * Get the migration connection name. - * - * @return string|null - */ - public function getConnection() - { - return config('passport.storage.database.connection'); + Schema::dropIfExists('oauth_refresh_tokens'); } } diff --git a/database/migrations/2016_06_01_000004_create_oauth_clients_table.php b/database/migrations/2016_06_01_000004_create_oauth_clients_table.php index 6ce3d99..f0884ee 100644 --- a/database/migrations/2016_06_01_000004_create_oauth_clients_table.php +++ b/database/migrations/2016_06_01_000004_create_oauth_clients_table.php @@ -6,33 +6,6 @@ class CreateOauthClientsTable extends Migration { - /** - * The database schema. - * - * @var \Illuminate\Database\Schema\Builder - */ - protected $schema; - - /** - * Create a new migration instance. - * - * @return void - */ - public function __construct() - { - $this->schema = Schema::connection($this->getConnection()); - } - - /** - * Get the migration connection name. - * - * @return string|null - */ - public function getConnection() - { - return config('passport.storage.database.connection'); - } - /** * Run the migrations. * @@ -40,7 +13,7 @@ public function getConnection() */ public function up() { - $this->schema->create('oauth_clients', function (Blueprint $table) { + Schema::create('oauth_clients', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('user_id')->nullable()->index(); $table->string('name'); @@ -61,6 +34,6 @@ public function up() */ public function down() { - $this->schema->dropIfExists('oauth_clients'); + Schema::dropIfExists('oauth_clients'); } } diff --git a/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php b/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php index c408248..4b56435 100644 --- a/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php +++ b/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php @@ -6,23 +6,6 @@ class CreateOauthPersonalAccessClientsTable extends Migration { - /** - * The database schema. - * - * @var \Illuminate\Database\Schema\Builder - */ - protected $schema; - - /** - * Create a new migration instance. - * - * @return void - */ - public function __construct() - { - $this->schema = Schema::connection($this->getConnection()); - } - /** * Run the migrations. * @@ -30,7 +13,7 @@ public function __construct() */ public function up() { - $this->schema->create('oauth_personal_access_clients', function (Blueprint $table) { + Schema::create('oauth_personal_access_clients', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('client_id'); $table->timestamps(); @@ -44,16 +27,6 @@ public function up() */ public function down() { - $this->schema->dropIfExists('oauth_personal_access_clients'); - } - - /** - * Get the migration connection name. - * - * @return string|null - */ - public function getConnection() - { - return config('passport.storage.database.connection'); + Schema::dropIfExists('oauth_personal_access_clients'); } } diff --git a/src/AuthCode.php b/src/AuthCode.php index 94441b5..09a79c8 100644 --- a/src/AuthCode.php +++ b/src/AuthCode.php @@ -68,14 +68,4 @@ public function client() { return $this->belongsTo(Passport::clientModel()); } - - /** - * Get the current connection name for the model. - * - * @return string|null - */ - public function getConnectionName() - { - return config('passport.storage.database.connection') ?? $this->connection; - } } diff --git a/src/Client.php b/src/Client.php index f75fb7b..7313b40 100644 --- a/src/Client.php +++ b/src/Client.php @@ -184,16 +184,6 @@ public function getIncrementing() return Passport::clientUuids() ? false : $this->incrementing; } - /** - * Get the current connection name for the model. - * - * @return string|null - */ - public function getConnectionName() - { - return config('passport.storage.database.connection') ?? $this->connection; - } - /** * Create a new factory instance for the model. * diff --git a/src/PersonalAccessClient.php b/src/PersonalAccessClient.php index 1d35b05..171b982 100644 --- a/src/PersonalAccessClient.php +++ b/src/PersonalAccessClient.php @@ -29,14 +29,4 @@ public function client() { return $this->belongsTo(Passport::clientModel()); } - - /** - * Get the current connection name for the model. - * - * @return string|null - */ - public function getConnectionName() - { - return config('passport.storage.database.connection') ?? $this->connection; - } } diff --git a/src/RefreshToken.php b/src/RefreshToken.php index 376a97b..00e5a1c 100644 --- a/src/RefreshToken.php +++ b/src/RefreshToken.php @@ -88,14 +88,4 @@ public function transient() { return false; } - - /** - * Get the current connection name for the model. - * - * @return string|null - */ - public function getConnectionName() - { - return config('passport.storage.database.connection') ?? $this->connection; - } } diff --git a/src/Token.php b/src/Token.php index 9dfd874..4a0a13d 100644 --- a/src/Token.php +++ b/src/Token.php @@ -160,14 +160,4 @@ public function transient() { return false; } - - /** - * Get the current connection name for the model. - * - * @return string|null - */ - public function getConnectionName() - { - return config('passport.storage.database.connection') ?? $this->connection; - } } diff --git a/tests/Feature/PassportTestCase.php b/tests/Feature/PassportTestCase.php index d7da023..47a752f 100644 --- a/tests/Feature/PassportTestCase.php +++ b/tests/Feature/PassportTestCase.php @@ -44,8 +44,6 @@ protected function getEnvironmentSetUp($app) $app['config']->set('database.default', 'testbench'); - $app['config']->set('passport.storage.database.connection', 'testbench'); - $app['config']->set('database.connections.testbench', [ 'driver' => 'sqlite', 'database' => ':memory:', From 66b9088993f1be9a4a95129b61dca951e04223ff Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 16 Mar 2021 18:09:22 +0100 Subject: [PATCH 04/73] Allow timestamps on Token model (#1425) --- src/Token.php | 7 ------- tests/Unit/BridgeAccessTokenRepositoryTest.php | 5 +++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Token.php b/src/Token.php index 4a0a13d..6f5d7b9 100644 --- a/src/Token.php +++ b/src/Token.php @@ -53,13 +53,6 @@ class Token extends Model 'expires_at', ]; - /** - * Indicates if the model should be timestamped. - * - * @var bool - */ - public $timestamps = false; - /** * Get the client that the token belongs to. * diff --git a/tests/Unit/BridgeAccessTokenRepositoryTest.php b/tests/Unit/BridgeAccessTokenRepositoryTest.php index 0d34d9b..aa99cd0 100644 --- a/tests/Unit/BridgeAccessTokenRepositoryTest.php +++ b/tests/Unit/BridgeAccessTokenRepositoryTest.php @@ -3,6 +3,7 @@ namespace Laravel\Passport\Tests\Unit; use Carbon\CarbonImmutable; +use DateTime; use Illuminate\Contracts\Events\Dispatcher; use Laravel\Passport\Bridge\AccessToken; use Laravel\Passport\Bridge\AccessTokenRepository; @@ -32,8 +33,8 @@ public function test_access_tokens_can_be_persisted() $this->assertSame('client-id', $array['client_id']); $this->assertEquals(['scopes'], $array['scopes']); $this->assertEquals(false, $array['revoked']); - $this->assertInstanceOf('DateTime', $array['created_at']); - $this->assertInstanceOf('DateTime', $array['updated_at']); + $this->assertInstanceOf(DateTime::class, $array['created_at']); + $this->assertInstanceOf(DateTime::class, $array['updated_at']); $this->assertEquals($expiration, $array['expires_at']); }); From 95bdc167391f2aba326eda674f58d7e77dd8ae60 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 26 May 2021 11:42:54 +0200 Subject: [PATCH 05/73] Improve authenticateViaBearerToken() performance --- src/Guards/TokenGuard.php | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/Guards/TokenGuard.php b/src/Guards/TokenGuard.php index 7d81ed0..da69464 100644 --- a/src/Guards/TokenGuard.php +++ b/src/Guards/TokenGuard.php @@ -81,23 +81,6 @@ public function __construct( $this->encrypter = $encrypter; } - /** - * Determine if the requested provider matches the client's provider. - * - * @param \Illuminate\Http\Request $request - * @return bool - */ - protected function hasValidProvider(Request $request) - { - $client = $this->client($request); - - if ($client && ! $client->provider) { - return true; - } - - return $client && $client->provider === $this->provider->getProviderName(); - } - /** * Get the user for the incoming request. * @@ -148,7 +131,17 @@ protected function authenticateViaBearerToken($request) return; } - if (! $this->hasValidProvider($request)) { + $client = $this->clients->findActive( + $psr->getAttribute('oauth_client_id') + ); + + // Verify if the client that issued this token exists and is still valid + if (! $client) { + return; + } + + // Verify if the client that issued this token matches the requested provider. + if ($client->provider && $client->provider !== $this->provider->getProviderName()) { return; } @@ -170,15 +163,6 @@ protected function authenticateViaBearerToken($request) $psr->getAttribute('oauth_access_token_id') ); - $clientId = $psr->getAttribute('oauth_client_id'); - - // Finally, we will verify if the client that issued this token is still valid and - // its tokens may still be used. If not, we will bail out since we don't want a - // user to be able to send access tokens for deleted or revoked applications. - if ($this->clients->revoked($clientId)) { - return; - } - return $token ? $user->withAccessToken($token) : null; } From b69f25a69ffe2897fff397ff56994f059538201e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 26 May 2021 08:09:39 -0500 Subject: [PATCH 06/73] formatting --- src/Guards/TokenGuard.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Guards/TokenGuard.php b/src/Guards/TokenGuard.php index da69464..88381f0 100644 --- a/src/Guards/TokenGuard.php +++ b/src/Guards/TokenGuard.php @@ -135,13 +135,9 @@ protected function authenticateViaBearerToken($request) $psr->getAttribute('oauth_client_id') ); - // Verify if the client that issued this token exists and is still valid - if (! $client) { - return; - } - - // Verify if the client that issued this token matches the requested provider. - if ($client->provider && $client->provider !== $this->provider->getProviderName()) { + if (! $client || + ($client->provider && + $client->provider !== $this->provider->getProviderName())) { return; } From 7a026acac7576224474f9f51b3b04d8b4541c0e7 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Sun, 18 Jul 2021 18:05:25 +0200 Subject: [PATCH 07/73] [11.x] Refactor routes to dedicated file (#1464) * Refactor routes to dedicated file * Update web.php * Apply fixes from StyleCI (#1465) * formatting Co-authored-by: Taylor Otwell --- routes/web.php | 81 ++++++++++++++ src/Passport.php | 26 ----- src/PassportServiceProvider.php | 77 +++++++++++--- src/RouteRegistrar.php | 165 ----------------------------- tests/Feature/PassportTestCase.php | 3 - 5 files changed, 143 insertions(+), 209 deletions(-) create mode 100644 routes/web.php delete mode 100644 src/RouteRegistrar.php diff --git a/routes/web.php b/routes/web.php new file mode 100644 index 0000000..dfe69dc --- /dev/null +++ b/routes/web.php @@ -0,0 +1,81 @@ + 'AccessTokenController@issueToken', + 'as' => 'token', + 'middleware' => 'throttle', +]); + +Route::middleware(['web', 'auth'])->group(function () { + Route::post('/token/refresh', [ + 'uses' => 'TransientTokenController@refresh', + 'as' => 'token.refresh', + ]); + + Route::get('/authorize', [ + 'uses' => 'AuthorizationController@authorize', + 'as' => 'authorizations.authorize', + ]); + + Route::post('/authorize', [ + 'uses' => 'ApproveAuthorizationController@approve', + 'as' => 'authorizations.approve', + ]); + + Route::delete('/authorize', [ + 'uses' => 'DenyAuthorizationController@deny', + 'as' => 'authorizations.deny', + ]); + + Route::get('/tokens', [ + 'uses' => 'AuthorizedAccessTokenController@forUser', + 'as' => 'tokens.index', + ]); + + Route::delete('/tokens/{token_id}', [ + 'uses' => 'AuthorizedAccessTokenController@destroy', + 'as' => 'tokens.destroy', + ]); + + Route::get('/clients', [ + 'uses' => 'ClientController@forUser', + 'as' => 'clients.index', + ]); + + Route::post('/clients', [ + 'uses' => 'ClientController@store', + 'as' => 'clients.store', + ]); + + Route::put('/clients/{client_id}', [ + 'uses' => 'ClientController@update', + 'as' => 'clients.update', + ]); + + Route::delete('/clients/{client_id}', [ + 'uses' => 'ClientController@destroy', + 'as' => 'clients.destroy', + ]); + + Route::get('/scopes', [ + 'uses' => 'ScopeController@all', + 'as' => 'scopes.index', + ]); + + Route::get('/personal-access-tokens', [ + 'uses' => 'PersonalAccessTokenController@forUser', + 'as' => 'personal.tokens.index', + ]); + + Route::post('/personal-access-tokens', [ + 'uses' => 'PersonalAccessTokenController@store', + 'as' => 'personal.tokens.store', + ]); + + Route::delete('/personal-access-tokens/{token_id}', [ + 'uses' => 'PersonalAccessTokenController@destroy', + 'as' => 'personal.tokens.destroy', + ]); +}); diff --git a/src/Passport.php b/src/Passport.php index 0db48e2..8ca81ed 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -5,7 +5,6 @@ use Carbon\Carbon; use DateInterval; use DateTimeInterface; -use Illuminate\Support\Facades\Route; use League\OAuth2\Server\ResourceServer; use Mockery; use Psr\Http\Message\ServerRequestInterface; @@ -157,31 +156,6 @@ public static function enableImplicitGrant() return new static; } - /** - * Binds the Passport routes into the controller. - * - * @param callable|null $callback - * @param array $options - * @return void - */ - public static function routes($callback = null, array $options = []) - { - $callback = $callback ?: function ($router) { - $router->all(); - }; - - $defaultOptions = [ - 'prefix' => 'oauth', - 'namespace' => '\Laravel\Passport\Http\Controllers', - ]; - - $options = array_merge($defaultOptions, $options); - - Route::group($options, function ($router) use ($callback) { - $callback(new RouteRegistrar($router)); - }); - } - /** * Set the default scope(s). Multiple scopes may be an array or specified delimited by spaces. * diff --git a/src/PassportServiceProvider.php b/src/PassportServiceProvider.php index daeb044..de02ca4 100644 --- a/src/PassportServiceProvider.php +++ b/src/PassportServiceProvider.php @@ -10,6 +10,7 @@ use Illuminate\Support\Facades\Cookie; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Request; +use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; use Laravel\Passport\Bridge\PersonalAccessGrant; use Laravel\Passport\Bridge\RefreshTokenRepository; @@ -34,13 +35,61 @@ class PassportServiceProvider extends ServiceProvider */ public function boot() { - $this->loadViewsFrom(__DIR__.'/../resources/views', 'passport'); + $this->registerRoutes(); + $this->registerResources(); + $this->registerMigrations(); + $this->registerPublishing(); + $this->registerCommands(); $this->deleteCookieOnLogout(); + } - if ($this->app->runningInConsole()) { - $this->registerMigrations(); + /** + * Register the Passport routes. + * + * @return void + */ + protected function registerRoutes() + { + Route::group([ + 'as' => 'passport.', + 'prefix' => config('passport.path', 'oauth'), + 'namespace' => 'Laravel\Passport\Http\Controllers', + ], function () { + $this->loadRoutesFrom(__DIR__.'/../routes/web.php'); + }); + } + + /** + * Register the Passport resources. + * + * @return void + */ + protected function registerResources() + { + $this->loadViewsFrom(__DIR__.'/../resources/views', 'passport'); + } + + /** + * Register the Passport migration files. + * + * @return void + */ + protected function registerMigrations() + { + if ($this->app->runningInConsole() && Passport::$runsMigrations && ! config('passport.client_uuids')) { + $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); + } + } + /** + * Register the package's publishable resources. + * + * @return void + */ + protected function registerPublishing() + { + if ($this->app->runningInConsole()) { $this->publishes([ __DIR__.'/../database/migrations' => database_path('migrations'), ], 'passport-migrations'); @@ -52,26 +101,24 @@ public function boot() $this->publishes([ __DIR__.'/../config/passport.php' => config_path('passport.php'), ], 'passport-config'); - - $this->commands([ - Console\InstallCommand::class, - Console\ClientCommand::class, - Console\HashCommand::class, - Console\KeysCommand::class, - Console\PurgeCommand::class, - ]); } } /** - * Register Passport's migration files. + * Register the Passport Artisan commands. * * @return void */ - protected function registerMigrations() + protected function registerCommands() { - if (Passport::$runsMigrations && ! config('passport.client_uuids')) { - $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); + if ($this->app->runningInConsole()) { + $this->commands([ + Console\InstallCommand::class, + Console\ClientCommand::class, + Console\HashCommand::class, + Console\KeysCommand::class, + Console\PurgeCommand::class, + ]); } } diff --git a/src/RouteRegistrar.php b/src/RouteRegistrar.php deleted file mode 100644 index 12ab3d7..0000000 --- a/src/RouteRegistrar.php +++ /dev/null @@ -1,165 +0,0 @@ -router = $router; - } - - /** - * Register routes for transient tokens, clients, and personal access tokens. - * - * @return void - */ - public function all() - { - $this->forAuthorization(); - $this->forAccessTokens(); - $this->forTransientTokens(); - $this->forClients(); - $this->forPersonalAccessTokens(); - } - - /** - * Register the routes needed for authorization. - * - * @return void - */ - public function forAuthorization() - { - $this->router->group(['middleware' => ['web', 'auth']], function ($router) { - $router->get('/authorize', [ - 'uses' => 'AuthorizationController@authorize', - 'as' => 'passport.authorizations.authorize', - ]); - - $router->post('/authorize', [ - 'uses' => 'ApproveAuthorizationController@approve', - 'as' => 'passport.authorizations.approve', - ]); - - $router->delete('/authorize', [ - 'uses' => 'DenyAuthorizationController@deny', - 'as' => 'passport.authorizations.deny', - ]); - }); - } - - /** - * Register the routes for retrieving and issuing access tokens. - * - * @return void - */ - public function forAccessTokens() - { - $this->router->post('/token', [ - 'uses' => 'AccessTokenController@issueToken', - 'as' => 'passport.token', - 'middleware' => 'throttle', - ]); - - $this->router->group(['middleware' => ['web', 'auth']], function ($router) { - $router->get('/tokens', [ - 'uses' => 'AuthorizedAccessTokenController@forUser', - 'as' => 'passport.tokens.index', - ]); - - $router->delete('/tokens/{token_id}', [ - 'uses' => 'AuthorizedAccessTokenController@destroy', - 'as' => 'passport.tokens.destroy', - ]); - }); - } - - /** - * Register the routes needed for refreshing transient tokens. - * - * @return void - */ - public function forTransientTokens() - { - $this->router->post('/token/refresh', [ - 'middleware' => ['web', 'auth'], - 'uses' => 'TransientTokenController@refresh', - 'as' => 'passport.token.refresh', - ]); - } - - /** - * Register the routes needed for managing clients. - * - * @return void - */ - public function forClients() - { - $this->router->group(['middleware' => ['web', 'auth']], function ($router) { - $router->get('/clients', [ - 'uses' => 'ClientController@forUser', - 'as' => 'passport.clients.index', - ]); - - $router->post('/clients', [ - 'uses' => 'ClientController@store', - 'as' => 'passport.clients.store', - ]); - - $router->put('/clients/{client_id}', [ - 'uses' => 'ClientController@update', - 'as' => 'passport.clients.update', - ]); - - $router->delete('/clients/{client_id}', [ - 'uses' => 'ClientController@destroy', - 'as' => 'passport.clients.destroy', - ]); - }); - } - - /** - * Register the routes needed for managing personal access tokens. - * - * @return void - */ - public function forPersonalAccessTokens() - { - $this->router->group(['middleware' => ['web', 'auth']], function ($router) { - $router->get('/scopes', [ - 'uses' => 'ScopeController@all', - 'as' => 'passport.scopes.index', - ]); - - $router->get('/personal-access-tokens', [ - 'uses' => 'PersonalAccessTokenController@forUser', - 'as' => 'passport.personal.tokens.index', - ]); - - $router->post('/personal-access-tokens', [ - 'uses' => 'PersonalAccessTokenController@store', - 'as' => 'passport.personal.tokens.store', - ]); - - $router->delete('/personal-access-tokens/{token_id}', [ - 'uses' => 'PersonalAccessTokenController@destroy', - 'as' => 'passport.personal.tokens.destroy', - ]); - }); - } -} diff --git a/tests/Feature/PassportTestCase.php b/tests/Feature/PassportTestCase.php index 47a752f..d67e841 100644 --- a/tests/Feature/PassportTestCase.php +++ b/tests/Feature/PassportTestCase.php @@ -4,7 +4,6 @@ use Illuminate\Contracts\Config\Repository; use Illuminate\Foundation\Testing\RefreshDatabase; -use Laravel\Passport\Passport; use Laravel\Passport\PassportServiceProvider; use Orchestra\Testbench\TestCase; @@ -22,8 +21,6 @@ protected function setUp(): void $this->artisan('migrate:fresh'); - Passport::routes(); - @unlink(self::PUBLIC_KEY); @unlink(self::PRIVATE_KEY); From 187580ab87352b1b5bc524aee62d32ff5183dce0 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Fri, 26 Nov 2021 16:38:14 +0100 Subject: [PATCH 08/73] [11.x] Allow authenticated client to be retrieved from the guard (#1508) * Allow authenticated client to be retrieved from the guard * Make token guard macroable * Use previously resolved client when available * Add tests ensuring client and user are only pulled from the database once --- src/Guards/TokenGuard.php | 91 +++++++++++++++---- src/PassportServiceProvider.php | 20 ++--- tests/Unit/TokenGuardTest.php | 151 ++++++++++++++++++++++---------- 3 files changed, 190 insertions(+), 72 deletions(-) diff --git a/src/Guards/TokenGuard.php b/src/Guards/TokenGuard.php index d602652..640c696 100644 --- a/src/Guards/TokenGuard.php +++ b/src/Guards/TokenGuard.php @@ -4,12 +4,15 @@ use Exception; use Firebase\JWT\JWT; +use Illuminate\Auth\GuardHelpers; use Illuminate\Container\Container; +use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Cookie\CookieValuePrefix; use Illuminate\Cookie\Middleware\EncryptCookies; use Illuminate\Http\Request; +use Illuminate\Support\Traits\Macroable; use Laravel\Passport\ClientRepository; use Laravel\Passport\Passport; use Laravel\Passport\PassportUserProvider; @@ -20,8 +23,10 @@ use Nyholm\Psr7\Factory\Psr17Factory; use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; -class TokenGuard +class TokenGuard implements Guard { + use GuardHelpers, Macroable; + /** * The resource server instance. * @@ -57,6 +62,20 @@ class TokenGuard */ protected $encrypter; + /** + * The request instance. + * + * @var \Illuminate\Http\Request + */ + protected $request; + + /** + * The currently authenticated client. + * + * @var \Laravel\Passport\Client|null + */ + protected $client; + /** * Create a new token guard instance. * @@ -65,6 +84,7 @@ class TokenGuard * @param \Laravel\Passport\TokenRepository $tokens * @param \Laravel\Passport\ClientRepository $clients * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter + * @param \Illuminate\Http\Request $request * @return void */ public function __construct( @@ -72,49 +92,75 @@ public function __construct( PassportUserProvider $provider, TokenRepository $tokens, ClientRepository $clients, - Encrypter $encrypter + Encrypter $encrypter, + Request $request ) { $this->server = $server; $this->tokens = $tokens; $this->clients = $clients; $this->provider = $provider; $this->encrypter = $encrypter; + $this->request = $request; } /** * Get the user for the incoming request. * - * @param \Illuminate\Http\Request $request * @return mixed */ - public function user(Request $request) + public function user() { - if ($request->bearerToken()) { - return $this->authenticateViaBearerToken($request); - } elseif ($request->cookie(Passport::cookie())) { - return $this->authenticateViaCookie($request); + if (! is_null($this->user)) { + return $this->user; + } + + if ($this->request->bearerToken()) { + return $this->user = $this->authenticateViaBearerToken($this->request); + } elseif ($this->request->cookie(Passport::cookie())) { + return $this->user = $this->authenticateViaCookie($this->request); } } + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + */ + public function validate(array $credentials = []) + { + return ! is_null((new static( + $this->server, + $this->provider, + $this->tokens, + $this->clients, + $this->encrypter, + $credentials['request'], + ))->user()); + } + /** * Get the client for the incoming request. * - * @param \Illuminate\Http\Request $request * @return mixed */ - public function client(Request $request) + public function client() { - if ($request->bearerToken()) { - if (! $psr = $this->getPsrRequestViaBearerToken($request)) { + if (! is_null($this->client)) { + return $this->client; + } + + if ($this->request->bearerToken()) { + if (! $psr = $this->getPsrRequestViaBearerToken($this->request)) { return; } - return $this->clients->findActive( + return $this->client = $this->clients->findActive( $psr->getAttribute('oauth_client_id') ); - } elseif ($request->cookie(Passport::cookie())) { - if ($token = $this->getTokenViaCookie($request)) { - return $this->clients->findActive($token['aud']); + } elseif ($this->request->cookie(Passport::cookie())) { + if ($token = $this->getTokenViaCookie($this->request)) { + return $this->client = $this->clients->findActive($token['aud']); } } } @@ -285,6 +331,19 @@ protected function getTokenFromRequest($request) return $token; } + /** + * Set the current request instance. + * + * @param \Illuminate\Http\Request $request + * @return $this + */ + public function setRequest(Request $request) + { + $this->request = $request; + + return $this; + } + /** * Determine if the cookie contents should be serialized. * diff --git a/src/PassportServiceProvider.php b/src/PassportServiceProvider.php index de02ca4..0dcc656 100644 --- a/src/PassportServiceProvider.php +++ b/src/PassportServiceProvider.php @@ -4,7 +4,6 @@ use DateInterval; use Illuminate\Auth\Events\Logout; -use Illuminate\Auth\RequestGuard; use Illuminate\Config\Repository as Config; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cookie; @@ -341,19 +340,18 @@ protected function registerGuard() * Make an instance of the token guard. * * @param array $config - * @return \Illuminate\Auth\RequestGuard + * @return \Laravel\Passport\Guards\TokenGuard */ protected function makeGuard(array $config) { - return new RequestGuard(function ($request) use ($config) { - return (new TokenGuard( - $this->app->make(ResourceServer::class), - new PassportUserProvider(Auth::createUserProvider($config['provider']), $config['provider']), - $this->app->make(TokenRepository::class), - $this->app->make(ClientRepository::class), - $this->app->make('encrypter') - ))->user($request); - }, $this->app['request']); + return new TokenGuard( + $this->app->make(ResourceServer::class), + new PassportUserProvider(Auth::createUserProvider($config['provider']), $config['provider']), + $this->app->make(TokenRepository::class), + $this->app->make(ClientRepository::class), + $this->app->make('encrypter'), + $this->app->make('request') + ); } /** diff --git a/tests/Unit/TokenGuardTest.php b/tests/Unit/TokenGuardTest.php index b586eff..0528f38 100644 --- a/tests/Unit/TokenGuardTest.php +++ b/tests/Unit/TokenGuardTest.php @@ -37,11 +37,40 @@ public function test_user_can_be_pulled_via_bearer_token() $clients = m::mock(ClientRepository::class); $encrypter = m::mock(Encrypter::class); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = m::mock()); + $psr->shouldReceive('getAttribute')->with('oauth_user_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); + $psr->shouldReceive('getAttribute')->with('oauth_access_token_id')->andReturn('token'); + $userProvider->shouldReceive('retrieveById')->with(1)->andReturn(new TokenGuardTestUser); + $userProvider->shouldReceive('getProviderName')->andReturn(null); + $tokens->shouldReceive('find')->once()->with('token')->andReturn($token = m::mock()); + $clients->shouldReceive('revoked')->with(1)->andReturn(false); + $clients->shouldReceive('findActive')->with(1)->andReturn(new TokenGuardTestClient); + + $user = $guard->user(); + + $this->assertInstanceOf(TokenGuardTestUser::class, $user); + $this->assertEquals($token, $user->token()); + } + + public function test_user_is_resolved_only_once() + { + $resourceServer = m::mock(ResourceServer::class); + $userProvider = m::mock(PassportUserProvider::class); + $tokens = m::mock(TokenRepository::class); + $clients = m::mock(ClientRepository::class); + $encrypter = m::mock(Encrypter::class); $request = Request::create('/'); $request->headers->set('Authorization', 'Bearer token'); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = m::mock()); $psr->shouldReceive('getAttribute')->with('oauth_user_id')->andReturn(1); $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); @@ -52,10 +81,15 @@ public function test_user_can_be_pulled_via_bearer_token() $clients->shouldReceive('revoked')->with(1)->andReturn(false); $clients->shouldReceive('findActive')->with(1)->andReturn(new TokenGuardTestClient); - $user = $guard->user($request); + $user = $guard->user(); + + $userProvider->shouldReceive('retrieveById')->never(); + + $user2 = $guard->user(); $this->assertInstanceOf(TokenGuardTestUser::class, $user); $this->assertEquals($token, $user->token()); + $this->assertSame($user, $user2); } public function test_no_user_is_returned_when_oauth_throws_exception() @@ -71,19 +105,19 @@ public function test_no_user_is_returned_when_oauth_throws_exception() $clients = m::mock(ClientRepository::class); $encrypter = m::mock(Encrypter::class); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('Authorization', 'Bearer token'); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andThrow( new OAuthServerException('message', 500, 'error type') ); - $this->assertNull($guard->user($request)); + $this->assertNull($guard->user()); // Assert that `validateAuthenticatedRequest` isn't called twice on failure. - $this->assertNull($guard->user($request)); + $this->assertNull($guard->user()); } public function test_null_is_returned_if_no_user_is_found() @@ -98,18 +132,18 @@ public function test_null_is_returned_if_no_user_is_found() ->with(1) ->andReturn(new TokenGuardTestClient); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('Authorization', 'Bearer token'); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = m::mock()); $psr->shouldReceive('getAttribute')->with('oauth_user_id')->andReturn(1); $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); $userProvider->shouldReceive('retrieveById')->with(1)->andReturn(null); $userProvider->shouldReceive('getProviderName')->andReturn(null); - $this->assertNull($guard->user($request)); + $this->assertNull($guard->user()); } public function test_users_may_be_retrieved_from_cookies_with_csrf_token_header() @@ -124,8 +158,6 @@ public function test_users_may_be_retrieved_from_cookies_with_csrf_token_header( ->with(1) ->andReturn(new TokenGuardTestClient); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('X-CSRF-TOKEN', 'token'); $request->cookies->set('laravel_token', @@ -137,10 +169,12 @@ public function test_users_may_be_retrieved_from_cookies_with_csrf_token_header( ], str_repeat('a', 16)), false) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->with(1)->andReturn($expectedUser = new TokenGuardTestUser); $userProvider->shouldReceive('getProviderName')->andReturn(null); - $user = $guard->user($request); + $user = $guard->user(); $this->assertEquals($expectedUser, $user); } @@ -157,8 +191,6 @@ public function test_users_may_be_retrieved_from_cookies_with_xsrf_token_header( ->with(1) ->andReturn(new TokenGuardTestClient); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('X-XSRF-TOKEN', $encrypter->encrypt(CookieValuePrefix::create('X-XSRF-TOKEN', $encrypter->getKey()).'token', false)); $request->cookies->set('laravel_token', @@ -170,10 +202,12 @@ public function test_users_may_be_retrieved_from_cookies_with_xsrf_token_header( ], str_repeat('a', 16)), false) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->with(1)->andReturn($expectedUser = new TokenGuardTestUser); $userProvider->shouldReceive('getProviderName')->andReturn(null); - $user = $guard->user($request); + $user = $guard->user(); $this->assertEquals($expectedUser, $user); } @@ -186,8 +220,6 @@ public function test_cookie_xsrf_is_verified_against_csrf_token_header() $clients = m::mock(ClientRepository::class); $encrypter = new Encrypter(str_repeat('a', 16)); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('X-CSRF-TOKEN', 'wrong_token'); $request->cookies->set('laravel_token', @@ -199,9 +231,11 @@ public function test_cookie_xsrf_is_verified_against_csrf_token_header() ], str_repeat('a', 16))) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->never(); - $this->assertNull($guard->user($request)); + $this->assertNull($guard->user()); } public function test_cookie_xsrf_is_verified_against_xsrf_token_header() @@ -212,8 +246,6 @@ public function test_cookie_xsrf_is_verified_against_xsrf_token_header() $clients = m::mock(ClientRepository::class); $encrypter = new Encrypter(str_repeat('a', 16)); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('X-XSRF-TOKEN', $encrypter->encrypt('wrong_token', false)); $request->cookies->set('laravel_token', @@ -225,9 +257,11 @@ public function test_cookie_xsrf_is_verified_against_xsrf_token_header() ], str_repeat('a', 16))) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->never(); - $this->assertNull($guard->user($request)); + $this->assertNull($guard->user()); } public function test_users_may_be_retrieved_from_cookies_with_xsrf_token_header_when_using_a_custom_encryption_key() @@ -246,8 +280,6 @@ public function test_users_may_be_retrieved_from_cookies_with_xsrf_token_header_ ->with(1) ->andReturn(new TokenGuardTestClient); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('X-XSRF-TOKEN', $encrypter->encrypt(CookieValuePrefix::create('X-XSRF-TOKEN', $encrypter->getKey()).'token', false)); $request->cookies->set('laravel_token', @@ -259,10 +291,12 @@ public function test_users_may_be_retrieved_from_cookies_with_xsrf_token_header_ ], Passport::tokenEncryptionKey($encrypter)), false) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->with(1)->andReturn($expectedUser = new TokenGuardTestUser); $userProvider->shouldReceive('getProviderName')->andReturn(null); - $user = $guard->user($request); + $user = $guard->user(); $this->assertEquals($expectedUser, $user); @@ -278,8 +312,6 @@ public function test_xsrf_token_cookie_without_a_token_header_is_not_accepted() $clients = m::mock(ClientRepository::class); $encrypter = new Encrypter(str_repeat('a', 16)); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->cookies->set('XSRF-TOKEN', $encrypter->encrypt('token', false)); $request->cookies->set('laravel_token', @@ -291,9 +323,11 @@ public function test_xsrf_token_cookie_without_a_token_header_is_not_accepted() ], str_repeat('a', 16))) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->never(); - $this->assertNull($guard->user($request)); + $this->assertNull($guard->user()); } public function test_expired_cookies_may_not_be_used() @@ -304,8 +338,6 @@ public function test_expired_cookies_may_not_be_used() $clients = m::mock(ClientRepository::class); $encrypter = new Encrypter(str_repeat('a', 16)); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('X-CSRF-TOKEN', 'token'); $request->cookies->set('laravel_token', @@ -317,9 +349,11 @@ public function test_expired_cookies_may_not_be_used() ], str_repeat('a', 16))) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->never(); - $this->assertNull($guard->user($request)); + $this->assertNull($guard->user()); } public function test_csrf_check_can_be_disabled() @@ -334,8 +368,6 @@ public function test_csrf_check_can_be_disabled() ->with(1) ->andReturn(new TokenGuardTestClient); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - Passport::ignoreCsrfToken(); $request = Request::create('/'); @@ -347,10 +379,12 @@ public function test_csrf_check_can_be_disabled() ], str_repeat('a', 16)), false) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $userProvider->shouldReceive('retrieveById')->with(1)->andReturn($expectedUser = new TokenGuardTestUser); $userProvider->shouldReceive('getProviderName')->andReturn(null); - $user = $guard->user($request); + $user = $guard->user(); $this->assertEquals($expectedUser, $user); } @@ -363,18 +397,45 @@ public function test_client_can_be_pulled_via_bearer_token() $clients = m::mock(ClientRepository::class); $encrypter = m::mock(Encrypter::class); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); + $request = Request::create('/'); + $request->headers->set('Authorization', 'Bearer token'); + + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = m::mock()); + $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); + $clients->shouldReceive('findActive')->with(1)->andReturn(new TokenGuardTestClient); + + $client = $guard->client(); + + $this->assertInstanceOf(TokenGuardTestClient::class, $client); + } + + public function test_client_is_resolved_only_once() + { + $resourceServer = m::mock(ResourceServer::class); + $userProvider = m::mock(PassportUserProvider::class); + $tokens = m::mock(TokenRepository::class); + $clients = m::mock(ClientRepository::class); + $encrypter = m::mock(Encrypter::class); $request = Request::create('/'); $request->headers->set('Authorization', 'Bearer token'); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = m::mock()); $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); $clients->shouldReceive('findActive')->with(1)->andReturn(new TokenGuardTestClient); - $client = $guard->client($request); + $client = $guard->client(); + + $clients->shouldReceive('findActive')->never(); + + $client2 = $guard->client(); $this->assertInstanceOf(TokenGuardTestClient::class, $client); + $this->assertSame($client, $client2); } public function test_no_client_is_returned_when_oauth_throws_exception() @@ -390,19 +451,19 @@ public function test_no_client_is_returned_when_oauth_throws_exception() $clients = m::mock(ClientRepository::class); $encrypter = m::mock(Encrypter::class); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('Authorization', 'Bearer token'); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andThrow( new OAuthServerException('message', 500, 'error type') ); - $this->assertNull($guard->client($request)); + $this->assertNull($guard->client()); // Assert that `validateAuthenticatedRequest` isn't called twice on failure. - $this->assertNull($guard->client($request)); + $this->assertNull($guard->client()); } public function test_null_is_returned_if_no_client_is_found() @@ -413,16 +474,16 @@ public function test_null_is_returned_if_no_client_is_found() $clients = m::mock(ClientRepository::class); $encrypter = m::mock(Encrypter::class); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('Authorization', 'Bearer token'); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $resourceServer->shouldReceive('validateAuthenticatedRequest')->andReturn($psr = m::mock()); $psr->shouldReceive('getAttribute')->with('oauth_client_id')->andReturn(1); $clients->shouldReceive('findActive')->with(1)->andReturn(null); - $this->assertNull($guard->client($request)); + $this->assertNull($guard->client()); } public function test_clients_may_be_retrieved_from_cookies() @@ -433,8 +494,6 @@ public function test_clients_may_be_retrieved_from_cookies() $clients = m::mock(ClientRepository::class); $encrypter = new Encrypter(str_repeat('a', 16)); - $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter); - $request = Request::create('/'); $request->headers->set('X-CSRF-TOKEN', 'token'); $request->cookies->set('laravel_token', @@ -446,9 +505,11 @@ public function test_clients_may_be_retrieved_from_cookies() ], str_repeat('a', 16)), false) ); + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + $clients->shouldReceive('findActive')->with(1)->andReturn($expectedClient = new TokenGuardTestClient); - $client = $guard->client($request); + $client = $guard->client(); $this->assertEquals($expectedClient, $client); } From d239c9829062da1c91919c8ce25b99ef3c90ea01 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 7 Dec 2021 16:24:22 +0000 Subject: [PATCH 09/73] Apply fixes from StyleCI --- tests/Feature/PassportTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/PassportTestCase.php b/tests/Feature/PassportTestCase.php index abffa7e..8daeb4e 100644 --- a/tests/Feature/PassportTestCase.php +++ b/tests/Feature/PassportTestCase.php @@ -4,8 +4,8 @@ use Illuminate\Contracts\Config\Repository; use Illuminate\Foundation\Testing\RefreshDatabase; -use Laravel\Passport\PassportServiceProvider; use Laravel\Passport\Passport; +use Laravel\Passport\PassportServiceProvider; use Orchestra\Testbench\TestCase; abstract class PassportTestCase extends TestCase From d511a3ca9ff97e65ff5de8a73a9c070c204f3b5a Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Mon, 24 Jan 2022 18:51:06 +0100 Subject: [PATCH 10/73] [11.x] Stub client on guard when calling Passport::actingAsClient() (#1519) * Allow token guard client to be set programmatically * Set the client on the TokenGuard when mocking the client * Apply fixes from StyleCI --- src/Guards/TokenGuard.php | 14 ++++++++++++++ src/Passport.php | 7 ++++++- tests/Feature/ActingAsClientTest.php | 10 ++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Guards/TokenGuard.php b/src/Guards/TokenGuard.php index 640c696..a10a1fe 100644 --- a/src/Guards/TokenGuard.php +++ b/src/Guards/TokenGuard.php @@ -13,6 +13,7 @@ use Illuminate\Cookie\Middleware\EncryptCookies; use Illuminate\Http\Request; use Illuminate\Support\Traits\Macroable; +use Laravel\Passport\Client; use Laravel\Passport\ClientRepository; use Laravel\Passport\Passport; use Laravel\Passport\PassportUserProvider; @@ -353,4 +354,17 @@ public static function serialized() { return EncryptCookies::serialized('XSRF-TOKEN'); } + + /** + * Set the client for the current request. + * + * @param \Laravel\Passport\Client $client + * @return $this + */ + public function setClient(Client $client) + { + $this->client = $client; + + return $this; + } } diff --git a/src/Passport.php b/src/Passport.php index b181511..bec7ce9 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -388,9 +388,10 @@ public static function actingAs($user, $scopes = [], $guard = 'api') * * @param \Laravel\Passport\Client $client * @param array $scopes + * @param string $guard * @return \Laravel\Passport\Client */ - public static function actingAsClient($client, $scopes = []) + public static function actingAsClient($client, $scopes = [], $guard = 'api') { $token = app(self::tokenModel()); @@ -414,6 +415,10 @@ public static function actingAsClient($client, $scopes = []) app()->instance(TokenRepository::class, $mock); + app('auth')->guard($guard)->setClient($client); + + app('auth')->shouldUse($guard); + return $client; } diff --git a/tests/Feature/ActingAsClientTest.php b/tests/Feature/ActingAsClientTest.php index 8fc99b7..f0a92c7 100644 --- a/tests/Feature/ActingAsClientTest.php +++ b/tests/Feature/ActingAsClientTest.php @@ -7,9 +7,8 @@ use Laravel\Passport\Http\Middleware\CheckClientCredentials; use Laravel\Passport\Http\Middleware\CheckClientCredentialsForAnyScope; use Laravel\Passport\Passport; -use Orchestra\Testbench\TestCase; -class ActingAsClientTest extends TestCase +class ActingAsClientTest extends PassportTestCase { public function testActingAsClientWhenTheRouteIsProtectedByCheckClientCredentialsMiddleware() { @@ -46,4 +45,11 @@ public function testActingAsClientWhenTheRouteIsProtectedByCheckClientCredential $response->assertSuccessful(); $response->assertSee('bar'); } + + public function testActingAsClientSetsTheClientOnTheGuard() + { + Passport::actingAsClient($client = new Client()); + + $this->assertSame($client, app('auth')->client()); + } } From 3498c408dee47b3b0081960d975de3b9644d77e8 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 19 Apr 2022 15:37:59 +0000 Subject: [PATCH 11/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6e9728..543b8f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v10.4.0...10.x) +## [Unreleased](https://github.com/laravel/passport/compare/v10.4.1...10.x) + +## [v10.4.1](https://github.com/laravel/passport/compare/v10.4.0...v10.4.1) - 2022-04-16 + +### Changed + +- Add new URI Rule to validate URI and use it to RedirectRule. by @victorbalssa in https://github.com/laravel/passport/pull/1544 ## [v10.4.0](https://github.com/laravel/passport/compare/v10.3.3...v10.4.0) - 2022-03-30 From 9c6e8c11b9a0cc116e70df0f9d86bf409872e043 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 8 Jun 2022 11:31:47 +0200 Subject: [PATCH 12/73] Update pull-requests.yml --- .github/workflows/pull-requests.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index 156b46e..18b32b3 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -1,9 +1,8 @@ -name: Pull Requests +name: pull requests on: pull_request_target: - types: - - opened + types: [opened] permissions: pull-requests: write From 75fd509928952ccbaff47e609d4f0e657a2c22cf Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 8 Jun 2022 11:32:00 +0200 Subject: [PATCH 13/73] Update update-changelog.yml --- .github/workflows/update-changelog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index eaeaf1f..1625bda 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -1,4 +1,4 @@ -name: "Update Changelog" +name: update changelog on: release: From ed6f6c1d7582d4650bd9ccdf37ee950f11383940 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Wed, 13 Jul 2022 16:39:47 +0200 Subject: [PATCH 14/73] [11.x] Fix scope inheritance when using Passport::actingAs() (#1551) * Fix scope inheritance when using Passport::actingAs() * Update Passport.php Co-authored-by: Taylor Otwell --- src/Passport.php | 6 ++---- tests/Feature/ActingAsTest.php | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Passport.php b/src/Passport.php index bec7ce9..67851b8 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -364,11 +364,9 @@ public static function ignoreCsrfToken($ignoreCsrfToken = true) */ public static function actingAs($user, $scopes = [], $guard = 'api') { - $token = Mockery::mock(self::tokenModel())->shouldIgnoreMissing(false); + $token = app(self::tokenModel()); - foreach ($scopes as $scope) { - $token->shouldReceive('can')->with($scope)->andReturn(true); - } + $token->scopes = $scopes; $user->withAccessToken($token); diff --git a/tests/Feature/ActingAsTest.php b/tests/Feature/ActingAsTest.php index aa1b3ec..bf0b953 100644 --- a/tests/Feature/ActingAsTest.php +++ b/tests/Feature/ActingAsTest.php @@ -4,6 +4,7 @@ use Illuminate\Contracts\Routing\Registrar; use Illuminate\Foundation\Auth\User; +use Illuminate\Support\Facades\Route; use Laravel\Passport\HasApiTokens; use Laravel\Passport\Http\Middleware\CheckForAnyScope; use Laravel\Passport\Http\Middleware\CheckScopes; @@ -64,6 +65,40 @@ public function testActingAsWhenTheRouteIsProtectedByCheckForAnyScopeMiddleware( $response->assertSuccessful(); $response->assertSee('bar'); } + + public function testActingAsWhenTheRouteIsProtectedByCheckScopesMiddlewareWithInheritance() + { + Passport::$withInheritedScopes = true; + + $this->withoutExceptionHandling(); + + Route::middleware(CheckScopes::class.':foo:bar,baz:qux')->get('/foo', function () { + return 'bar'; + }); + + Passport::actingAs(new PassportUser(), ['foo', 'baz']); + + $response = $this->get('/foo'); + $response->assertSuccessful(); + $response->assertSee('bar'); + } + + public function testActingAsWhenTheRouteIsProtectedByCheckForAnyScopeMiddlewareWithInheritance() + { + Passport::$withInheritedScopes = true; + + $this->withoutExceptionHandling(); + + Route::middleware(CheckForAnyScope::class.':foo:baz,baz:qux')->get('/foo', function () { + return 'bar'; + }); + + Passport::actingAs(new PassportUser(), ['foo']); + + $response = $this->get('/foo'); + $response->assertSuccessful(); + $response->assertSee('bar'); + } } class PassportUser extends User From 836f5506aaf1095c8f4dc7c358ce83a85c3f5fde Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 16 Aug 2022 16:29:05 +0200 Subject: [PATCH 15/73] Drop PHP 7.x and Laravel v8 (#1558) --- .github/workflows/tests.yml | 9 ++------- composer.json | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 64514f8..d6cf7f4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,13 +13,8 @@ jobs: strategy: fail-fast: true matrix: - php: [7.3, 7.4, '8.0', 8.1] - laravel: [8, 9] - exclude: - - php: 7.3 - laravel: 9 - - php: 7.4 - laravel: 9 + php: ['8.0', 8.1] + laravel: [9] name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} diff --git a/composer.json b/composer.json index 124b5e5..6762200 100644 --- a/composer.json +++ b/composer.json @@ -14,18 +14,18 @@ } ], "require": { - "php": "^7.3|^8.0", + "php": "^8.0", "ext-json": "*", "firebase/php-jwt": "^6.0", - "illuminate/auth": "^8.37|^9.0", - "illuminate/console": "^8.37|^9.0", - "illuminate/container": "^8.37|^9.0", - "illuminate/contracts": "^8.37|^9.0", - "illuminate/cookie": "^8.37|^9.0", - "illuminate/database": "^8.37|^9.0", - "illuminate/encryption": "^8.37|^9.0", - "illuminate/http": "^8.37|^9.0", - "illuminate/support": "^8.37|^9.0", + "illuminate/auth": "^9.0", + "illuminate/console": "^9.0", + "illuminate/container": "^9.0", + "illuminate/contracts": "^9.0", + "illuminate/cookie": "^9.0", + "illuminate/database": "^9.0", + "illuminate/encryption": "^9.0", + "illuminate/http": "^9.0", + "illuminate/support": "^9.0", "lcobucci/jwt": "^3.4|^4.0", "league/oauth2-server": "^8.2", "nyholm/psr7": "^1.3", @@ -34,7 +34,7 @@ }, "require-dev": { "mockery/mockery": "^1.0", - "orchestra/testbench": "^6.0|^7.0", + "orchestra/testbench": "^7.0", "phpunit/phpunit": "^9.3" }, "autoload": { From 516cddbb817a01a176cea413a2df0976844572c3 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 16 Aug 2022 16:47:51 +0200 Subject: [PATCH 16/73] Remove deprecated properties (#1560) --- src/Passport.php | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/Passport.php b/src/Passport.php index 67851b8..f3c11d9 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -35,15 +35,6 @@ class Passport // ]; - /** - * The date when access tokens expire. - * - * @var \DateTimeInterface|null - * - * @deprecated Will be removed in the next major Passport release. - */ - public static $tokensExpireAt; - /** * The interval when access tokens expire. * @@ -51,15 +42,6 @@ class Passport */ public static $tokensExpireIn; - /** - * The date when refresh tokens expire. - * - * @var \DateTimeInterface|null - * - * @deprecated Will be removed in the next major Passport release. - */ - public static $refreshTokensExpireAt; - /** * The date when refresh tokens expire. * @@ -67,15 +49,6 @@ class Passport */ public static $refreshTokensExpireIn; - /** - * The date when personal access tokens expire. - * - * @var \DateTimeInterface|null - * - * @deprecated Will be removed in the next major Passport release. - */ - public static $personalAccessTokensExpireAt; - /** * The date when personal access tokens expire. * @@ -282,7 +255,6 @@ public static function tokensExpireIn(DateTimeInterface $date = null) return static::$tokensExpireIn ?? new DateInterval('P1Y'); } - static::$tokensExpireAt = $date; static::$tokensExpireIn = Carbon::now()->diff($date); return new static; @@ -300,7 +272,6 @@ public static function refreshTokensExpireIn(DateTimeInterface $date = null) return static::$refreshTokensExpireIn ?? new DateInterval('P1Y'); } - static::$refreshTokensExpireAt = $date; static::$refreshTokensExpireIn = Carbon::now()->diff($date); return new static; @@ -318,7 +289,6 @@ public static function personalAccessTokensExpireIn(DateTimeInterface $date = nu return static::$personalAccessTokensExpireIn ?? new DateInterval('P1Y'); } - static::$personalAccessTokensExpireAt = $date; static::$personalAccessTokensExpireIn = Carbon::now()->diff($date); return new static; From a17975f438b86f494f29f7ebfcd44c7d8562af12 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 19 Aug 2022 13:53:39 +0200 Subject: [PATCH 17/73] wip --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c151df..7dbaac2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v10.4.1...master) +## [Unreleased](https://github.com/laravel/passport/compare/v10.4.1...11.x) ## [v10.4.1](https://github.com/laravel/passport/compare/v10.4.0...v10.4.1) - 2022-04-16 From a57723e58faaa70c5629d2a15f7ecc291e98fd73 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 19 Aug 2022 17:00:43 +0200 Subject: [PATCH 18/73] Passport v11 upgrade guide (#1561) * Passport v11 upgrade guide * Update UPGRADE.md Co-authored-by: Taylor Otwell --- UPGRADE.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/UPGRADE.md b/UPGRADE.md index 4df35ce..643f764 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -2,6 +2,50 @@ ## General Notes +## Upgrading To 11.0 From 10.x + +### Minimum PHP Version + +PHP 8.0 is now the minimum required version. + +### Minimum Laravel Version + +Laravel 9.0 is now the minimum required version. + +### Reverting Model DB Connection Customization + +PR: https://github.com/laravel/passport/pull/1412 + +Customizing model database connections through the migration files has been reverted. This was first introduced in [this PR](https://github.com/laravel/passport/pull/1255). + +If you need to customize the database connection for a model you should override the models [as explained in the documentation](https://laravel.com/docs/9.x/passport#overriding-default-models). + +### Allow Timestamps On Token model + +PR: https://github.com/laravel/passport/pull/1425 + +Timestamps are now allowed on the `Token` model. If you specifically didn't want these model's timestamps to be updated then you may override the `Token` model [as explained in the documentation](https://laravel.com/docs/9.x/passport#overriding-default-models). + +### Refactor Routes To Dedicated File + +PR: https://github.com/laravel/passport/pull/1464 + +Passport's routes have been moved to a dedicated route file. You can remove the `Passport::routes()` call from your application's service provider. + +If you previously relied on overwriting routes using `routes($callback = null, array $options = [])` you may now achieve the same behavior by simply overwriting the routes in your application's own `web.php` route file. + +### Stubbing Client In Tests + +PR: https://github.com/laravel/passport/pull/1519 + +Previously, a stubbed client created via `Passport::actingAsClient(...)` wasn't retrieved when calling the `->client()` method on the API guard. This has been fixed in Passport v11 to reflect real-world situations and you may need to accommodate for this behavior in your tests. + +### Scope Inheritance In Tests + +PR: https://github.com/laravel/passport/pull/1551 + +Previously, scopes weren't inherited when using `Passport::actingAs(...)`. This has been fixed in Passport v11 to reflect real-world situations and you may need to accommodate for this behavior in your tests. + ## Upgrading To 10.0 From 9.x ### Minimum PHP Version From dd00df75cc10f14186f71edb39a8839627ef837e Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 19 Aug 2022 17:05:01 +0200 Subject: [PATCH 19/73] [11.x] Remove deprecated functionality and simplify some feature tests (#1559) * Drop JWT v3 * wip --- src/Http/Controllers/AccessTokenController.php | 15 +-------------- src/PersonalAccessTokenFactory.php | 4 +--- tests/Feature/AccessTokenControllerTest.php | 15 +++------------ tests/Unit/AccessTokenControllerTest.php | 7 ++----- 4 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/Http/Controllers/AccessTokenController.php b/src/Http/Controllers/AccessTokenController.php index 3667c2d..7c3b395 100644 --- a/src/Http/Controllers/AccessTokenController.php +++ b/src/Http/Controllers/AccessTokenController.php @@ -3,7 +3,6 @@ namespace Laravel\Passport\Http\Controllers; use Laravel\Passport\TokenRepository; -use Lcobucci\JWT\Parser as JwtParser; use League\OAuth2\Server\AuthorizationServer; use Nyholm\Psr7\Response as Psr7Response; use Psr\Http\Message\ServerRequestInterface; @@ -26,28 +25,16 @@ class AccessTokenController */ protected $tokens; - /** - * The JWT parser instance. - * - * @var \Lcobucci\JWT\Parser - * - * @deprecated This property will be removed in a future Passport version. - */ - protected $jwt; - /** * Create a new controller instance. * * @param \League\OAuth2\Server\AuthorizationServer $server * @param \Laravel\Passport\TokenRepository $tokens - * @param \Lcobucci\JWT\Parser $jwt * @return void */ public function __construct(AuthorizationServer $server, - TokenRepository $tokens, - JwtParser $jwt) + TokenRepository $tokens) { - $this->jwt = $jwt; $this->server = $server; $this->tokens = $tokens; } diff --git a/src/PersonalAccessTokenFactory.php b/src/PersonalAccessTokenFactory.php index b849d06..65817a7 100644 --- a/src/PersonalAccessTokenFactory.php +++ b/src/PersonalAccessTokenFactory.php @@ -35,8 +35,6 @@ class PersonalAccessTokenFactory * The JWT token parser instance. * * @var \Lcobucci\JWT\Parser - * - * @deprecated This property will be removed in a future Passport version. */ protected $jwt; @@ -126,7 +124,7 @@ protected function dispatchRequestToAuthorizationServer(ServerRequestInterface $ * @param array $response * @return \Laravel\Passport\Token */ - protected function findAccessToken(array $response) + public function findAccessToken(array $response) { return $this->tokens->find( $this->jwt->parse($response['access_token'])->claims()->get('jti') diff --git a/tests/Feature/AccessTokenControllerTest.php b/tests/Feature/AccessTokenControllerTest.php index 451107d..073f65d 100644 --- a/tests/Feature/AccessTokenControllerTest.php +++ b/tests/Feature/AccessTokenControllerTest.php @@ -7,13 +7,11 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Laravel\Passport\Client; -use Laravel\Passport\ClientRepository; use Laravel\Passport\Database\Factories\ClientFactory; use Laravel\Passport\HasApiTokens; use Laravel\Passport\Passport; +use Laravel\Passport\PersonalAccessTokenFactory; use Laravel\Passport\Token; -use Laravel\Passport\TokenRepository; -use Lcobucci\JWT\Configuration; class AccessTokenControllerTest extends PassportTestCase { @@ -78,10 +76,7 @@ public function testGettingAccessTokenWithClientCredentialsGrant() $expiresInSeconds = 31536000; $this->assertEqualsWithDelta($expiresInSeconds, $decodedResponse['expires_in'], 5); - $jwtAccessToken = Configuration::forUnsecuredSigner()->parser()->parse($decodedResponse['access_token']); - $this->assertTrue($this->app->make(ClientRepository::class)->findActive($jwtAccessToken->claims()->get('aud'))->is($client)); - - $token = $this->app->make(TokenRepository::class)->find($jwtAccessToken->claims()->get('jti')); + $token = $this->app->make(PersonalAccessTokenFactory::class)->findAccessToken($decodedResponse); $this->assertInstanceOf(Token::class, $token); $this->assertTrue($token->client->is($client)); $this->assertFalse($token->revoked); @@ -171,11 +166,7 @@ public function testGettingAccessTokenWithPasswordGrant() $expiresInSeconds = 31536000; $this->assertEqualsWithDelta($expiresInSeconds, $decodedResponse['expires_in'], 5); - $jwtAccessToken = Configuration::forUnsecuredSigner()->parser()->parse($decodedResponse['access_token']); - $this->assertTrue($this->app->make(ClientRepository::class)->findActive($jwtAccessToken->claims()->get('aud'))->is($client)); - $this->assertTrue($this->app->make('auth')->createUserProvider()->retrieveById($jwtAccessToken->claims()->get('sub'))->is($user)); - - $token = $this->app->make(TokenRepository::class)->find($jwtAccessToken->claims()->get('jti')); + $token = $this->app->make(PersonalAccessTokenFactory::class)->findAccessToken($decodedResponse); $this->assertInstanceOf(Token::class, $token); $this->assertFalse($token->revoked); $this->assertTrue($token->user->is($user)); diff --git a/tests/Unit/AccessTokenControllerTest.php b/tests/Unit/AccessTokenControllerTest.php index 0e451fc..bcd72cb 100644 --- a/tests/Unit/AccessTokenControllerTest.php +++ b/tests/Unit/AccessTokenControllerTest.php @@ -5,7 +5,6 @@ use Laravel\Passport\Exceptions\OAuthServerException; use Laravel\Passport\Http\Controllers\AccessTokenController; use Laravel\Passport\TokenRepository; -use Lcobucci\JWT\Parser; use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException as LeagueException; use Mockery as m; @@ -26,7 +25,6 @@ public function test_a_token_can_be_issued() $request = m::mock(ServerRequestInterface::class); $response = m::type(ResponseInterface::class); $tokens = m::mock(TokenRepository::class); - $jwt = m::mock(Parser::class); $psrResponse = new Response(); $psrResponse->getBody()->write(json_encode(['access_token' => 'access-token'])); @@ -36,7 +34,7 @@ public function test_a_token_can_be_issued() ->with($request, $response) ->andReturn($psrResponse); - $controller = new AccessTokenController($server, $tokens, $jwt); + $controller = new AccessTokenController($server, $tokens); $this->assertSame('{"access_token":"access-token"}', $controller->issueToken($request)->getContent()); } @@ -44,14 +42,13 @@ public function test_a_token_can_be_issued() public function test_exceptions_are_handled() { $tokens = m::mock(TokenRepository::class); - $jwt = m::mock(Parser::class); $server = m::mock(AuthorizationServer::class); $server->shouldReceive('respondToAccessTokenRequest')->with( m::type(ServerRequestInterface::class), m::type(ResponseInterface::class) )->andThrow(LeagueException::invalidCredentials()); - $controller = new AccessTokenController($server, $tokens, $jwt); + $controller = new AccessTokenController($server, $tokens); $this->expectException(OAuthServerException::class); From dac2be68174104d9d56051144d2c3b634f37d54d Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 23 Aug 2022 15:07:40 +0000 Subject: [PATCH 20/73] Update CHANGELOG --- CHANGELOG.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dbaac2..e8e4a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,30 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v10.4.1...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.0.0...11.x) + +## [v11.0.0](https://github.com/laravel/passport/compare/v10.4.1...v11.0.0) - 2022-08-19 + +### Added + +- Allow authenticated client to be retrieved from the guard by @axlon in https://github.com/laravel/passport/pull/1508 + +### Changed + +- Revert model DB connection customization by @driesvints in https://github.com/laravel/passport/pull/1412 +- Allow timestamps on Token model by @driesvints in https://github.com/laravel/passport/pull/1425 +- Improve authenticateViaBearerToken() performance by @alecpl in https://github.com/laravel/passport/pull/1447 +- Refactor routes to dedicated file by @driesvints in https://github.com/laravel/passport/pull/1464 + +### Fixed + +- Stub client on guard when calling Passport::actingAsClient() by @axlon in https://github.com/laravel/passport/pull/1519 +- Fix scope inheritance when using Passport::actingAs() by @axlon in https://github.com/laravel/passport/pull/1551 + +### Removed + +- Drop PHP 7.x and Laravel v8 by @driesvints in https://github.com/laravel/passport/pull/1558 +- Remove deprecated properties by @driesvints in https://github.com/laravel/passport/pull/1560 +- Remove deprecated functionality and simplify some feature tests by @driesvints in https://github.com/laravel/passport/pull/1559 ## [v10.4.1](https://github.com/laravel/passport/compare/v10.4.0...v10.4.1) - 2022-04-16 From 5629f1ac822dc1abb59c292aab8c454f67080ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Garc=C3=ADa?= Date: Wed, 24 Aug 2022 15:20:26 +0100 Subject: [PATCH 21/73] [11.x] Custom days and hours to passport purge command (#1563) * Custom days and hours to passport purge command * lint fix * formatting Co-authored-by: Ruben Garcia Co-authored-by: Taylor Otwell --- src/Console/PurgeCommand.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Console/PurgeCommand.php b/src/Console/PurgeCommand.php index 7854c6a..e42a6ad 100644 --- a/src/Console/PurgeCommand.php +++ b/src/Console/PurgeCommand.php @@ -15,7 +15,8 @@ class PurgeCommand extends Command */ protected $signature = 'passport:purge {--revoked : Only purge revoked tokens and authentication codes} - {--expired : Only purge expired tokens and authentication codes}'; + {--expired : Only purge expired tokens and authentication codes} + {--hours= : The number of hours to retain expired tokens}'; /** * The console command description. @@ -29,7 +30,9 @@ class PurgeCommand extends Command */ public function handle() { - $expired = Carbon::now()->subDays(7); + $expired = $this->option('hours') + ? Carbon::now()->subHours($this->option('hours')) + : Carbon::now()->subDays(7); if (($this->option('revoked') && $this->option('expired')) || (! $this->option('revoked') && ! $this->option('expired'))) { From e312f36e35e695877c4f4eee54c9cc1dcca20eef Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Mon, 29 Aug 2022 15:56:25 +0200 Subject: [PATCH 22/73] [11.x] Allow for bootstrapping without loading routes (#1564) * Allow for bootstrapping without loading routes * Update Passport.php Co-authored-by: Taylor Otwell --- src/Passport.php | 19 +++++++++++++++++++ src/PassportServiceProvider.php | 16 +++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/Passport.php b/src/Passport.php index f3c11d9..6e577eb 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -161,6 +161,13 @@ class Passport */ public static $authorizationServerResponseType; + /** + * Indicates if Passport routes will be registered. + * + * @var bool + */ + public static $registersRoutes = true; + /** * Enable the implicit grant type. * @@ -630,6 +637,18 @@ public static function tokenEncryptionKey(Encrypter $encrypter) $encrypter->getKey(); } + /** + * Configure Passport to not register its routes. + * + * @return static + */ + public static function ignoreRoutes() + { + static::$registersRoutes = false; + + return new static; + } + /** * Configure Passport to not register its migrations. * diff --git a/src/PassportServiceProvider.php b/src/PassportServiceProvider.php index 7ce8834..236e7d8 100644 --- a/src/PassportServiceProvider.php +++ b/src/PassportServiceProvider.php @@ -50,13 +50,15 @@ public function boot() */ protected function registerRoutes() { - Route::group([ - 'as' => 'passport.', - 'prefix' => config('passport.path', 'oauth'), - 'namespace' => 'Laravel\Passport\Http\Controllers', - ], function () { - $this->loadRoutesFrom(__DIR__.'/../routes/web.php'); - }); + if (Passport::$registersRoutes) { + Route::group([ + 'as' => 'passport.', + 'prefix' => config('passport.path', 'oauth'), + 'namespace' => 'Laravel\Passport\Http\Controllers', + ], function () { + $this->loadRoutesFrom(__DIR__.'/../routes/web.php'); + }); + } } /** From 8aeec7106a9a2f7c98fc1989e8de072e76b565f7 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 30 Aug 2022 15:24:46 +0000 Subject: [PATCH 23/73] Update CHANGELOG --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e4a60..c2f07eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.0.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.0.1...11.x) + +## [v11.0.1](https://github.com/laravel/passport/compare/v11.0.0...v11.0.1) - 2022-08-29 + +### Changed + +- Custom days and hours to passport purge command by @rubengg86 in https://github.com/laravel/passport/pull/1563 +- Allow for bootstrapping without loading routes by @axlon in https://github.com/laravel/passport/pull/1564 ## [v11.0.0](https://github.com/laravel/passport/compare/v10.4.1...v11.0.0) - 2022-08-19 From cae735ae430bd882e6469839ca814ae9e378d870 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Thu, 1 Sep 2022 14:59:37 +0000 Subject: [PATCH 24/73] [11.x] Support prompting re-consent when redirecting for authorization (#1567) * Support prompting re-consent * Update AuthorizationController.php Co-authored-by: Taylor Otwell --- .../Controllers/AuthorizationController.php | 27 +++++++--- tests/Unit/AuthorizationControllerTest.php | 53 ++++++++++++++++++- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/Http/Controllers/AuthorizationController.php b/src/Http/Controllers/AuthorizationController.php index 22e08ef..5eb2d5d 100644 --- a/src/Http/Controllers/AuthorizationController.php +++ b/src/Http/Controllers/AuthorizationController.php @@ -63,14 +63,11 @@ public function authorize(ServerRequestInterface $psrRequest, }); $scopes = $this->parseScopes($authRequest); + $user = $request->user(); + $client = $clients->find($authRequest->getClient()->getIdentifier()); - $token = $tokens->findValidToken( - $user = $request->user(), - $client = $clients->find($authRequest->getClient()->getIdentifier()) - ); - - if (($token && $token->scopes === collect($scopes)->pluck('id')->all()) || - $client->skipsAuthorization()) { + if ($request->get('prompt') !== 'consent' && + ($client->skipsAuthorization() || $this->hasValidToken($tokens, $user, $client, $scopes))) { return $this->approveRequest($authRequest, $user); } @@ -101,6 +98,22 @@ protected function parseScopes($authRequest) ); } + /** + * Determine if a valid token exists for the given user, client, and scopes. + * + * @param \Laravel\Passport\TokenRepository $tokens + * @param \Illuminate\Database\Eloquent\Model $user + * @param \Laravel\Passport\Client $client + * @param array $scopes + * @return bool + */ + protected function hasValidToken($tokens, $user, $client, $scopes) + { + $token = $tokens->findValidToken($user, $client); + + return $token && $token->scopes === collect($scopes)->pluck('id')->all(); + } + /** * Approve the authorization request. * diff --git a/tests/Unit/AuthorizationControllerTest.php b/tests/Unit/AuthorizationControllerTest.php index a8672cf..8631e06 100644 --- a/tests/Unit/AuthorizationControllerTest.php +++ b/tests/Unit/AuthorizationControllerTest.php @@ -46,6 +46,7 @@ public function test_authorization_view_is_presented() $session->shouldReceive('put')->withSomeOfArgs('authToken'); $session->shouldReceive('put')->with('authRequest', $authRequest); $request->shouldReceive('user')->andReturn($user = m::mock()); + $request->shouldReceive('get')->with('prompt')->andReturn(null); $authRequest->shouldReceive('getClient->getIdentifier')->andReturn(1); $authRequest->shouldReceive('getScopes')->andReturn([new Scope('scope-1')]); @@ -116,6 +117,7 @@ public function test_request_is_approved_if_valid_token_exists() $request->shouldReceive('user')->once()->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldNotReceive('session'); + $request->shouldReceive('get')->with('prompt')->andReturn(null); $authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1); $authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]); @@ -123,11 +125,13 @@ public function test_request_is_approved_if_valid_token_exists() $authRequest->shouldReceive('setAuthorizationApproved')->once()->with(true); $clients = m::mock(ClientRepository::class); - $clients->shouldReceive('find')->with(1)->andReturn('client'); + $clients->shouldReceive('find')->with(1)->andReturn($client = m::mock(Client::class)); + + $client->shouldReceive('skipsAuthorization')->andReturn(false); $tokens = m::mock(TokenRepository::class); $tokens->shouldReceive('findValidToken') - ->with($user, 'client') + ->with($user, $client) ->andReturn($token = m::mock(Token::class)); $token->shouldReceive('getAttribute')->with('scopes')->andReturn(['scope-1']); @@ -158,6 +162,7 @@ public function test_request_is_approved_if_client_can_skip_authorization() $request->shouldReceive('user')->once()->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldNotReceive('session'); + $request->shouldReceive('get')->with('prompt')->andReturn(null); $authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1); $authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]); @@ -178,4 +183,48 @@ public function test_request_is_approved_if_client_can_skip_authorization() m::mock(ServerRequestInterface::class), $request, $clients, $tokens )->getContent()); } + + public function test_authorization_view_is_presented_if_request_has_prompt_equals_to_consent() + { + Passport::tokensCan([ + 'scope-1' => 'description', + ]); + + $server = m::mock(AuthorizationServer::class); + $response = m::mock(ResponseFactory::class); + + $controller = new AuthorizationController($server, $response); + $server->shouldReceive('validateAuthorizationRequest') + ->andReturn($authRequest = m::mock(AuthorizationRequest::class)); + + $request = m::mock(Request::class); + $request->shouldReceive('session')->andReturn($session = m::mock()); + $session->shouldReceive('put')->withSomeOfArgs('authToken'); + $session->shouldReceive('put')->with('authRequest', $authRequest); + $request->shouldReceive('user')->andReturn($user = m::mock()); + $request->shouldReceive('get')->with('prompt')->andReturn('consent'); + + $authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1); + $authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]); + + $clients = m::mock(ClientRepository::class); + $clients->shouldReceive('find')->with(1)->andReturn($client = m::mock(Client::class)); + $client->shouldReceive('skipsAuthorization')->andReturn(false); + + $tokens = m::mock(TokenRepository::class); + $tokens->shouldNotReceive('findValidToken'); + + $response->shouldReceive('view')->once()->andReturnUsing(function ($view, $data) use ($client, $user) { + $this->assertSame('passport::authorize', $view); + $this->assertEquals($client, $data['client']); + $this->assertEquals($user, $data['user']); + $this->assertSame('description', $data['scopes'][0]->description); + + return 'view'; + }); + + $this->assertSame('view', $controller->authorize( + m::mock(ServerRequestInterface::class), $request, $clients, $tokens + )); + } } From 89cc1976a25e2fa53ba8a3773e101189149852fa Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Mon, 5 Sep 2022 14:35:34 +0000 Subject: [PATCH 25/73] Support disabling prompt when redirecting for authorization (#1569) --- .../Controllers/AuthorizationController.php | 24 +++++++++++ tests/Unit/AuthorizationControllerTest.php | 43 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/Http/Controllers/AuthorizationController.php b/src/Http/Controllers/AuthorizationController.php index 5eb2d5d..09e561b 100644 --- a/src/Http/Controllers/AuthorizationController.php +++ b/src/Http/Controllers/AuthorizationController.php @@ -71,6 +71,10 @@ public function authorize(ServerRequestInterface $psrRequest, return $this->approveRequest($authRequest, $user); } + if ($request->get('prompt') === 'none') { + return $this->denyRequest($authRequest, $user); + } + $request->session()->put('authToken', $authToken = Str::random()); $request->session()->put('authRequest', $authRequest); @@ -133,4 +137,24 @@ protected function approveRequest($authRequest, $user) ); }); } + + /** + * Deny the authorization request. + * + * @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest + * @param \Illuminate\Database\Eloquent\Model $user + * @return \Illuminate\Http\Response + */ + protected function denyRequest($authRequest, $user) + { + $authRequest->setUser(new User($user->getAuthIdentifier())); + + $authRequest->setAuthorizationApproved(false); + + return $this->withErrorHandling(function () use ($authRequest) { + return $this->convertResponse( + $this->server->completeAuthorizationRequest($authRequest, new Psr7Response) + ); + }); + } } diff --git a/tests/Unit/AuthorizationControllerTest.php b/tests/Unit/AuthorizationControllerTest.php index 8631e06..f914834 100644 --- a/tests/Unit/AuthorizationControllerTest.php +++ b/tests/Unit/AuthorizationControllerTest.php @@ -227,4 +227,47 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal m::mock(ServerRequestInterface::class), $request, $clients, $tokens )); } + + public function test_authorization_denied_if_request_has_prompt_equals_to_none() + { + $this->expectException('Laravel\Passport\Exceptions\OAuthServerException'); + + Passport::tokensCan([ + 'scope-1' => 'description', + ]); + + $server = m::mock(AuthorizationServer::class); + $response = m::mock(ResponseFactory::class); + + $controller = new AuthorizationController($server, $response); + $server->shouldReceive('validateAuthorizationRequest') + ->andReturn($authRequest = m::mock(AuthorizationRequest::class)); + $server->shouldReceive('completeAuthorizationRequest') + ->with($authRequest, m::type(ResponseInterface::class)) + ->once() + ->andThrow('League\OAuth2\Server\Exception\OAuthServerException'); + + $request = m::mock(Request::class); + $request->shouldReceive('user')->andReturn($user = m::mock()); + $user->shouldReceive('getAuthIdentifier')->andReturn(1); + $request->shouldReceive('get')->with('prompt')->andReturn('none'); + + $authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1); + $authRequest->shouldReceive('getScopes')->once()->andReturn([new Scope('scope-1')]); + $authRequest->shouldReceive('setUser')->once()->andReturnNull(); + $authRequest->shouldReceive('setAuthorizationApproved')->once()->with(false); + + $clients = m::mock(ClientRepository::class); + $clients->shouldReceive('find')->with(1)->andReturn($client = m::mock(Client::class)); + $client->shouldReceive('skipsAuthorization')->andReturn(false); + + $tokens = m::mock(TokenRepository::class); + $tokens->shouldReceive('findValidToken') + ->with($user, $client) + ->andReturnNull(); + + $controller->authorize( + m::mock(ServerRequestInterface::class), $request, $clients, $tokens + ); + } } From 721df114d5a036d8fb3f542b83ab2879ecea7d69 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 6 Sep 2022 16:00:05 +0000 Subject: [PATCH 26/73] Update CHANGELOG --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2f07eb..74086e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.0.1...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.1.0...11.x) + +## [v11.1.0](https://github.com/laravel/passport/compare/v11.0.1...v11.1.0) - 2022-09-05 + +### Added + +- Support prompting re-consent when redirecting for authorization by @hafezdivandari in https://github.com/laravel/passport/pull/1567 +- Support disabling prompt when redirecting for authorization by @hafezdivandari in https://github.com/laravel/passport/pull/1569 ## [v11.0.1](https://github.com/laravel/passport/compare/v11.0.0...v11.0.1) - 2022-08-29 From fb2a4029c6cf4df1ce0cf79ddbb874508f7a73e9 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Wed, 7 Sep 2022 13:14:45 +0000 Subject: [PATCH 27/73] Let OAuth2 server handle denying the request (#1572) --- .../ApproveAuthorizationController.php | 12 +- .../DenyAuthorizationController.php | 34 ++--- .../RetrievesAuthRequestFromSession.php | 2 - .../Unit/DenyAuthorizationControllerTest.php | 131 +++--------------- 4 files changed, 41 insertions(+), 138 deletions(-) diff --git a/src/Http/Controllers/ApproveAuthorizationController.php b/src/Http/Controllers/ApproveAuthorizationController.php index 90023d5..6a2d415 100644 --- a/src/Http/Controllers/ApproveAuthorizationController.php +++ b/src/Http/Controllers/ApproveAuthorizationController.php @@ -8,7 +8,7 @@ class ApproveAuthorizationController { - use ConvertsPsrResponses, RetrievesAuthRequestFromSession; + use ConvertsPsrResponses, HandlesOAuthErrors, RetrievesAuthRequestFromSession; /** * The authorization server. @@ -40,8 +40,12 @@ public function approve(Request $request) $authRequest = $this->getAuthRequestFromSession($request); - return $this->convertResponse( - $this->server->completeAuthorizationRequest($authRequest, new Psr7Response) - ); + $authRequest->setAuthorizationApproved(true); + + return $this->withErrorHandling(function () use ($authRequest) { + return $this->convertResponse( + $this->server->completeAuthorizationRequest($authRequest, new Psr7Response) + ); + }); } } diff --git a/src/Http/Controllers/DenyAuthorizationController.php b/src/Http/Controllers/DenyAuthorizationController.php index 613dfd4..3a46e61 100644 --- a/src/Http/Controllers/DenyAuthorizationController.php +++ b/src/Http/Controllers/DenyAuthorizationController.php @@ -2,30 +2,30 @@ namespace Laravel\Passport\Http\Controllers; -use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\Request; -use Illuminate\Support\Arr; +use League\OAuth2\Server\AuthorizationServer; +use Nyholm\Psr7\Response as Psr7Response; class DenyAuthorizationController { - use RetrievesAuthRequestFromSession; + use ConvertsPsrResponses, HandlesOAuthErrors, RetrievesAuthRequestFromSession; /** - * The response factory implementation. + * The authorization server. * - * @var \Illuminate\Contracts\Routing\ResponseFactory + * @var \League\OAuth2\Server\AuthorizationServer */ - protected $response; + protected $server; /** * Create a new controller instance. * - * @param \Illuminate\Contracts\Routing\ResponseFactory $response + * @param \League\OAuth2\Server\AuthorizationServer $server * @return void */ - public function __construct(ResponseFactory $response) + public function __construct(AuthorizationServer $server) { - $this->response = $response; + $this->server = $server; } /** @@ -40,16 +40,12 @@ public function deny(Request $request) $authRequest = $this->getAuthRequestFromSession($request); - $clientUris = Arr::wrap($authRequest->getClient()->getRedirectUri()); + $authRequest->setAuthorizationApproved(false); - if (! in_array($uri = $authRequest->getRedirectUri(), $clientUris)) { - $uri = Arr::first($clientUris); - } - - $separator = $authRequest->getGrantTypeId() === 'implicit' ? '#' : (strstr($uri, '?') ? '&' : '?'); - - return $this->response->redirectTo( - $uri.$separator.'error=access_denied&state='.$request->input('state') - ); + return $this->withErrorHandling(function () use ($authRequest) { + return $this->convertResponse( + $this->server->completeAuthorizationRequest($authRequest, new Psr7Response) + ); + }); } } diff --git a/src/Http/Controllers/RetrievesAuthRequestFromSession.php b/src/Http/Controllers/RetrievesAuthRequestFromSession.php index b129627..0a23e1e 100644 --- a/src/Http/Controllers/RetrievesAuthRequestFromSession.php +++ b/src/Http/Controllers/RetrievesAuthRequestFromSession.php @@ -42,8 +42,6 @@ protected function getAuthRequestFromSession(Request $request) } $authRequest->setUser(new User($request->user()->getAuthIdentifier())); - - $authRequest->setAuthorizationApproved(true); }); } } diff --git a/tests/Unit/DenyAuthorizationControllerTest.php b/tests/Unit/DenyAuthorizationControllerTest.php index cfb5e01..366cc86 100644 --- a/tests/Unit/DenyAuthorizationControllerTest.php +++ b/tests/Unit/DenyAuthorizationControllerTest.php @@ -2,12 +2,13 @@ namespace Laravel\Passport\Tests\Unit; -use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\Request; use Laravel\Passport\Http\Controllers\DenyAuthorizationController; +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use Mockery as m; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseInterface; class DenyAuthorizationControllerTest extends TestCase { @@ -18,130 +19,34 @@ protected function tearDown(): void public function test_authorization_can_be_denied() { - $response = m::mock(ResponseFactory::class); + $this->expectException('Laravel\Passport\Exceptions\OAuthServerException'); - $controller = new DenyAuthorizationController($response); + $server = m::mock(AuthorizationServer::class); + $controller = new DenyAuthorizationController($server); $request = m::mock(Request::class); $request->shouldReceive('session')->andReturn($session = m::mock()); $request->shouldReceive('user')->andReturn(new DenyAuthorizationControllerFakeUser); - $request->shouldReceive('input')->with('state')->andReturn('state'); $request->shouldReceive('has')->with('auth_token')->andReturn(true); $request->shouldReceive('get')->with('auth_token')->andReturn('foo'); $session->shouldReceive('get')->once()->with('authToken')->andReturn('foo'); - $session->shouldReceive('get')->once()->with('authRequest')->andReturn($authRequest = m::mock( + $session->shouldReceive('get') + ->once() + ->with('authRequest') + ->andReturn($authRequest = m::mock( AuthorizationRequest::class - )); + )); $authRequest->shouldReceive('setUser')->once(); - $authRequest->shouldReceive('getGrantTypeId')->andReturn('authorization_code'); - $authRequest->shouldReceive('setAuthorizationApproved')->once()->with(true); - $authRequest->shouldReceive('getRedirectUri')->andReturn('http://localhost'); - $authRequest->shouldReceive('getClient->getRedirectUri')->andReturn('http://localhost'); + $authRequest->shouldReceive('setAuthorizationApproved')->once()->with(false); - $response->shouldReceive('redirectTo')->once()->andReturnUsing(function ($url) { - return $url; - }); + $server->shouldReceive('completeAuthorizationRequest') + ->with($authRequest, m::type(ResponseInterface::class)) + ->andThrow('League\OAuth2\Server\Exception\OAuthServerException'); - $this->assertSame('http://localhost?error=access_denied&state=state', $controller->deny($request)); - } - - public function test_authorization_can_be_denied_with_multiple_redirect_uris() - { - $response = m::mock(ResponseFactory::class); - - $controller = new DenyAuthorizationController($response); - - $request = m::mock(Request::class); - - $request->shouldReceive('session')->andReturn($session = m::mock()); - $request->shouldReceive('user')->andReturn(new DenyAuthorizationControllerFakeUser); - $request->shouldReceive('input')->with('state')->andReturn('state'); - $request->shouldReceive('has')->with('auth_token')->andReturn(true); - $request->shouldReceive('get')->with('auth_token')->andReturn('foo'); - - $session->shouldReceive('get')->once()->with('authRequest')->andReturn($authRequest = m::mock( - AuthorizationRequest::class - )); - - $authRequest->shouldReceive('setUser')->once(); - $authRequest->shouldReceive('getGrantTypeId')->andReturn('authorization_code'); - $authRequest->shouldReceive('setAuthorizationApproved')->once()->with(true); - $authRequest->shouldReceive('getRedirectUri')->andReturn('http://localhost'); - $authRequest->shouldReceive('getClient->getRedirectUri')->andReturn(['http://localhost.localdomain', 'http://localhost']); - - $session->shouldReceive('get')->once()->with('authToken')->andReturn('foo'); - $response->shouldReceive('redirectTo')->once()->andReturnUsing(function ($url) { - return $url; - }); - - $this->assertSame('http://localhost?error=access_denied&state=state', $controller->deny($request)); - } - - public function test_authorization_can_be_denied_implicit() - { - $response = m::mock(ResponseFactory::class); - - $controller = new DenyAuthorizationController($response); - - $request = m::mock(Request::class); - - $request->shouldReceive('session')->andReturn($session = m::mock()); - $request->shouldReceive('user')->andReturn(new DenyAuthorizationControllerFakeUser); - $request->shouldReceive('input')->with('state')->andReturn('state'); - $request->shouldReceive('has')->with('auth_token')->andReturn(true); - $request->shouldReceive('get')->with('auth_token')->andReturn('foo'); - - $session->shouldReceive('get')->once()->with('authToken')->andReturn('foo'); - $session->shouldReceive('get')->once()->with('authRequest')->andReturn($authRequest = m::mock( - AuthorizationRequest::class - )); - - $authRequest->shouldReceive('setUser')->once(); - $authRequest->shouldReceive('getGrantTypeId')->andReturn('implicit'); - $authRequest->shouldReceive('setAuthorizationApproved')->once()->with(true); - $authRequest->shouldReceive('getRedirectUri')->andReturn('http://localhost'); - $authRequest->shouldReceive('getClient->getRedirectUri')->andReturn('http://localhost'); - - $response->shouldReceive('redirectTo')->once()->andReturnUsing(function ($url) { - return $url; - }); - - $this->assertSame('http://localhost#error=access_denied&state=state', $controller->deny($request)); - } - - public function test_authorization_can_be_denied_with_existing_query_string() - { - $response = m::mock(ResponseFactory::class); - - $controller = new DenyAuthorizationController($response); - - $request = m::mock(Request::class); - - $request->shouldReceive('session')->andReturn($session = m::mock()); - $request->shouldReceive('user')->andReturn(new DenyAuthorizationControllerFakeUser); - $request->shouldReceive('input')->with('state')->andReturn('state'); - $request->shouldReceive('has')->with('auth_token')->andReturn(true); - $request->shouldReceive('get')->with('auth_token')->andReturn('foo'); - - $session->shouldReceive('get')->once()->with('authToken')->andReturn('foo'); - $session->shouldReceive('get')->once()->with('authRequest')->andReturn($authRequest = m::mock( - AuthorizationRequest::class - )); - - $authRequest->shouldReceive('setUser')->once(); - $authRequest->shouldReceive('getGrantTypeId')->andReturn('authorization_code'); - $authRequest->shouldReceive('setAuthorizationApproved')->once()->with(true); - $authRequest->shouldReceive('getRedirectUri')->andReturn('http://localhost?action=some_action'); - $authRequest->shouldReceive('getClient->getRedirectUri')->andReturn('http://localhost?action=some_action'); - - $response->shouldReceive('redirectTo')->once()->andReturnUsing(function ($url) { - return $url; - }); - - $this->assertSame('http://localhost?action=some_action&error=access_denied&state=state', $controller->deny($request)); + $controller->deny($request); } public function test_auth_request_should_exist() @@ -149,9 +54,9 @@ public function test_auth_request_should_exist() $this->expectException('Exception'); $this->expectExceptionMessage('Authorization request was not present in the session.'); - $response = m::mock(ResponseFactory::class); + $server = m::mock(AuthorizationServer::class); - $controller = new DenyAuthorizationController($response); + $controller = new DenyAuthorizationController($server); $request = m::mock(Request::class); @@ -164,7 +69,7 @@ public function test_auth_request_should_exist() $session->shouldReceive('get')->once()->with('authToken')->andReturn('foo'); $session->shouldReceive('get')->once()->with('authRequest')->andReturnNull(); - $response->shouldReceive('redirectTo')->never(); + $server->shouldReceive('completeAuthorizationRequest')->never(); $controller->deny($request); } From 7a514ccb1ef3e83be285ad0a0a83b03d701f8c3f Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 13 Sep 2022 15:06:14 +0000 Subject: [PATCH 28/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74086e1..134492a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.1.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.2.0...11.x) + +## [v11.2.0](https://github.com/laravel/passport/compare/v11.1.0...v11.2.0) - 2022-09-07 + +### Changed + +- Let OAuth2 server handle the denying response by @hafezdivandari in https://github.com/laravel/passport/pull/1572 ## [v11.1.0](https://github.com/laravel/passport/compare/v11.0.1...v11.1.0) - 2022-09-05 From 5a26d6cbf56544c9f56994c6978f8fbe4d82bb33 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Thu, 29 Sep 2022 17:52:25 +0200 Subject: [PATCH 29/73] Improve token guard return type (#1579) --- src/Guards/TokenGuard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Guards/TokenGuard.php b/src/Guards/TokenGuard.php index 7d3751f..7e478ce 100644 --- a/src/Guards/TokenGuard.php +++ b/src/Guards/TokenGuard.php @@ -144,7 +144,7 @@ public function validate(array $credentials = []) /** * Get the client for the incoming request. * - * @return mixed + * @return \Laravel\Passport\Client|null */ public function client() { From 3a4d6e524cc2fe0c45d56c728aa1973a7a3d5d69 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 4 Oct 2022 14:11:06 +0000 Subject: [PATCH 30/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 134492a..8042749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.2.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.2.1...11.x) + +## [v11.2.1](https://github.com/laravel/passport/compare/v11.2.0...v11.2.1) - 2022-09-29 + +### Fixed + +- Improve token guard return type by @axlon in https://github.com/laravel/passport/pull/1579 ## [v11.2.0](https://github.com/laravel/passport/compare/v11.1.0...v11.2.0) - 2022-09-07 From 741595738b80f64ec35ad82de477adee925fff7e Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Wed, 5 Oct 2022 18:57:02 +0330 Subject: [PATCH 31/73] [11.x] Support prompting login when redirecting for authorization (#1577) * Support prompting login when redirecting for authorization * use fragment on redirect uri for implicit grant * bind StatefulGuard * formatting Co-authored-by: Taylor Otwell --- routes/web.php | 11 +- .../Controllers/AuthorizationController.php | 66 ++++++++- src/PassportServiceProvider.php | 6 + tests/Unit/AuthorizationControllerTest.php | 135 +++++++++++++++++- 4 files changed, 204 insertions(+), 14 deletions(-) diff --git a/routes/web.php b/routes/web.php index dfe69dc..c9d78fb 100644 --- a/routes/web.php +++ b/routes/web.php @@ -8,17 +8,18 @@ 'middleware' => 'throttle', ]); +Route::get('/authorize', [ + 'uses' => 'AuthorizationController@authorize', + 'as' => 'authorizations.authorize', + 'middleware' => 'web', +]); + Route::middleware(['web', 'auth'])->group(function () { Route::post('/token/refresh', [ 'uses' => 'TransientTokenController@refresh', 'as' => 'token.refresh', ]); - Route::get('/authorize', [ - 'uses' => 'AuthorizationController@authorize', - 'as' => 'authorizations.authorize', - ]); - Route::post('/authorize', [ 'uses' => 'ApproveAuthorizationController@approve', 'as' => 'authorizations.approve', diff --git a/src/Http/Controllers/AuthorizationController.php b/src/Http/Controllers/AuthorizationController.php index 09e561b..597a5c1 100644 --- a/src/Http/Controllers/AuthorizationController.php +++ b/src/Http/Controllers/AuthorizationController.php @@ -2,6 +2,8 @@ namespace Laravel\Passport\Http\Controllers; +use Illuminate\Auth\AuthenticationException; +use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\Request; use Illuminate\Support\Str; @@ -10,6 +12,7 @@ use Laravel\Passport\Passport; use Laravel\Passport\TokenRepository; use League\OAuth2\Server\AuthorizationServer; +use League\OAuth2\Server\Exception\OAuthServerException; use Nyholm\Psr7\Response as Psr7Response; use Psr\Http\Message\ServerRequestInterface; @@ -31,17 +34,28 @@ class AuthorizationController */ protected $response; + /** + * The guard implementation. + * + * @var \Illuminate\Contracts\Auth\StatefulGuard + */ + protected $guard; + /** * Create a new controller instance. * * @param \League\OAuth2\Server\AuthorizationServer $server * @param \Illuminate\Contracts\Routing\ResponseFactory $response + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ - public function __construct(AuthorizationServer $server, ResponseFactory $response) + public function __construct(AuthorizationServer $server, + ResponseFactory $response, + StatefulGuard $guard) { $this->server = $server; $this->response = $response; + $this->guard = $guard; } /** @@ -62,6 +76,23 @@ public function authorize(ServerRequestInterface $psrRequest, return $this->server->validateAuthorizationRequest($psrRequest); }); + if ($this->guard->guest()) { + return $request->get('prompt') === 'none' + ? $this->denyRequest($authRequest) + : $this->promptForLogin($request); + } + + if ($request->get('prompt') === 'login' && + ! $request->session()->get('promptedForLogin', false)) { + $this->guard->logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return $this->promptForLogin($request); + } + + $request->session()->forget('promptedForLogin'); + $scopes = $this->parseScopes($authRequest); $user = $request->user(); $client = $clients->find($authRequest->getClient()->getIdentifier()); @@ -142,11 +173,26 @@ protected function approveRequest($authRequest, $user) * Deny the authorization request. * * @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest - * @param \Illuminate\Database\Eloquent\Model $user + * @param \Illuminate\Database\Eloquent\Model|null $user * @return \Illuminate\Http\Response */ - protected function denyRequest($authRequest, $user) + protected function denyRequest($authRequest, $user = null) { + if (is_null($user)) { + $uri = $authRequest->getRedirectUri() + ?? (is_array($authRequest->getClient()->getRedirectUri()) + ? $authRequest->getClient()->getRedirectUri()[0] + : $authRequest->getClient()->getRedirectUri()); + + $separator = $authRequest->getGrantTypeId() === 'implicit' ? '#' : '?'; + + $uri = $uri.(str_contains($uri, $separator) ? '&' : $separator).'state='.$authRequest->getState(); + + return $this->withErrorHandling(function () use ($uri) { + throw OAuthServerException::accessDenied('Unauthenticated', $uri); + }); + } + $authRequest->setUser(new User($user->getAuthIdentifier())); $authRequest->setAuthorizationApproved(false); @@ -157,4 +203,18 @@ protected function denyRequest($authRequest, $user) ); }); } + + /** + * Prompt the user to login by throwing an AuthenticationException. + * + * @param \Illuminate\Http\Request $request + * + * @throws \Illuminate\Auth\AuthenticationException + */ + protected function promptForLogin($request) + { + $request->session()->put('promptedForLogin', true); + + throw new AuthenticationException; + } } diff --git a/src/PassportServiceProvider.php b/src/PassportServiceProvider.php index 236e7d8..efe1361 100644 --- a/src/PassportServiceProvider.php +++ b/src/PassportServiceProvider.php @@ -5,6 +5,7 @@ use DateInterval; use Illuminate\Auth\Events\Logout; use Illuminate\Config\Repository as Config; +use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cookie; use Illuminate\Support\Facades\Event; @@ -14,6 +15,7 @@ use Laravel\Passport\Bridge\PersonalAccessGrant; use Laravel\Passport\Bridge\RefreshTokenRepository; use Laravel\Passport\Guards\TokenGuard; +use Laravel\Passport\Http\Controllers\AuthorizationController; use Lcobucci\JWT\Configuration; use Lcobucci\JWT\Parser; use League\OAuth2\Server\AuthorizationServer; @@ -134,6 +136,10 @@ public function register() Passport::setClientUuids($this->app->make(Config::class)->get('passport.client_uuids', false)); + $this->app->when(AuthorizationController::class) + ->needs(StatefulGuard::class) + ->give(fn () => Auth::guard(config('passport.guard', null))); + $this->registerAuthorizationServer(); $this->registerClientRepository(); $this->registerJWTParser(); diff --git a/tests/Unit/AuthorizationControllerTest.php b/tests/Unit/AuthorizationControllerTest.php index f914834..f9d0d82 100644 --- a/tests/Unit/AuthorizationControllerTest.php +++ b/tests/Unit/AuthorizationControllerTest.php @@ -2,6 +2,7 @@ namespace Laravel\Passport\Tests\Unit; +use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\Request; use Laravel\Passport\Bridge\Scope; @@ -36,15 +37,18 @@ public function test_authorization_view_is_presented() $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response); + $controller = new AuthorizationController($server, $response, $guard); + $guard->shouldReceive('guest')->andReturn(false); $server->shouldReceive('validateAuthorizationRequest')->andReturn($authRequest = m::mock()); $request = m::mock(Request::class); $request->shouldReceive('session')->andReturn($session = m::mock()); $session->shouldReceive('put')->withSomeOfArgs('authToken'); $session->shouldReceive('put')->with('authRequest', $authRequest); + $session->shouldReceive('forget')->with('promptedForLogin')->once(); $request->shouldReceive('user')->andReturn($user = m::mock()); $request->shouldReceive('get')->with('prompt')->andReturn(null); @@ -77,9 +81,11 @@ public function test_authorization_exceptions_are_handled() { $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response); + $controller = new AuthorizationController($server, $response, $guard); + $guard->shouldReceive('guest')->andReturn(false); $server->shouldReceive('validateAuthorizationRequest')->andThrow(LeagueException::invalidCredentials()); $request = m::mock(Request::class); @@ -103,8 +109,11 @@ public function test_request_is_approved_if_valid_token_exists() $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response); + $controller = new AuthorizationController($server, $response, $guard); + + $guard->shouldReceive('guest')->andReturn(false); $psrResponse = new Response(); $psrResponse->getBody()->write('approved'); $server->shouldReceive('validateAuthorizationRequest') @@ -114,6 +123,8 @@ public function test_request_is_approved_if_valid_token_exists() ->andReturn($psrResponse); $request = m::mock(Request::class); + $request->shouldReceive('session')->andReturn($session = m::mock()); + $session->shouldReceive('forget')->with('promptedForLogin')->once(); $request->shouldReceive('user')->once()->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldNotReceive('session'); @@ -148,8 +159,11 @@ public function test_request_is_approved_if_client_can_skip_authorization() $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response); + $controller = new AuthorizationController($server, $response, $guard); + + $guard->shouldReceive('guest')->andReturn(false); $psrResponse = new Response(); $psrResponse->getBody()->write('approved'); $server->shouldReceive('validateAuthorizationRequest') @@ -159,6 +173,8 @@ public function test_request_is_approved_if_client_can_skip_authorization() ->andReturn($psrResponse); $request = m::mock(Request::class); + $request->shouldReceive('session')->andReturn($session = m::mock()); + $session->shouldReceive('forget')->with('promptedForLogin')->once(); $request->shouldReceive('user')->once()->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldNotReceive('session'); @@ -192,8 +208,11 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response); + $controller = new AuthorizationController($server, $response, $guard); + + $guard->shouldReceive('guest')->andReturn(false); $server->shouldReceive('validateAuthorizationRequest') ->andReturn($authRequest = m::mock(AuthorizationRequest::class)); @@ -201,6 +220,7 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal $request->shouldReceive('session')->andReturn($session = m::mock()); $session->shouldReceive('put')->withSomeOfArgs('authToken'); $session->shouldReceive('put')->with('authRequest', $authRequest); + $session->shouldReceive('forget')->with('promptedForLogin')->once(); $request->shouldReceive('user')->andReturn($user = m::mock()); $request->shouldReceive('get')->with('prompt')->andReturn('consent'); @@ -238,8 +258,11 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none() $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); + + $controller = new AuthorizationController($server, $response, $guard); - $controller = new AuthorizationController($server, $response); + $guard->shouldReceive('guest')->andReturn(false); $server->shouldReceive('validateAuthorizationRequest') ->andReturn($authRequest = m::mock(AuthorizationRequest::class)); $server->shouldReceive('completeAuthorizationRequest') @@ -248,6 +271,8 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none() ->andThrow('League\OAuth2\Server\Exception\OAuthServerException'); $request = m::mock(Request::class); + $request->shouldReceive('session')->andReturn($session = m::mock()); + $session->shouldReceive('forget')->with('promptedForLogin')->once(); $request->shouldReceive('user')->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldReceive('get')->with('prompt')->andReturn('none'); @@ -270,4 +295,102 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none() m::mock(ServerRequestInterface::class), $request, $clients, $tokens ); } + + public function test_authorization_denied_if_unauthenticated_and_request_has_prompt_equals_to_none() + { + $server = m::mock(AuthorizationServer::class); + $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); + + $controller = new AuthorizationController($server, $response, $guard); + + $guard->shouldReceive('guest')->andReturn(true); + $server->shouldReceive('validateAuthorizationRequest') + ->andReturn($authRequest = m::mock(AuthorizationRequest::class)); + $server->shouldNotReceive('completeAuthorizationRequest'); + + $request = m::mock(Request::class); + $request->shouldNotReceive('user'); + $request->shouldReceive('get')->with('prompt')->andReturn('none'); + + $authRequest->shouldNotReceive('setUser'); + $authRequest->shouldReceive('setAuthorizationApproved')->with(false); + $authRequest->shouldReceive('getRedirectUri')->andReturn('http://localhost'); + $authRequest->shouldReceive('getClient->getRedirectUri')->andReturn('http://localhost'); + $authRequest->shouldReceive('getState')->andReturn('state'); + $authRequest->shouldReceive('getGrantTypeId')->andReturn('authorization_code'); + + $clients = m::mock(ClientRepository::class); + $tokens = m::mock(TokenRepository::class); + + try { + $controller->authorize( + m::mock(ServerRequestInterface::class), $request, $clients, $tokens + ); + } catch (\Laravel\Passport\Exceptions\OAuthServerException $e) { + $this->assertStringStartsWith( + 'http://localhost?state=state&error=access_denied&error_description=', + $e->render($request)->headers->get('location') + ); + } + } + + public function test_logout_and_prompt_login_if_request_has_prompt_equals_to_login() + { + $this->expectException('Illuminate\Auth\AuthenticationException'); + + $server = m::mock(AuthorizationServer::class); + $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); + + $controller = new AuthorizationController($server, $response, $guard); + + $guard->shouldReceive('guest')->andReturn(false); + $server->shouldReceive('validateAuthorizationRequest')->once(); + $guard->shouldReceive('logout')->once(); + + $request = m::mock(Request::class); + $request->shouldReceive('session')->andReturn($session = m::mock()); + $session->shouldReceive('invalidate')->once(); + $session->shouldReceive('regenerateToken')->once(); + $session->shouldReceive('get')->with('promptedForLogin', false)->once()->andReturn(false); + $session->shouldReceive('put')->with('promptedForLogin', true)->once(); + $session->shouldNotReceive('forget')->with('promptedForLogin'); + $request->shouldReceive('get')->with('prompt')->andReturn('login'); + + $clients = m::mock(ClientRepository::class); + $tokens = m::mock(TokenRepository::class); + + $controller->authorize( + m::mock(ServerRequestInterface::class), $request, $clients, $tokens + ); + } + + public function test_user_should_be_authenticated() + { + $this->expectException('Illuminate\Auth\AuthenticationException'); + + $server = m::mock(AuthorizationServer::class); + $response = m::mock(ResponseFactory::class); + $guard = m::mock(StatefulGuard::class); + + $controller = new AuthorizationController($server, $response, $guard); + + $guard->shouldReceive('guest')->andReturn(true); + $server->shouldReceive('validateAuthorizationRequest')->once(); + + $request = m::mock(Request::class); + $request->shouldNotReceive('user'); + $request->shouldReceive('session')->andReturn($session = m::mock()); + $session->shouldReceive('put')->with('promptedForLogin', true)->once(); + $session->shouldNotReceive('forget')->with('promptedForLogin'); + $request->shouldReceive('get')->with('prompt')->andReturn(null); + + $clients = m::mock(ClientRepository::class); + $tokens = m::mock(TokenRepository::class); + + $controller->authorize( + m::mock(ServerRequestInterface::class), $request, $clients, $tokens + ); + } } From 22281ff77c33ec6f474b5a2ada166e33543629cd Mon Sep 17 00:00:00 2001 From: TosID Date: Mon, 17 Oct 2022 16:15:54 +0200 Subject: [PATCH 32/73] Update PurgeCommand.php (#1586) I get a lot confused when I use this command it always return seven days :) now return hours instead of days. --- src/Console/PurgeCommand.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Console/PurgeCommand.php b/src/Console/PurgeCommand.php index e42a6ad..26a3591 100644 --- a/src/Console/PurgeCommand.php +++ b/src/Console/PurgeCommand.php @@ -40,7 +40,9 @@ public function handle() Passport::authCode()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete(); Passport::refreshToken()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete(); - $this->info('Purged revoked items and items expired for more than seven days.'); + $this->option('hours') + ? $this->info('Purged revoked items and items expired for more than '.$this->option('hours').' hours.') + : $this->info('Purged revoked items and items expired for more than seven days.'); } elseif ($this->option('revoked')) { Passport::token()->where('revoked', 1)->delete(); Passport::authCode()->where('revoked', 1)->delete(); @@ -52,7 +54,9 @@ public function handle() Passport::authCode()->whereDate('expires_at', '<', $expired)->delete(); Passport::refreshToken()->whereDate('expires_at', '<', $expired)->delete(); - $this->info('Purged items expired for more than seven days.'); + $this->option('hours') + ? $this->info('Purged items expired for more than '.$this->option('hours').' hours.') + : $this->info('Purged items expired for more than seven days.'); } } } From c73285f05de3fb808091da47769ccb53f69e4fb1 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 17 Oct 2022 14:16:15 +0000 Subject: [PATCH 33/73] Apply fixes from StyleCI --- src/Console/PurgeCommand.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Console/PurgeCommand.php b/src/Console/PurgeCommand.php index 26a3591..9d9e66b 100644 --- a/src/Console/PurgeCommand.php +++ b/src/Console/PurgeCommand.php @@ -41,8 +41,8 @@ public function handle() Passport::refreshToken()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete(); $this->option('hours') - ? $this->info('Purged revoked items and items expired for more than '.$this->option('hours').' hours.') - : $this->info('Purged revoked items and items expired for more than seven days.'); + ? $this->info('Purged revoked items and items expired for more than '.$this->option('hours').' hours.') + : $this->info('Purged revoked items and items expired for more than seven days.'); } elseif ($this->option('revoked')) { Passport::token()->where('revoked', 1)->delete(); Passport::authCode()->where('revoked', 1)->delete(); @@ -55,8 +55,8 @@ public function handle() Passport::refreshToken()->whereDate('expires_at', '<', $expired)->delete(); $this->option('hours') - ? $this->info('Purged items expired for more than '.$this->option('hours').' hours.') - : $this->info('Purged items expired for more than seven days.'); + ? $this->info('Purged items expired for more than '.$this->option('hours').' hours.') + : $this->info('Purged items expired for more than seven days.'); } } } From 3bc63674619d2edf14440267149137b51ab54f87 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Tue, 18 Oct 2022 18:07:57 +0200 Subject: [PATCH 34/73] Fix ClientRepository doc blocks (#1587) --- src/ClientRepository.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ClientRepository.php b/src/ClientRepository.php index 6a6af39..aaef295 100644 --- a/src/ClientRepository.php +++ b/src/ClientRepository.php @@ -37,7 +37,7 @@ public function __construct($personalAccessClientId = null, $personalAccessClien /** * Get a client by the given ID. * - * @param int $id + * @param int|string $id * @return \Laravel\Passport\Client|null */ public function find($id) @@ -50,7 +50,7 @@ public function find($id) /** * Get an active client by the given ID. * - * @param int $id + * @param int|string $id * @return \Laravel\Passport\Client|null */ public function findActive($id) @@ -63,7 +63,7 @@ public function findActive($id) /** * Get a client instance for the given ID and user ID. * - * @param int $clientId + * @param int|string $clientId * @param mixed $userId * @return \Laravel\Passport\Client|null */ @@ -221,7 +221,7 @@ public function regenerateSecret(Client $client) /** * Determine if the given client is revoked. * - * @param int $id + * @param int|string $id * @return bool */ public function revoked($id) From 4c2105887c724fe05fc4cd9b7d6c8d8df30e1bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Sat, 22 Oct 2022 18:38:00 +0200 Subject: [PATCH 35/73] Update docblock (#1588) --- src/ClientRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ClientRepository.php b/src/ClientRepository.php index aaef295..aebe33b 100644 --- a/src/ClientRepository.php +++ b/src/ClientRepository.php @@ -128,7 +128,7 @@ public function personalAccessClient() /** * Store a new client. * - * @param int $userId + * @param int|null $userId * @param string $name * @param string $redirect * @param string|null $provider From 620fc16d16ccd70b3c10d1395e1dd856c09a0ddd Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 25 Oct 2022 16:38:35 +0000 Subject: [PATCH 36/73] Update CHANGELOG --- CHANGELOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8042749..9deec5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.2.1...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.3.0...11.x) + +## [v11.3.0](https://github.com/laravel/passport/compare/v11.2.1...v11.3.0) - 2022-10-22 + +### Added + +- Support prompting login when redirecting for authorization by @hafezdivandari in https://github.com/laravel/passport/pull/1577 + +### Changed + +- Update PurgeCommand.php by @fatoskurtishi in https://github.com/laravel/passport/pull/1586 +- Fix ClientRepository doc blocks by @axlon in https://github.com/laravel/passport/pull/1587 +- Update docblock by @mnabialek in https://github.com/laravel/passport/pull/1588 ## [v11.2.1](https://github.com/laravel/passport/compare/v11.2.0...v11.2.1) - 2022-09-29 From 298ea64aa42c14a35146b1d902df95655a0cb35e Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 2 Nov 2022 11:01:22 +0100 Subject: [PATCH 37/73] Test on PHP 8.2 (#1592) * Test on PHP 8.2 * Update composer.json --- .github/workflows/tests.yml | 5 ++++- composer.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d6cf7f4..fce193c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,6 +2,9 @@ name: tests on: push: + branches: + - master + - '*.x' pull_request: schedule: - cron: '0 0 * * *' @@ -13,7 +16,7 @@ jobs: strategy: fail-fast: true matrix: - php: ['8.0', 8.1] + php: ['8.0', 8.1, 8.2] laravel: [9] name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} diff --git a/composer.json b/composer.json index 6762200..bf44d9b 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "require": { "php": "^8.0", "ext-json": "*", - "firebase/php-jwt": "^6.0", + "firebase/php-jwt": "^6.3.1", "illuminate/auth": "^9.0", "illuminate/console": "^9.0", "illuminate/container": "^9.0", From 662325a90b8c3184c548eaf66ce971925f2b90dc Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 23 Nov 2022 10:06:21 +0100 Subject: [PATCH 38/73] Create issues.yml --- .github/workflows/issues.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/issues.yml diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml new file mode 100644 index 0000000..9634a0e --- /dev/null +++ b/.github/workflows/issues.yml @@ -0,0 +1,12 @@ +name: issues + +on: + issues: + types: [labeled] + +permissions: + issues: write + +jobs: + help-wanted: + uses: laravel/.github/.github/workflows/issues.yml@main From 835febbfe875ba97306c026fdaa94f58f167363e Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 2 Dec 2022 21:50:16 +0330 Subject: [PATCH 39/73] Add auth guard to routes (#1603) --- config/passport.php | 13 +++++++++++++ routes/web.php | 4 +++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/config/passport.php b/config/passport.php index 79c59ac..06053cd 100644 --- a/config/passport.php +++ b/config/passport.php @@ -2,6 +2,19 @@ return [ + /* + |-------------------------------------------------------------------------- + | Passport Guard + |-------------------------------------------------------------------------- + | + | Here you may specify which authentication guard Passport will use when + | authenticating users. This value should correspond with one of your + | guards that is already present in your "auth" configuration file. + | + */ + + 'guard' => 'web', + /* |-------------------------------------------------------------------------- | Encryption Keys diff --git a/routes/web.php b/routes/web.php index c9d78fb..fa2ecf3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,7 +14,9 @@ 'middleware' => 'web', ]); -Route::middleware(['web', 'auth'])->group(function () { +$guard = config('passport.guard', null); + +Route::middleware(['web', $guard ? 'auth:'.$guard : 'auth'])->group(function () { Route::post('/token/refresh', [ 'uses' => 'TransientTokenController@refresh', 'as' => 'token.refresh', From 78c9d3a0f38fa28b9be9dbf0282cc766354e0e52 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 6 Dec 2022 16:25:16 +0000 Subject: [PATCH 40/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9deec5c..da644c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.3.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.3.1...11.x) + +## [v11.3.1](https://github.com/laravel/passport/compare/v11.3.0...v11.3.1) - 2022-12-02 + +### Changed + +- Add auth guard to routes by @hafezdivandari in https://github.com/laravel/passport/pull/1603 ## [v11.3.0](https://github.com/laravel/passport/compare/v11.2.1...v11.3.0) - 2022-10-22 From 13329bee36a414323f5e545c5d5355c38cb6639c Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 28 Dec 2022 13:30:41 +0100 Subject: [PATCH 41/73] Update tests.yml --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fce193c..432efe7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ on: jobs: tests: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: true @@ -23,7 +23,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 From 2d746b752b08e47f6b5bd69d8e76fbe477e23532 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Tue, 3 Jan 2023 09:40:19 +0000 Subject: [PATCH 42/73] Adds types to migrations (#1594) --- .../2016_06_01_000001_create_oauth_auth_codes_table.php | 8 ++------ ...2016_06_01_000002_create_oauth_access_tokens_table.php | 8 ++------ ...016_06_01_000003_create_oauth_refresh_tokens_table.php | 8 ++------ .../2016_06_01_000004_create_oauth_clients_table.php | 8 ++------ ..._000005_create_oauth_personal_access_clients_table.php | 8 ++------ 5 files changed, 10 insertions(+), 30 deletions(-) diff --git a/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php b/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php index 1826c09..7b93b40 100644 --- a/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php +++ b/database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php @@ -8,10 +8,8 @@ { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('oauth_auth_codes', function (Blueprint $table) { $table->string('id', 100)->primary(); @@ -25,10 +23,8 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('oauth_auth_codes'); } diff --git a/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php b/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php index 045ca1b..598798e 100644 --- a/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php +++ b/database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php @@ -8,10 +8,8 @@ { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('oauth_access_tokens', function (Blueprint $table) { $table->string('id', 100)->primary(); @@ -27,10 +25,8 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('oauth_access_tokens'); } diff --git a/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php b/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php index 3da3f76..b007904 100644 --- a/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php +++ b/database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php @@ -8,10 +8,8 @@ { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('oauth_refresh_tokens', function (Blueprint $table) { $table->string('id', 100)->primary(); @@ -23,10 +21,8 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('oauth_refresh_tokens'); } diff --git a/database/migrations/2016_06_01_000004_create_oauth_clients_table.php b/database/migrations/2016_06_01_000004_create_oauth_clients_table.php index 8961c3a..776ccfa 100644 --- a/database/migrations/2016_06_01_000004_create_oauth_clients_table.php +++ b/database/migrations/2016_06_01_000004_create_oauth_clients_table.php @@ -8,10 +8,8 @@ { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('oauth_clients', function (Blueprint $table) { $table->bigIncrements('id'); @@ -29,10 +27,8 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('oauth_clients'); } diff --git a/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php b/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php index 8a99f46..7c9d1e8 100644 --- a/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php +++ b/database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php @@ -8,10 +8,8 @@ { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('oauth_personal_access_clients', function (Blueprint $table) { $table->bigIncrements('id'); @@ -22,10 +20,8 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('oauth_personal_access_clients'); } From e7df6ac5cf95ff476f5fb7965b27bd4d3c5d49b3 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 3 Jan 2023 17:29:04 +0000 Subject: [PATCH 43/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da644c4..1e37a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.3.1...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.4.0...11.x) + +## [v11.4.0](https://github.com/laravel/passport/compare/v11.3.1...v11.4.0) - 2023-01-03 + +### Changed + +- Uses PHP Native Type Declarations 🐘 by @nunomaduro in https://github.com/laravel/passport/pull/1594 ## [v11.3.1](https://github.com/laravel/passport/compare/v11.3.0...v11.3.1) - 2022-12-02 From 3c17574d58f8a796fadee4d5cc946b89b4ec260f Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 9 Jan 2023 16:13:26 +0100 Subject: [PATCH 44/73] Update tests.yml --- .github/workflows/tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 432efe7..d61da8a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,10 @@ jobs: fail-fast: true matrix: php: ['8.0', 8.1, 8.2] - laravel: [9] + laravel: [9, 10] + exclude: + - php: '8.0' + laravel: 10 name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} From 87dcab8ba37ba3a8c0d4958d251ab87a5c95b329 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 9 Jan 2023 17:46:42 +0100 Subject: [PATCH 45/73] Update composer.json (#1615) --- composer.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index bf44d9b..364339a 100644 --- a/composer.json +++ b/composer.json @@ -17,15 +17,15 @@ "php": "^8.0", "ext-json": "*", "firebase/php-jwt": "^6.3.1", - "illuminate/auth": "^9.0", - "illuminate/console": "^9.0", - "illuminate/container": "^9.0", - "illuminate/contracts": "^9.0", - "illuminate/cookie": "^9.0", - "illuminate/database": "^9.0", - "illuminate/encryption": "^9.0", - "illuminate/http": "^9.0", - "illuminate/support": "^9.0", + "illuminate/auth": "^9.0|^10.0", + "illuminate/console": "^9.0|^10.0", + "illuminate/container": "^9.0|^10.0", + "illuminate/contracts": "^9.0|^10.0", + "illuminate/cookie": "^9.0|^10.0", + "illuminate/database": "^9.0|^10.0", + "illuminate/encryption": "^9.0|^10.0", + "illuminate/http": "^9.0|^10.0", + "illuminate/support": "^9.0|^10.0", "lcobucci/jwt": "^3.4|^4.0", "league/oauth2-server": "^8.2", "nyholm/psr7": "^1.3", @@ -34,7 +34,7 @@ }, "require-dev": { "mockery/mockery": "^1.0", - "orchestra/testbench": "^7.0", + "orchestra/testbench": "^7.0|^8.0", "phpunit/phpunit": "^9.3" }, "autoload": { From e97f05d1ac1c8b7db0fd7202631d7c098da73f28 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 10 Jan 2023 19:54:34 +0000 Subject: [PATCH 46/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e37a19..ff3b6d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.4.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.5.0...11.x) + +## [v11.5.0](https://github.com/laravel/passport/compare/v11.4.0...v11.5.0) - 2023-01-09 + +### Added + +- Laravel v10 Support by @driesvints in https://github.com/laravel/passport/pull/1615 ## [v11.4.0](https://github.com/laravel/passport/compare/v11.3.1...v11.4.0) - 2023-01-03 From b20282266211a0a19b0294d3459b5fd268807a6c Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Mon, 16 Jan 2023 18:22:08 +0330 Subject: [PATCH 47/73] Get authenticated user from the guard (#1617) --- src/Http/Controllers/AuthorizationController.php | 8 ++++---- src/TokenRepository.php | 4 ++-- tests/Unit/AuthorizationControllerTest.php | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Http/Controllers/AuthorizationController.php b/src/Http/Controllers/AuthorizationController.php index 597a5c1..afaa9e2 100644 --- a/src/Http/Controllers/AuthorizationController.php +++ b/src/Http/Controllers/AuthorizationController.php @@ -94,7 +94,7 @@ public function authorize(ServerRequestInterface $psrRequest, $request->session()->forget('promptedForLogin'); $scopes = $this->parseScopes($authRequest); - $user = $request->user(); + $user = $this->guard->user(); $client = $clients->find($authRequest->getClient()->getIdentifier()); if ($request->get('prompt') !== 'consent' && @@ -137,7 +137,7 @@ protected function parseScopes($authRequest) * Determine if a valid token exists for the given user, client, and scopes. * * @param \Laravel\Passport\TokenRepository $tokens - * @param \Illuminate\Database\Eloquent\Model $user + * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param \Laravel\Passport\Client $client * @param array $scopes * @return bool @@ -153,7 +153,7 @@ protected function hasValidToken($tokens, $user, $client, $scopes) * Approve the authorization request. * * @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest - * @param \Illuminate\Database\Eloquent\Model $user + * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return \Illuminate\Http\Response */ protected function approveRequest($authRequest, $user) @@ -173,7 +173,7 @@ protected function approveRequest($authRequest, $user) * Deny the authorization request. * * @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest - * @param \Illuminate\Database\Eloquent\Model|null $user + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @return \Illuminate\Http\Response */ protected function denyRequest($authRequest, $user = null) diff --git a/src/TokenRepository.php b/src/TokenRepository.php index 8f992b3..b68f339 100644 --- a/src/TokenRepository.php +++ b/src/TokenRepository.php @@ -54,7 +54,7 @@ public function forUser($userId) /** * Get a valid token instance for the given user and client. * - * @param \Illuminate\Database\Eloquent\Model $user + * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param \Laravel\Passport\Client $client * @return \Laravel\Passport\Token|null */ @@ -107,7 +107,7 @@ public function isAccessTokenRevoked($id) /** * Find a valid token for the given user and client. * - * @param \Illuminate\Database\Eloquent\Model $user + * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param \Laravel\Passport\Client $client * @return \Laravel\Passport\Token|null */ diff --git a/tests/Unit/AuthorizationControllerTest.php b/tests/Unit/AuthorizationControllerTest.php index f9d0d82..03f5819 100644 --- a/tests/Unit/AuthorizationControllerTest.php +++ b/tests/Unit/AuthorizationControllerTest.php @@ -42,6 +42,7 @@ public function test_authorization_view_is_presented() $controller = new AuthorizationController($server, $response, $guard); $guard->shouldReceive('guest')->andReturn(false); + $guard->shouldReceive('user')->andReturn($user = m::mock()); $server->shouldReceive('validateAuthorizationRequest')->andReturn($authRequest = m::mock()); $request = m::mock(Request::class); @@ -49,7 +50,6 @@ public function test_authorization_view_is_presented() $session->shouldReceive('put')->withSomeOfArgs('authToken'); $session->shouldReceive('put')->with('authRequest', $authRequest); $session->shouldReceive('forget')->with('promptedForLogin')->once(); - $request->shouldReceive('user')->andReturn($user = m::mock()); $request->shouldReceive('get')->with('prompt')->andReturn(null); $authRequest->shouldReceive('getClient->getIdentifier')->andReturn(1); @@ -114,6 +114,7 @@ public function test_request_is_approved_if_valid_token_exists() $controller = new AuthorizationController($server, $response, $guard); $guard->shouldReceive('guest')->andReturn(false); + $guard->shouldReceive('user')->andReturn($user = m::mock()); $psrResponse = new Response(); $psrResponse->getBody()->write('approved'); $server->shouldReceive('validateAuthorizationRequest') @@ -125,7 +126,6 @@ public function test_request_is_approved_if_valid_token_exists() $request = m::mock(Request::class); $request->shouldReceive('session')->andReturn($session = m::mock()); $session->shouldReceive('forget')->with('promptedForLogin')->once(); - $request->shouldReceive('user')->once()->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldNotReceive('session'); $request->shouldReceive('get')->with('prompt')->andReturn(null); @@ -164,6 +164,7 @@ public function test_request_is_approved_if_client_can_skip_authorization() $controller = new AuthorizationController($server, $response, $guard); $guard->shouldReceive('guest')->andReturn(false); + $guard->shouldReceive('user')->andReturn($user = m::mock()); $psrResponse = new Response(); $psrResponse->getBody()->write('approved'); $server->shouldReceive('validateAuthorizationRequest') @@ -175,7 +176,6 @@ public function test_request_is_approved_if_client_can_skip_authorization() $request = m::mock(Request::class); $request->shouldReceive('session')->andReturn($session = m::mock()); $session->shouldReceive('forget')->with('promptedForLogin')->once(); - $request->shouldReceive('user')->once()->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldNotReceive('session'); $request->shouldReceive('get')->with('prompt')->andReturn(null); @@ -213,6 +213,7 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal $controller = new AuthorizationController($server, $response, $guard); $guard->shouldReceive('guest')->andReturn(false); + $guard->shouldReceive('user')->andReturn($user = m::mock()); $server->shouldReceive('validateAuthorizationRequest') ->andReturn($authRequest = m::mock(AuthorizationRequest::class)); @@ -221,7 +222,6 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal $session->shouldReceive('put')->withSomeOfArgs('authToken'); $session->shouldReceive('put')->with('authRequest', $authRequest); $session->shouldReceive('forget')->with('promptedForLogin')->once(); - $request->shouldReceive('user')->andReturn($user = m::mock()); $request->shouldReceive('get')->with('prompt')->andReturn('consent'); $authRequest->shouldReceive('getClient->getIdentifier')->once()->andReturn(1); @@ -263,6 +263,7 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none() $controller = new AuthorizationController($server, $response, $guard); $guard->shouldReceive('guest')->andReturn(false); + $guard->shouldReceive('user')->andReturn($user = m::mock()); $server->shouldReceive('validateAuthorizationRequest') ->andReturn($authRequest = m::mock(AuthorizationRequest::class)); $server->shouldReceive('completeAuthorizationRequest') @@ -273,7 +274,6 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none() $request = m::mock(Request::class); $request->shouldReceive('session')->andReturn($session = m::mock()); $session->shouldReceive('forget')->with('promptedForLogin')->once(); - $request->shouldReceive('user')->andReturn($user = m::mock()); $user->shouldReceive('getAuthIdentifier')->andReturn(1); $request->shouldReceive('get')->with('prompt')->andReturn('none'); From b0b0758eac20aeaa229204cbc7fa8fd6ee9f9e09 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 17 Jan 2023 16:29:11 +0000 Subject: [PATCH 48/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff3b6d6..09354db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.5.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.5.1...11.x) + +## [v11.5.1](https://github.com/laravel/passport/compare/v11.5.0...v11.5.1) - 2023-01-16 + +### Fixed + +- Get authenticated user from the guard by @hafezdivandari in https://github.com/laravel/passport/pull/1617 ## [v11.5.0](https://github.com/laravel/passport/compare/v11.4.0...v11.5.0) - 2023-01-09 From 3ac7b1e8f9814e47af5a9d5ab88c415060d5c782 Mon Sep 17 00:00:00 2001 From: "P. De Bleye" Date: Sun, 22 Jan 2023 18:37:04 +0100 Subject: [PATCH 49/73] Update ClientCommand.php's user_id description (#1619) * Update ClientCommand.php's user_id description We get a fair amount of confused passport users on the laravel discord wondering what this user_id is even for. It might help to indicate that the input is optional. * Update ClientCommand.php Co-authored-by: Taylor Otwell --- src/Console/ClientCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/ClientCommand.php b/src/Console/ClientCommand.php index f645cf6..15f2f92 100644 --- a/src/Console/ClientCommand.php +++ b/src/Console/ClientCommand.php @@ -133,7 +133,7 @@ protected function createClientCredentialsClient(ClientRepository $clients) protected function createAuthCodeClient(ClientRepository $clients) { $userId = $this->option('user_id') ?: $this->ask( - 'Which user ID should the client be assigned to?' + 'Which user ID should the client be assigned to? (Optional)' ); $name = $this->option('name') ?: $this->ask( From b7bc60c9df4b7ba42bc193e36f392880865250ee Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Wed, 25 Jan 2023 15:32:58 +0100 Subject: [PATCH 50/73] Fix doc block for `withAccessToken()` (#1620) --- src/HasApiTokens.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HasApiTokens.php b/src/HasApiTokens.php index 71853fe..025c7f2 100644 --- a/src/HasApiTokens.php +++ b/src/HasApiTokens.php @@ -71,7 +71,7 @@ public function createToken($name, array $scopes = []) /** * Set the current access token for the user. * - * @param \Laravel\Passport\Token $accessToken + * @param \Laravel\Passport\Token|\Laravel\Passport\TransientToken $accessToken * @return $this */ public function withAccessToken($accessToken) From 1d8204e40c63bb6cbb981907fdbeb5c69a4fbae9 Mon Sep 17 00:00:00 2001 From: "Lucas Moraes (Panik)" Date: Tue, 31 Jan 2023 10:41:55 -0300 Subject: [PATCH 51/73] [11.x] Get model PK instead of forcibly id column (#1626) * Get model PK instead of forcibly id column * Get model PK instead of forcibly id column in tests * Get model PK instead of forcibly id column in command * Get model PK instead of forcibly id column in repository * Get model PK instead of forcibly id column in Passport * stub extending from model * Fix namespace order * Get model PK instead of forcibly id column in blade --- resources/views/authorize.blade.php | 4 ++-- src/ClientRepository.php | 2 +- src/Console/ClientCommand.php | 2 +- src/Passport.php | 2 +- src/PersonalAccessTokenFactory.php | 2 +- tests/Feature/AccessTokenControllerTest.php | 24 +++++++++---------- tests/Unit/PersonalAccessTokenFactoryTest.php | 3 ++- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/resources/views/authorize.blade.php b/resources/views/authorize.blade.php index ecbdcaa..d0a4a99 100644 --- a/resources/views/authorize.blade.php +++ b/resources/views/authorize.blade.php @@ -68,7 +68,7 @@ @csrf - + @@ -79,7 +79,7 @@ @method('DELETE') - + diff --git a/src/ClientRepository.php b/src/ClientRepository.php index aebe33b..402deb0 100644 --- a/src/ClientRepository.php +++ b/src/ClientRepository.php @@ -167,7 +167,7 @@ public function createPersonalAccessClient($userId, $name, $redirect) { return tap($this->create($userId, $name, $redirect, null, true), function ($client) { $accessClient = Passport::personalAccessClient(); - $accessClient->client_id = $client->id; + $accessClient->client_id = $client->getKey(); $accessClient->save(); }); } diff --git a/src/Console/ClientCommand.php b/src/Console/ClientCommand.php index 15f2f92..c46f63b 100644 --- a/src/Console/ClientCommand.php +++ b/src/Console/ClientCommand.php @@ -167,7 +167,7 @@ protected function outputClientDetails(Client $client) $this->line(''); } - $this->line('Client ID: '.$client->id); + $this->line('Client ID: '.$client->getKey()); $this->line('Client secret: '.$client->plainSecret); } } diff --git a/src/Passport.php b/src/Passport.php index 6e577eb..eb85e0a 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -370,7 +370,7 @@ public static function actingAsClient($client, $scopes = [], $guard = 'api') { $token = app(self::tokenModel()); - $token->client_id = $client->id; + $token->client_id = $client->getKey(); $token->setRelation('client', $client); $token->scopes = $scopes; diff --git a/src/PersonalAccessTokenFactory.php b/src/PersonalAccessTokenFactory.php index 65817a7..15ac840 100644 --- a/src/PersonalAccessTokenFactory.php +++ b/src/PersonalAccessTokenFactory.php @@ -98,7 +98,7 @@ protected function createRequest($client, $userId, array $scopes) return (new ServerRequest('POST', 'not-important'))->withParsedBody([ 'grant_type' => 'personal_access', - 'client_id' => $client->id, + 'client_id' => $client->getKey(), 'client_secret' => $secret, 'user_id' => $userId, 'scope' => implode(' ', $scopes), diff --git a/tests/Feature/AccessTokenControllerTest.php b/tests/Feature/AccessTokenControllerTest.php index 073f65d..54cb4ff 100644 --- a/tests/Feature/AccessTokenControllerTest.php +++ b/tests/Feature/AccessTokenControllerTest.php @@ -50,13 +50,13 @@ public function testGettingAccessTokenWithClientCredentialsGrant() $user->save(); /** @var Client $client */ - $client = ClientFactory::new()->asClientCredentials()->create(['user_id' => $user->id]); + $client = ClientFactory::new()->asClientCredentials()->create(['user_id' => $user->getKey()]); $response = $this->post( '/oauth/token', [ 'grant_type' => 'client_credentials', - 'client_id' => $client->id, + 'client_id' => $client->getKey(), 'client_secret' => $client->secret, ] ); @@ -93,13 +93,13 @@ public function testGettingAccessTokenWithClientCredentialsGrantInvalidClientSec $user->save(); /** @var Client $client */ - $client = ClientFactory::new()->asClientCredentials()->create(['user_id' => $user->id]); + $client = ClientFactory::new()->asClientCredentials()->create(['user_id' => $user->getKey()]); $response = $this->post( '/oauth/token', [ 'grant_type' => 'client_credentials', - 'client_id' => $client->id, + 'client_id' => $client->getKey(), 'client_secret' => $client->secret.'foo', ] ); @@ -137,13 +137,13 @@ public function testGettingAccessTokenWithPasswordGrant() $user->save(); /** @var Client $client */ - $client = ClientFactory::new()->asPasswordClient()->create(['user_id' => $user->id]); + $client = ClientFactory::new()->asPasswordClient()->create(['user_id' => $user->getKey()]); $response = $this->post( '/oauth/token', [ 'grant_type' => 'password', - 'client_id' => $client->id, + 'client_id' => $client->getKey(), 'client_secret' => $client->secret, 'username' => $user->email, 'password' => $password, @@ -184,13 +184,13 @@ public function testGettingAccessTokenWithPasswordGrantWithInvalidPassword() $user->save(); /** @var Client $client */ - $client = ClientFactory::new()->asPasswordClient()->create(['user_id' => $user->id]); + $client = ClientFactory::new()->asPasswordClient()->create(['user_id' => $user->getKey()]); $response = $this->post( '/oauth/token', [ 'grant_type' => 'password', - 'client_id' => $client->id, + 'client_id' => $client->getKey(), 'client_secret' => $client->secret, 'username' => $user->email, 'password' => $password.'foo', @@ -227,13 +227,13 @@ public function testGettingAccessTokenWithPasswordGrantWithInvalidClientSecret() $user->save(); /** @var Client $client */ - $client = ClientFactory::new()->asPasswordClient()->create(['user_id' => $user->id]); + $client = ClientFactory::new()->asPasswordClient()->create(['user_id' => $user->getKey()]); $response = $this->post( '/oauth/token', [ 'grant_type' => 'password', - 'client_id' => $client->id, + 'client_id' => $client->getKey(), 'client_secret' => $client->secret.'foo', 'username' => $user->email, 'password' => $password, @@ -274,13 +274,13 @@ public function testGettingCustomResponseType() $user->save(); /** @var Client $client */ - $client = ClientFactory::new()->asClientCredentials()->create(['user_id' => $user->id]); + $client = ClientFactory::new()->asClientCredentials()->create(['user_id' => $user->getKey()]); $response = $this->post( '/oauth/token', [ 'grant_type' => 'client_credentials', - 'client_id' => $client->id, + 'client_id' => $client->getKey(), 'client_secret' => $client->secret, ] ); diff --git a/tests/Unit/PersonalAccessTokenFactoryTest.php b/tests/Unit/PersonalAccessTokenFactoryTest.php index f4731bd..33e5764 100644 --- a/tests/Unit/PersonalAccessTokenFactoryTest.php +++ b/tests/Unit/PersonalAccessTokenFactoryTest.php @@ -2,6 +2,7 @@ namespace Laravel\Passport\Tests\Unit; +use Laravel\Passport\Client; use Laravel\Passport\ClientRepository; use Laravel\Passport\PersonalAccessTokenFactory; use Laravel\Passport\PersonalAccessTokenResult; @@ -56,7 +57,7 @@ public function test_access_token_can_be_created() } } -class PersonalAccessTokenFactoryTestClientStub +class PersonalAccessTokenFactoryTestClientStub extends Client { public $id = 1; From 9ee5bd94abf0698f414dcfcb179b2b311a72c13e Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 31 Jan 2023 15:42:22 +0000 Subject: [PATCH 52/73] Update CHANGELOG --- CHANGELOG.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09354db..a7e1056 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.5.1...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.6.0...11.x) + +## [v11.6.0](https://github.com/laravel/passport/compare/v11.5.1...v11.6.0) - 2023-01-31 + +### Changed + +- Update ClientCommand.php's user_id description by @Smoggert in https://github.com/laravel/passport/pull/1619 +- Get model PK instead of forcibly id column by @lucaspanik in https://github.com/laravel/passport/pull/1626 + +### Fixed + +- Fix doc block for `withAccessToken()` by @axlon in https://github.com/laravel/passport/pull/1620 ## [v11.5.1](https://github.com/laravel/passport/compare/v11.5.0...v11.5.1) - 2023-01-16 From d8cc34766635da552a9ddff80248c5505f19bd04 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:45:23 +0100 Subject: [PATCH 53/73] Indicate current token can be `TransientToken` (#1627) --- src/HasApiTokens.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HasApiTokens.php b/src/HasApiTokens.php index 025c7f2..f68bc1e 100644 --- a/src/HasApiTokens.php +++ b/src/HasApiTokens.php @@ -9,7 +9,7 @@ trait HasApiTokens /** * The current access token for the authentication user. * - * @var \Laravel\Passport\Token + * @var \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null */ protected $accessToken; @@ -36,7 +36,7 @@ public function tokens() /** * Get the current access token being used by the user. * - * @return \Laravel\Passport\Token|null + * @return \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null */ public function token() { From 31ed56954f044ffd6dcef237d5087955376693ff Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 7 Feb 2023 16:08:23 +0000 Subject: [PATCH 54/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7e1056..669cd76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.6.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.6.1...11.x) + +## [v11.6.1](https://github.com/laravel/passport/compare/v11.6.0...v11.6.1) - 2023-02-03 + +### Changed + +- Indicate current token can be `TransientToken` by @axlon in https://github.com/laravel/passport/pull/1627 ## [v11.6.0](https://github.com/laravel/passport/compare/v11.5.1...v11.6.0) - 2023-01-31 From 5b57dbc9fc5e350d70b5c612fd53c65dd0bbebb2 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Wed, 8 Feb 2023 18:24:40 +0100 Subject: [PATCH 55/73] Add support for `EncryptCookies` middleware (#1628) --- src/Guards/TokenGuard.php | 6 ++++- src/Passport.php | 31 ++++++++++++++++++++++++++ tests/Unit/TokenGuardTest.php | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/Guards/TokenGuard.php b/src/Guards/TokenGuard.php index 7e478ce..6798ca3 100644 --- a/src/Guards/TokenGuard.php +++ b/src/Guards/TokenGuard.php @@ -295,8 +295,12 @@ protected function getTokenViaCookie($request) */ protected function decodeJwtTokenCookie($request) { + $jwt = $request->cookie(Passport::cookie()); + return (array) JWT::decode( - CookieValuePrefix::remove($this->encrypter->decrypt($request->cookie(Passport::cookie()), Passport::$unserializesCookies)), + Passport::$decryptsCookies + ? CookieValuePrefix::remove($this->encrypter->decrypt($jwt, Passport::$unserializesCookies)) + : $jwt, new Key(Passport::tokenEncryptionKey($this->encrypter), 'HS256') ); } diff --git a/src/Passport.php b/src/Passport.php index eb85e0a..3fddf87 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -133,6 +133,13 @@ class Passport */ public static $unserializesCookies = false; + /** + * Indicates if Passport should decrypt cookies. + * + * @var bool + */ + public static $decryptsCookies = true; + /** * Indicates if client secrets will be hashed. * @@ -684,4 +691,28 @@ public static function withoutCookieSerialization() return new static; } + + /** + * Instruct Passport to enable cookie encryption. + * + * @return static + */ + public static function withCookieEncryption() + { + static::$decryptsCookies = true; + + return new static; + } + + /** + * Instruct Passport to disable cookie encryption. + * + * @return static + */ + public static function withoutCookieEncryption() + { + static::$decryptsCookies = false; + + return new static; + } } diff --git a/tests/Unit/TokenGuardTest.php b/tests/Unit/TokenGuardTest.php index c29cc10..6143938 100644 --- a/tests/Unit/TokenGuardTest.php +++ b/tests/Unit/TokenGuardTest.php @@ -304,6 +304,48 @@ public function test_users_may_be_retrieved_from_cookies_with_xsrf_token_header_ Passport::encryptTokensUsing(null); } + public function test_users_may_be_retrieved_from_cookies_without_encryption() + { + Passport::withoutCookieEncryption(); + Passport::encryptTokensUsing(function (EncrypterContract $encrypter) { + return $encrypter->getKey().'.mykey'; + }); + + $resourceServer = m::mock(ResourceServer::class); + $userProvider = m::mock(PassportUserProvider::class); + $tokens = m::mock(TokenRepository::class); + $clients = m::mock(ClientRepository::class); + $encrypter = new Encrypter(str_repeat('a', 16)); + + $clients->shouldReceive('findActive') + ->with(1) + ->andReturn(new TokenGuardTestClient); + + $request = Request::create('/'); + $request->headers->set('X-XSRF-TOKEN', $encrypter->encrypt(CookieValuePrefix::create('X-XSRF-TOKEN', $encrypter->getKey()).'token', false)); + $request->cookies->set('laravel_token', + JWT::encode([ + 'sub' => 1, + 'aud' => 1, + 'csrf' => 'token', + 'expiry' => Carbon::now()->addMinutes(10)->getTimestamp(), + ], Passport::tokenEncryptionKey($encrypter), 'HS256') + ); + + $guard = new TokenGuard($resourceServer, $userProvider, $tokens, $clients, $encrypter, $request); + + $userProvider->shouldReceive('retrieveById')->with(1)->andReturn($expectedUser = new TokenGuardTestUser); + $userProvider->shouldReceive('getProviderName')->andReturn(null); + + $user = $guard->user(); + + $this->assertEquals($expectedUser, $user); + + // Revert to the default encryption method + Passport::withCookieEncryption(); + Passport::encryptTokensUsing(null); + } + public function test_xsrf_token_cookie_without_a_token_header_is_not_accepted() { $resourceServer = m::mock(ResourceServer::class); From 174a12a8d80476c16bcae78b404395154721d815 Mon Sep 17 00:00:00 2001 From: driesvints Date: Tue, 14 Feb 2023 16:51:43 +0000 Subject: [PATCH 56/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 669cd76..b1f86d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.6.1...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.7.0...11.x) + +## [v11.7.0](https://github.com/laravel/passport/compare/v11.6.1...v11.7.0) - 2023-02-08 + +### Added + +- Add support for `EncryptCookies` middleware by @axlon in https://github.com/laravel/passport/pull/1628 ## [v11.6.1](https://github.com/laravel/passport/compare/v11.6.0...v11.6.1) - 2023-02-03 From 08b1dabfdddbdf2472ef193609f75f475208ec90 Mon Sep 17 00:00:00 2001 From: Chris Page Date: Tue, 14 Feb 2023 21:08:49 +0000 Subject: [PATCH 57/73] Added AuthenticationException to extend the behaviour of Laravel's default exception handler (#1633) Co-authored-by: Chris Page --- src/Exceptions/AuthenticationException.php | 9 +++++++++ src/Http/Controllers/AuthorizationController.php | 4 ++-- src/Http/Middleware/CheckClientCredentials.php | 4 ++-- .../Middleware/CheckClientCredentialsForAnyScope.php | 4 ++-- src/Http/Middleware/CheckCredentials.php | 6 +++--- src/Http/Middleware/CheckForAnyScope.php | 4 ++-- src/Http/Middleware/CheckScopes.php | 4 ++-- tests/Unit/AuthorizationControllerTest.php | 5 +++-- tests/Unit/CheckClientCredentialsForAnyScopeTest.php | 3 ++- tests/Unit/CheckClientCredentialsTest.php | 3 ++- tests/Unit/CheckForAnyScopeTest.php | 5 +++-- tests/Unit/CheckScopesTest.php | 5 +++-- 12 files changed, 35 insertions(+), 21 deletions(-) create mode 100644 src/Exceptions/AuthenticationException.php diff --git a/src/Exceptions/AuthenticationException.php b/src/Exceptions/AuthenticationException.php new file mode 100644 index 0000000..75ec03d --- /dev/null +++ b/src/Exceptions/AuthenticationException.php @@ -0,0 +1,9 @@ +expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); @@ -368,7 +369,7 @@ public function test_logout_and_prompt_login_if_request_has_prompt_equals_to_log public function test_user_should_be_authenticated() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $server = m::mock(AuthorizationServer::class); $response = m::mock(ResponseFactory::class); diff --git a/tests/Unit/CheckClientCredentialsForAnyScopeTest.php b/tests/Unit/CheckClientCredentialsForAnyScopeTest.php index 754d9a7..807bf93 100644 --- a/tests/Unit/CheckClientCredentialsForAnyScopeTest.php +++ b/tests/Unit/CheckClientCredentialsForAnyScopeTest.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Laravel\Passport\Client; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckClientCredentialsForAnyScope; use Laravel\Passport\Token; use Laravel\Passport\TokenRepository; @@ -85,7 +86,7 @@ public function test_request_is_passed_along_if_token_has_any_required_scope() public function test_exception_is_thrown_when_oauth_throws_exception() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $tokenRepository = m::mock(TokenRepository::class); $resourceServer = m::mock(ResourceServer::class); diff --git a/tests/Unit/CheckClientCredentialsTest.php b/tests/Unit/CheckClientCredentialsTest.php index 36e410d..0a30b19 100644 --- a/tests/Unit/CheckClientCredentialsTest.php +++ b/tests/Unit/CheckClientCredentialsTest.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Laravel\Passport\Client; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckClientCredentials; use Laravel\Passport\Token; use Laravel\Passport\TokenRepository; @@ -84,7 +85,7 @@ public function test_request_is_passed_along_if_token_and_scope_are_valid() public function test_exception_is_thrown_when_oauth_throws_exception() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $tokenRepository = m::mock(TokenRepository::class); $resourceServer = m::mock(ResourceServer::class); diff --git a/tests/Unit/CheckForAnyScopeTest.php b/tests/Unit/CheckForAnyScopeTest.php index cf9e04c..e567fee 100644 --- a/tests/Unit/CheckForAnyScopeTest.php +++ b/tests/Unit/CheckForAnyScopeTest.php @@ -2,6 +2,7 @@ namespace Laravel\Passport\Tests\Unit; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckForAnyScope as CheckScopes; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -47,7 +48,7 @@ public function test_exception_is_thrown_if_token_doesnt_have_scope() public function test_exception_is_thrown_if_no_authenticated_user() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); @@ -60,7 +61,7 @@ public function test_exception_is_thrown_if_no_authenticated_user() public function test_exception_is_thrown_if_no_token() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); diff --git a/tests/Unit/CheckScopesTest.php b/tests/Unit/CheckScopesTest.php index 3eb172b..21e8b40 100644 --- a/tests/Unit/CheckScopesTest.php +++ b/tests/Unit/CheckScopesTest.php @@ -2,6 +2,7 @@ namespace Laravel\Passport\Tests\Unit; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckScopes; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -46,7 +47,7 @@ public function test_exception_is_thrown_if_token_doesnt_have_scope() public function test_exception_is_thrown_if_no_authenticated_user() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); @@ -59,7 +60,7 @@ public function test_exception_is_thrown_if_no_authenticated_user() public function test_exception_is_thrown_if_no_token() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); From e305ff0488f3e125f3f22e1576d613dd1d95ac7e Mon Sep 17 00:00:00 2001 From: Jon Erickson Date: Thu, 16 Feb 2023 14:02:39 -0700 Subject: [PATCH 58/73] [11.x] Custom authorization view response (#1629) * Implements authorization view response contract that allows for being overridden with custom views * Updated namespace * Updated namespace * Moved individual arguments to an array of parameters and one argument * Removed authorize return type * Remove old return statement * Add IntelliJ IDE files to gitignore * Formatting * Update tests * Update rest of tests with new response class * Style fixes and make sure parameters pushed to authorization view are in an array. * Remove parameters from authorization view function * Update .gitignore * Update src/Contracts/AuthorizationViewResponse.php Co-authored-by: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> * Update src/Http/Responses/AuthorizationViewResponse.php Co-authored-by: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> * Updated doc block return types * formatting * remove extra line --------- Co-authored-by: Dries Vints Co-authored-by: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Co-authored-by: Taylor Otwell --- src/Contracts/AuthorizationViewResponse.php | 16 +++++ .../Controllers/AuthorizationController.php | 25 ++++--- .../Responses/AuthorizationViewResponse.php | 68 +++++++++++++++++++ src/Passport.php | 15 ++++ src/PassportServiceProvider.php | 2 + tests/Unit/AuthorizationControllerTest.php | 53 +++++++-------- 6 files changed, 139 insertions(+), 40 deletions(-) create mode 100644 src/Contracts/AuthorizationViewResponse.php create mode 100644 src/Http/Responses/AuthorizationViewResponse.php diff --git a/src/Contracts/AuthorizationViewResponse.php b/src/Contracts/AuthorizationViewResponse.php new file mode 100644 index 0000000..6594c66 --- /dev/null +++ b/src/Contracts/AuthorizationViewResponse.php @@ -0,0 +1,16 @@ +server = $server; - $this->response = $response; $this->guard = $guard; + $this->response = $response; } /** @@ -65,7 +64,7 @@ public function __construct(AuthorizationServer $server, * @param \Illuminate\Http\Request $request * @param \Laravel\Passport\ClientRepository $clients * @param \Laravel\Passport\TokenRepository $tokens - * @return \Illuminate\Http\Response + * @return \Laravel\Passport\Contracts\AuthorizationViewResponse */ public function authorize(ServerRequestInterface $psrRequest, Request $request, @@ -109,7 +108,7 @@ public function authorize(ServerRequestInterface $psrRequest, $request->session()->put('authToken', $authToken = Str::random()); $request->session()->put('authRequest', $authRequest); - return $this->response->view('passport::authorize', [ + return $this->response->withParameters([ 'client' => $client, 'user' => $user, 'scopes' => $scopes, diff --git a/src/Http/Responses/AuthorizationViewResponse.php b/src/Http/Responses/AuthorizationViewResponse.php new file mode 100644 index 0000000..36761d4 --- /dev/null +++ b/src/Http/Responses/AuthorizationViewResponse.php @@ -0,0 +1,68 @@ +view = $view; + } + + /** + * Add parameters to response. + * + * @param array $parameters + * @return $this + */ + public function withParameters($parameters = []) + { + $this->parameters = $parameters; + + return $this; + } + + /** + * Create an HTTP response that represents the object. + * + * @param \Illuminate\Http\Request $request + * @return \Symfony\Component\HttpFoundation\Response + */ + public function toResponse($request) + { + if (! is_callable($this->view) || is_string($this->view)) { + return response()->view($this->view, $this->parameters); + } + + $response = call_user_func($this->view, $this->parameters); + + if ($response instanceof Responsable) { + return $response->toResponse($request); + } + + return $response; + } +} diff --git a/src/Passport.php b/src/Passport.php index 3fddf87..706a754 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -6,6 +6,8 @@ use DateInterval; use DateTimeInterface; use Illuminate\Contracts\Encryption\Encrypter; +use Laravel\Passport\Contracts\AuthorizationViewResponse as AuthorizationViewResponseContract; +use Laravel\Passport\Http\Responses\AuthorizationViewResponse; use League\OAuth2\Server\ResourceServer; use Mockery; use Psr\Http\Message\ServerRequestInterface; @@ -644,6 +646,19 @@ public static function tokenEncryptionKey(Encrypter $encrypter) $encrypter->getKey(); } + /** + * Specify which view should be used as the authorization view. + * + * @param callable|string $view + * @return void + */ + public static function authorizationView($view) + { + app()->singleton(AuthorizationViewResponseContract::class, function ($app) use ($view) { + return new AuthorizationViewResponse($view); + }); + } + /** * Configure Passport to not register its routes. * diff --git a/src/PassportServiceProvider.php b/src/PassportServiceProvider.php index efe1361..64ed0b9 100644 --- a/src/PassportServiceProvider.php +++ b/src/PassportServiceProvider.php @@ -145,6 +145,8 @@ public function register() $this->registerJWTParser(); $this->registerResourceServer(); $this->registerGuard(); + + Passport::authorizationView('passport::authorize'); } /** diff --git a/tests/Unit/AuthorizationControllerTest.php b/tests/Unit/AuthorizationControllerTest.php index ec79a08..fe6e7f3 100644 --- a/tests/Unit/AuthorizationControllerTest.php +++ b/tests/Unit/AuthorizationControllerTest.php @@ -3,7 +3,6 @@ namespace Laravel\Passport\Tests\Unit; use Illuminate\Contracts\Auth\StatefulGuard; -use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Http\Request; use Laravel\Passport\Bridge\Scope; use Laravel\Passport\Client; @@ -11,6 +10,7 @@ use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Exceptions\OAuthServerException; use Laravel\Passport\Http\Controllers\AuthorizationController; +use Laravel\Passport\Http\Responses\AuthorizationViewResponse; use Laravel\Passport\Passport; use Laravel\Passport\Token; use Laravel\Passport\TokenRepository; @@ -37,10 +37,10 @@ public function test_authorization_view_is_presented() ]); $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(false); $guard->shouldReceive('user')->andReturn($user = m::mock()); @@ -58,21 +58,20 @@ public function test_authorization_view_is_presented() $clients = m::mock(ClientRepository::class); $clients->shouldReceive('find')->with(1)->andReturn($client = m::mock(Client::class)); - $client->shouldReceive('skipsAuthorization')->andReturn(false); - $response->shouldReceive('view')->once()->andReturnUsing(function ($view, $data) use ($client, $user) { - $this->assertSame('passport::authorize', $view); + $tokens = m::mock(TokenRepository::class); + $tokens->shouldReceive('findValidToken')->with($user, $client)->andReturnNull(); + + $response->shouldReceive('withParameters')->once()->andReturnUsing(function ($data) use ($client, $user, $request) { $this->assertEquals($client, $data['client']); $this->assertEquals($user, $data['user']); + $this->assertEquals($request, $data['request']); $this->assertSame('description', $data['scopes'][0]->description); return 'view'; }); - $tokens = m::mock(TokenRepository::class); - $tokens->shouldReceive('findValidToken')->with($user, $client)->andReturnNull(); - $this->assertSame('view', $controller->authorize( m::mock(ServerRequestInterface::class), $request, $clients, $tokens )); @@ -81,10 +80,10 @@ public function test_authorization_view_is_presented() public function test_authorization_exceptions_are_handled() { $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(false); $server->shouldReceive('validateAuthorizationRequest')->andThrow(LeagueException::invalidCredentials()); @@ -109,10 +108,10 @@ public function test_request_is_approved_if_valid_token_exists() ]); $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(false); $guard->shouldReceive('user')->andReturn($user = m::mock()); @@ -159,10 +158,10 @@ public function test_request_is_approved_if_client_can_skip_authorization() ]); $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(false); $guard->shouldReceive('user')->andReturn($user = m::mock()); @@ -208,10 +207,10 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal ]); $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(false); $guard->shouldReceive('user')->andReturn($user = m::mock()); @@ -235,10 +234,10 @@ public function test_authorization_view_is_presented_if_request_has_prompt_equal $tokens = m::mock(TokenRepository::class); $tokens->shouldNotReceive('findValidToken'); - $response->shouldReceive('view')->once()->andReturnUsing(function ($view, $data) use ($client, $user) { - $this->assertSame('passport::authorize', $view); + $response->shouldReceive('withParameters')->once()->andReturnUsing(function ($data) use ($client, $user, $request) { $this->assertEquals($client, $data['client']); $this->assertEquals($user, $data['user']); + $this->assertEquals($request, $data['request']); $this->assertSame('description', $data['scopes'][0]->description); return 'view'; @@ -258,10 +257,10 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none() ]); $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(false); $guard->shouldReceive('user')->andReturn($user = m::mock()); @@ -300,10 +299,10 @@ public function test_authorization_denied_if_request_has_prompt_equals_to_none() public function test_authorization_denied_if_unauthenticated_and_request_has_prompt_equals_to_none() { $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(true); $server->shouldReceive('validateAuthorizationRequest') @@ -341,10 +340,10 @@ public function test_logout_and_prompt_login_if_request_has_prompt_equals_to_log $this->expectException(AuthenticationException::class); $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(false); $server->shouldReceive('validateAuthorizationRequest')->once(); @@ -372,10 +371,10 @@ public function test_user_should_be_authenticated() $this->expectException(AuthenticationException::class); $server = m::mock(AuthorizationServer::class); - $response = m::mock(ResponseFactory::class); + $response = m::mock(AuthorizationViewResponse::class); $guard = m::mock(StatefulGuard::class); - $controller = new AuthorizationController($server, $response, $guard); + $controller = new AuthorizationController($server, $guard, $response); $guard->shouldReceive('guest')->andReturn(true); $server->shouldReceive('validateAuthorizationRequest')->once(); From 2008d86244297a9fa291faf63f59d0949bddf91e Mon Sep 17 00:00:00 2001 From: "TONY.W" <33448724+TonyWong9527@users.noreply.github.com> Date: Fri, 17 Feb 2023 17:08:51 +0800 Subject: [PATCH 59/73] laravel10 The Eloquent model's deprecated $dates property has been removed.application should now use the $casts property (#1636) Co-authored-by: tony --- src/Token.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Token.php b/src/Token.php index 6f5d7b9..a84cbba 100644 --- a/src/Token.php +++ b/src/Token.php @@ -42,15 +42,7 @@ class Token extends Model protected $casts = [ 'scopes' => 'array', 'revoked' => 'bool', - ]; - - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = [ - 'expires_at', + 'expires_at' => 'datetime', ]; /** From ab51e2b013a020ac3f28e772ced15730baf77a45 Mon Sep 17 00:00:00 2001 From: driesvints Date: Fri, 17 Feb 2023 09:10:16 +0000 Subject: [PATCH 60/73] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1f86d6..94fe37c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.7.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.8.0...11.x) + +## [v11.8.0](https://github.com/laravel/passport/compare/v11.7.0...v11.8.0) - 2023-02-17 + +- Move AuthenticationException into the scope of Laravel Passport by @chrispage1 in https://github.com/laravel/passport/pull/1633 +- Custom authorization view response by @JonErickson in https://github.com/laravel/passport/pull/1629 +- Fix deprecated $dates property by @TonyWong9527 in https://github.com/laravel/passport/pull/1636 ## [v11.7.0](https://github.com/laravel/passport/compare/v11.6.1...v11.7.0) - 2023-02-08 From db543b0cc13ed3f56f1bffda04707fbe2a8c7ab5 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 20 Feb 2023 10:20:04 +0100 Subject: [PATCH 61/73] Revert "Added AuthenticationException to extend the behaviour of Laravel's default exception handler (#1633)" This reverts commit 08b1dabfdddbdf2472ef193609f75f475208ec90. --- src/Exceptions/AuthenticationException.php | 9 --------- src/Http/Controllers/AuthorizationController.php | 4 ++-- src/Http/Middleware/CheckClientCredentials.php | 4 ++-- .../Middleware/CheckClientCredentialsForAnyScope.php | 4 ++-- src/Http/Middleware/CheckCredentials.php | 6 +++--- src/Http/Middleware/CheckForAnyScope.php | 4 ++-- src/Http/Middleware/CheckScopes.php | 4 ++-- tests/Unit/AuthorizationControllerTest.php | 5 ++--- tests/Unit/CheckClientCredentialsForAnyScopeTest.php | 3 +-- tests/Unit/CheckClientCredentialsTest.php | 3 +-- tests/Unit/CheckForAnyScopeTest.php | 5 ++--- tests/Unit/CheckScopesTest.php | 5 ++--- 12 files changed, 21 insertions(+), 35 deletions(-) delete mode 100644 src/Exceptions/AuthenticationException.php diff --git a/src/Exceptions/AuthenticationException.php b/src/Exceptions/AuthenticationException.php deleted file mode 100644 index 75ec03d..0000000 --- a/src/Exceptions/AuthenticationException.php +++ /dev/null @@ -1,9 +0,0 @@ -expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $server = m::mock(AuthorizationServer::class); $response = m::mock(AuthorizationViewResponse::class); @@ -368,7 +367,7 @@ public function test_logout_and_prompt_login_if_request_has_prompt_equals_to_log public function test_user_should_be_authenticated() { - $this->expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $server = m::mock(AuthorizationServer::class); $response = m::mock(AuthorizationViewResponse::class); diff --git a/tests/Unit/CheckClientCredentialsForAnyScopeTest.php b/tests/Unit/CheckClientCredentialsForAnyScopeTest.php index 807bf93..754d9a7 100644 --- a/tests/Unit/CheckClientCredentialsForAnyScopeTest.php +++ b/tests/Unit/CheckClientCredentialsForAnyScopeTest.php @@ -4,7 +4,6 @@ use Illuminate\Http\Request; use Laravel\Passport\Client; -use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckClientCredentialsForAnyScope; use Laravel\Passport\Token; use Laravel\Passport\TokenRepository; @@ -86,7 +85,7 @@ public function test_request_is_passed_along_if_token_has_any_required_scope() public function test_exception_is_thrown_when_oauth_throws_exception() { - $this->expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $tokenRepository = m::mock(TokenRepository::class); $resourceServer = m::mock(ResourceServer::class); diff --git a/tests/Unit/CheckClientCredentialsTest.php b/tests/Unit/CheckClientCredentialsTest.php index 0a30b19..36e410d 100644 --- a/tests/Unit/CheckClientCredentialsTest.php +++ b/tests/Unit/CheckClientCredentialsTest.php @@ -4,7 +4,6 @@ use Illuminate\Http\Request; use Laravel\Passport\Client; -use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckClientCredentials; use Laravel\Passport\Token; use Laravel\Passport\TokenRepository; @@ -85,7 +84,7 @@ public function test_request_is_passed_along_if_token_and_scope_are_valid() public function test_exception_is_thrown_when_oauth_throws_exception() { - $this->expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $tokenRepository = m::mock(TokenRepository::class); $resourceServer = m::mock(ResourceServer::class); diff --git a/tests/Unit/CheckForAnyScopeTest.php b/tests/Unit/CheckForAnyScopeTest.php index e567fee..cf9e04c 100644 --- a/tests/Unit/CheckForAnyScopeTest.php +++ b/tests/Unit/CheckForAnyScopeTest.php @@ -2,7 +2,6 @@ namespace Laravel\Passport\Tests\Unit; -use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckForAnyScope as CheckScopes; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -48,7 +47,7 @@ public function test_exception_is_thrown_if_token_doesnt_have_scope() public function test_exception_is_thrown_if_no_authenticated_user() { - $this->expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $middleware = new CheckScopes; $request = m::mock(); @@ -61,7 +60,7 @@ public function test_exception_is_thrown_if_no_authenticated_user() public function test_exception_is_thrown_if_no_token() { - $this->expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $middleware = new CheckScopes; $request = m::mock(); diff --git a/tests/Unit/CheckScopesTest.php b/tests/Unit/CheckScopesTest.php index 21e8b40..3eb172b 100644 --- a/tests/Unit/CheckScopesTest.php +++ b/tests/Unit/CheckScopesTest.php @@ -2,7 +2,6 @@ namespace Laravel\Passport\Tests\Unit; -use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckScopes; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -47,7 +46,7 @@ public function test_exception_is_thrown_if_token_doesnt_have_scope() public function test_exception_is_thrown_if_no_authenticated_user() { - $this->expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $middleware = new CheckScopes; $request = m::mock(); @@ -60,7 +59,7 @@ public function test_exception_is_thrown_if_no_authenticated_user() public function test_exception_is_thrown_if_no_token() { - $this->expectException(AuthenticationException::class); + $this->expectException('Illuminate\Auth\AuthenticationException'); $middleware = new CheckScopes; $request = m::mock(); From f3d03156046951fcb54868265a795ef92abca200 Mon Sep 17 00:00:00 2001 From: driesvints Date: Mon, 20 Feb 2023 09:23:45 +0000 Subject: [PATCH 62/73] Update CHANGELOG --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94fe37c..4c75eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.8.0...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.8.1...11.x) + +## [v11.8.1](https://github.com/laravel/passport/compare/v11.8.0...v11.8.1) - 2023-02-20 + +- Revert "Move AuthenticationException into the scope of Laravel Passport" by @driesvints in https://github.com/laravel/passport/commit/db543b0cc13ed3f56f1bffda04707fbe2a8c7ab5 ## [v11.8.0](https://github.com/laravel/passport/compare/v11.7.0...v11.8.0) - 2023-02-17 From 67c3e336af163f6eba5dbca8e5db46275ff0e433 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Mon, 20 Feb 2023 14:43:07 +0100 Subject: [PATCH 63/73] Revert "Revert "Added AuthenticationException to extend the behaviour of Laravel's default exception handler (#1633)"" This reverts commit db543b0cc13ed3f56f1bffda04707fbe2a8c7ab5. --- src/Exceptions/AuthenticationException.php | 9 +++++++++ src/Http/Controllers/AuthorizationController.php | 4 ++-- src/Http/Middleware/CheckClientCredentials.php | 4 ++-- .../Middleware/CheckClientCredentialsForAnyScope.php | 4 ++-- src/Http/Middleware/CheckCredentials.php | 6 +++--- src/Http/Middleware/CheckForAnyScope.php | 4 ++-- src/Http/Middleware/CheckScopes.php | 4 ++-- tests/Unit/AuthorizationControllerTest.php | 5 +++-- tests/Unit/CheckClientCredentialsForAnyScopeTest.php | 3 ++- tests/Unit/CheckClientCredentialsTest.php | 3 ++- tests/Unit/CheckForAnyScopeTest.php | 5 +++-- tests/Unit/CheckScopesTest.php | 5 +++-- 12 files changed, 35 insertions(+), 21 deletions(-) create mode 100644 src/Exceptions/AuthenticationException.php diff --git a/src/Exceptions/AuthenticationException.php b/src/Exceptions/AuthenticationException.php new file mode 100644 index 0000000..75ec03d --- /dev/null +++ b/src/Exceptions/AuthenticationException.php @@ -0,0 +1,9 @@ +expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $server = m::mock(AuthorizationServer::class); $response = m::mock(AuthorizationViewResponse::class); @@ -367,7 +368,7 @@ public function test_logout_and_prompt_login_if_request_has_prompt_equals_to_log public function test_user_should_be_authenticated() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $server = m::mock(AuthorizationServer::class); $response = m::mock(AuthorizationViewResponse::class); diff --git a/tests/Unit/CheckClientCredentialsForAnyScopeTest.php b/tests/Unit/CheckClientCredentialsForAnyScopeTest.php index 754d9a7..807bf93 100644 --- a/tests/Unit/CheckClientCredentialsForAnyScopeTest.php +++ b/tests/Unit/CheckClientCredentialsForAnyScopeTest.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Laravel\Passport\Client; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckClientCredentialsForAnyScope; use Laravel\Passport\Token; use Laravel\Passport\TokenRepository; @@ -85,7 +86,7 @@ public function test_request_is_passed_along_if_token_has_any_required_scope() public function test_exception_is_thrown_when_oauth_throws_exception() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $tokenRepository = m::mock(TokenRepository::class); $resourceServer = m::mock(ResourceServer::class); diff --git a/tests/Unit/CheckClientCredentialsTest.php b/tests/Unit/CheckClientCredentialsTest.php index 36e410d..0a30b19 100644 --- a/tests/Unit/CheckClientCredentialsTest.php +++ b/tests/Unit/CheckClientCredentialsTest.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Laravel\Passport\Client; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckClientCredentials; use Laravel\Passport\Token; use Laravel\Passport\TokenRepository; @@ -84,7 +85,7 @@ public function test_request_is_passed_along_if_token_and_scope_are_valid() public function test_exception_is_thrown_when_oauth_throws_exception() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $tokenRepository = m::mock(TokenRepository::class); $resourceServer = m::mock(ResourceServer::class); diff --git a/tests/Unit/CheckForAnyScopeTest.php b/tests/Unit/CheckForAnyScopeTest.php index cf9e04c..e567fee 100644 --- a/tests/Unit/CheckForAnyScopeTest.php +++ b/tests/Unit/CheckForAnyScopeTest.php @@ -2,6 +2,7 @@ namespace Laravel\Passport\Tests\Unit; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckForAnyScope as CheckScopes; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -47,7 +48,7 @@ public function test_exception_is_thrown_if_token_doesnt_have_scope() public function test_exception_is_thrown_if_no_authenticated_user() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); @@ -60,7 +61,7 @@ public function test_exception_is_thrown_if_no_authenticated_user() public function test_exception_is_thrown_if_no_token() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); diff --git a/tests/Unit/CheckScopesTest.php b/tests/Unit/CheckScopesTest.php index 3eb172b..21e8b40 100644 --- a/tests/Unit/CheckScopesTest.php +++ b/tests/Unit/CheckScopesTest.php @@ -2,6 +2,7 @@ namespace Laravel\Passport\Tests\Unit; +use Laravel\Passport\Exceptions\AuthenticationException; use Laravel\Passport\Http\Middleware\CheckScopes; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -46,7 +47,7 @@ public function test_exception_is_thrown_if_token_doesnt_have_scope() public function test_exception_is_thrown_if_no_authenticated_user() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); @@ -59,7 +60,7 @@ public function test_exception_is_thrown_if_no_authenticated_user() public function test_exception_is_thrown_if_no_token() { - $this->expectException('Illuminate\Auth\AuthenticationException'); + $this->expectException(AuthenticationException::class); $middleware = new CheckScopes; $request = m::mock(); From d95c09566541e5a7fb731f7f8ca00fa0619f5f7e Mon Sep 17 00:00:00 2001 From: driesvints Date: Mon, 20 Feb 2023 13:44:26 +0000 Subject: [PATCH 64/73] Update CHANGELOG --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c75eaa..f618e32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.8.1...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.8.2...11.x) + +## [v11.8.2](https://github.com/laravel/passport/compare/v11.8.1...v11.8.2) - 2023-02-20 + +- Re-apply "Added AuthenticationException to extend the behaviour of Laravel's default exception handler" by @driesvints in https://github.com/laravel/passport/commit/67c3e336af163f6eba5dbca8e5db46275ff0e433 ## [v11.8.1](https://github.com/laravel/passport/compare/v11.8.0...v11.8.1) - 2023-02-20 From 587aa1460fb8a4ac24d042b68513ef86b78d760a Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Tue, 21 Feb 2023 19:40:22 +0330 Subject: [PATCH 65/73] allow overriding the `AccessToken` class (#1638) --- src/Bridge/AccessTokenRepository.php | 3 ++- src/Passport.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Bridge/AccessTokenRepository.php b/src/Bridge/AccessTokenRepository.php index 0fe2be4..23572d7 100644 --- a/src/Bridge/AccessTokenRepository.php +++ b/src/Bridge/AccessTokenRepository.php @@ -5,6 +5,7 @@ use DateTime; use Illuminate\Contracts\Events\Dispatcher; use Laravel\Passport\Events\AccessTokenCreated; +use Laravel\Passport\Passport; use Laravel\Passport\TokenRepository; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; @@ -46,7 +47,7 @@ public function __construct(TokenRepository $tokenRepository, Dispatcher $events */ public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null) { - return new AccessToken($userIdentifier, $scopes, $clientEntity); + return new Passport::$accessTokenEntity($userIdentifier, $scopes, $clientEntity); } /** diff --git a/src/Passport.php b/src/Passport.php index 706a754..d1a6c0e 100644 --- a/src/Passport.php +++ b/src/Passport.php @@ -79,6 +79,13 @@ class Passport */ public static $keyPath; + /** + * The access token entity class name. + * + * @var string + */ + public static $accessTokenEntity = 'Laravel\Passport\Bridge\AccessToken'; + /** * The auth code model class name. * @@ -432,6 +439,17 @@ public static function keyPath($file) : storage_path($file); } + /** + * Set the access token entity class name. + * + * @param string $accessTokenEntity + * @return void + */ + public static function useAccessTokenEntity($accessTokenEntity) + { + static::$accessTokenEntity = $accessTokenEntity; + } + /** * Set the auth code model class name. * From 112e94561b1df90985493f8e0e65630bd70b8575 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Thu, 23 Feb 2023 08:21:11 +0000 Subject: [PATCH 66/73] Adds type checking (#1640) --- .gitattributes | 1 + .github/workflows/static-analysis.yml | 41 +++++++++++++++++++++++++++ composer.json | 1 + phpstan.neon.dist | 11 +++++++ src/Guards/TokenGuard.php | 2 +- 5 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/static-analysis.yml create mode 100644 phpstan.neon.dist diff --git a/.gitattributes b/.gitattributes index efd7a3a..6c56d0f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14,5 +14,6 @@ .gitignore export-ignore .styleci.yml export-ignore CHANGELOG.md export-ignore +phpstan.neon.dist export-ignore phpunit.xml.dist export-ignore UPGRADE.md diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..453d8a6 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,41 @@ +name: static analysis + +on: + push: + branches: + - master + - '*.x' + pull_request: + +permissions: + contents: read + +jobs: + tests: + runs-on: ubuntu-22.04 + + strategy: + fail-fast: true + + name: Static Analysis + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + tools: composer:v2 + coverage: none + + - name: Install dependencies + uses: nick-fields/retry@v2 + with: + timeout_minutes: 5 + max_attempts: 5 + command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress + + - name: Execute type checking + run: vendor/bin/phpstan diff --git a/composer.json b/composer.json index 364339a..d7b2f0f 100644 --- a/composer.json +++ b/composer.json @@ -35,6 +35,7 @@ "require-dev": { "mockery/mockery": "^1.0", "orchestra/testbench": "^7.0|^8.0", + "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.3" }, "autoload": { diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..649776a --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,11 @@ +parameters: + paths: + - config + - database + - routes + - src + + level: 0 + + ignoreErrors: + - "#Unsafe usage of new static\\(\\)#" diff --git a/src/Guards/TokenGuard.php b/src/Guards/TokenGuard.php index 6798ca3..fe067e8 100644 --- a/src/Guards/TokenGuard.php +++ b/src/Guards/TokenGuard.php @@ -214,7 +214,7 @@ protected function authenticateViaBearerToken($request) * Authenticate and get the incoming PSR-7 request via the Bearer token. * * @param \Illuminate\Http\Request $request - * @return \Psr\Http\Message\ServerRequestInterface + * @return \Psr\Http\Message\ServerRequestInterface|null */ protected function getPsrRequestViaBearerToken($request) { From fcfac3fe70a01d6ad23b33a9f562c3d4067b2713 Mon Sep 17 00:00:00 2001 From: Bram Date: Wed, 1 Mar 2023 08:32:45 +0000 Subject: [PATCH 67/73] Update ClientRepository.php (#1642) --- src/ClientRepository.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ClientRepository.php b/src/ClientRepository.php index 402deb0..2809b3a 100644 --- a/src/ClientRepository.php +++ b/src/ClientRepository.php @@ -158,7 +158,7 @@ public function create($userId, $name, $redirect, $provider = null, $personalAcc /** * Store a new personal access token client. * - * @param int $userId + * @param int|null $userId * @param string $name * @param string $redirect * @return \Laravel\Passport\Client @@ -175,7 +175,7 @@ public function createPersonalAccessClient($userId, $name, $redirect) /** * Store a new password grant client. * - * @param int $userId + * @param int|null $userId * @param string $name * @param string $redirect * @param string|null $provider From d60300185cfd066190b7842982cce314f779f9dd Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 1 Mar 2023 16:56:44 +0100 Subject: [PATCH 68/73] Fix tests --- tests/Feature/AccessTokenControllerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Feature/AccessTokenControllerTest.php b/tests/Feature/AccessTokenControllerTest.php index 54cb4ff..87d31b3 100644 --- a/tests/Feature/AccessTokenControllerTest.php +++ b/tests/Feature/AccessTokenControllerTest.php @@ -73,7 +73,7 @@ public function testGettingAccessTokenWithClientCredentialsGrant() $this->assertArrayHasKey('expires_in', $decodedResponse); $this->assertArrayHasKey('access_token', $decodedResponse); $this->assertSame('Bearer', $decodedResponse['token_type']); - $expiresInSeconds = 31536000; + $expiresInSeconds = 31622400; $this->assertEqualsWithDelta($expiresInSeconds, $decodedResponse['expires_in'], 5); $token = $this->app->make(PersonalAccessTokenFactory::class)->findAccessToken($decodedResponse); @@ -163,7 +163,7 @@ public function testGettingAccessTokenWithPasswordGrant() $this->assertArrayHasKey('access_token', $decodedResponse); $this->assertArrayHasKey('refresh_token', $decodedResponse); $this->assertSame('Bearer', $decodedResponse['token_type']); - $expiresInSeconds = 31536000; + $expiresInSeconds = 31622400; $this->assertEqualsWithDelta($expiresInSeconds, $decodedResponse['expires_in'], 5); $token = $this->app->make(PersonalAccessTokenFactory::class)->findAccessToken($decodedResponse); From 37ce6e6b6a2dab591978903795454cdfa80e9c2a Mon Sep 17 00:00:00 2001 From: driesvints Date: Thu, 2 Mar 2023 16:24:50 +0000 Subject: [PATCH 69/73] Update CHANGELOG --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f618e32..9328e6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Release Notes -## [Unreleased](https://github.com/laravel/passport/compare/v11.8.2...11.x) +## [Unreleased](https://github.com/laravel/passport/compare/v11.8.3...11.x) + +## [v11.8.3](https://github.com/laravel/passport/compare/v11.8.2...v11.8.3) - 2023-03-01 + +- Allow overriding the `AccessToken` class by @hafezdivandari in https://github.com/laravel/passport/pull/1638 +- Make `$userId` nullable in `ClientRepository->createPersonalAccessClient` by @bram-pkg in https://github.com/laravel/passport/pull/1642 ## [v11.8.2](https://github.com/laravel/passport/compare/v11.8.1...v11.8.2) - 2023-02-20 From 95a2258b396af786e5a8ae2a5e9ed3fa7c1a57ce Mon Sep 17 00:00:00 2001 From: Sergey Pashkevich Date: Fri, 17 Mar 2023 16:39:15 +0300 Subject: [PATCH 70/73] Update RefreshToken.php (#1645) --- src/RefreshToken.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/RefreshToken.php b/src/RefreshToken.php index 00e5a1c..df45c42 100644 --- a/src/RefreshToken.php +++ b/src/RefreshToken.php @@ -41,15 +41,7 @@ class RefreshToken extends Model */ protected $casts = [ 'revoked' => 'bool', - ]; - - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = [ - 'expires_at', + 'expires_at' => 'datetime', ]; /** From a1682d39b7730d318d1a6e3139836e06bda692d4 Mon Sep 17 00:00:00 2001 From: Sergey Pashkevich Date: Fri, 17 Mar 2023 16:39:26 +0300 Subject: [PATCH 71/73] Update AuthCode.php (#1644) --- src/AuthCode.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/AuthCode.php b/src/AuthCode.php index 09a79c8..5c045ba 100644 --- a/src/AuthCode.php +++ b/src/AuthCode.php @@ -34,15 +34,7 @@ class AuthCode extends Model */ protected $casts = [ 'revoked' => 'bool', - ]; - - /** - * The attributes that should be mutated to dates. - * - * @var array - */ - protected $dates = [ - 'expires_at', + 'expires_at' => 'datetime', ]; /** From b33fa25458c26465e6acf5ed6989ba48e2628eef Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Fri, 17 Mar 2023 13:39:43 +0000 Subject: [PATCH 72/73] Apply fixes from StyleCI --- tests/Unit/DenyAuthorizationControllerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/DenyAuthorizationControllerTest.php b/tests/Unit/DenyAuthorizationControllerTest.php index 366cc86..e2cd26f 100644 --- a/tests/Unit/DenyAuthorizationControllerTest.php +++ b/tests/Unit/DenyAuthorizationControllerTest.php @@ -36,7 +36,7 @@ public function test_authorization_can_be_denied() ->once() ->with('authRequest') ->andReturn($authRequest = m::mock( - AuthorizationRequest::class + AuthorizationRequest::class )); $authRequest->shouldReceive('setUser')->once(); From b6b68fad1d02e39c6c659705159487f643393cdd Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Sat, 18 Mar 2023 22:25:20 +0330 Subject: [PATCH 73/73] fix doc types (#1647) --- src/Http/Controllers/AuthorizationController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Http/Controllers/AuthorizationController.php b/src/Http/Controllers/AuthorizationController.php index 0c2bc6e..3894223 100644 --- a/src/Http/Controllers/AuthorizationController.php +++ b/src/Http/Controllers/AuthorizationController.php @@ -46,6 +46,7 @@ class AuthorizationController * * @param \League\OAuth2\Server\AuthorizationServer $server * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param \Laravel\Passport\Contracts\AuthorizationViewResponse $response * @return void */ public function __construct(AuthorizationServer $server, @@ -64,7 +65,7 @@ public function __construct(AuthorizationServer $server, * @param \Illuminate\Http\Request $request * @param \Laravel\Passport\ClientRepository $clients * @param \Laravel\Passport\TokenRepository $tokens - * @return \Laravel\Passport\Contracts\AuthorizationViewResponse + * @return \Illuminate\Http\Response|\Laravel\Passport\Contracts\AuthorizationViewResponse */ public function authorize(ServerRequestInterface $psrRequest, Request $request,