diff --git a/backend/app/Http/Controllers/AuthController.php b/backend/app/Http/Controllers/AuthController.php index 9679548..11dbd6e 100644 --- a/backend/app/Http/Controllers/AuthController.php +++ b/backend/app/Http/Controllers/AuthController.php @@ -62,11 +62,32 @@ class AuthController extends Controller public function me(Request $request) { + $impersonateManager = app('impersonate'); return [ ...$request->user()->toArray(), "permissions" => array_map(function($p) { return $p["name"]; }, $request->user()->allPermissions()->toArray()), + "impersonating_user" => $impersonateManager->isImpersonating(), + "impersonator_id" => $impersonateManager->getImpersonatorId() ]; } + + public function impersonate(Request $request, $user) + { + $impersonatedUser = User::find($user); + $request->user()->impersonate($impersonatedUser); + $token = $impersonatedUser->createToken('auth_token')->plainTextToken; + + return response()->json([ + 'access_token' => $token, + 'token_type' => 'Bearer', + ]); + } + + public function stopImpersonating(Request $request) + { + $request->user()->leaveImpersonation(); + return; + } } diff --git a/backend/app/Models/User.php b/backend/app/Models/User.php index 1f538ea..c10f7a7 100644 --- a/backend/app/Models/User.php +++ b/backend/app/Models/User.php @@ -8,10 +8,12 @@ use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; use Laratrust\Traits\LaratrustUserTrait; +use Lab404\Impersonate\Models\Impersonate; class User extends Authenticatable { use LaratrustUserTrait; + use Impersonate; use HasApiTokens, HasFactory, Notifiable; /** @@ -55,4 +57,20 @@ class User extends Authenticatable 'email_verified_at' => 'datetime', 'last_access' => 'datetime', ]; + + /** + * @return bool + */ + public function canImpersonate() + { + return $this->hasPermission("users-impersonate"); + } + + /** + * @return bool + */ + public function canBeImpersonated() + { + return !$this->hasPermission("users-impersonate"); + } } diff --git a/backend/app/Providers/EventServiceProvider.php b/backend/app/Providers/EventServiceProvider.php index 2d65aac..1754aa6 100644 --- a/backend/app/Providers/EventServiceProvider.php +++ b/backend/app/Providers/EventServiceProvider.php @@ -25,7 +25,18 @@ class EventServiceProvider extends ServiceProvider */ public function boot(): void { - // + Event::listen( + \Lab404\Impersonate\Events\TakeImpersonation::class, + function (\Lab404\Impersonate\Events\TakeImpersonation $event) { + session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword()); + } + ); + Event::listen( + \Lab404\Impersonate\Events\LeaveImpersonation::class, + function (\Lab404\Impersonate\Events\LeaveImpersonation $event) { + session()->put('password_hash_sanctum', $event->impersonator->getAuthPassword()); + } + ); } /** diff --git a/backend/composer.json b/backend/composer.json index fb60bc9..fc0a09a 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^8.1", "guzzlehttp/guzzle": "^7.2", + "lab404/laravel-impersonate": "^1.7", "laravel/framework": "^10.0", "laravel/sanctum": "^3.2", "laravel/tinker": "^2.8", diff --git a/backend/composer.lock b/backend/composer.lock index ce162fc..76ce803 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b5d89cfe094ee5746cee5265ecab952d", + "content-hash": "c1b31b310ab296e893ef90608cd91a72", "packages": [ { "name": "brick/math", @@ -780,16 +780,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.4.3", + "version": "2.4.5", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "67c26b443f348a51926030c83481b85718457d3d" + "reference": "0454e12ef0cd597ccd2adb036f7bda4e7fface66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d", - "reference": "67c26b443f348a51926030c83481b85718457d3d", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/0454e12ef0cd597ccd2adb036f7bda4e7fface66", + "reference": "0454e12ef0cd597ccd2adb036f7bda4e7fface66", "shasum": "" }, "require": { @@ -815,9 +815,6 @@ "bamarni-bin": { "bin-links": true, "forward-command": false - }, - "branch-alias": { - "dev-master": "2.4-dev" } }, "autoload": { @@ -879,7 +876,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.4.3" + "source": "https://github.com/guzzle/psr7/tree/2.4.5" }, "funding": [ { @@ -895,7 +892,7 @@ "type": "tidelift" } ], - "time": "2022-10-26T14:07:24+00:00" + "time": "2023-04-17T16:00:45+00:00" }, { "name": "guzzlehttp/uri-template", @@ -1031,6 +1028,74 @@ }, "time": "2022-03-02T17:32:19+00:00" }, + { + "name": "lab404/laravel-impersonate", + "version": "1.7.4", + "source": { + "type": "git", + "url": "https://github.com/404labfr/laravel-impersonate.git", + "reference": "d8ab69f05daab4117b313e11ca007fbf3199a1ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/404labfr/laravel-impersonate/zipball/d8ab69f05daab4117b313e11ca007fbf3199a1ab", + "reference": "d8ab69f05daab4117b313e11ca007fbf3199a1ab", + "shasum": "" + }, + "require": { + "laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0", + "php": "^7.2 | ^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.3", + "orchestra/database": "^4.0 | ^5.0 | ^6.0 | ^7.0 | ^8.0", + "orchestra/testbench": "^4.0 | ^5.0 | ^6.0 | ^7.0 | ^8.0", + "phpunit/phpunit": "^7.5 | ^8.0 | ^9.0 | ^10.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Lab404\\Impersonate\\ImpersonateServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Lab404\\Impersonate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marceau Casals", + "email": "marceau@casals.fr" + } + ], + "description": "Laravel Impersonate is a plugin that allows to you to authenticate as your users.", + "keywords": [ + "auth", + "impersonate", + "impersonation", + "laravel", + "laravel-package", + "laravel-plugin", + "package", + "plugin", + "user" + ], + "support": { + "issues": "https://github.com/404labfr/laravel-impersonate/issues", + "source": "https://github.com/404labfr/laravel-impersonate/tree/1.7.4" + }, + "time": "2023-01-25T16:56:05+00:00" + }, { "name": "laravel/framework", "version": "v10.0.3", diff --git a/backend/config/app.php b/backend/config/app.php index 04994fe..1f40070 100644 --- a/backend/config/app.php +++ b/backend/config/app.php @@ -185,6 +185,7 @@ return [ /* * Package Service Providers... */ + Lab404\Impersonate\ImpersonateServiceProvider::class, /* * Application Service Providers... diff --git a/backend/config/laratrust_seeder.php b/backend/config/laratrust_seeder.php index 4ca2aee..2a6ab17 100644 --- a/backend/config/laratrust_seeder.php +++ b/backend/config/laratrust_seeder.php @@ -13,7 +13,7 @@ return [ 'roles_structure' => [ 'superadmin' => [ - 'users' => 'c,r,u,d', + 'users' => 'c,r,u,d,i', ], 'admin' => [ 'users' => 'c,r,u' @@ -31,6 +31,7 @@ return [ 'lr' => 'limitedRead', 'r' => 'read', 'u' => 'update', - 'd' => 'delete' + 'd' => 'delete', + 'i' => 'impersonate' ] ]; diff --git a/backend/config/laravel-impersonate.php b/backend/config/laravel-impersonate.php new file mode 100644 index 0000000..f1aef8d --- /dev/null +++ b/backend/config/laravel-impersonate.php @@ -0,0 +1,41 @@ + 'impersonated_by', + + /** + * The session key used to stored the original user guard. + */ + 'session_guard' => 'impersonator_guard', + + /** + * The session key used to stored what guard is impersonator using. + */ + 'session_guard_using' => 'impersonator_guard_using', + + /** + * The default impersonator guard used. + */ + 'default_impersonator_guard' => 'web', + + /** + * The URI to redirect after taking an impersonation. + * + * Only used in the built-in controller. + * * Use 'back' to redirect to the previous page + */ + 'take_redirect_to' => '/', + + /** + * The URI to redirect after leaving an impersonation. + * + * Only used in the built-in controller. + * Use 'back' to redirect to the previous page + */ + 'leave_redirect_to' => '/', + +]; diff --git a/backend/routes/api.php b/backend/routes/api.php index 31e96f3..aaadf02 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -22,9 +22,12 @@ use Illuminate\Support\Facades\Artisan; Route::post('/register', [AuthController::class, 'register']); Route::post('/login', [AuthController::class, 'login']); -Route::middleware('auth:sanctum')->group( function () { +Route::middleware('auth:web')->group( function () { Route::get('/me', [AuthController::class, 'me']); Route::post('/me', [AuthController::class, 'me']); + + Route::post('/impersonate/{user}', [AuthController::class, 'impersonate']); + Route::post('/stop_impersonating', [AuthController::class, 'stopImpersonating']); Route::get('/list', [UserController::class, 'index']); diff --git a/frontend/src/app/_components/table/table.component.html b/frontend/src/app/_components/table/table.component.html index 1c626b3..6720d71 100644 --- a/frontend/src/app/_components/table/table.component.html +++ b/frontend/src/app/_components/table/table.component.html @@ -15,8 +15,7 @@