Completed
Push — master ( f82a9f...84b7ee )
by Alexander
03:23
created

Impersonate::handle()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 34
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 7.0071

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 18
cts 19
cp 0.9474
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 21
nc 8
nop 2
crap 7.0071
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 4
    public function __construct(
34
        Guard $guard,
35
        Gate $gate,
36
        Repository $config,
37
        Impersonator $impersonator,
38
        Redirector $redirect
39
    )
40
    {
41 4
        $this->guard        = $guard;
42 4
        $this->gate         = $gate;
43 4
        $this->config       = $config;
44 4
        $this->impersonator = $impersonator;
45 4
        $this->redirect     = $redirect;
46 4
    }
47
48
    /**
49
     * Handle an incoming request.
50
     *
51
     * @throws \HttpException In event of double attempt to impersonate
52
     *
53
     * @param  \Illuminate\Http\Request $request
54
     * @param  \Closure                 $next
55
     *
56
     * @return mixed
57
     */
58 4
    public function handle(Request $request, Closure $next)
59
    {
60 4
        $name = $request->query('_switch_user', null);
61
62 4
        if (null !== $name) {
63 4
            $this->checkPermission($name);
0 ignored issues
show
Bug introduced by
It seems like $name defined by $request->query('_switch_user', null) on line 60 can also be of type array; however, Scif\LaravelPretend\Midd...nate::checkPermission() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
64
65 3
            if ('_exit' === $name) {
66 1
                $this->impersonator->exitImpersonation();
67
            } else {
68 3
                if ($this->impersonator->isImpersonated()) {
69
                    abort(403, 'Cannot use impersonation once you already done that');
70
                }
71
72 3
                $this->impersonator->enterImpersonation($name);
0 ignored issues
show
Bug introduced by
It seems like $name defined by $request->query('_switch_user', null) on line 60 can also be of type array; however, Scif\LaravelPretend\Serv...r::enterImpersonation() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
73
            }
74
75 1
            if (!$request->isXmlHttpRequest() && $request->isMethod('GET')) {
76 1
                $input = $request->input();
77 1
                unset($input['_switch_user']);
78 1
                $input += $request->route()->parameters();
79
80 1
                return $this->redirect->route(
81 1
                    $request->route()->getName(),
82
                    $input
83
                );
84
            }
85 1
        } elseif ($this->impersonator->isImpersonated()) {
86 1
            $this->checkPermission($this->impersonator->getImpersonatingIdentifier());
87 1
            $this->impersonator->continueImpersonation();
88
        }
89
90 1
        return $next($request);
91
    }
92
93
    /**
94
     * @throws \HttpException In event of lack required abilities will be throw 403 exception
95
     *
96
     * @param string $username Username of impersonable user
97
     */
98 4
    protected function checkPermission(string $username)
99
    {
100 4
        $ability  = $this->config->get('pretend.impersonate.auth_check');
101
102 4
        if (!$this->gate->has($ability)) {
103
104
            $this->gate->define($ability, function ($user): bool {
105
                if (!$user instanceof Impersonable) {
106
                    return false;
107
                }
108
109
                return $user->canImpersonate();
110
            });
111
        }
112
113 4
        if (!$this->gate->forUser($this->guard->user())->check($ability, [ $username] )) {
114 1
            abort(403, "Current user have no ability '{$ability}'");
115
        }
116 3
    }
117
}
118