Completed
Pull Request — master (#100)
by
unknown
01:13
created

ImpersonateManager::extractAuthCookieFromSession()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace Lab404\Impersonate\Services;
4
5
use Exception;
6
use Illuminate\Database\Eloquent\ModelNotFoundException;
7
use Illuminate\Foundation\Application;
8
use Lab404\Impersonate\Events\LeaveImpersonation;
9
use Lab404\Impersonate\Events\TakeImpersonation;
10
11
class ImpersonateManager
12
{
13
    const REMEMBER_PREFIX = 'remember_web';
14
15
    /** @var Application $app */
16
    private $app;
17
    /**
18
     * Authentication manager
19
     * @var
20
     */
21
    private $auth;
22
    /** @var string $token */
23
    private $token;
24
25
    public function __construct(Application $app)
26
    {
27
        $this->app = $app;
28
        $this->auth = $app['auth'];
29
    }
30
31
    /**
32
     * @param int $id
33
     * @return \Illuminate\Contracts\Auth\Authenticatable
34
     * @throws Exception
35
     */
36
    public function findUserById($id, $guardName = null)
37
    {
38
        if (empty($guardName)) {
39
            $guardName = $this->app['config']->get('auth.default.guard', 'web');
40
        }
41
42
        $providerName = $this->app['config']->get("auth.guards.$guardName.provider");
43
        $userProvider = $this->auth->createUserProvider($providerName);
44
45
        if (!($modelInstance = $userProvider->retrieveById($id))) {
46
            $model = $this->app['config']->get("auth.providers.$providerName.model");
47
48
            throw (new ModelNotFoundException())->setModel(
49
                $model,
50
                $id
51
            );
52
        }
53
54
        return $modelInstance;
55
    }
56
57
    public function isImpersonating(): bool
58
    {
59
        return session()->has($this->getSessionKey());
60
    }
61
62
    /**
63
     * @return  int|null
64
     */
65
    public function getImpersonatorId()
66
    {
67
        return session($this->getSessionKey(), null);
68
    }
69
70
    /**
71
     * @return \Illuminate\Contracts\Auth\Authenticatable
72
     */
73
    public function getImpersonator()
74
    {
75
        $id = session($this->getSessionKey(), null);
76
77
        return is_null($id) ? null : $this->findUserById($id);
78
    }
79
80
    /**
81
     * @return string|null
82
     */
83
    public function getImpersonatorGuardName()
84
    {
85
        return session($this->getSessionGuard(), null);
86
    }
87
88
    /**
89
     * @return string|null
90
     */
91
    public function getImpersonatorGuardUsingName()
92
    {
93
        return session($this->getSessionGuardUsing(), null);
94
    }
95
96
    /**
97
     * @param \Illuminate\Contracts\Auth\Authenticatable $from
98
     * @param \Illuminate\Contracts\Auth\Authenticatable $to
99
     * @param string|null                         $guardName
100
     * @return bool
101
     */
102
    public function take($from, $to, $guardName = null)
103
    {
104
        // Оно нам тут нужно?
105
//        $this->saveAuthCookieInSession();
106
107
        try {
108
            $this->auth->customClaims([
109
                $this->getSessionKey() => $from->getKey(),
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Authenticatable as the method getKey() does only exist in the following implementations of said interface: Illuminate\Foundation\Auth\User.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
110
                $this->getSessionGuard() => $this->getCurrentAuthGuardName(),
111
                $this->getSessionGuardUsing() => $guardName,
112
            ]);
113
114
            $this->auth->guard($this->getCurrentAuthGuardName())->quietLogout();
115
            $this->token = $this->auth->login($to);
116
            $this->auth->setToken($this->token);
117
        } catch (\Exception $e) {
118
            unset($e);
119
            return false;
120
        }
121
122
        $this->app['events']->dispatch(new TakeImpersonation($from, $to));
123
124
        return true;
125
    }
126
127
    public function leave(): bool
128
    {
129
        try {
130
            $impersonated = $this->auth->guard($this->getImpersonatorGuardUsingName())->user();
131
            $impersonator = $this->findUserById($this->getImpersonatorId(), $this->getImpersonatorGuardName());
132
133
            $this->auth->guard($this->getCurrentAuthGuardName())->quietLogout();
134
            $this->auth->guard($this->getImpersonatorGuardName())->quietLogin($impersonator);
135
136
            $this->extractAuthCookieFromSession();
0 ignored issues
show
Bug introduced by
The method extractAuthCookieFromSession() does not seem to exist on object<Lab404\Impersonat...ces\ImpersonateManager>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
137
138
            $this->clear();
139
140
        } catch (\Exception $e) {
141
            unset($e);
142
            return false;
143
        }
144
145
        $this->app['events']->dispatch(new LeaveImpersonation($impersonator, $impersonated));
146
147
        return true;
148
    }
149
150
    public function clear()
151
    {
152
        $this->auth->customClaims([
153
            $this->getSessionKey() => null,
154
            $this->getSessionGuard() => null,
155
            $this->getSessionGuardUsing() => null,
156
        ]);
157
    }
158
159
    public function getSessionKey(): string
160
    {
161
        return config('laravel-impersonate.session_key');
162
    }
163
164
    public function getSessionGuard(): string
165
    {
166
        return config('laravel-impersonate.session_guard');
167
    }
168
169
    public function getSessionGuardUsing(): string
170
    {
171
        return config('laravel-impersonate.session_guard_using');
172
    }
173
174
    public function getDefaultSessionGuard(): string
175
    {
176
        return config('laravel-impersonate.default_impersonator_guard');
177
    }
178
179
    public function getTakeRedirectTo(): string
180
    {
181
        try {
182
            $uri = config('laravel-impersonate.take_redirect_to') . '?' . http_build_query(['token' => $this->token]);
183
        } catch (\InvalidArgumentException $e) {
184
            $uri = config('laravel-impersonate.take_redirect_to') . '?' . http_build_query(['token' => $this->token]);
185
        }
186
187
        return $uri;
188
    }
189
190
    public function getLeaveRedirectTo(): string
191
    {
192
        try {
193
            $uri = route(config('laravel-impersonate.leave_redirect_to'));
194
        } catch (\InvalidArgumentException $e) {
195
            $uri = config('laravel-impersonate.leave_redirect_to');
196
        }
197
198
        return $uri;
199
    }
200
201
    /**
202
     * @return array|null
203
     */
204
    public function getCurrentAuthGuardName()
205
    {
206
        $guards = array_keys(config('auth.guards'));
207
208
        foreach ($guards as $guard) {
209
            if ($this->auth->guard($guard)->check()) {
210
                return $guard;
211
            }
212
        }
213
214
        return null;
215
    }
216
217
//    protected function saveAuthCookieInSession(): void
218
//    {
219
//        $cookie = $this->findByKeyInArray($this->app['request']->cookies->all(), static::REMEMBER_PREFIX);
220
//        $key = $cookie->keys()->first();
221
//        $val = $cookie->values()->first();
222
//
223
//        if (!$key || !$val) {
224
//            return;
225
//        }
226
//
227
//        session()->put(static::REMEMBER_PREFIX, [
228
//            $key,
229
//            $val,
230
//        ]);
231
//    }
232
//
233
//    protected function extractAuthCookieFromSession(): void
234
//    {
235
//        if (!$session = $this->findByKeyInArray(session()->all(), static::REMEMBER_PREFIX)->first()) {
236
//            return;
237
//        }
238
//
239
//        $this->app['cookie']->queue($session[0], $session[1]);
240
//        session()->forget($session);
241
//    }
242
//
243
//    /**
244
//     * @param array  $values
245
//     * @param string $search
246
//     * @return \Illuminate\Support\Collection
247
//     */
248
//    protected function findByKeyInArray(array $values, string $search)
249
//    {
250
//        return collect($values ?? session()->all())
251
//            ->filter(function ($val, $key) use ($search) {
252
//                return strpos($key, $search) !== false;
253
//            });
254
//    }
255
}
256