Impersonate::handle()   B
last analyzed

Complexity

Conditions 9
Paths 17

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 9.0051

Importance

Changes 0
Metric Value
dl 0
loc 42
ccs 24
cts 25
cp 0.96
rs 7.6924
c 0
b 0
f 0
cc 9
nc 17
nop 2
crap 9.0051
1
<?php declare(strict_types=1);
2
3
namespace Scif\LaravelPretend\Middleware;
4
5
use Closure;
6
use Illuminate\Contracts\Auth\Access\Gate;
7
use Illuminate\Contracts\Auth\Guard;
8
use Illuminate\Contracts\Config\Repository;
9
use Illuminate\Http\Request;
10
use Illuminate\Routing\Redirector;
11
use Scif\LaravelPretend\Interfaces\Impersonable;
12
use Scif\LaravelPretend\Service\Impersonator;
13
14
class Impersonate
15
{
16
    /** @var Gate $gate */
17
    protected $gate;
18
19
    /** @var Repository $config */
20
    protected $config;
21
22
    /** @var Impersonator $impersonator */
23
    protected $impersonator;
24
25
    /** @var Guard  */
26
    protected $guard;
27
28
    /** @var Redirector */
29
    protected $redirect;
30
31
    const SESSION_NAME = 'pretend:_switch_user';
32
33 7
    public function __construct(
34
        Guard $guard,
35
        Gate $gate,
36
        Repository $config,
37
        Impersonator $impersonator,
38
        Redirector $redirect
39
    ) {
40 7
        $this->guard        = $guard;
41 7
        $this->gate         = $gate;
42 7
        $this->config       = $config;
43 7
        $this->impersonator = $impersonator;
44 7
        $this->redirect     = $redirect;
45 7
    }
46
47
    /**
48
     * Handle an incoming request.
49
     *
50
     * @throws \HttpException In event of double attempt to impersonate
51
     *
52
     * @param  \Illuminate\Http\Request $request
53
     * @param  \Closure                 $next
54
     *
55
     * @return mixed
56
     */
57 7
    public function handle(Request $request, Closure $next)
58
    {
59 7
        if ($this->guard->guest()) {
60
            return $next($request);
61
        }
62
63
        /** @var string $name */
64 7
        $name = $request->query('_switch_user', null);
65 7
        $allMiddlewares = $request->route()->gatherMiddleware();
66
67 7
        if (in_array(ForbidImpersonation::class, $allMiddlewares, true)) {
68 1
            abort(403, 'This route is forbidden to access as impersonated user');
69
        }
70
71 6
        if (null !== $name) {
72 6
            $this->checkPermission($name);
73
74 5
            if ('_exit' === $name) {
75 2
                $this->impersonator->exitImpersonation();
76 4
            } elseif ($this->impersonator->isImpersonated()) {
77 1
                    abort(403, 'Cannot use impersonation once you already done that');
78
            } else {
79 4
                $this->impersonator->enterImpersonation($name);
80
            }
81
82 3
            if (!$request->isXmlHttpRequest() && $request->isMethod('GET')) {
83 3
                $input = $request->input();
84 3
                unset($input['_switch_user']);
85 3
                $input += $request->route()->parameters();
86
87 3
                return $this->redirect->route(
88 3
                    $request->route()->getName(),
89 3
                    $input
90
                );
91
            }
92 1
        } elseif ($this->impersonator->isImpersonated()) {
93 1
            $this->checkPermission($this->impersonator->getImpersonatingIdentifier());
94 1
            $this->impersonator->continueImpersonation();
95
        }
96
97 1
        return $next($request);
98
    }
99
100
    /**
101
     * @throws \HttpException In event of lack required abilities will be throw 403 exception
102
     *
103
     * @param string $username Username of impersonable user
104
     */
105 6
    protected function checkPermission(string $username)
106
    {
107 6
        $ability  = $this->config->get('pretend.impersonate.auth_check');
108
109 6
        if (!$this->gate->has($ability)) {
110
111 1
            $this->gate->define($ability, function ($user): bool {
112 1
                if (!$user instanceof Impersonable) {
113 1
                    return false;
114
                }
115
116 1
                return $user->canImpersonate();
117 1
            });
118
        }
119
120
        if (!$this->gate->forUser($this->guard->user())->check($ability, [$username])) {
121
            abort(403, "Current user have no ability '{$ability}'");
122
        }
123
    }
124
}
125