Uploaded From CV. Swandhana Server
This commit is contained in:
No files matched your search
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Taylor Otwell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
<p align="center"><img src="/art/logo.svg" alt="Logo Laravel Passport"></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/laravel/passport/actions"><img src="https://github.com/laravel/passport/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/passport"><img src="https://img.shields.io/packagist/dt/laravel/passport" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/passport"><img src="https://img.shields.io/packagist/v/laravel/passport" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/passport"><img src="https://img.shields.io/packagist/l/laravel/passport" alt="License"></a>
|
||||
</p>
|
||||
|
||||
## Introduction
|
||||
|
||||
Laravel Passport is an OAuth2 server and API authentication package that is simple and enjoyable to use.
|
||||
|
||||
## Official Documentation
|
||||
|
||||
Documentation for Passport can be found on the [Laravel website](https://laravel.com/docs/passport).
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for considering contributing to Passport! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
Please review [our security policy](https://github.com/laravel/passport/security/policy) on how to report security vulnerabilities.
|
||||
|
||||
## License
|
||||
|
||||
Laravel Passport is open-sourced software licensed under the [MIT license](LICENSE.md).
|
||||
Vendored
+154
@@ -0,0 +1,154 @@
|
||||
# Upgrade Guide
|
||||
|
||||
## 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
|
||||
|
||||
PHP 7.3 is now the minimum required version.
|
||||
|
||||
### Minimum Laravel Version
|
||||
|
||||
Laravel 8.0 is now the minimum required version.
|
||||
|
||||
### Old Static Personal Client Methods Removed
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1325
|
||||
|
||||
The personal client configuration methods have been removed from the `Passport` class since they are no longer necessary. You should remove any calls to these methods from your application's service providers.
|
||||
|
||||
## Upgrading To 9.0 From 8.x
|
||||
|
||||
### Support For Multiple Guards
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1220
|
||||
|
||||
Passport now has support for multiple guard user providers. Because of this change, you must add a `provider` column to the `oauth_clients` database table:
|
||||
|
||||
Schema::table('oauth_clients', function (Blueprint $table) {
|
||||
$table->string('provider')->after('secret')->nullable();
|
||||
});
|
||||
|
||||
If you have not previously published the Passport migrations, you should manually add the `provider` column to your database.
|
||||
|
||||
### Client Credentials Secret Hashing
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1145
|
||||
|
||||
Client secrets may now be stored using a Bcrypt hash. However, before enabling this functionality, please consider the following. First, there is no way to reverse the hashing process once you have migrated your existing tokens. Secondly, when hashing client secrets, you will only have one opportunity to display the plain-text value to the user before it is hashed and stored in the database.
|
||||
|
||||
#### Personal Access Clients
|
||||
|
||||
Before you continue, you should set your personal access client ID and unhashed secret in your `.env` file:
|
||||
|
||||
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=client-id-value
|
||||
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=unhashed-client-secret-value
|
||||
|
||||
Next, you should register these values by placing the following calls within the `boot` method of your `AppServiceProvider`:
|
||||
|
||||
Passport::personalAccessClientId(config('passport.personal_access_client.id'));
|
||||
Passport::personalAccessClientSecret(config('passport.personal_access_client.secret'));
|
||||
|
||||
> Make sure you follow the instructions above before hashing your secrets. Otherwise, irreversible data loss may occur.
|
||||
|
||||
#### Hashing Existing Secrets
|
||||
|
||||
You may enable client secret hashing by calling the `Passport::hashClientSecrets()` method within the `boot` method of your `AppServiceProvider`. For convenience, we've included a new Artisan command which you can run to hash all existing client secrets:
|
||||
|
||||
php artisan passport:hash
|
||||
|
||||
**Again, please be aware that running this command cannot be undone. For extra precaution, you may wish to create a backup of your database before running the command.**
|
||||
|
||||
### Client Credentials Middleware Changes
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1132
|
||||
|
||||
[After a lengthy debate](https://github.com/laravel/passport/issues/1125), it was decided to revert the change made [in a previous PR](https://github.com/laravel/passport/pull/1040) that introduced an exception when the client credentials middleware was used to authenticate first party clients.
|
||||
|
||||
### Switch From `getKey` To `getAuthIdentifier`
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1134
|
||||
|
||||
Internally, Passport will now use the `getAuthIdentifier` method to determine a model's primary key. This is consistent with the framework and Laravel's first party libraries.
|
||||
|
||||
### Remove Deprecated Functionality
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1235
|
||||
|
||||
The deprecated `revokeOtherTokens` and `pruneRevokedTokens` methods and the `revokeOtherTokens` and `pruneRevokedTokens` properties were removed from the `Passport` object.
|
||||
|
||||
|
||||
## Upgrading To 8.0 From 7.x
|
||||
|
||||
### Minimum & Upgraded Versions
|
||||
|
||||
Commit: https://github.com/laravel/passport/commit/97e3026790d953d7a67fe487e30775cd995e93df
|
||||
|
||||
The minimum Laravel version is now v6.0 and the minimum PHP version is now 7.2. The underlying `league/oauth2-server` has also been updated to v8.
|
||||
|
||||
### Public Clients
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1065
|
||||
|
||||
Passport now supports public clients and PCKE. To leverage this feature, you should update the the `secret` column of the `oauth_clients` table to be `nullable`:
|
||||
|
||||
Schema::table('oauth_clients', function (Blueprint $table) {
|
||||
$table->string('secret', 100)->nullable()->change();
|
||||
});
|
||||
|
||||
### Renderable Exceptions For OAuth Errors
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1066
|
||||
|
||||
OAuth exceptions can now be rendered. They will first be converted to Passport exceptions. If you are explicitly handling `League\OAuth2\Server\Exception\OAuthServerException` in your exception handler's report method you will now need to check for an instance of `Laravel\Passport\Exceptions\OAuthServerException` instead.
|
||||
|
||||
### Fixed Credential Checking
|
||||
|
||||
PR: https://github.com/laravel/passport/pull/1040
|
||||
|
||||
In the previous versions of Passport, you could pass tokens granted by a different client type to the `CheckClientCredential` and `CheckClientCredentialForAnyScope` middleware. This behavior has been corrected and an exception will be thrown if you attempt to pass a token generated by a different client type.
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "laravel/passport",
|
||||
"description": "Laravel Passport provides OAuth2 server support to Laravel.",
|
||||
"keywords": ["laravel", "passport", "oauth"],
|
||||
"license": "MIT",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/passport/issues",
|
||||
"source": "https://github.com/laravel/passport"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"ext-json": "*",
|
||||
"firebase/php-jwt": "^6.4",
|
||||
"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": "^4.3|^5.0",
|
||||
"league/oauth2-server": "^8.5.3",
|
||||
"nyholm/psr7": "^1.5",
|
||||
"phpseclib/phpseclib": "^2.0|^3.0",
|
||||
"symfony/psr-http-message-bridge": "^2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.0",
|
||||
"orchestra/testbench": "^7.31|^8.11",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Passport\\": "src/",
|
||||
"Laravel\\Passport\\Database\\Factories\\": "database/factories/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Laravel\\Passport\\Tests\\": "tests/",
|
||||
"Workbench\\App\\": "workbench/app/",
|
||||
"Workbench\\Database\\Factories\\": "workbench/database/factories/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "11.x-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Passport\\PassportServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": "@prepare",
|
||||
"prepare": "@php vendor/bin/testbench package:discover --ansi"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
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
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Passport uses encryption keys while generating secure access tokens for
|
||||
| your application. By default, the keys are stored as local files but
|
||||
| can be set via environment variables when that is more convenient.
|
||||
|
|
||||
*/
|
||||
|
||||
'private_key' => env('PASSPORT_PRIVATE_KEY'),
|
||||
|
||||
'public_key' => env('PASSPORT_PUBLIC_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Client UUIDs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, Passport uses auto-incrementing primary keys when assigning
|
||||
| IDs to clients. However, if Passport is installed using the provided
|
||||
| --uuids switch, this will be set to "true" and UUIDs will be used.
|
||||
|
|
||||
*/
|
||||
|
||||
'client_uuids' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Personal Access Client
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you enable client hashing, you should set the personal access client
|
||||
| ID and unhashed secret within your environment file. The values will
|
||||
| get used while issuing fresh personal access tokens to your users.
|
||||
|
|
||||
*/
|
||||
|
||||
'personal_access_client' => [
|
||||
'id' => env('PASSPORT_PERSONAL_ACCESS_CLIENT_ID'),
|
||||
'secret' => env('PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET'),
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Passport\Client;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\Laravel\Passport\Client>
|
||||
*/
|
||||
class ClientFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Client::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return $this->ensurePrimaryKeyIsSet([
|
||||
'user_id' => null,
|
||||
'name' => $this->faker->company(),
|
||||
'secret' => Str::random(40),
|
||||
'redirect' => $this->faker->url(),
|
||||
'personal_access_client' => false,
|
||||
'password_client' => false,
|
||||
'revoked' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the primary key is set on the model when using UUIDs.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function ensurePrimaryKeyIsSet(array $data)
|
||||
{
|
||||
if (Passport::clientUuids()) {
|
||||
$keyName = (new $this->model)->getKeyName();
|
||||
|
||||
$data[$keyName] = (string) Str::orderedUuid();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use as Password Client.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function asPasswordClient()
|
||||
{
|
||||
return $this->state([
|
||||
'personal_access_client' => false,
|
||||
'password_client' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use as Client Credentials.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function asClientCredentials()
|
||||
{
|
||||
return $this->state([
|
||||
'personal_access_client' => false,
|
||||
'password_client' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('oauth_auth_codes', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->unsignedBigInteger('user_id')->index();
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_auth_codes');
|
||||
}
|
||||
};
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('oauth_access_tokens', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->unsignedBigInteger('user_id')->nullable()->index();
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->string('name')->nullable();
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->timestamps();
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_access_tokens');
|
||||
}
|
||||
};
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('oauth_refresh_tokens', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->string('access_token_id', 100)->index();
|
||||
$table->boolean('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_refresh_tokens');
|
||||
}
|
||||
};
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('oauth_clients', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('user_id')->nullable()->index();
|
||||
$table->string('name');
|
||||
$table->string('secret', 100)->nullable();
|
||||
$table->string('provider')->nullable();
|
||||
$table->text('redirect');
|
||||
$table->boolean('personal_access_client');
|
||||
$table->boolean('password_client');
|
||||
$table->boolean('revoked');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_clients');
|
||||
}
|
||||
};
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('oauth_personal_access_clients', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_personal_access_clients');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>{{ config('app.name') }} - Authorization</title>
|
||||
|
||||
<!-- Styles -->
|
||||
<link href="{{ asset('/css/app.css') }}" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
.passport-authorize .container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.passport-authorize .scopes {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.passport-authorize .buttons {
|
||||
margin-top: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.passport-authorize .btn {
|
||||
width: 125px;
|
||||
}
|
||||
|
||||
.passport-authorize .btn-approve {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.passport-authorize form {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="passport-authorize">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card card-default">
|
||||
<div class="card-header">
|
||||
Authorization Request
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Introduction -->
|
||||
<p><strong>{{ $client->name }}</strong> is requesting permission to access your account.</p>
|
||||
|
||||
<!-- Scope List -->
|
||||
@if (count($scopes) > 0)
|
||||
<div class="scopes">
|
||||
<p><strong>This application will be able to:</strong></p>
|
||||
|
||||
<ul>
|
||||
@foreach ($scopes as $scope)
|
||||
<li>{{ $scope->description }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="buttons">
|
||||
<!-- Authorize Button -->
|
||||
<form method="post" action="{{ route('passport.authorizations.approve') }}">
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="state" value="{{ $request->state }}">
|
||||
<input type="hidden" name="client_id" value="{{ $client->getKey() }}">
|
||||
<input type="hidden" name="auth_token" value="{{ $authToken }}">
|
||||
<button type="submit" class="btn btn-success btn-approve">Authorize</button>
|
||||
</form>
|
||||
|
||||
<!-- Cancel Button -->
|
||||
<form method="post" action="{{ route('passport.authorizations.deny') }}">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
|
||||
<input type="hidden" name="state" value="{{ $request->state }}">
|
||||
<input type="hidden" name="client_id" value="{{ $client->getKey() }}">
|
||||
<input type="hidden" name="auth_token" value="{{ $authToken }}">
|
||||
<button class="btn btn-danger">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::post('/token', [
|
||||
'uses' => 'AccessTokenController@issueToken',
|
||||
'as' => 'token',
|
||||
'middleware' => 'throttle',
|
||||
]);
|
||||
|
||||
Route::get('/authorize', [
|
||||
'uses' => 'AuthorizationController@authorize',
|
||||
'as' => 'authorizations.authorize',
|
||||
'middleware' => 'web',
|
||||
]);
|
||||
|
||||
$guard = config('passport.guard', null);
|
||||
|
||||
Route::middleware(['web', $guard ? 'auth:'.$guard : 'auth'])->group(function () {
|
||||
Route::post('/token/refresh', [
|
||||
'uses' => 'TransientTokenController@refresh',
|
||||
'as' => 'token.refresh',
|
||||
]);
|
||||
|
||||
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',
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Firebase\JWT\JWT;
|
||||
use Illuminate\Contracts\Config\Repository as Config;
|
||||
use Illuminate\Contracts\Encryption\Encrypter;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
|
||||
class ApiTokenCookieFactory
|
||||
{
|
||||
/**
|
||||
* The configuration repository implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The encrypter implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Encryption\Encrypter
|
||||
*/
|
||||
protected $encrypter;
|
||||
|
||||
/**
|
||||
* Create an API token cookie factory instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Config $config, Encrypter $encrypter)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->encrypter = $encrypter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new API token cookie.
|
||||
*
|
||||
* @param mixed $userId
|
||||
* @param string $csrfToken
|
||||
* @return \Symfony\Component\HttpFoundation\Cookie
|
||||
*/
|
||||
public function make($userId, $csrfToken)
|
||||
{
|
||||
$config = $this->config->get('session');
|
||||
|
||||
$expiration = Carbon::now()->addMinutes($config['lifetime']);
|
||||
|
||||
return new Cookie(
|
||||
Passport::cookie(),
|
||||
$this->createToken($userId, $csrfToken, $expiration),
|
||||
$expiration,
|
||||
$config['path'],
|
||||
$config['domain'],
|
||||
$config['secure'],
|
||||
true,
|
||||
false,
|
||||
$config['same_site'] ?? null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new JWT token for the given user ID and CSRF token.
|
||||
*
|
||||
* @param mixed $userId
|
||||
* @param string $csrfToken
|
||||
* @param \Carbon\Carbon $expiration
|
||||
* @return string
|
||||
*/
|
||||
protected function createToken($userId, $csrfToken, Carbon $expiration)
|
||||
{
|
||||
return JWT::encode([
|
||||
'sub' => $userId,
|
||||
'csrf' => $csrfToken,
|
||||
'expiry' => $expiration->getTimestamp(),
|
||||
], Passport::tokenEncryptionKey($this->encrypter), 'HS256');
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AuthCode extends Model
|
||||
{
|
||||
/**
|
||||
* The database table used by the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'oauth_auth_codes';
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
/**
|
||||
* The guarded attributes on the model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'revoked' => 'bool',
|
||||
'expires_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The "type" of the primary key ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $keyType = 'string';
|
||||
|
||||
/**
|
||||
* Get the client that owns the authentication code.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function client()
|
||||
{
|
||||
return $this->belongsTo(Passport::clientModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||
|
||||
class AccessToken implements AccessTokenEntityInterface
|
||||
{
|
||||
use AccessTokenTrait, EntityTrait, TokenEntityTrait;
|
||||
|
||||
/**
|
||||
* Create a new token instance.
|
||||
*
|
||||
* @param string $userIdentifier
|
||||
* @param array $scopes
|
||||
* @param \League\OAuth2\Server\Entities\ClientEntityInterface $client
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($userIdentifier, array $scopes, ClientEntityInterface $client)
|
||||
{
|
||||
$this->setUserIdentifier($userIdentifier);
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$this->addScope($scope);
|
||||
}
|
||||
|
||||
$this->setClient($client);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
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;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
|
||||
class AccessTokenRepository implements AccessTokenRepositoryInterface
|
||||
{
|
||||
use FormatsScopesForStorage;
|
||||
|
||||
/**
|
||||
* The token repository instance.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokenRepository;
|
||||
|
||||
/**
|
||||
* The event dispatcher instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Events\Dispatcher
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @param \Laravel\Passport\TokenRepository $tokenRepository
|
||||
* @param \Illuminate\Contracts\Events\Dispatcher $events
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(TokenRepository $tokenRepository, Dispatcher $events)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->tokenRepository = $tokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
|
||||
{
|
||||
return new Passport::$accessTokenEntity($userIdentifier, $scopes, $clientEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
|
||||
{
|
||||
$this->tokenRepository->create([
|
||||
'id' => $accessTokenEntity->getIdentifier(),
|
||||
'user_id' => $accessTokenEntity->getUserIdentifier(),
|
||||
'client_id' => $accessTokenEntity->getClient()->getIdentifier(),
|
||||
'scopes' => $this->scopesToArray($accessTokenEntity->getScopes()),
|
||||
'revoked' => false,
|
||||
'created_at' => new DateTime,
|
||||
'updated_at' => new DateTime,
|
||||
'expires_at' => $accessTokenEntity->getExpiryDateTime(),
|
||||
]);
|
||||
|
||||
$this->events->dispatch(new AccessTokenCreated(
|
||||
$accessTokenEntity->getIdentifier(),
|
||||
$accessTokenEntity->getUserIdentifier(),
|
||||
$accessTokenEntity->getClient()->getIdentifier()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function revokeAccessToken($tokenId)
|
||||
{
|
||||
$this->tokenRepository->revokeAccessToken($tokenId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAccessTokenRevoked($tokenId)
|
||||
{
|
||||
return $this->tokenRepository->isAccessTokenRevoked($tokenId);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\AuthCodeTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||
|
||||
class AuthCode implements AuthCodeEntityInterface
|
||||
{
|
||||
use AuthCodeTrait, EntityTrait, TokenEntityTrait;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use Laravel\Passport\Passport;
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
|
||||
class AuthCodeRepository implements AuthCodeRepositoryInterface
|
||||
{
|
||||
use FormatsScopesForStorage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewAuthCode()
|
||||
{
|
||||
return new AuthCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
|
||||
{
|
||||
$attributes = [
|
||||
'id' => $authCodeEntity->getIdentifier(),
|
||||
'user_id' => $authCodeEntity->getUserIdentifier(),
|
||||
'client_id' => $authCodeEntity->getClient()->getIdentifier(),
|
||||
'scopes' => $this->formatScopesForStorage($authCodeEntity->getScopes()),
|
||||
'revoked' => false,
|
||||
'expires_at' => $authCodeEntity->getExpiryDateTime(),
|
||||
];
|
||||
|
||||
Passport::authCode()->forceFill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function revokeAuthCode($codeId)
|
||||
{
|
||||
Passport::authCode()->where('id', $codeId)->update(['revoked' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAuthCodeRevoked($codeId)
|
||||
{
|
||||
return Passport::authCode()->where('id', $codeId)->where('revoked', 1)->exists();
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\ClientTrait;
|
||||
|
||||
class Client implements ClientEntityInterface
|
||||
{
|
||||
use ClientTrait;
|
||||
|
||||
/**
|
||||
* The client identifier.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* The client's provider.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $provider;
|
||||
|
||||
/**
|
||||
* Create a new client instance.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @param string $name
|
||||
* @param string $redirectUri
|
||||
* @param bool $isConfidential
|
||||
* @param string|null $provider
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($identifier, $name, $redirectUri, $isConfidential = false, $provider = null)
|
||||
{
|
||||
$this->setIdentifier((string) $identifier);
|
||||
|
||||
$this->name = $name;
|
||||
$this->isConfidential = $isConfidential;
|
||||
$this->redirectUri = explode(',', $redirectUri);
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return (string) $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client's identifier.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @return void
|
||||
*/
|
||||
public function setIdentifier($identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use Laravel\Passport\ClientRepository as ClientModelRepository;
|
||||
use Laravel\Passport\Passport;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
|
||||
class ClientRepository implements ClientRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* The client model repository.
|
||||
*
|
||||
* @var \Laravel\Passport\ClientRepository
|
||||
*/
|
||||
protected $clients;
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ClientModelRepository $clients)
|
||||
{
|
||||
$this->clients = $clients;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier)
|
||||
{
|
||||
$record = $this->clients->findActive($clientIdentifier);
|
||||
|
||||
if (! $record) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new Client(
|
||||
$clientIdentifier,
|
||||
$record->name,
|
||||
$record->redirect,
|
||||
$record->confidential(),
|
||||
$record->provider
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateClient($clientIdentifier, $clientSecret, $grantType)
|
||||
{
|
||||
// First, we will verify that the client exists and is authorized to create personal
|
||||
// access tokens. Generally personal access tokens are only generated by the user
|
||||
// from the main interface. We'll only let certain clients generate the tokens.
|
||||
$record = $this->clients->findActive($clientIdentifier);
|
||||
|
||||
if (! $record || ! $this->handlesGrant($record, $grantType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! $record->confidential() || $this->verifySecret((string) $clientSecret, $record->secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given client can handle the given grant type.
|
||||
*
|
||||
* @param \Laravel\Passport\Client $record
|
||||
* @param string $grantType
|
||||
* @return bool
|
||||
*/
|
||||
protected function handlesGrant($record, $grantType)
|
||||
{
|
||||
if (! $record->hasGrantType($grantType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($grantType) {
|
||||
case 'authorization_code':
|
||||
return ! $record->firstParty();
|
||||
case 'personal_access':
|
||||
return $record->personal_access_client && $record->confidential();
|
||||
case 'password':
|
||||
return $record->password_client;
|
||||
case 'client_credentials':
|
||||
return $record->confidential();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the client secret is valid.
|
||||
*
|
||||
* @param string $clientSecret
|
||||
* @param string $storedHash
|
||||
* @return bool
|
||||
*/
|
||||
protected function verifySecret($clientSecret, $storedHash)
|
||||
{
|
||||
return Passport::$hashesClientSecrets
|
||||
? password_verify($clientSecret, $storedHash)
|
||||
: hash_equals($storedHash, $clientSecret);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
trait FormatsScopesForStorage
|
||||
{
|
||||
/**
|
||||
* Format the given scopes for storage.
|
||||
*
|
||||
* @param array $scopes
|
||||
* @return string
|
||||
*/
|
||||
public function formatScopesForStorage(array $scopes)
|
||||
{
|
||||
return json_encode($this->scopesToArray($scopes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of scope identifiers for storage.
|
||||
*
|
||||
* @param array $scopes
|
||||
* @return array
|
||||
*/
|
||||
public function scopesToArray(array $scopes)
|
||||
{
|
||||
return array_map(function ($scope) {
|
||||
return $scope->getIdentifier();
|
||||
}, $scopes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\Grant\AbstractGrant;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class PersonalAccessGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
|
||||
$userIdentifier = $this->getRequestParameter('user_id', $request);
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes(
|
||||
$scopes,
|
||||
$this->getIdentifier(),
|
||||
$client,
|
||||
$userIdentifier
|
||||
);
|
||||
|
||||
// Issue and persist access token
|
||||
$accessToken = $this->issueAccessToken(
|
||||
$accessTokenTTL,
|
||||
$client,
|
||||
$userIdentifier,
|
||||
$scopes
|
||||
);
|
||||
|
||||
// Inject access token into response type
|
||||
$responseType->setAccessToken($accessToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'personal_access';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
|
||||
|
||||
class RefreshToken implements RefreshTokenEntityInterface
|
||||
{
|
||||
use EntityTrait, RefreshTokenTrait;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Laravel\Passport\Events\RefreshTokenCreated;
|
||||
use Laravel\Passport\RefreshTokenRepository as PassportRefreshTokenRepository;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
|
||||
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* The refresh token repository instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Connection
|
||||
*/
|
||||
protected $refreshTokenRepository;
|
||||
|
||||
/**
|
||||
* The event dispatcher instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Events\Dispatcher
|
||||
*/
|
||||
protected $events;
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @param \Laravel\Passport\RefreshTokenRepository $refreshTokenRepository
|
||||
* @param \Illuminate\Contracts\Events\Dispatcher $events
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(PassportRefreshTokenRepository $refreshTokenRepository, Dispatcher $events)
|
||||
{
|
||||
$this->events = $events;
|
||||
$this->refreshTokenRepository = $refreshTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNewRefreshToken()
|
||||
{
|
||||
return new RefreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity)
|
||||
{
|
||||
$this->refreshTokenRepository->create([
|
||||
'id' => $id = $refreshTokenEntity->getIdentifier(),
|
||||
'access_token_id' => $accessTokenId = $refreshTokenEntity->getAccessToken()->getIdentifier(),
|
||||
'revoked' => false,
|
||||
'expires_at' => $refreshTokenEntity->getExpiryDateTime(),
|
||||
]);
|
||||
|
||||
$this->events->dispatch(new RefreshTokenCreated($id, $accessTokenId));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function revokeRefreshToken($tokenId)
|
||||
{
|
||||
$this->refreshTokenRepository->revokeRefreshToken($tokenId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isRefreshTokenRevoked($tokenId)
|
||||
{
|
||||
return $this->refreshTokenRepository->isRefreshTokenRevoked($tokenId);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use League\OAuth2\Server\Entities\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
|
||||
class Scope implements ScopeEntityInterface
|
||||
{
|
||||
use EntityTrait;
|
||||
|
||||
/**
|
||||
* Create a new scope instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->setIdentifier($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data that should be serialized to JSON.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getIdentifier();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use Laravel\Passport\ClientRepository;
|
||||
use Laravel\Passport\Passport;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
|
||||
class ScopeRepository implements ScopeRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* The client repository.
|
||||
*
|
||||
* @var \Laravel\Passport\ClientRepository|null
|
||||
*/
|
||||
protected ?ClientRepository $clients;
|
||||
|
||||
/**
|
||||
* Create a new scope repository.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository|null $clients
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(?ClientRepository $clients = null)
|
||||
{
|
||||
$this->clients = $clients;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScopeEntityByIdentifier($identifier)
|
||||
{
|
||||
if (Passport::hasScope($identifier)) {
|
||||
return new Scope($identifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function finalizeScopes(
|
||||
array $scopes, $grantType,
|
||||
ClientEntityInterface $clientEntity, $userIdentifier = null)
|
||||
{
|
||||
if (! in_array($grantType, ['password', 'personal_access', 'client_credentials'])) {
|
||||
$scopes = collect($scopes)->reject(function ($scope) {
|
||||
return trim($scope->getIdentifier()) === '*';
|
||||
})->values()->all();
|
||||
}
|
||||
|
||||
$client = $this->clients?->findActive($clientEntity->getIdentifier());
|
||||
|
||||
return collect($scopes)->filter(function ($scope) {
|
||||
return Passport::hasScope($scope->getIdentifier());
|
||||
})->when($client, function ($scopes, $client) {
|
||||
return $scopes->filter(fn ($scope) => $client->hasScope($scope->getIdentifier()));
|
||||
})->values()->all();
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\UserEntityInterface;
|
||||
|
||||
class User implements UserEntityInterface
|
||||
{
|
||||
use EntityTrait;
|
||||
|
||||
/**
|
||||
* Create a new user instance.
|
||||
*
|
||||
* @param string|int $identifier
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($identifier)
|
||||
{
|
||||
$this->setIdentifier($identifier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Bridge;
|
||||
|
||||
use Illuminate\Contracts\Hashing\Hasher;
|
||||
use League\OAuth2\Server\Entities\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class UserRepository implements UserRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* The hasher implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Hashing\Hasher
|
||||
*/
|
||||
protected $hasher;
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Hashing\Hasher $hasher
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Hasher $hasher)
|
||||
{
|
||||
$this->hasher = $hasher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity)
|
||||
{
|
||||
$provider = $clientEntity->provider ?: config('auth.guards.api.provider');
|
||||
|
||||
if (is_null($model = config('auth.providers.'.$provider.'.model'))) {
|
||||
throw new RuntimeException('Unable to determine authentication model from configuration.');
|
||||
}
|
||||
|
||||
if (method_exists($model, 'findAndValidateForPassport')) {
|
||||
$user = (new $model)->findAndValidateForPassport($username, $password);
|
||||
|
||||
if (! $user) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new User($user->getAuthIdentifier());
|
||||
}
|
||||
|
||||
if (method_exists($model, 'findForPassport')) {
|
||||
$user = (new $model)->findForPassport($username);
|
||||
} else {
|
||||
$user = (new $model)->where('email', $username)->first();
|
||||
}
|
||||
|
||||
if (! $user) {
|
||||
return;
|
||||
} elseif (method_exists($user, 'validateForPassportPasswordGrant')) {
|
||||
if (! $user->validateForPassportPasswordGrant($password)) {
|
||||
return;
|
||||
}
|
||||
} elseif (! $this->hasher->check($password, $user->getAuthPassword())) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new User($user->getAuthIdentifier());
|
||||
}
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Passport\Database\Factories\ClientFactory;
|
||||
|
||||
class Client extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use ResolvesInheritedScopes;
|
||||
|
||||
/**
|
||||
* The database table used by the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'oauth_clients';
|
||||
|
||||
/**
|
||||
* The guarded attributes on the model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes excluded from the model's JSON form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hidden = [
|
||||
'secret',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'grant_types' => 'array',
|
||||
'scopes' => 'array',
|
||||
'personal_access_client' => 'bool',
|
||||
'password_client' => 'bool',
|
||||
'revoked' => 'bool',
|
||||
];
|
||||
|
||||
/**
|
||||
* The temporary plain-text client secret.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $plainSecret;
|
||||
|
||||
/**
|
||||
* Bootstrap the model and its traits.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($model) {
|
||||
if (Passport::clientUuids()) {
|
||||
$model->{$model->getKeyName()} = $model->{$model->getKeyName()} ?: (string) Str::orderedUuid();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that the client belongs to.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
$provider = $this->provider ?: config('auth.guards.api.provider');
|
||||
|
||||
return $this->belongsTo(
|
||||
config("auth.providers.{$provider}.model")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the authentication codes for the client.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function authCodes()
|
||||
{
|
||||
return $this->hasMany(Passport::authCodeModel(), 'client_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the tokens that belong to the client.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function tokens()
|
||||
{
|
||||
return $this->hasMany(Passport::tokenModel(), 'client_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* The temporary non-hashed client secret.
|
||||
*
|
||||
* This is only available once during the request that created the client.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPlainSecretAttribute()
|
||||
{
|
||||
return $this->plainSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the secret attribute.
|
||||
*
|
||||
* @param string|null $value
|
||||
* @return void
|
||||
*/
|
||||
public function setSecretAttribute($value)
|
||||
{
|
||||
$this->plainSecret = $value;
|
||||
|
||||
if (is_null($value) || ! Passport::$hashesClientSecrets) {
|
||||
$this->attributes['secret'] = $value;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->attributes['secret'] = password_hash($value, PASSWORD_BCRYPT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the client is a "first party" client.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function firstParty()
|
||||
{
|
||||
return $this->personal_access_client || $this->password_client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the client should skip the authorization prompt.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function skipsAuthorization()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the client has the given grant type.
|
||||
*
|
||||
* @param string $grantType
|
||||
* @return bool
|
||||
*/
|
||||
public function hasGrantType($grantType)
|
||||
{
|
||||
if (! isset($this->attributes['grant_types']) || ! is_array($this->grant_types)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return in_array($grantType, $this->grant_types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the client has the given scope.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return bool
|
||||
*/
|
||||
public function hasScope($scope)
|
||||
{
|
||||
if (! isset($this->attributes['scopes']) || ! is_array($this->scopes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$scopes = Passport::$withInheritedScopes
|
||||
? $this->resolveInheritedScopes($scope)
|
||||
: [$scope];
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
if (in_array($scope, $this->scopes)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the client is a confidential client.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function confidential()
|
||||
{
|
||||
return ! empty($this->secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the auto-incrementing key type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyType()
|
||||
{
|
||||
return Passport::clientUuids() ? 'string' : $this->keyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value indicating whether the IDs are incrementing.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getIncrementing()
|
||||
{
|
||||
return Passport::clientUuids() ? false : $this->incrementing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
public static function newFactory()
|
||||
{
|
||||
return ClientFactory::new();
|
||||
}
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use RuntimeException;
|
||||
|
||||
class ClientRepository
|
||||
{
|
||||
/**
|
||||
* The personal access client ID.
|
||||
*
|
||||
* @var int|string|null
|
||||
*/
|
||||
protected $personalAccessClientId;
|
||||
|
||||
/**
|
||||
* The personal access client secret.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $personalAccessClientSecret;
|
||||
|
||||
/**
|
||||
* Create a new client repository.
|
||||
*
|
||||
* @param int|string|null $personalAccessClientId
|
||||
* @param string|null $personalAccessClientSecret
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($personalAccessClientId = null, $personalAccessClientSecret = null)
|
||||
{
|
||||
$this->personalAccessClientId = $personalAccessClientId;
|
||||
$this->personalAccessClientSecret = $personalAccessClientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a client by the given ID.
|
||||
*
|
||||
* @param int|string $id
|
||||
* @return \Laravel\Passport\Client|null
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
$client = Passport::client();
|
||||
|
||||
return $client->where($client->getKeyName(), $id)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an active client by the given ID.
|
||||
*
|
||||
* @param int|string $id
|
||||
* @return \Laravel\Passport\Client|null
|
||||
*/
|
||||
public function findActive($id)
|
||||
{
|
||||
$client = $this->find($id);
|
||||
|
||||
return $client && ! $client->revoked ? $client : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a client instance for the given ID and user ID.
|
||||
*
|
||||
* @param int|string $clientId
|
||||
* @param mixed $userId
|
||||
* @return \Laravel\Passport\Client|null
|
||||
*/
|
||||
public function findForUser($clientId, $userId)
|
||||
{
|
||||
$client = Passport::client();
|
||||
|
||||
return $client
|
||||
->where($client->getKeyName(), $clientId)
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client instances for the given user ID.
|
||||
*
|
||||
* @param mixed $userId
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function forUser($userId)
|
||||
{
|
||||
return Passport::client()
|
||||
->where('user_id', $userId)
|
||||
->orderBy('name', 'asc')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the active client instances for the given user ID.
|
||||
*
|
||||
* @param mixed $userId
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function activeForUser($userId)
|
||||
{
|
||||
return $this->forUser($userId)->reject(function ($client) {
|
||||
return $client->revoked;
|
||||
})->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the personal access token client for the application.
|
||||
*
|
||||
* @return \Laravel\Passport\Client
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function personalAccessClient()
|
||||
{
|
||||
if ($this->personalAccessClientId) {
|
||||
return $this->find($this->personalAccessClientId);
|
||||
}
|
||||
|
||||
$client = Passport::personalAccessClient();
|
||||
|
||||
if (! $client->exists()) {
|
||||
throw new RuntimeException('Personal access client not found. Please create one.');
|
||||
}
|
||||
|
||||
return $client->orderBy($client->getKeyName(), 'desc')->first()->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new client.
|
||||
*
|
||||
* @param int|null $userId
|
||||
* @param string $name
|
||||
* @param string $redirect
|
||||
* @param string|null $provider
|
||||
* @param bool $personalAccess
|
||||
* @param bool $password
|
||||
* @param bool $confidential
|
||||
* @return \Laravel\Passport\Client
|
||||
*/
|
||||
public function create($userId, $name, $redirect, $provider = null, $personalAccess = false, $password = false, $confidential = true)
|
||||
{
|
||||
$client = Passport::client()->forceFill([
|
||||
'user_id' => $userId,
|
||||
'name' => $name,
|
||||
'secret' => ($confidential || $personalAccess) ? Str::random(40) : null,
|
||||
'provider' => $provider,
|
||||
'redirect' => $redirect,
|
||||
'personal_access_client' => $personalAccess,
|
||||
'password_client' => $password,
|
||||
'revoked' => false,
|
||||
]);
|
||||
|
||||
$client->save();
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new personal access token client.
|
||||
*
|
||||
* @param int|null $userId
|
||||
* @param string $name
|
||||
* @param string $redirect
|
||||
* @return \Laravel\Passport\Client
|
||||
*/
|
||||
public function createPersonalAccessClient($userId, $name, $redirect)
|
||||
{
|
||||
return tap($this->create($userId, $name, $redirect, null, true), function ($client) {
|
||||
$accessClient = Passport::personalAccessClient();
|
||||
$accessClient->client_id = $client->getKey();
|
||||
$accessClient->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new password grant client.
|
||||
*
|
||||
* @param int|null $userId
|
||||
* @param string $name
|
||||
* @param string $redirect
|
||||
* @param string|null $provider
|
||||
* @return \Laravel\Passport\Client
|
||||
*/
|
||||
public function createPasswordGrantClient($userId, $name, $redirect, $provider = null)
|
||||
{
|
||||
return $this->create($userId, $name, $redirect, $provider, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given client.
|
||||
*
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @param string $name
|
||||
* @param string $redirect
|
||||
* @return \Laravel\Passport\Client
|
||||
*/
|
||||
public function update(Client $client, $name, $redirect)
|
||||
{
|
||||
$client->forceFill([
|
||||
'name' => $name, 'redirect' => $redirect,
|
||||
])->save();
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate the client secret.
|
||||
*
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @return \Laravel\Passport\Client
|
||||
*/
|
||||
public function regenerateSecret(Client $client)
|
||||
{
|
||||
$client->forceFill([
|
||||
'secret' => Str::random(40),
|
||||
])->save();
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given client is revoked.
|
||||
*
|
||||
* @param int|string $id
|
||||
* @return bool
|
||||
*/
|
||||
public function revoked($id)
|
||||
{
|
||||
$client = $this->find($id);
|
||||
|
||||
return is_null($client) || $client->revoked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given client.
|
||||
*
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Client $client)
|
||||
{
|
||||
$client->tokens()->update(['revoked' => true]);
|
||||
|
||||
$client->forceFill(['revoked' => true])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the personal access client id.
|
||||
*
|
||||
* @return int|string|null
|
||||
*/
|
||||
public function getPersonalAccessClientId()
|
||||
{
|
||||
return $this->personalAccessClientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the personal access client secret.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPersonalAccessClientSecret()
|
||||
{
|
||||
return $this->personalAccessClientSecret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Laravel\Passport\Client;
|
||||
use Laravel\Passport\ClientRepository;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
class ClientCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'passport:client
|
||||
{--personal : Create a personal access token client}
|
||||
{--password : Create a password grant client}
|
||||
{--client : Create a client credentials grant client}
|
||||
{--name= : The name of the client}
|
||||
{--provider= : The name of the user provider}
|
||||
{--redirect_uri= : The URI to redirect to after authorization }
|
||||
{--user_id= : The user ID the client should be assigned to }
|
||||
{--public : Create a public client (Auth code grant type only) }';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create a client for issuing access tokens';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @return void
|
||||
*/
|
||||
public function handle(ClientRepository $clients)
|
||||
{
|
||||
if ($this->option('personal')) {
|
||||
$this->createPersonalClient($clients);
|
||||
} elseif ($this->option('password')) {
|
||||
$this->createPasswordClient($clients);
|
||||
} elseif ($this->option('client')) {
|
||||
$this->createClientCredentialsClient($clients);
|
||||
} else {
|
||||
$this->createAuthCodeClient($clients);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new personal access client.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @return void
|
||||
*/
|
||||
protected function createPersonalClient(ClientRepository $clients)
|
||||
{
|
||||
$name = $this->option('name') ?: $this->ask(
|
||||
'What should we name the personal access client?',
|
||||
config('app.name').' Personal Access Client'
|
||||
);
|
||||
|
||||
$client = $clients->createPersonalAccessClient(
|
||||
null, $name, 'http://localhost'
|
||||
);
|
||||
|
||||
$this->info('Personal access client created successfully.');
|
||||
|
||||
$this->outputClientDetails($client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new password grant client.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @return void
|
||||
*/
|
||||
protected function createPasswordClient(ClientRepository $clients)
|
||||
{
|
||||
$name = $this->option('name') ?: $this->ask(
|
||||
'What should we name the password grant client?',
|
||||
config('app.name').' Password Grant Client'
|
||||
);
|
||||
|
||||
$providers = array_keys(config('auth.providers'));
|
||||
|
||||
$provider = $this->option('provider') ?: $this->choice(
|
||||
'Which user provider should this client use to retrieve users?',
|
||||
$providers,
|
||||
in_array('users', $providers) ? 'users' : null
|
||||
);
|
||||
|
||||
$client = $clients->createPasswordGrantClient(
|
||||
null, $name, 'http://localhost', $provider
|
||||
);
|
||||
|
||||
$this->info('Password grant client created successfully.');
|
||||
|
||||
$this->outputClientDetails($client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a client credentials grant client.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @return void
|
||||
*/
|
||||
protected function createClientCredentialsClient(ClientRepository $clients)
|
||||
{
|
||||
$name = $this->option('name') ?: $this->ask(
|
||||
'What should we name the client?',
|
||||
config('app.name').' ClientCredentials Grant Client'
|
||||
);
|
||||
|
||||
$client = $clients->create(
|
||||
null, $name, ''
|
||||
);
|
||||
|
||||
$this->info('New client created successfully.');
|
||||
|
||||
$this->outputClientDetails($client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a authorization code client.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @return void
|
||||
*/
|
||||
protected function createAuthCodeClient(ClientRepository $clients)
|
||||
{
|
||||
$userId = $this->option('user_id') ?: $this->ask(
|
||||
'Which user ID should the client be assigned to? (Optional)'
|
||||
);
|
||||
|
||||
$name = $this->option('name') ?: $this->ask(
|
||||
'What should we name the client?'
|
||||
);
|
||||
|
||||
$redirect = $this->option('redirect_uri') ?: $this->ask(
|
||||
'Where should we redirect the request after authorization?',
|
||||
url('/auth/callback')
|
||||
);
|
||||
|
||||
$client = $clients->create(
|
||||
$userId, $name, $redirect, null, false, false, ! $this->option('public')
|
||||
);
|
||||
|
||||
$this->info('New client created successfully.');
|
||||
|
||||
$this->outputClientDetails($client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the client's ID and secret key.
|
||||
*
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @return void
|
||||
*/
|
||||
protected function outputClientDetails(Client $client)
|
||||
{
|
||||
if (Passport::$hashesClientSecrets) {
|
||||
$this->line('<comment>Here is your new client secret. This is the only time it will be shown so don\'t lose it!</comment>');
|
||||
$this->line('');
|
||||
}
|
||||
|
||||
$this->line('<comment>Client ID:</comment> '.$client->getKey());
|
||||
$this->line('<comment>Client secret:</comment> '.$client->plainSecret);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
class HashCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'passport:hash {--force : Force the operation to run without confirmation prompt}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Hash all of the existing secrets in the clients table';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (! Passport::$hashesClientSecrets) {
|
||||
$this->warn('Please enable client hashing yet in your AppServiceProvider before continuing.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->option('force') || $this->confirm('Are you sure you want to hash all client secrets? This cannot be undone.')) {
|
||||
$model = Passport::clientModel();
|
||||
|
||||
foreach ((new $model)->whereNotNull('secret')->cursor() as $client) {
|
||||
if (password_get_info($client->secret)['algo'] === PASSWORD_BCRYPT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$client->timestamps = false;
|
||||
|
||||
$client->forceFill([
|
||||
'secret' => $client->secret,
|
||||
])->save();
|
||||
}
|
||||
|
||||
$this->info('All client secrets were successfully hashed.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'passport:install
|
||||
{--uuids : Use UUIDs for all client IDs}
|
||||
{--force : Overwrite keys they already exist}
|
||||
{--length=4096 : The length of the private key}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Run the commands necessary to prepare Passport for use';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$provider = in_array('users', array_keys(config('auth.providers'))) ? 'users' : null;
|
||||
|
||||
$this->call('passport:keys', ['--force' => $this->option('force'), '--length' => $this->option('length')]);
|
||||
|
||||
if ($this->option('uuids')) {
|
||||
$this->configureUuids();
|
||||
}
|
||||
|
||||
$this->call('passport:client', ['--personal' => true, '--name' => config('app.name').' Personal Access Client']);
|
||||
$this->call('passport:client', ['--password' => true, '--name' => config('app.name').' Password Grant Client', '--provider' => $provider]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure Passport for client UUIDs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureUuids()
|
||||
{
|
||||
$this->call('vendor:publish', ['--tag' => 'passport-config']);
|
||||
$this->call('vendor:publish', ['--tag' => 'passport-migrations']);
|
||||
|
||||
config(['passport.client_uuids' => true]);
|
||||
Passport::setClientUuids(true);
|
||||
|
||||
$this->replaceInFile(config_path('passport.php'), '\'client_uuids\' => false', '\'client_uuids\' => true');
|
||||
$this->replaceInFile(database_path('migrations/2016_06_01_000001_create_oauth_auth_codes_table.php'), '$table->unsignedBigInteger(\'client_id\');', '$table->uuid(\'client_id\');');
|
||||
$this->replaceInFile(database_path('migrations/2016_06_01_000002_create_oauth_access_tokens_table.php'), '$table->unsignedBigInteger(\'client_id\');', '$table->uuid(\'client_id\');');
|
||||
$this->replaceInFile(database_path('migrations/2016_06_01_000004_create_oauth_clients_table.php'), '$table->bigIncrements(\'id\');', '$table->uuid(\'id\')->primary();');
|
||||
$this->replaceInFile(database_path('migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php'), '$table->unsignedBigInteger(\'client_id\');', '$table->uuid(\'client_id\');');
|
||||
|
||||
if ($this->confirm('In order to finish configuring client UUIDs, we need to rebuild the Passport database tables. Would you like to rollback and re-run your last migration?')) {
|
||||
$this->call('migrate:rollback');
|
||||
$this->call('migrate');
|
||||
$this->line('');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace a given string in a given file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $search
|
||||
* @param string $replace
|
||||
* @return void
|
||||
*/
|
||||
protected function replaceInFile($path, $search, $replace)
|
||||
{
|
||||
file_put_contents(
|
||||
$path,
|
||||
str_replace($search, $replace, file_get_contents($path))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Arr;
|
||||
use Laravel\Passport\Passport;
|
||||
use phpseclib\Crypt\RSA as LegacyRSA;
|
||||
use phpseclib3\Crypt\RSA;
|
||||
|
||||
class KeysCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'passport:keys
|
||||
{--force : Overwrite keys they already exist}
|
||||
{--length=4096 : The length of the private key}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create the encryption keys for API authentication';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
[$publicKey, $privateKey] = [
|
||||
Passport::keyPath('oauth-public.key'),
|
||||
Passport::keyPath('oauth-private.key'),
|
||||
];
|
||||
|
||||
if ((file_exists($publicKey) || file_exists($privateKey)) && ! $this->option('force')) {
|
||||
$this->error('Encryption keys already exist. Use the --force option to overwrite them.');
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
if (class_exists(LegacyRSA::class)) {
|
||||
$keys = (new LegacyRSA)->createKey($this->input ? (int) $this->option('length') : 4096);
|
||||
|
||||
file_put_contents($publicKey, Arr::get($keys, 'publickey'));
|
||||
file_put_contents($privateKey, Arr::get($keys, 'privatekey'));
|
||||
} else {
|
||||
$key = RSA::createKey($this->input ? (int) $this->option('length') : 4096);
|
||||
|
||||
file_put_contents($publicKey, (string) $key->getPublicKey());
|
||||
file_put_contents($privateKey, (string) $key);
|
||||
}
|
||||
|
||||
$this->info('Encryption keys generated successfully.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
class PurgeCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'passport:purge
|
||||
{--revoked : Only purge revoked 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.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Purge revoked and / or expired tokens and authentication codes';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$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'))) {
|
||||
Passport::token()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();
|
||||
Passport::authCode()->where('revoked', 1)->orWhereDate('expires_at', '<', $expired)->delete();
|
||||
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.');
|
||||
} elseif ($this->option('revoked')) {
|
||||
Passport::token()->where('revoked', 1)->delete();
|
||||
Passport::authCode()->where('revoked', 1)->delete();
|
||||
Passport::refreshToken()->where('revoked', 1)->delete();
|
||||
|
||||
$this->info('Purged revoked items.');
|
||||
} elseif ($this->option('expired')) {
|
||||
Passport::token()->whereDate('expires_at', '<', $expired)->delete();
|
||||
Passport::authCode()->whereDate('expires_at', '<', $expired)->delete();
|
||||
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.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Contracts;
|
||||
|
||||
use Illuminate\Contracts\Support\Responsable;
|
||||
|
||||
interface AuthorizationViewResponse extends Responsable
|
||||
{
|
||||
/**
|
||||
* Specify the parameters that should be passed to the view.
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return $this
|
||||
*/
|
||||
public function withParameters($parameters = []);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Events;
|
||||
|
||||
class AccessTokenCreated
|
||||
{
|
||||
/**
|
||||
* The newly created token ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $tokenId;
|
||||
|
||||
/**
|
||||
* The ID of the user associated with the token.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $userId;
|
||||
|
||||
/**
|
||||
* The ID of the client associated with the token.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $clientId;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $tokenId
|
||||
* @param string|int|null $userId
|
||||
* @param string $clientId
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($tokenId, $userId, $clientId)
|
||||
{
|
||||
$this->userId = $userId;
|
||||
$this->tokenId = $tokenId;
|
||||
$this->clientId = $clientId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Events;
|
||||
|
||||
class RefreshTokenCreated
|
||||
{
|
||||
/**
|
||||
* The newly created refresh token ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $refreshTokenId;
|
||||
|
||||
/**
|
||||
* The access token ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $accessTokenId;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param string $refreshTokenId
|
||||
* @param string $accessTokenId
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($refreshTokenId, $accessTokenId)
|
||||
{
|
||||
$this->accessTokenId = $accessTokenId;
|
||||
$this->refreshTokenId = $refreshTokenId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Exceptions;
|
||||
|
||||
use Illuminate\Auth\AuthenticationException as Exception;
|
||||
|
||||
class AuthenticationException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Exceptions;
|
||||
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
|
||||
class InvalidAuthTokenException extends AuthorizationException
|
||||
{
|
||||
/**
|
||||
* Create a new InvalidAuthTokenException for different auth tokens.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function different()
|
||||
{
|
||||
return new static('The provided auth token for the request is different from the session auth token.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Exceptions;
|
||||
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class MissingScopeException extends AuthorizationException
|
||||
{
|
||||
/**
|
||||
* The scopes that the user did not have.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes;
|
||||
|
||||
/**
|
||||
* Create a new missing scope exception.
|
||||
*
|
||||
* @param array|string $scopes
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($scopes = [], $message = 'Invalid scope(s) provided.')
|
||||
{
|
||||
parent::__construct($message);
|
||||
|
||||
$this->scopes = Arr::wrap($scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scopes that the user did not have.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function scopes()
|
||||
{
|
||||
return $this->scopes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\Response;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException as LeagueException;
|
||||
|
||||
class OAuthServerException extends Exception
|
||||
{
|
||||
/**
|
||||
* The response to render.
|
||||
*
|
||||
* @var \Illuminate\Http\Response
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* Create a new OAuthServerException.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Exception\OAuthServerException $e
|
||||
* @param \Illuminate\Http\Response $response
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(LeagueException $e, Response $response)
|
||||
{
|
||||
parent::__construct($e->getMessage(), $e->getCode(), $e);
|
||||
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the exception into an HTTP response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request)
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTTP response status code.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function statusCode()
|
||||
{
|
||||
return $this->response->getStatusCode();
|
||||
}
|
||||
}
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Guards;
|
||||
|
||||
use Exception;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
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\Client;
|
||||
use Laravel\Passport\ClientRepository;
|
||||
use Laravel\Passport\Passport;
|
||||
use Laravel\Passport\PassportUserProvider;
|
||||
use Laravel\Passport\TokenRepository;
|
||||
use Laravel\Passport\TransientToken;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
|
||||
|
||||
class TokenGuard implements Guard
|
||||
{
|
||||
use GuardHelpers, Macroable;
|
||||
|
||||
/**
|
||||
* The resource server instance.
|
||||
*
|
||||
* @var \League\OAuth2\Server\ResourceServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* The user provider implementation.
|
||||
*
|
||||
* @var \Laravel\Passport\PassportUserProvider
|
||||
*/
|
||||
protected $provider;
|
||||
|
||||
/**
|
||||
* The token repository instance.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokens;
|
||||
|
||||
/**
|
||||
* The client repository instance.
|
||||
*
|
||||
* @var \Laravel\Passport\ClientRepository
|
||||
*/
|
||||
protected $clients;
|
||||
|
||||
/**
|
||||
* The encrypter implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Encryption\Encrypter
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param \League\OAuth2\Server\ResourceServer $server
|
||||
* @param \Laravel\Passport\PassportUserProvider $provider
|
||||
* @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(
|
||||
ResourceServer $server,
|
||||
PassportUserProvider $provider,
|
||||
TokenRepository $tokens,
|
||||
ClientRepository $clients,
|
||||
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.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
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.
|
||||
*
|
||||
* @return \Laravel\Passport\Client|null
|
||||
*/
|
||||
public function client()
|
||||
{
|
||||
if (! is_null($this->client)) {
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
if ($this->request->bearerToken()) {
|
||||
if (! $psr = $this->getPsrRequestViaBearerToken($this->request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->client = $this->clients->findActive(
|
||||
$psr->getAttribute('oauth_client_id')
|
||||
);
|
||||
} elseif ($this->request->cookie(Passport::cookie())) {
|
||||
if ($token = $this->getTokenViaCookie($this->request)) {
|
||||
return $this->client = $this->clients->findActive($token['aud']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the incoming request via the Bearer token.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
protected function authenticateViaBearerToken($request)
|
||||
{
|
||||
if (! $psr = $this->getPsrRequestViaBearerToken($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$client = $this->clients->findActive(
|
||||
$psr->getAttribute('oauth_client_id')
|
||||
);
|
||||
|
||||
if (! $client ||
|
||||
($client->provider &&
|
||||
$client->provider !== $this->provider->getProviderName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the access token is valid we will retrieve the user according to the user ID
|
||||
// associated with the token. We will use the provider implementation which may
|
||||
// be used to retrieve users from Eloquent. Next, we'll be ready to continue.
|
||||
$user = $this->provider->retrieveById(
|
||||
$psr->getAttribute('oauth_user_id') ?: null
|
||||
);
|
||||
|
||||
if (! $user) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Next, we will assign a token instance to this user which the developers may use
|
||||
// to determine if the token has a given scope, etc. This will be useful during
|
||||
// authorization such as within the developer's Laravel model policy classes.
|
||||
$token = $this->tokens->find(
|
||||
$psr->getAttribute('oauth_access_token_id')
|
||||
);
|
||||
|
||||
return $token ? $user->withAccessToken($token) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate and get the incoming PSR-7 request via the Bearer token.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Psr\Http\Message\ServerRequestInterface|null
|
||||
*/
|
||||
protected function getPsrRequestViaBearerToken($request)
|
||||
{
|
||||
// First, we will convert the Symfony request to a PSR-7 implementation which will
|
||||
// be compatible with the base OAuth2 library. The Symfony bridge can perform a
|
||||
// conversion for us to a new Nyholm implementation of this PSR-7 request.
|
||||
$psr = (new PsrHttpFactory(
|
||||
new Psr17Factory,
|
||||
new Psr17Factory,
|
||||
new Psr17Factory,
|
||||
new Psr17Factory
|
||||
))->createRequest($request);
|
||||
|
||||
try {
|
||||
return $this->server->validateAuthenticatedRequest($psr);
|
||||
} catch (OAuthServerException $e) {
|
||||
$request->headers->set('Authorization', '', true);
|
||||
|
||||
Container::getInstance()->make(
|
||||
ExceptionHandler::class
|
||||
)->report($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the incoming request via the token cookie.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
protected function authenticateViaCookie($request)
|
||||
{
|
||||
if (! $token = $this->getTokenViaCookie($request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this user exists, we will return this user and attach a "transient" token to
|
||||
// the user model. The transient token assumes it has all scopes since the user
|
||||
// is physically logged into the application via the application's interface.
|
||||
if ($user = $this->provider->retrieveById($token['sub'])) {
|
||||
return $user->withAccessToken(new TransientToken);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token cookie via the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getTokenViaCookie($request)
|
||||
{
|
||||
// If we need to retrieve the token from the cookie, it'll be encrypted so we must
|
||||
// first decrypt the cookie and then attempt to find the token value within the
|
||||
// database. If we can't decrypt the value we'll bail out with a null return.
|
||||
try {
|
||||
$token = $this->decodeJwtTokenCookie($request);
|
||||
} catch (Exception $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We will compare the CSRF token in the decoded API token against the CSRF header
|
||||
// sent with the request. If they don't match then this request isn't sent from
|
||||
// a valid source and we won't authenticate the request for further handling.
|
||||
if (! Passport::$ignoreCsrfToken && (! $this->validCsrf($token, $request) ||
|
||||
time() >= $token['expiry'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode and decrypt the JWT token cookie.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
protected function decodeJwtTokenCookie($request)
|
||||
{
|
||||
$jwt = $request->cookie(Passport::cookie());
|
||||
|
||||
return (array) JWT::decode(
|
||||
Passport::$decryptsCookies
|
||||
? CookieValuePrefix::remove($this->encrypter->decrypt($jwt, Passport::$unserializesCookies))
|
||||
: $jwt,
|
||||
new Key(Passport::tokenEncryptionKey($this->encrypter), 'HS256')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the CSRF / header are valid and match.
|
||||
*
|
||||
* @param array $token
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected function validCsrf($token, $request)
|
||||
{
|
||||
return isset($token['csrf']) && hash_equals(
|
||||
$token['csrf'], (string) $this->getTokenFromRequest($request)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CSRF token from the request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenFromRequest($request)
|
||||
{
|
||||
$token = $request->header('X-CSRF-TOKEN');
|
||||
|
||||
if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
|
||||
$token = CookieValuePrefix::remove($this->encrypter->decrypt($header, static::serialized()));
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
|
||||
trait HasApiTokens
|
||||
{
|
||||
/**
|
||||
* The current access token for the authentication user.
|
||||
*
|
||||
* @var \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* Get all of the user's registered OAuth clients.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function clients()
|
||||
{
|
||||
return $this->hasMany(Passport::clientModel(), 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the access tokens for the user.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function tokens()
|
||||
{
|
||||
return $this->hasMany(Passport::tokenModel(), 'user_id')->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current access token being used by the user.
|
||||
*
|
||||
* @return \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null
|
||||
*/
|
||||
public function token()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current API token has a given scope.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return bool
|
||||
*/
|
||||
public function tokenCan($scope)
|
||||
{
|
||||
return $this->accessToken ? $this->accessToken->can($scope) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new personal access token for the user.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $scopes
|
||||
* @return \Laravel\Passport\PersonalAccessTokenResult
|
||||
*/
|
||||
public function createToken($name, array $scopes = [])
|
||||
{
|
||||
return Container::getInstance()->make(PersonalAccessTokenFactory::class)->make(
|
||||
$this->getKey(), $name, $scopes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current access token for the user.
|
||||
*
|
||||
* @param \Laravel\Passport\Token|\Laravel\Passport\TransientToken|null $accessToken
|
||||
* @return $this
|
||||
*/
|
||||
public function withAccessToken($accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Laravel\Passport\TokenRepository;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use Nyholm\Psr7\Response as Psr7Response;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class AccessTokenController
|
||||
{
|
||||
use HandlesOAuthErrors;
|
||||
|
||||
/**
|
||||
* The authorization server.
|
||||
*
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* The token repository instance.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokens;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\AuthorizationServer $server
|
||||
* @param \Laravel\Passport\TokenRepository $tokens
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AuthorizationServer $server,
|
||||
TokenRepository $tokens)
|
||||
{
|
||||
$this->server = $server;
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize a client to access the user's account.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function issueToken(ServerRequestInterface $request)
|
||||
{
|
||||
return $this->withErrorHandling(function () use ($request) {
|
||||
return $this->convertResponse(
|
||||
$this->server->respondToAccessTokenRequest($request, new Psr7Response)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use Nyholm\Psr7\Response as Psr7Response;
|
||||
|
||||
class ApproveAuthorizationController
|
||||
{
|
||||
use ConvertsPsrResponses, HandlesOAuthErrors, RetrievesAuthRequestFromSession;
|
||||
|
||||
/**
|
||||
* The authorization server.
|
||||
*
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\AuthorizationServer $server
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AuthorizationServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve the authorization request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function approve(Request $request)
|
||||
{
|
||||
$this->assertValidAuthToken($request);
|
||||
|
||||
$authRequest = $this->getAuthRequestFromSession($request);
|
||||
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
|
||||
return $this->withErrorHandling(function () use ($authRequest) {
|
||||
return $this->convertResponse(
|
||||
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Passport\Bridge\User;
|
||||
use Laravel\Passport\ClientRepository;
|
||||
use Laravel\Passport\Contracts\AuthorizationViewResponse;
|
||||
use Laravel\Passport\Exceptions\AuthenticationException;
|
||||
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;
|
||||
|
||||
class AuthorizationController
|
||||
{
|
||||
use HandlesOAuthErrors;
|
||||
|
||||
/**
|
||||
* The authorization server.
|
||||
*
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* The guard implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected $guard;
|
||||
|
||||
/**
|
||||
* The authorization view response implementation.
|
||||
*
|
||||
* @var \Laravel\Passport\Contracts\AuthorizationViewResponse
|
||||
*/
|
||||
protected $response;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @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,
|
||||
StatefulGuard $guard,
|
||||
AuthorizationViewResponse $response)
|
||||
{
|
||||
$this->server = $server;
|
||||
$this->guard = $guard;
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize a client to access the user's account.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $psrRequest
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @param \Laravel\Passport\TokenRepository $tokens
|
||||
* @return \Illuminate\Http\Response|\Laravel\Passport\Contracts\AuthorizationViewResponse
|
||||
*/
|
||||
public function authorize(ServerRequestInterface $psrRequest,
|
||||
Request $request,
|
||||
ClientRepository $clients,
|
||||
TokenRepository $tokens)
|
||||
{
|
||||
$authRequest = $this->withErrorHandling(function () use ($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 = $this->guard->user();
|
||||
$client = $clients->find($authRequest->getClient()->getIdentifier());
|
||||
|
||||
if ($request->get('prompt') !== 'consent' &&
|
||||
($client->skipsAuthorization() || $this->hasValidToken($tokens, $user, $client, $scopes))) {
|
||||
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);
|
||||
|
||||
return $this->response->withParameters([
|
||||
'client' => $client,
|
||||
'user' => $user,
|
||||
'scopes' => $scopes,
|
||||
'request' => $request,
|
||||
'authToken' => $authToken,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the authorization requests's scopes into Scope instances.
|
||||
*
|
||||
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
|
||||
* @return array
|
||||
*/
|
||||
protected function parseScopes($authRequest)
|
||||
{
|
||||
return Passport::scopesFor(
|
||||
collect($authRequest->getScopes())->map(function ($scope) {
|
||||
return $scope->getIdentifier();
|
||||
})->unique()->all()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a valid token exists for the given user, client, and scopes.
|
||||
*
|
||||
* @param \Laravel\Passport\TokenRepository $tokens
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $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.
|
||||
*
|
||||
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
protected function approveRequest($authRequest, $user)
|
||||
{
|
||||
$authRequest->setUser(new User($user->getAuthIdentifier()));
|
||||
|
||||
$authRequest->setAuthorizationApproved(true);
|
||||
|
||||
return $this->withErrorHandling(function () use ($authRequest) {
|
||||
return $this->convertResponse(
|
||||
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny the authorization request.
|
||||
*
|
||||
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
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);
|
||||
|
||||
return $this->withErrorHandling(function () use ($authRequest) {
|
||||
return $this->convertResponse(
|
||||
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt the user to login by throwing an AuthenticationException.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\AuthenticationException
|
||||
*/
|
||||
protected function promptForLogin($request)
|
||||
{
|
||||
$request->session()->put('promptedForLogin', true);
|
||||
|
||||
throw new AuthenticationException;
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Laravel\Passport\RefreshTokenRepository;
|
||||
use Laravel\Passport\TokenRepository;
|
||||
|
||||
class AuthorizedAccessTokenController
|
||||
{
|
||||
/**
|
||||
* The token repository implementation.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokenRepository;
|
||||
|
||||
/**
|
||||
* The refresh token repository implementation.
|
||||
*
|
||||
* @var \Laravel\Passport\RefreshTokenRepository
|
||||
*/
|
||||
protected $refreshTokenRepository;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param \Laravel\Passport\TokenRepository $tokenRepository
|
||||
* @param \Laravel\Passport\RefreshTokenRepository $refreshTokenRepository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(TokenRepository $tokenRepository, RefreshTokenRepository $refreshTokenRepository)
|
||||
{
|
||||
$this->tokenRepository = $tokenRepository;
|
||||
$this->refreshTokenRepository = $refreshTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the authorized tokens for the authenticated user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function forUser(Request $request)
|
||||
{
|
||||
$tokens = $this->tokenRepository->forUser($request->user()->getAuthIdentifier());
|
||||
|
||||
return $tokens->load('client')->filter(function ($token) {
|
||||
return ! $token->client->firstParty() && ! $token->revoked;
|
||||
})->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given token.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $tokenId
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request, $tokenId)
|
||||
{
|
||||
$token = $this->tokenRepository->findForUser(
|
||||
$tokenId, $request->user()->getAuthIdentifier()
|
||||
);
|
||||
|
||||
if (is_null($token)) {
|
||||
return new Response('', 404);
|
||||
}
|
||||
|
||||
$token->revoke();
|
||||
|
||||
$this->refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);
|
||||
|
||||
return new Response('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Laravel\Passport\ClientRepository;
|
||||
use Laravel\Passport\Http\Rules\RedirectRule;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
class ClientController
|
||||
{
|
||||
/**
|
||||
* The client repository instance.
|
||||
*
|
||||
* @var \Laravel\Passport\ClientRepository
|
||||
*/
|
||||
protected $clients;
|
||||
|
||||
/**
|
||||
* The validation factory implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Validation\Factory
|
||||
*/
|
||||
protected $validation;
|
||||
|
||||
/**
|
||||
* The redirect validation rule.
|
||||
*
|
||||
* @var \Laravel\Passport\Http\Rules\RedirectRule
|
||||
*/
|
||||
protected $redirectRule;
|
||||
|
||||
/**
|
||||
* Create a client controller instance.
|
||||
*
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @param \Illuminate\Contracts\Validation\Factory $validation
|
||||
* @param \Laravel\Passport\Http\Rules\RedirectRule $redirectRule
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
ClientRepository $clients,
|
||||
ValidationFactory $validation,
|
||||
RedirectRule $redirectRule
|
||||
) {
|
||||
$this->clients = $clients;
|
||||
$this->validation = $validation;
|
||||
$this->redirectRule = $redirectRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the clients for the authenticated user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function forUser(Request $request)
|
||||
{
|
||||
$userId = $request->user()->getAuthIdentifier();
|
||||
|
||||
$clients = $this->clients->activeForUser($userId);
|
||||
|
||||
if (Passport::$hashesClientSecrets) {
|
||||
return $clients;
|
||||
}
|
||||
|
||||
return $clients->makeVisible('secret');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new client.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Laravel\Passport\Client|array
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->validation->make($request->all(), [
|
||||
'name' => 'required|max:191',
|
||||
'redirect' => ['required', $this->redirectRule],
|
||||
'confidential' => 'boolean',
|
||||
])->validate();
|
||||
|
||||
$client = $this->clients->create(
|
||||
$request->user()->getAuthIdentifier(), $request->name, $request->redirect,
|
||||
null, false, false, (bool) $request->input('confidential', true)
|
||||
);
|
||||
|
||||
if (Passport::$hashesClientSecrets) {
|
||||
return ['plainSecret' => $client->plainSecret] + $client->toArray();
|
||||
}
|
||||
|
||||
return $client->makeVisible('secret');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given client.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $clientId
|
||||
* @return \Illuminate\Http\Response|\Laravel\Passport\Client
|
||||
*/
|
||||
public function update(Request $request, $clientId)
|
||||
{
|
||||
$client = $this->clients->findForUser($clientId, $request->user()->getAuthIdentifier());
|
||||
|
||||
if (! $client) {
|
||||
return new Response('', 404);
|
||||
}
|
||||
|
||||
$this->validation->make($request->all(), [
|
||||
'name' => 'required|max:191',
|
||||
'redirect' => ['required', $this->redirectRule],
|
||||
])->validate();
|
||||
|
||||
return $this->clients->update(
|
||||
$client, $request->name, $request->redirect
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given client.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $clientId
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request, $clientId)
|
||||
{
|
||||
$client = $this->clients->findForUser($clientId, $request->user()->getAuthIdentifier());
|
||||
|
||||
if (! $client) {
|
||||
return new Response('', 404);
|
||||
}
|
||||
|
||||
$this->clients->delete($client);
|
||||
|
||||
return new Response('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
trait ConvertsPsrResponses
|
||||
{
|
||||
/**
|
||||
* Convert a PSR7 response to a Illuminate Response.
|
||||
*
|
||||
* @param \Psr\Http\Message\ResponseInterface $psrResponse
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function convertResponse($psrResponse)
|
||||
{
|
||||
return new Response(
|
||||
$psrResponse->getBody(),
|
||||
$psrResponse->getStatusCode(),
|
||||
$psrResponse->getHeaders()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use Nyholm\Psr7\Response as Psr7Response;
|
||||
|
||||
class DenyAuthorizationController
|
||||
{
|
||||
use ConvertsPsrResponses, HandlesOAuthErrors, RetrievesAuthRequestFromSession;
|
||||
|
||||
/**
|
||||
* The authorization server.
|
||||
*
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\AuthorizationServer $server
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AuthorizationServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny the authorization request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function deny(Request $request)
|
||||
{
|
||||
$this->assertValidAuthToken($request);
|
||||
|
||||
$authRequest = $this->getAuthRequestFromSession($request);
|
||||
|
||||
$authRequest->setAuthorizationApproved(false);
|
||||
|
||||
return $this->withErrorHandling(function () use ($authRequest) {
|
||||
return $this->convertResponse(
|
||||
$this->server->completeAuthorizationRequest($authRequest, new Psr7Response)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Laravel\Passport\Exceptions\OAuthServerException;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException as LeagueException;
|
||||
use Nyholm\Psr7\Response as Psr7Response;
|
||||
|
||||
trait HandlesOAuthErrors
|
||||
{
|
||||
use ConvertsPsrResponses;
|
||||
|
||||
/**
|
||||
* Perform the given callback with exception handling.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\OAuthServerException
|
||||
*/
|
||||
protected function withErrorHandling($callback)
|
||||
{
|
||||
try {
|
||||
return $callback();
|
||||
} catch (LeagueException $e) {
|
||||
throw new OAuthServerException(
|
||||
$e,
|
||||
$this->convertResponse($e->generateHttpResponse(new Psr7Response))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\Validation\Factory as ValidationFactory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Laravel\Passport\Passport;
|
||||
use Laravel\Passport\TokenRepository;
|
||||
|
||||
class PersonalAccessTokenController
|
||||
{
|
||||
/**
|
||||
* The token repository implementation.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokenRepository;
|
||||
|
||||
/**
|
||||
* The validation factory implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Validation\Factory
|
||||
*/
|
||||
protected $validation;
|
||||
|
||||
/**
|
||||
* Create a controller instance.
|
||||
*
|
||||
* @param \Laravel\Passport\TokenRepository $tokenRepository
|
||||
* @param \Illuminate\Contracts\Validation\Factory $validation
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(TokenRepository $tokenRepository, ValidationFactory $validation)
|
||||
{
|
||||
$this->validation = $validation;
|
||||
$this->tokenRepository = $tokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the personal access tokens for the authenticated user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function forUser(Request $request)
|
||||
{
|
||||
$tokens = $this->tokenRepository->forUser($request->user()->getAuthIdentifier());
|
||||
|
||||
return $tokens->load('client')->filter(function ($token) {
|
||||
return $token->client->personal_access_client && ! $token->revoked;
|
||||
})->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new personal access token for the user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Laravel\Passport\PersonalAccessTokenResult
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->validation->make($request->all(), [
|
||||
'name' => 'required|max:191',
|
||||
'scopes' => 'array|in:'.implode(',', Passport::scopeIds()),
|
||||
])->validate();
|
||||
|
||||
return $request->user()->createToken(
|
||||
$request->name, $request->scopes ?: []
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the given token.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $tokenId
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request, $tokenId)
|
||||
{
|
||||
$token = $this->tokenRepository->findForUser(
|
||||
$tokenId, $request->user()->getAuthIdentifier()
|
||||
);
|
||||
|
||||
if (is_null($token)) {
|
||||
return new Response('', 404);
|
||||
}
|
||||
|
||||
$token->revoke();
|
||||
|
||||
return new Response('', Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Passport\Bridge\User;
|
||||
use Laravel\Passport\Exceptions\InvalidAuthTokenException;
|
||||
|
||||
trait RetrievesAuthRequestFromSession
|
||||
{
|
||||
/**
|
||||
* Make sure the auth token matches the one in the session.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\InvalidAuthTokenException
|
||||
*/
|
||||
protected function assertValidAuthToken(Request $request)
|
||||
{
|
||||
if ($request->has('auth_token') && $request->session()->get('authToken') !== $request->get('auth_token')) {
|
||||
$request->session()->forget(['authToken', 'authRequest']);
|
||||
|
||||
throw InvalidAuthTokenException::different();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authorization request from the session.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getAuthRequestFromSession(Request $request)
|
||||
{
|
||||
return tap($request->session()->get('authRequest'), function ($authRequest) use ($request) {
|
||||
if (! $authRequest) {
|
||||
throw new Exception('Authorization request was not present in the session.');
|
||||
}
|
||||
|
||||
$authRequest->setUser(new User($request->user()->getAuthIdentifier()));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
class ScopeController
|
||||
{
|
||||
/**
|
||||
* Get all of the available scopes for the application.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return Passport::scopes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Laravel\Passport\ApiTokenCookieFactory;
|
||||
|
||||
class TransientTokenController
|
||||
{
|
||||
/**
|
||||
* The cookie factory instance.
|
||||
*
|
||||
* @var \Laravel\Passport\ApiTokenCookieFactory
|
||||
*/
|
||||
protected $cookieFactory;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param \Laravel\Passport\ApiTokenCookieFactory $cookieFactory
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ApiTokenCookieFactory $cookieFactory)
|
||||
{
|
||||
$this->cookieFactory = $cookieFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fresh transient token cookie for the authenticated user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function refresh(Request $request)
|
||||
{
|
||||
return (new Response('Refreshed.'))->withCookie($this->cookieFactory->make(
|
||||
$request->user()->getAuthIdentifier(), $request->session()->token()
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Middleware;
|
||||
|
||||
use Laravel\Passport\Exceptions\AuthenticationException;
|
||||
use Laravel\Passport\Exceptions\MissingScopeException;
|
||||
|
||||
class CheckClientCredentials extends CheckCredentials
|
||||
{
|
||||
/**
|
||||
* Validate token credentials.
|
||||
*
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\AuthenticationException
|
||||
*/
|
||||
protected function validateCredentials($token)
|
||||
{
|
||||
if (! $token) {
|
||||
throw new AuthenticationException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate token credentials.
|
||||
*
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @param array $scopes
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\MissingScopeException
|
||||
*/
|
||||
protected function validateScopes($token, $scopes)
|
||||
{
|
||||
if (in_array('*', $token->scopes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
if ($token->cant($scope)) {
|
||||
throw new MissingScopeException($scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Middleware;
|
||||
|
||||
use Laravel\Passport\Exceptions\AuthenticationException;
|
||||
use Laravel\Passport\Exceptions\MissingScopeException;
|
||||
|
||||
class CheckClientCredentialsForAnyScope extends CheckCredentials
|
||||
{
|
||||
/**
|
||||
* Validate token credentials.
|
||||
*
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\AuthenticationException
|
||||
*/
|
||||
protected function validateCredentials($token)
|
||||
{
|
||||
if (! $token) {
|
||||
throw new AuthenticationException;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate token credentials.
|
||||
*
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @param array $scopes
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\MissingScopeException
|
||||
*/
|
||||
protected function validateScopes($token, $scopes)
|
||||
{
|
||||
if (in_array('*', $token->scopes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
if ($token->can($scope)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new MissingScopeException($scopes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Laravel\Passport\Exceptions\AuthenticationException;
|
||||
use Laravel\Passport\TokenRepository;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
|
||||
|
||||
abstract class CheckCredentials
|
||||
{
|
||||
/**
|
||||
* The Resource Server instance.
|
||||
*
|
||||
* @var \League\OAuth2\Server\ResourceServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Token Repository.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\ResourceServer $server
|
||||
* @param \Laravel\Passport\TokenRepository $repository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ResourceServer $server, TokenRepository $repository)
|
||||
{
|
||||
$this->server = $server;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the scopes for the middleware.
|
||||
*
|
||||
* @param array|string $scopes
|
||||
* @return string
|
||||
*/
|
||||
public static function using(...$scopes)
|
||||
{
|
||||
if (is_array($scopes[0])) {
|
||||
return static::class.':'.implode(',', $scopes[0]);
|
||||
}
|
||||
|
||||
return static::class.':'.implode(',', $scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param mixed ...$scopes
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\AuthenticationException
|
||||
*/
|
||||
public function handle($request, Closure $next, ...$scopes)
|
||||
{
|
||||
$psr = (new PsrHttpFactory(
|
||||
new Psr17Factory,
|
||||
new Psr17Factory,
|
||||
new Psr17Factory,
|
||||
new Psr17Factory
|
||||
))->createRequest($request);
|
||||
|
||||
try {
|
||||
$psr = $this->server->validateAuthenticatedRequest($psr);
|
||||
} catch (OAuthServerException $e) {
|
||||
throw new AuthenticationException;
|
||||
}
|
||||
|
||||
$this->validate($psr, $scopes);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the scopes and token on the incoming request.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $psr
|
||||
* @param array $scopes
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\MissingScopeException|\Illuminate\Auth\AuthenticationException
|
||||
*/
|
||||
protected function validate($psr, $scopes)
|
||||
{
|
||||
$token = $this->repository->find($psr->getAttribute('oauth_access_token_id'));
|
||||
|
||||
$this->validateCredentials($token);
|
||||
|
||||
$this->validateScopes($token, $scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate token credentials.
|
||||
*
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\AuthenticationException
|
||||
*/
|
||||
abstract protected function validateCredentials($token);
|
||||
|
||||
/**
|
||||
* Validate token scopes.
|
||||
*
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @param array $scopes
|
||||
* @return void
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\MissingScopeException
|
||||
*/
|
||||
abstract protected function validateScopes($token, $scopes);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Middleware;
|
||||
|
||||
use Laravel\Passport\Exceptions\AuthenticationException;
|
||||
use Laravel\Passport\Exceptions\MissingScopeException;
|
||||
|
||||
class CheckForAnyScope
|
||||
{
|
||||
/**
|
||||
* Specify the scopes for the middleware.
|
||||
*
|
||||
* @param array|string $scopes
|
||||
* @return string
|
||||
*/
|
||||
public static function using(...$scopes)
|
||||
{
|
||||
if (is_array($scopes[0])) {
|
||||
return static::class.':'.implode(',', $scopes[0]);
|
||||
}
|
||||
|
||||
return static::class.':'.implode(',', $scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param mixed ...$scopes
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\AuthenticationException|\Laravel\Passport\Exceptions\MissingScopeException
|
||||
*/
|
||||
public function handle($request, $next, ...$scopes)
|
||||
{
|
||||
if (! $request->user() || ! $request->user()->token()) {
|
||||
throw new AuthenticationException;
|
||||
}
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
if ($request->user()->tokenCan($scope)) {
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
||||
throw new MissingScopeException($scopes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Middleware;
|
||||
|
||||
use Laravel\Passport\Exceptions\AuthenticationException;
|
||||
use Laravel\Passport\Exceptions\MissingScopeException;
|
||||
|
||||
class CheckScopes
|
||||
{
|
||||
/**
|
||||
* Specify the scopes for the middleware.
|
||||
*
|
||||
* @param array|string $scopes
|
||||
* @return string
|
||||
*/
|
||||
public static function using(...$scopes)
|
||||
{
|
||||
if (is_array($scopes[0])) {
|
||||
return static::class.':'.implode(',', $scopes[0]);
|
||||
}
|
||||
|
||||
return static::class.':'.implode(',', $scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param mixed ...$scopes
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Laravel\Passport\Exceptions\AuthenticationException|\Laravel\Passport\Exceptions\MissingScopeException
|
||||
*/
|
||||
public function handle($request, $next, ...$scopes)
|
||||
{
|
||||
if (! $request->user() || ! $request->user()->token()) {
|
||||
throw new AuthenticationException;
|
||||
}
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
if (! $request->user()->tokenCan($scope)) {
|
||||
throw new MissingScopeException($scope);
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Laravel\Passport\ApiTokenCookieFactory;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
class CreateFreshApiToken
|
||||
{
|
||||
/**
|
||||
* The API token cookie factory instance.
|
||||
*
|
||||
* @var \Laravel\Passport\ApiTokenCookieFactory
|
||||
*/
|
||||
protected $cookieFactory;
|
||||
|
||||
/**
|
||||
* The authentication guard.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $guard;
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \Laravel\Passport\ApiTokenCookieFactory $cookieFactory
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ApiTokenCookieFactory $cookieFactory)
|
||||
{
|
||||
$this->cookieFactory = $cookieFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the guard for the middleware.
|
||||
*
|
||||
* @param string|null $guard
|
||||
* @return string
|
||||
*/
|
||||
public static function using($guard = null)
|
||||
{
|
||||
$guard = is_null($guard) ? '' : ':'.$guard;
|
||||
|
||||
return static::class.$guard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
{
|
||||
$this->guard = $guard;
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
if ($this->shouldReceiveFreshToken($request, $response)) {
|
||||
$response->withCookie($this->cookieFactory->make(
|
||||
$request->user($this->guard)->getAuthIdentifier(), $request->session()->token()
|
||||
));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given request should receive a fresh token.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Http\Response $response
|
||||
* @return bool
|
||||
*/
|
||||
protected function shouldReceiveFreshToken($request, $response)
|
||||
{
|
||||
return $this->requestShouldReceiveFreshToken($request) &&
|
||||
$this->responseShouldReceiveFreshToken($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the request should receive a fresh token.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected function requestShouldReceiveFreshToken($request)
|
||||
{
|
||||
return $request->isMethod('GET') && $request->user($this->guard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the response should receive a fresh token.
|
||||
*
|
||||
* @param \Illuminate\Http\Response $response
|
||||
* @return bool
|
||||
*/
|
||||
protected function responseShouldReceiveFreshToken($response)
|
||||
{
|
||||
return ($response instanceof Response ||
|
||||
$response instanceof JsonResponse) &&
|
||||
! $this->alreadyContainsToken($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given response already contains an API token.
|
||||
*
|
||||
* This avoids us overwriting a just "refreshed" token.
|
||||
*
|
||||
* @param \Illuminate\Http\Response $response
|
||||
* @return bool
|
||||
*/
|
||||
protected function alreadyContainsToken($response)
|
||||
{
|
||||
foreach ($response->headers->getCookies() as $cookie) {
|
||||
if ($cookie->getName() === Passport::cookie()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Responses;
|
||||
|
||||
use Illuminate\Contracts\Support\Responsable;
|
||||
use Laravel\Passport\Contracts\AuthorizationViewResponse as AuthorizationViewResponseContract;
|
||||
|
||||
class AuthorizationViewResponse implements AuthorizationViewResponseContract
|
||||
{
|
||||
/**
|
||||
* The name of the view or the callable used to generate the view.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* An array of arguments that may be passed to the view response and used in the view.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $parameters;
|
||||
|
||||
/**
|
||||
* Create a new response instance.
|
||||
*
|
||||
* @param callable|string $view
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($view)
|
||||
{
|
||||
$this->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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Factory;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
class RedirectRule implements Rule
|
||||
{
|
||||
/**
|
||||
* The validator instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Validation\Factory
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
/**
|
||||
* Create a new rule instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Validation\Factory $validator
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Factory $validator)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
foreach (explode(',', $value) as $redirect) {
|
||||
$validator = $this->validator->make(['redirect' => $redirect], ['redirect' => new UriRule]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function message()
|
||||
{
|
||||
return 'One or more redirects have an invalid URI format.';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport\Http\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
class UriRule implements Rule
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function passes($attribute, $value): bool
|
||||
{
|
||||
if (filter_var($value, FILTER_VALIDATE_URL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function message(): string
|
||||
{
|
||||
return 'The :attribute must be valid URI.';
|
||||
}
|
||||
}
|
||||
+758
@@ -0,0 +1,758 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Carbon\Carbon;
|
||||
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;
|
||||
|
||||
class Passport
|
||||
{
|
||||
/**
|
||||
* Indicates if the implicit grant type is enabled.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public static $implicitGrantEnabled = false;
|
||||
|
||||
/**
|
||||
* Indicates if the password grant type is enabled.
|
||||
*
|
||||
* @var bool|null
|
||||
*/
|
||||
public static $passwordGrantEnabled = true;
|
||||
|
||||
/**
|
||||
* The default scope.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $defaultScope;
|
||||
|
||||
/**
|
||||
* All of the scopes defined for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $scopes = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* The interval when access tokens expire.
|
||||
*
|
||||
* @var \DateInterval|null
|
||||
*/
|
||||
public static $tokensExpireIn;
|
||||
|
||||
/**
|
||||
* The date when refresh tokens expire.
|
||||
*
|
||||
* @var \DateInterval|null
|
||||
*/
|
||||
public static $refreshTokensExpireIn;
|
||||
|
||||
/**
|
||||
* The date when personal access tokens expire.
|
||||
*
|
||||
* @var \DateInterval|null
|
||||
*/
|
||||
public static $personalAccessTokensExpireIn;
|
||||
|
||||
/**
|
||||
* The name for API token cookies.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $cookie = 'laravel_token';
|
||||
|
||||
/**
|
||||
* Indicates if Passport should ignore incoming CSRF tokens.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $ignoreCsrfToken = false;
|
||||
|
||||
/**
|
||||
* The storage location of the encryption keys.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $keyPath;
|
||||
|
||||
/**
|
||||
* The access token entity class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $accessTokenEntity = 'Laravel\Passport\Bridge\AccessToken';
|
||||
|
||||
/**
|
||||
* The auth code model class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $authCodeModel = 'Laravel\Passport\AuthCode';
|
||||
|
||||
/**
|
||||
* The client model class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $clientModel = 'Laravel\Passport\Client';
|
||||
|
||||
/**
|
||||
* Indicates if client's are identified by UUIDs.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $clientUuids = false;
|
||||
|
||||
/**
|
||||
* The personal access client model class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $personalAccessClientModel = 'Laravel\Passport\PersonalAccessClient';
|
||||
|
||||
/**
|
||||
* The token model class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $tokenModel = 'Laravel\Passport\Token';
|
||||
|
||||
/**
|
||||
* The refresh token model class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $refreshTokenModel = 'Laravel\Passport\RefreshToken';
|
||||
|
||||
/**
|
||||
* Indicates if Passport migrations will be run.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $runsMigrations = true;
|
||||
|
||||
/**
|
||||
* Indicates if Passport should unserializes cookies.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $unserializesCookies = false;
|
||||
|
||||
/**
|
||||
* Indicates if Passport should decrypt cookies.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $decryptsCookies = true;
|
||||
|
||||
/**
|
||||
* Indicates if client secrets will be hashed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $hashesClientSecrets = false;
|
||||
|
||||
/**
|
||||
* The callback that should be used to generate JWT encryption keys.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
public static $tokenEncryptionKeyCallback;
|
||||
|
||||
/**
|
||||
* Indicates the scope should inherit its parent scope.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $withInheritedScopes = false;
|
||||
|
||||
/**
|
||||
* The authorization server response type.
|
||||
*
|
||||
* @var \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface|null
|
||||
*/
|
||||
public static $authorizationServerResponseType;
|
||||
|
||||
/**
|
||||
* Indicates if Passport routes will be registered.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $registersRoutes = true;
|
||||
|
||||
/**
|
||||
* Enable the implicit grant type.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function enableImplicitGrant()
|
||||
{
|
||||
static::$implicitGrantEnabled = true;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default scope(s). Multiple scopes may be an array or specified delimited by spaces.
|
||||
*
|
||||
* @param array|string $scope
|
||||
* @return void
|
||||
*/
|
||||
public static function setDefaultScope($scope)
|
||||
{
|
||||
static::$defaultScope = is_array($scope) ? implode(' ', $scope) : $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the defined scope IDs.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function scopeIds()
|
||||
{
|
||||
return static::scopes()->pluck('id')->values()->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given scope has been defined.
|
||||
*
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasScope($id)
|
||||
{
|
||||
return $id === '*' || array_key_exists($id, static::$scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the scopes defined for the application.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public static function scopes()
|
||||
{
|
||||
return collect(static::$scopes)->map(function ($description, $id) {
|
||||
return new Scope($id, $description);
|
||||
})->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the scopes matching the given IDs.
|
||||
*
|
||||
* @param array $ids
|
||||
* @return array
|
||||
*/
|
||||
public static function scopesFor(array $ids)
|
||||
{
|
||||
return collect($ids)->map(function ($id) {
|
||||
if (isset(static::$scopes[$id])) {
|
||||
return new Scope($id, static::$scopes[$id]);
|
||||
}
|
||||
})->filter()->values()->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the scopes for the application.
|
||||
*
|
||||
* @param array $scopes
|
||||
* @return void
|
||||
*/
|
||||
public static function tokensCan(array $scopes)
|
||||
{
|
||||
static::$scopes = $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set when access tokens expire.
|
||||
*
|
||||
* @param \DateTimeInterface|null $date
|
||||
* @return \DateInterval|static
|
||||
*/
|
||||
public static function tokensExpireIn(DateTimeInterface $date = null)
|
||||
{
|
||||
if (is_null($date)) {
|
||||
return static::$tokensExpireIn ?? new DateInterval('P1Y');
|
||||
}
|
||||
|
||||
static::$tokensExpireIn = Carbon::now()->diff($date);
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set when refresh tokens expire.
|
||||
*
|
||||
* @param \DateTimeInterface|null $date
|
||||
* @return \DateInterval|static
|
||||
*/
|
||||
public static function refreshTokensExpireIn(DateTimeInterface $date = null)
|
||||
{
|
||||
if (is_null($date)) {
|
||||
return static::$refreshTokensExpireIn ?? new DateInterval('P1Y');
|
||||
}
|
||||
|
||||
static::$refreshTokensExpireIn = Carbon::now()->diff($date);
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set when personal access tokens expire.
|
||||
*
|
||||
* @param \DateTimeInterface|null $date
|
||||
* @return \DateInterval|static
|
||||
*/
|
||||
public static function personalAccessTokensExpireIn(DateTimeInterface $date = null)
|
||||
{
|
||||
if (is_null($date)) {
|
||||
return static::$personalAccessTokensExpireIn ?? new DateInterval('P1Y');
|
||||
}
|
||||
|
||||
static::$personalAccessTokensExpireIn = Carbon::now()->diff($date);
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set the name for API token cookies.
|
||||
*
|
||||
* @param string|null $cookie
|
||||
* @return string|static
|
||||
*/
|
||||
public static function cookie($cookie = null)
|
||||
{
|
||||
if (is_null($cookie)) {
|
||||
return static::$cookie;
|
||||
}
|
||||
|
||||
static::$cookie = $cookie;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that Passport should ignore incoming CSRF tokens.
|
||||
*
|
||||
* @param bool $ignoreCsrfToken
|
||||
* @return static
|
||||
*/
|
||||
public static function ignoreCsrfToken($ignoreCsrfToken = true)
|
||||
{
|
||||
static::$ignoreCsrfToken = $ignoreCsrfToken;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current user for the application with the given scopes.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable|\Laravel\Passport\HasApiTokens $user
|
||||
* @param array $scopes
|
||||
* @param string $guard
|
||||
* @return \Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
public static function actingAs($user, $scopes = [], $guard = 'api')
|
||||
{
|
||||
$token = app(self::tokenModel());
|
||||
|
||||
$token->scopes = $scopes;
|
||||
|
||||
$user->withAccessToken($token);
|
||||
|
||||
if (isset($user->wasRecentlyCreated) && $user->wasRecentlyCreated) {
|
||||
$user->wasRecentlyCreated = false;
|
||||
}
|
||||
|
||||
app('auth')->guard($guard)->setUser($user);
|
||||
|
||||
app('auth')->shouldUse($guard);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current client for the application with the given scopes.
|
||||
*
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @param array $scopes
|
||||
* @param string $guard
|
||||
* @return \Laravel\Passport\Client
|
||||
*/
|
||||
public static function actingAsClient($client, $scopes = [], $guard = 'api')
|
||||
{
|
||||
$token = app(self::tokenModel());
|
||||
|
||||
$token->client_id = $client->getKey();
|
||||
$token->setRelation('client', $client);
|
||||
|
||||
$token->scopes = $scopes;
|
||||
|
||||
$mock = Mockery::mock(ResourceServer::class);
|
||||
$mock->shouldReceive('validateAuthenticatedRequest')
|
||||
->andReturnUsing(function (ServerRequestInterface $request) use ($token) {
|
||||
return $request->withAttribute('oauth_client_id', $token->client->id)
|
||||
->withAttribute('oauth_access_token_id', $token->id)
|
||||
->withAttribute('oauth_scopes', $token->scopes);
|
||||
});
|
||||
|
||||
app()->instance(ResourceServer::class, $mock);
|
||||
|
||||
$mock = Mockery::mock(TokenRepository::class);
|
||||
$mock->shouldReceive('find')->andReturn($token);
|
||||
|
||||
app()->instance(TokenRepository::class, $mock);
|
||||
|
||||
app('auth')->guard($guard)->setClient($client);
|
||||
|
||||
app('auth')->shouldUse($guard);
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the storage location of the encryption keys.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public static function loadKeysFrom($path)
|
||||
{
|
||||
static::$keyPath = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* The location of the encryption keys.
|
||||
*
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
public static function keyPath($file)
|
||||
{
|
||||
$file = ltrim($file, '/\\');
|
||||
|
||||
return static::$keyPath
|
||||
? rtrim(static::$keyPath, '/\\').DIRECTORY_SEPARATOR.$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.
|
||||
*
|
||||
* @param string $authCodeModel
|
||||
* @return void
|
||||
*/
|
||||
public static function useAuthCodeModel($authCodeModel)
|
||||
{
|
||||
static::$authCodeModel = $authCodeModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the auth code model class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function authCodeModel()
|
||||
{
|
||||
return static::$authCodeModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new auth code model instance.
|
||||
*
|
||||
* @return \Laravel\Passport\AuthCode
|
||||
*/
|
||||
public static function authCode()
|
||||
{
|
||||
return new static::$authCodeModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client model class name.
|
||||
*
|
||||
* @param string $clientModel
|
||||
* @return void
|
||||
*/
|
||||
public static function useClientModel($clientModel)
|
||||
{
|
||||
static::$clientModel = $clientModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client model class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function clientModel()
|
||||
{
|
||||
return static::$clientModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new client model instance.
|
||||
*
|
||||
* @return \Laravel\Passport\Client
|
||||
*/
|
||||
public static function client()
|
||||
{
|
||||
return new static::$clientModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if clients are identified using UUIDs.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function clientUuids()
|
||||
{
|
||||
return static::$clientUuids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify if clients are identified using UUIDs.
|
||||
*
|
||||
* @param bool $value
|
||||
* @return void
|
||||
*/
|
||||
public static function setClientUuids($value)
|
||||
{
|
||||
static::$clientUuids = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the personal access client model class name.
|
||||
*
|
||||
* @param string $clientModel
|
||||
* @return void
|
||||
*/
|
||||
public static function usePersonalAccessClientModel($clientModel)
|
||||
{
|
||||
static::$personalAccessClientModel = $clientModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the personal access client model class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function personalAccessClientModel()
|
||||
{
|
||||
return static::$personalAccessClientModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new personal access client model instance.
|
||||
*
|
||||
* @return \Laravel\Passport\PersonalAccessClient
|
||||
*/
|
||||
public static function personalAccessClient()
|
||||
{
|
||||
return new static::$personalAccessClientModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token model class name.
|
||||
*
|
||||
* @param string $tokenModel
|
||||
* @return void
|
||||
*/
|
||||
public static function useTokenModel($tokenModel)
|
||||
{
|
||||
static::$tokenModel = $tokenModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token model class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function tokenModel()
|
||||
{
|
||||
return static::$tokenModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new personal access client model instance.
|
||||
*
|
||||
* @return \Laravel\Passport\Token
|
||||
*/
|
||||
public static function token()
|
||||
{
|
||||
return new static::$tokenModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the refresh token model class name.
|
||||
*
|
||||
* @param string $refreshTokenModel
|
||||
* @return void
|
||||
*/
|
||||
public static function useRefreshTokenModel($refreshTokenModel)
|
||||
{
|
||||
static::$refreshTokenModel = $refreshTokenModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the refresh token model class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function refreshTokenModel()
|
||||
{
|
||||
return static::$refreshTokenModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new refresh token model instance.
|
||||
*
|
||||
* @return \Laravel\Passport\RefreshToken
|
||||
*/
|
||||
public static function refreshToken()
|
||||
{
|
||||
return new static::$refreshTokenModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure Passport to hash client credential secrets.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function hashClientSecrets()
|
||||
{
|
||||
static::$hashesClientSecrets = true;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the callback that should be invoked to generate encryption keys for encrypting JWT tokens.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return static
|
||||
*/
|
||||
public static function encryptTokensUsing($callback)
|
||||
{
|
||||
static::$tokenEncryptionKeyCallback = $callback;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an encryption key for encrypting JWT tokens.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
|
||||
* @return string
|
||||
*/
|
||||
public static function tokenEncryptionKey(Encrypter $encrypter)
|
||||
{
|
||||
return is_callable(static::$tokenEncryptionKeyCallback) ?
|
||||
(static::$tokenEncryptionKeyCallback)($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.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function ignoreRoutes()
|
||||
{
|
||||
static::$registersRoutes = false;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure Passport to not register its migrations.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function ignoreMigrations()
|
||||
{
|
||||
static::$runsMigrations = false;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct Passport to enable cookie serialization.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function withCookieSerialization()
|
||||
{
|
||||
static::$unserializesCookies = true;
|
||||
|
||||
return new static;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct Passport to disable cookie serialization.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function withoutCookieSerialization()
|
||||
{
|
||||
static::$unserializesCookies = false;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
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;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Passport\Bridge\PersonalAccessGrant;
|
||||
use Laravel\Passport\Bridge\RefreshTokenRepository;
|
||||
use Laravel\Passport\Guards\TokenGuard;
|
||||
use Laravel\Passport\Http\Controllers\AuthorizationController;
|
||||
use Lcobucci\JWT\Encoding\JoseEncoder;
|
||||
use Lcobucci\JWT\Parser as ParserContract;
|
||||
use Lcobucci\JWT\Token\Parser;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\CryptKey;
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
||||
use League\OAuth2\Server\Grant\ImplicitGrant;
|
||||
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||
use League\OAuth2\Server\ResourceServer;
|
||||
|
||||
class PassportServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->registerRoutes();
|
||||
$this->registerResources();
|
||||
$this->registerMigrations();
|
||||
$this->registerPublishing();
|
||||
$this->registerCommands();
|
||||
|
||||
$this->deleteCookieOnLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Passport routes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerRoutes()
|
||||
{
|
||||
if (Passport::$registersRoutes) {
|
||||
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 && ! Passport::clientUuids()) {
|
||||
$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');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../resources/views' => base_path('resources/views/vendor/passport'),
|
||||
], 'passport-views');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../config/passport.php' => config_path('passport.php'),
|
||||
], 'passport-config');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Passport Artisan commands.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerCommands()
|
||||
{
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
Console\InstallCommand::class,
|
||||
Console\ClientCommand::class,
|
||||
Console\HashCommand::class,
|
||||
Console\KeysCommand::class,
|
||||
Console\PurgeCommand::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->mergeConfigFrom(__DIR__.'/../config/passport.php', 'passport');
|
||||
|
||||
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();
|
||||
$this->registerResourceServer();
|
||||
$this->registerGuard();
|
||||
|
||||
Passport::authorizationView('passport::authorize');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the authorization server.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerAuthorizationServer()
|
||||
{
|
||||
$this->app->singleton(AuthorizationServer::class, function () {
|
||||
return tap($this->makeAuthorizationServer(), function ($server) {
|
||||
$server->setDefaultScope(Passport::$defaultScope);
|
||||
|
||||
$server->enableGrantType(
|
||||
$this->makeAuthCodeGrant(), Passport::tokensExpireIn()
|
||||
);
|
||||
|
||||
$server->enableGrantType(
|
||||
$this->makeRefreshTokenGrant(), Passport::tokensExpireIn()
|
||||
);
|
||||
|
||||
if (Passport::$passwordGrantEnabled) {
|
||||
$server->enableGrantType(
|
||||
$this->makePasswordGrant(), Passport::tokensExpireIn()
|
||||
);
|
||||
}
|
||||
|
||||
$server->enableGrantType(
|
||||
new PersonalAccessGrant, Passport::personalAccessTokensExpireIn()
|
||||
);
|
||||
|
||||
$server->enableGrantType(
|
||||
new ClientCredentialsGrant, Passport::tokensExpireIn()
|
||||
);
|
||||
|
||||
if (Passport::$implicitGrantEnabled) {
|
||||
$server->enableGrantType(
|
||||
$this->makeImplicitGrant(), Passport::tokensExpireIn()
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure an instance of the Auth Code grant.
|
||||
*
|
||||
* @return \League\OAuth2\Server\Grant\AuthCodeGrant
|
||||
*/
|
||||
protected function makeAuthCodeGrant()
|
||||
{
|
||||
return tap($this->buildAuthCodeGrant(), function ($grant) {
|
||||
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Auth Code grant instance.
|
||||
*
|
||||
* @return \League\OAuth2\Server\Grant\AuthCodeGrant
|
||||
*/
|
||||
protected function buildAuthCodeGrant()
|
||||
{
|
||||
return new AuthCodeGrant(
|
||||
$this->app->make(Bridge\AuthCodeRepository::class),
|
||||
$this->app->make(Bridge\RefreshTokenRepository::class),
|
||||
new DateInterval('PT10M')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure a Refresh Token grant instance.
|
||||
*
|
||||
* @return \League\OAuth2\Server\Grant\RefreshTokenGrant
|
||||
*/
|
||||
protected function makeRefreshTokenGrant()
|
||||
{
|
||||
$repository = $this->app->make(RefreshTokenRepository::class);
|
||||
|
||||
return tap(new RefreshTokenGrant($repository), function ($grant) {
|
||||
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure a Password grant instance.
|
||||
*
|
||||
* @return \League\OAuth2\Server\Grant\PasswordGrant
|
||||
*/
|
||||
protected function makePasswordGrant()
|
||||
{
|
||||
$grant = new PasswordGrant(
|
||||
$this->app->make(Bridge\UserRepository::class),
|
||||
$this->app->make(Bridge\RefreshTokenRepository::class)
|
||||
);
|
||||
|
||||
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
|
||||
|
||||
return $grant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure an instance of the Implicit grant.
|
||||
*
|
||||
* @return \League\OAuth2\Server\Grant\ImplicitGrant
|
||||
*/
|
||||
protected function makeImplicitGrant()
|
||||
{
|
||||
return new ImplicitGrant(Passport::tokensExpireIn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the authorization service instance.
|
||||
*
|
||||
* @return \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
public function makeAuthorizationServer()
|
||||
{
|
||||
return new AuthorizationServer(
|
||||
$this->app->make(Bridge\ClientRepository::class),
|
||||
$this->app->make(Bridge\AccessTokenRepository::class),
|
||||
$this->app->make(Bridge\ScopeRepository::class),
|
||||
$this->makeCryptKey('private'),
|
||||
app('encrypter')->getKey(),
|
||||
Passport::$authorizationServerResponseType
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the client repository.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerClientRepository()
|
||||
{
|
||||
$this->app->singleton(ClientRepository::class, function ($container) {
|
||||
$config = $container->make('config')->get('passport.personal_access_client');
|
||||
|
||||
return new ClientRepository($config['id'] ?? null, $config['secret'] ?? null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the JWT Parser.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerJWTParser()
|
||||
{
|
||||
$this->app->singleton(ParserContract::class, function () {
|
||||
return new Parser(new JoseEncoder);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the resource server.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerResourceServer()
|
||||
{
|
||||
$this->app->singleton(ResourceServer::class, function ($container) {
|
||||
return new ResourceServer(
|
||||
$container->make(Bridge\AccessTokenRepository::class),
|
||||
$this->makeCryptKey('public')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CryptKey instance without permissions check.
|
||||
*
|
||||
* @param string $type
|
||||
* @return \League\OAuth2\Server\CryptKey
|
||||
*/
|
||||
protected function makeCryptKey($type)
|
||||
{
|
||||
$key = str_replace('\\n', "\n", $this->app->make(Config::class)->get('passport.'.$type.'_key') ?? '');
|
||||
|
||||
if (! $key) {
|
||||
$key = 'file://'.Passport::keyPath('oauth-'.$type.'.key');
|
||||
}
|
||||
|
||||
return new CryptKey($key, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the token guard.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerGuard()
|
||||
{
|
||||
Auth::resolved(function ($auth) {
|
||||
$auth->extend('passport', function ($app, $name, array $config) {
|
||||
return tap($this->makeGuard($config), function ($guard) {
|
||||
app()->refresh('request', $guard, 'setRequest');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an instance of the token guard.
|
||||
*
|
||||
* @param array $config
|
||||
* @return \Laravel\Passport\Guards\TokenGuard
|
||||
*/
|
||||
protected function makeGuard(array $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'),
|
||||
$this->app->make('request')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the cookie deletion event handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function deleteCookieOnLogout()
|
||||
{
|
||||
Event::listen(Logout::class, function () {
|
||||
if (Request::hasCookie(Passport::cookie())) {
|
||||
Cookie::queue(Cookie::forget(Passport::cookie()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\UserProvider;
|
||||
|
||||
class PassportUserProvider implements UserProvider
|
||||
{
|
||||
/**
|
||||
* The user provider instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\UserProvider
|
||||
*/
|
||||
protected $provider;
|
||||
|
||||
/**
|
||||
* The user provider name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $providerName;
|
||||
|
||||
/**
|
||||
* Create a new passport user provider.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\UserProvider $provider
|
||||
* @param string $providerName
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(UserProvider $provider, $providerName)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
$this->providerName = $providerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function retrieveById($identifier)
|
||||
{
|
||||
return $this->provider->retrieveById($identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function retrieveByToken($identifier, $token)
|
||||
{
|
||||
return $this->provider->retrieveByToken($identifier, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateRememberToken(Authenticatable $user, $token)
|
||||
{
|
||||
$this->provider->updateRememberToken($user, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function retrieveByCredentials(array $credentials)
|
||||
{
|
||||
return $this->provider->retrieveByCredentials($credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateCredentials(Authenticatable $user, array $credentials)
|
||||
{
|
||||
return $this->provider->validateCredentials($user, $credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the user provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getProviderName()
|
||||
{
|
||||
return $this->providerName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PersonalAccessClient extends Model
|
||||
{
|
||||
/**
|
||||
* The database table used by the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'oauth_personal_access_clients';
|
||||
|
||||
/**
|
||||
* The guarded attributes on the model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* Get all of the authentication codes for the client.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function client()
|
||||
{
|
||||
return $this->belongsTo(Passport::clientModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Lcobucci\JWT\Parser as JwtParser;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use Nyholm\Psr7\Response;
|
||||
use Nyholm\Psr7\ServerRequest;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class PersonalAccessTokenFactory
|
||||
{
|
||||
/**
|
||||
* The authorization server instance.
|
||||
*
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* The client repository instance.
|
||||
*
|
||||
* @var \Laravel\Passport\ClientRepository
|
||||
*/
|
||||
protected $clients;
|
||||
|
||||
/**
|
||||
* The token repository instance.
|
||||
*
|
||||
* @var \Laravel\Passport\TokenRepository
|
||||
*/
|
||||
protected $tokens;
|
||||
|
||||
/**
|
||||
* The JWT token parser instance.
|
||||
*
|
||||
* @var \Lcobucci\JWT\Parser
|
||||
*/
|
||||
protected $jwt;
|
||||
|
||||
/**
|
||||
* Create a new personal access token factory instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\AuthorizationServer $server
|
||||
* @param \Laravel\Passport\ClientRepository $clients
|
||||
* @param \Laravel\Passport\TokenRepository $tokens
|
||||
* @param \Lcobucci\JWT\Parser $jwt
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AuthorizationServer $server,
|
||||
ClientRepository $clients,
|
||||
TokenRepository $tokens,
|
||||
JwtParser $jwt)
|
||||
{
|
||||
$this->jwt = $jwt;
|
||||
$this->tokens = $tokens;
|
||||
$this->server = $server;
|
||||
$this->clients = $clients;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new personal access token.
|
||||
*
|
||||
* @param mixed $userId
|
||||
* @param string $name
|
||||
* @param array $scopes
|
||||
* @return \Laravel\Passport\PersonalAccessTokenResult
|
||||
*/
|
||||
public function make($userId, $name, array $scopes = [])
|
||||
{
|
||||
$response = $this->dispatchRequestToAuthorizationServer(
|
||||
$this->createRequest($this->clients->personalAccessClient(), $userId, $scopes)
|
||||
);
|
||||
|
||||
$token = tap($this->findAccessToken($response), function ($token) use ($userId, $name) {
|
||||
$this->tokens->save($token->forceFill([
|
||||
'user_id' => $userId,
|
||||
'name' => $name,
|
||||
]));
|
||||
});
|
||||
|
||||
return new PersonalAccessTokenResult(
|
||||
$response['access_token'], $token
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a request instance for the given client.
|
||||
*
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @param mixed $userId
|
||||
* @param array $scopes
|
||||
* @return \Psr\Http\Message\ServerRequestInterface
|
||||
*/
|
||||
protected function createRequest($client, $userId, array $scopes)
|
||||
{
|
||||
$secret = Passport::$hashesClientSecrets ? $this->clients->getPersonalAccessClientSecret() : $client->secret;
|
||||
|
||||
return (new ServerRequest('POST', 'not-important'))->withParsedBody([
|
||||
'grant_type' => 'personal_access',
|
||||
'client_id' => $client->getKey(),
|
||||
'client_secret' => $secret,
|
||||
'user_id' => $userId,
|
||||
'scope' => implode(' ', $scopes),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the given request to the authorization server.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @return array
|
||||
*/
|
||||
protected function dispatchRequestToAuthorizationServer(ServerRequestInterface $request)
|
||||
{
|
||||
return json_decode($this->server->respondToAccessTokenRequest(
|
||||
$request, new Response
|
||||
)->getBody()->__toString(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token instance for the parsed response.
|
||||
*
|
||||
* @param array $response
|
||||
* @return \Laravel\Passport\Token
|
||||
*/
|
||||
public function findAccessToken(array $response)
|
||||
{
|
||||
return $this->tokens->find(
|
||||
$this->jwt->parse($response['access_token'])->claims()->get('jti')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Jsonable;
|
||||
|
||||
class PersonalAccessTokenResult implements Arrayable, Jsonable
|
||||
{
|
||||
/**
|
||||
* The access token.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $accessToken;
|
||||
|
||||
/**
|
||||
* The token model instance.
|
||||
*
|
||||
* @var \Laravel\Passport\Token
|
||||
*/
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* Create a new result instance.
|
||||
*
|
||||
* @param string $accessToken
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($accessToken, $token)
|
||||
{
|
||||
$this->token = $token;
|
||||
$this->accessToken = $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'accessToken' => $this->accessToken,
|
||||
'token' => $this->token,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to its JSON representation.
|
||||
*
|
||||
* @param int $options
|
||||
* @return string
|
||||
*/
|
||||
public function toJson($options = 0)
|
||||
{
|
||||
return json_encode($this->toArray(), $options);
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class RefreshToken extends Model
|
||||
{
|
||||
/**
|
||||
* The database table used by the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'oauth_refresh_tokens';
|
||||
|
||||
/**
|
||||
* The "type" of the primary key ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $keyType = 'string';
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
/**
|
||||
* The guarded attributes on the model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'revoked' => 'bool',
|
||||
'expires_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* Get the access token that the refresh token belongs to.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function accessToken()
|
||||
{
|
||||
return $this->belongsTo(Passport::tokenModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke the token instance.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function revoke()
|
||||
{
|
||||
return $this->forceFill(['revoked' => true])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the token is a transient JWT token.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function transient()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
class RefreshTokenRepository
|
||||
{
|
||||
/**
|
||||
* Creates a new refresh token.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return \Laravel\Passport\RefreshToken
|
||||
*/
|
||||
public function create($attributes)
|
||||
{
|
||||
return Passport::refreshToken()->create($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a refresh token by the given ID.
|
||||
*
|
||||
* @param string $id
|
||||
* @return \Laravel\Passport\RefreshToken
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
return Passport::refreshToken()->where('id', $id)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given token instance.
|
||||
*
|
||||
* @param \Laravel\Passport\RefreshToken $token
|
||||
* @return void
|
||||
*/
|
||||
public function save(RefreshToken $token)
|
||||
{
|
||||
$token->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes the refresh token.
|
||||
*
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function revokeRefreshToken($id)
|
||||
{
|
||||
return Passport::refreshToken()->where('id', $id)->update(['revoked' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes refresh tokens by access token id.
|
||||
*
|
||||
* @param string $tokenId
|
||||
* @return mixed
|
||||
*/
|
||||
public function revokeRefreshTokensByAccessTokenId($tokenId)
|
||||
{
|
||||
return Passport::refreshToken()->where('access_token_id', $tokenId)->update(['revoked' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the refresh token has been revoked.
|
||||
*
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*/
|
||||
public function isRefreshTokenRevoked($id)
|
||||
{
|
||||
if ($token = $this->find($id)) {
|
||||
return $token->revoked;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
trait ResolvesInheritedScopes
|
||||
{
|
||||
/**
|
||||
* Resolve all possible scopes.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return array
|
||||
*/
|
||||
protected function resolveInheritedScopes($scope)
|
||||
{
|
||||
$parts = explode(':', $scope);
|
||||
|
||||
$partsCount = count($parts);
|
||||
|
||||
$scopes = [];
|
||||
|
||||
for ($i = 1; $i <= $partsCount; $i++) {
|
||||
$scopes[] = implode(':', array_slice($parts, 0, $i));
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Jsonable;
|
||||
|
||||
class Scope implements Arrayable, Jsonable
|
||||
{
|
||||
/**
|
||||
* The name / ID of the scope.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The scope description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* Create a new scope instance.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $description
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($id, $description)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'description' => $this->description,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to its JSON representation.
|
||||
*
|
||||
* @param int $options
|
||||
* @return string
|
||||
*/
|
||||
public function toJson($options = 0)
|
||||
{
|
||||
return json_encode($this->toArray(), $options);
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Token extends Model
|
||||
{
|
||||
use ResolvesInheritedScopes;
|
||||
|
||||
/**
|
||||
* The database table used by the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'oauth_access_tokens';
|
||||
|
||||
/**
|
||||
* The "type" of the primary key ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $keyType = 'string';
|
||||
|
||||
/**
|
||||
* Indicates if the IDs are auto-incrementing.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $incrementing = false;
|
||||
|
||||
/**
|
||||
* The guarded attributes on the model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'scopes' => 'array',
|
||||
'revoked' => 'bool',
|
||||
'expires_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the client that the token belongs to.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function client()
|
||||
{
|
||||
return $this->belongsTo(Passport::clientModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that the token belongs to.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
$provider = config('auth.guards.api.provider');
|
||||
|
||||
$model = config('auth.providers.'.$provider.'.model');
|
||||
|
||||
return $this->belongsTo($model, 'user_id', (new $model)->getKeyName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the token has a given scope.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return bool
|
||||
*/
|
||||
public function can($scope)
|
||||
{
|
||||
if (in_array('*', $this->scopes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$scopes = Passport::$withInheritedScopes
|
||||
? $this->resolveInheritedScopes($scope)
|
||||
: [$scope];
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
if (array_key_exists($scope, array_flip($this->scopes))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the token is missing a given scope.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return bool
|
||||
*/
|
||||
public function cant($scope)
|
||||
{
|
||||
return ! $this->can($scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke the token instance.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function revoke()
|
||||
{
|
||||
return $this->forceFill(['revoked' => true])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the token is a transient JWT token.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function transient()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
class TokenRepository
|
||||
{
|
||||
/**
|
||||
* Creates a new Access Token.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return \Laravel\Passport\Token
|
||||
*/
|
||||
public function create($attributes)
|
||||
{
|
||||
return Passport::token()->create($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a token by the given ID.
|
||||
*
|
||||
* @param string $id
|
||||
* @return \Laravel\Passport\Token
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
return Passport::token()->where('id', $id)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a token by the given user ID and token ID.
|
||||
*
|
||||
* @param string $id
|
||||
* @param int $userId
|
||||
* @return \Laravel\Passport\Token|null
|
||||
*/
|
||||
public function findForUser($id, $userId)
|
||||
{
|
||||
return Passport::token()->where('id', $id)->where('user_id', $userId)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token instances for the given user ID.
|
||||
*
|
||||
* @param mixed $userId
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function forUser($userId)
|
||||
{
|
||||
return Passport::token()->where('user_id', $userId)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a valid token instance for the given user and client.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @return \Laravel\Passport\Token|null
|
||||
*/
|
||||
public function getValidToken($user, $client)
|
||||
{
|
||||
return $client->tokens()
|
||||
->whereUserId($user->getAuthIdentifier())
|
||||
->where('revoked', 0)
|
||||
->where('expires_at', '>', Carbon::now())
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the given token instance.
|
||||
*
|
||||
* @param \Laravel\Passport\Token $token
|
||||
* @return void
|
||||
*/
|
||||
public function save(Token $token)
|
||||
{
|
||||
$token->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an access token.
|
||||
*
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function revokeAccessToken($id)
|
||||
{
|
||||
return Passport::token()->where('id', $id)->update(['revoked' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the access token has been revoked.
|
||||
*
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*/
|
||||
public function isAccessTokenRevoked($id)
|
||||
{
|
||||
if ($token = $this->find($id)) {
|
||||
return $token->revoked;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a valid token for the given user and client.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Authenticatable $user
|
||||
* @param \Laravel\Passport\Client $client
|
||||
* @return \Laravel\Passport\Token|null
|
||||
*/
|
||||
public function findValidToken($user, $client)
|
||||
{
|
||||
return $client->tokens()
|
||||
->whereUserId($user->getAuthIdentifier())
|
||||
->where('revoked', 0)
|
||||
->where('expires_at', '>', Carbon::now())
|
||||
->latest('expires_at')
|
||||
->first();
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Laravel\Passport;
|
||||
|
||||
class TransientToken
|
||||
{
|
||||
/**
|
||||
* Determine if the token has a given scope.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return bool
|
||||
*/
|
||||
public function can($scope)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the token is missing a given scope.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return bool
|
||||
*/
|
||||
public function cant($scope)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the token is a transient JWT token.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function transient()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
providers:
|
||||
- Laravel\Passport\PassportServiceProvider
|
||||
|
||||
migrations: true
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Workbench\App\Models;
|
||||
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Passport\HasApiTokens;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Workbench\Database\Factories;
|
||||
|
||||
use Workbench\App\Models\User;
|
||||
|
||||
/**
|
||||
* @template TModel of \Workbench\App\Models\User
|
||||
*
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<TModel>
|
||||
*/
|
||||
class UserFactory extends \Orchestra\Testbench\Factories\UserFactory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var class-string<\TModel>
|
||||
*/
|
||||
protected $model = User::class;
|
||||
}
|
||||
Reference in New Issue
Block a user