├── .github └── issue_template.md ├── .styleci.yml ├── LICENSE ├── README.md ├── codesize.xml ├── composer.json ├── database └── migrations │ └── 2017_01_01_128500_create_structure_for_impersonate.php ├── routes └── api.php ├── src ├── AppServiceProvider.php ├── AuthServiceProvider.php ├── Dynamics │ └── IsImpersonationg.php ├── Http │ ├── Controllers │ │ ├── Start.php │ │ └── Stop.php │ └── Middleware │ │ └── Impersonate.php └── State │ └── Impersonating.php └── tests └── features └── ImpersonateTest.php /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | 2 | This is a **bug | feature request**. 3 | 4 | 5 | ### Prerequisites 6 | * [ ] Are you running the latest version? 7 | * [ ] Are you reporting to the correct repository? 8 | * [ ] Did you check the documentation? 9 | * [ ] Did you perform a cursory search? 10 | 11 | ### Description 12 | 13 | 14 | ### Steps to Reproduce 15 | 20 | 21 | ### Expected behavior 22 | 23 | 24 | ### Actual behavior 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | risky: true 2 | 3 | preset: laravel 4 | 5 | enabled: 6 | - strict 7 | - unalign_double_arrow 8 | - phpdoc_order 9 | - phpdoc_separation 10 | 11 | disabled: 12 | - short_array_syntax 13 | 14 | finder: 15 | exclude: 16 | - "public" 17 | - "resources" 18 | - "tests" 19 | name: 20 | - "*.php" 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 laravel-enso 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Impersonate 2 | 3 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/a6e7ad3ebd5a46cfb8625d37cb68ad9c)](https://www.codacy.com/gh/laravel-enso/impersonate?utm_source=github.com&utm_medium=referral&utm_content=laravel-enso/impersonate&utm_campaign=Badge_Grade) 4 | [![StyleCI](https://github.styleci.io/repos/94622194/shield?branch=master)](https://github.styleci.io/repos/94622194) 5 | [![License](https://poser.pugx.org/laravel-enso/impersonate/license)](https://packagist.org/packages/laravel-enso/impersonate) 6 | [![Total Downloads](https://poser.pugx.org/laravel-enso/impersonate/downloads)](https://packagist.org/packages/laravel-enso/impersonate) 7 | [![Latest Stable Version](https://poser.pugx.org/laravel-enso/impersonate/version)](https://packagist.org/packages/laravel-enso/impersonate) 8 | 9 | User impersonation dependency for [Laravel Enso](https://github.com/laravel-enso/Enso). 10 | 11 | This package works exclusively within the [Enso](https://github.com/laravel-enso/Enso) ecosystem. 12 | 13 | The front end assets that utilize this api are present in the [ui](https://github.com/enso-ui/ui) package. 14 | 15 | For live examples and demos, you may visit [laravel-enso.com](https://www.laravel-enso.com) 16 | 17 | [![Watch the demo](https://laravel-enso.github.io/impersonate/screenshots/bulma_014_thumb.png)](https://laravel-enso.github.io/impersonate/videos/bulma_how_to_impersonate.webm) 18 | click on the photo to view a short demo in compatible browsers 19 | 20 | ### Installation, Configuration & Usage 21 | 22 | Be sure to check out the full documentation for this package available at [docs.laravel-enso.com](https://docs.laravel-enso.com/backend/impersonate.html) 23 | 24 | ## Contributions 25 | 26 | are welcome. Pull requests are great, but issues are good too. 27 | 28 | ## License 29 | 30 | This package is released under the MIT license. 31 | -------------------------------------------------------------------------------- /codesize.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | custom rules 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-enso/impersonate", 3 | "description": "User impersonation dependency for Laravel Enso", 4 | "keywords": [ 5 | "laravel-enso", 6 | "impersonate", 7 | "impersonate-users" 8 | ], 9 | "homepage": "https://github.com/laravel-enso/impersonate", 10 | "type": "library", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Adrian Ocneanu", 15 | "email": "aocneanu@gmail.com", 16 | "homepage": "https://laravel-enso.com", 17 | "role": "Developer" 18 | } 19 | ], 20 | "require": { 21 | "laravel-enso/core": "^10.0", 22 | "laravel-enso/migrator": "^2.1", 23 | "laravel-enso/dynamic-methods": "^3.0" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "LaravelEnso\\Impersonate\\": "src/" 28 | } 29 | }, 30 | "extra": { 31 | "laravel": { 32 | "providers": [ 33 | "LaravelEnso\\Impersonate\\AppServiceProvider", 34 | "LaravelEnso\\Impersonate\\AuthServiceProvider" 35 | ], 36 | "aliases": [] 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/migrations/2017_01_01_128500_create_structure_for_impersonate.php: -------------------------------------------------------------------------------- 1 | 'core.impersonate.start', 'description' => 'Start impersonating user', 'is_default' => false], 9 | ['name' => 'core.impersonate.stop', 'description' => 'Stop impersonating user', 'is_default' => true], 10 | ]; 11 | }; 12 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | prefix('api/core/impersonate')->as('core.impersonate.') 9 | ->group(function () { 10 | Route::get('stop', Stop::class)->name('stop'); 11 | Route::get('{user}', Start::class)->name('start'); 12 | }); 13 | -------------------------------------------------------------------------------- /src/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | app['router']->aliasMiddleware('impersonate', Impersonate::class); 13 | 14 | $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); 15 | 16 | $this->loadRoutesFrom(__DIR__.'/../routes/api.php'); 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | $user 14 | ->can('access-route', 'core.impersonate.start') 15 | && ! $targetUser->isAdmin() 16 | && $user->id !== $targetUser->id 17 | && ! $user->isImpersonating()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Dynamics/IsImpersonationg.php: -------------------------------------------------------------------------------- 1 | Session::has('impersonating'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Http/Controllers/Start.php: -------------------------------------------------------------------------------- 1 | authorize('impersonate', $user); 17 | 18 | Session::put('impersonating', $user->id); 19 | 20 | return ['message' => __('Impersonating :user', ['user' => $user->person->name])]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Http/Controllers/Stop.php: -------------------------------------------------------------------------------- 1 | forget('impersonating'); 12 | 13 | return ['message' => __('Welcome Back')]; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Http/Middleware/Impersonate.php: -------------------------------------------------------------------------------- 1 | hasSession() && $request->session()->has('impersonating')) { 14 | $provider = Config::get('auth.guards.web.provider'); 15 | $model = Config::get("auth.providers.{$provider}.model"); 16 | $user = $model::find($request->session()->get('impersonating')); 17 | Auth::setUser($user); 18 | 19 | return $next($request); 20 | } 21 | 22 | return $next($request); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/State/Impersonating.php: -------------------------------------------------------------------------------- 1 | seed(); 24 | 25 | $this->guard = 'web'; 26 | } 27 | 28 | /** @test */ 29 | public function can_impersonate() 30 | { 31 | $this->setUpUsers($this->adminRole()); 32 | 33 | $this->get(route('core.impersonate.start', $this->userToImpersonate->id, false)) 34 | ->assertStatus(200) 35 | ->assertSessionHas('impersonating') 36 | ->assertJsonStructure(['message']); 37 | } 38 | 39 | /** @test */ 40 | public function cant_impersonate_if_is_not_allowed() 41 | { 42 | $this->setUpUsers($this->defaultAccessRole()); 43 | 44 | $this->get(route('core.impersonate.start', $this->userToImpersonate->id, false)) 45 | ->assertStatus(403); 46 | } 47 | 48 | /** @test */ 49 | public function cant_impersonate_if_is_impersonating() 50 | { 51 | $this->setUpUsers($this->adminRole()); 52 | 53 | $this->withSession(['impersonating' => $this->userToImpersonate->id]) 54 | ->get(route('core.impersonate.start', $this->userToImpersonate->id, false)) 55 | ->assertStatus(403); 56 | } 57 | 58 | /** @test */ 59 | public function cant_impersonate_self() 60 | { 61 | $this->userToImpersonate = $this->createUser($this->adminRole()); 62 | 63 | $this->loginAs($this->userToImpersonate); 64 | 65 | $this->get(route('core.impersonate.start', $this->userToImpersonate->id, false)) 66 | ->assertStatus(403); 67 | } 68 | 69 | /** @test */ 70 | public function stop_impersonating() 71 | { 72 | $this->setUpUsers($this->adminRole()); 73 | 74 | $this->withSession(['impersonating' => $this->userToImpersonate->id]) 75 | ->get(route('core.impersonate.stop', [], false)) 76 | ->assertSessionMissing('impersonating') 77 | ->assertStatus(200) 78 | ->assertJsonStructure(['message']); 79 | } 80 | 81 | private function setUpUsers(Role $role) 82 | { 83 | $this->impersonator = $this->createUser($role); 84 | $this->userToImpersonate = $this->createUser($role); 85 | $this->loginAs($this->impersonator); 86 | } 87 | 88 | private function adminRole() 89 | { 90 | $role = $this->createRole(); 91 | 92 | $role->permissions() 93 | ->sync(Permission::pluck('id')); 94 | 95 | return $role; 96 | } 97 | 98 | private function defaultAccessRole() 99 | { 100 | $role = $this->createRole(); 101 | 102 | $role->permissions() 103 | ->sync(Permission::implicit()->pluck('id')); 104 | 105 | return $role; 106 | } 107 | 108 | private function createUser($role) 109 | { 110 | return User::factory()->create([ 111 | 'role_id' => $role->id, 112 | 'is_active' => true, 113 | ]); 114 | } 115 | 116 | private function createRole() 117 | { 118 | $menu = Menu::first(['id']); 119 | 120 | return Role::factory()->create([ 121 | 'menu_id' => $menu->id, 122 | ]); 123 | } 124 | 125 | public function loginAs(Authenticatable $user) 126 | { 127 | return $this->actingAs($user, $this->guard); 128 | } 129 | } 130 | --------------------------------------------------------------------------------