├── .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 | [](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 | [](https://github.styleci.io/repos/94622194)
5 | [](https://packagist.org/packages/laravel-enso/impersonate)
6 | [](https://packagist.org/packages/laravel-enso/impersonate)
7 | [](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 | [](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 |
--------------------------------------------------------------------------------