Passed
Push — master ( e30fd8...99d70b )
by
unknown
03:04
created

TokenGuard::domain()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 9
rs 10
1
<?php
2
3
namespace Slides\Connector\Auth;
4
5
use Illuminate\Http\Request;
6
use Illuminate\Auth\GuardHelpers;
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Facades\Cookie;
9
use Illuminate\Contracts\Auth\UserProvider;
10
11
/**
12
 * Class TokenGuard
13
 *
14
 * @package App\Auth
15
 */
16
class TokenGuard implements \Illuminate\Contracts\Auth\Guard
17
{
18
    use GuardHelpers;
19
20
    /**
21
     * @var Request
22
     */
23
    protected $request;
24
25
    /**
26
     * @var Client
27
     */
28
    protected $client;
29
30
    /**
31
     * @var AuthService
32
     */
33
    protected $authService;
34
35
    /**
36
     * The name of cookie parameter where bearer token stores.
37
     *
38
     * @var string
39
     */
40
    protected $authCookie;
41
42
    /**
43
     * The JWT token
44
     *
45
     * @var string
46
     */
47
    protected $token;
48
49
    /**
50
     * The last error message.
51
     *
52
     * @var string
53
     */
54
    protected $lastError;
55
56
    /**
57
     * TokenGuard constructor.
58
     *
59
     * @param UserProvider $provider
60
     * @param Request $request
61
     * @param AuthService $authService
62
     * @param Client|null $client
63
     */
64
    public function __construct(
65
        UserProvider $provider,
66
        Request $request,
67
        AuthService $authService,
68
        Client $client = null
69
    )
70
    {
71
        $this->provider = $provider;
72
        $this->request = $request;
73
        $this->authService = $authService;
74
75
        $this->client = $client ?? new Client();
76
        $this->authCookie = env('APP_AUTH_COOKIE', 'authKey');
77
    }
78
79
    /**
80
     * Authenticate a user.
81
     *
82
     * @param string $email
83
     * @param string $password
84
     * @param bool $remember
85
     *
86
     * @return mixed
87
     *
88
     * @throws
89
     */
90
    public function login(string $email, string $password, bool $remember = false)
91
    {
92
        $response = $this->client->request('login', compact('email', 'password', 'remember'));
93
94
        if(!$this->client->success(true)) {
95
            $this->lastError = Arr::get($response, 'message');
96
            return false;
97
        }
98
99
        if(!$this->token = $this->client->getToken()) {
100
            return false;
101
        }
102
103
        $this->storeToken($this->token);
104
105
        return $this->token;
106
    }
107
108
    /**
109
     * Authenticate a user without the password.
110
     *
111
     * Warning! This method has implemented temporarily to make able to login users
112
     * who use Social Auth on 24Templates. MUST NOT be used in any other cases.
113
     *
114
     * @param string $email
115
     * @param string $password
116
     * @param bool $remember
117
     *
118
     * @return mixed
119
     *
120
     * @throws
121
     */
122
    public function unsafeLogin(string $email, bool $remember = false)
123
    {
124
        $this->client->request('unsafeLogin', compact('email', 'remember'));
125
126
        if(!$this->client->success()) {
127
            return false;
128
        }
129
130
        if(!$this->token = $this->client->getToken()) {
131
            return false;
132
        }
133
134
        $this->storeToken($this->token);
135
136
        return $this->token;
137
    }
138
139
    /**
140
     * Get the currently authenticated user.
141
     *
142
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
143
     */
144
    public function user()
145
    {
146
        // If we've already retrieved the user for the current request we can just
147
        // return it back immediately. We do not want to fetch the user data on
148
        // every call to this method because that would be tremendously slow.
149
        if (! is_null($this->user)) {
150
            return $this->user;
151
        }
152
153
        $user = null;
154
155
        if($token = $this->token()) {
156
            $user = $this->retrieveUserFromToken($token);
157
        }
158
159
        return $this->user = $user;
160
    }
161
162
    /**
163
     * Get the token for the current request.
164
     *
165
     * @return string|null
166
     */
167
    public function token()
168
    {
169
        if($this->token) {
170
            return $this->token;
171
        }
172
173
        $token = $this->request->cookie($this->authCookie);
174
175
        if (empty($token)) {
176
            $token = $this->request->bearerToken();
177
        }
178
179
        return $this->token = $token;
0 ignored issues
show
Documentation Bug introduced by
It seems like $token can also be of type array. However, the property $token is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
180
    }
181
182
    /**
183
     * Validate a user's credentials.
184
     *
185
     * @param  array  $credentials
186
     * @return bool
187
     */
188
    public function validate(array $credentials = [])
189
    {
190
        return true;
191
    }
192
193
    /**
194
     * Store a token
195
     *
196
     * @param string $token
197
     */
198
    private function storeToken(string $token)
199
    {
200
        $cookie = cookie()->forever($this->authCookie, $token, null, $this->domain());
201
202
        Cookie::queue($cookie);
203
    }
204
205
    /**
206
     * Retrieve a user model from the parsed JWT token.
207
     *
208
     * @param string $token
209
     *
210
     * @return \Illuminate\Contracts\Auth\Authenticatable|\Illuminate\Database\Query\Builder|null
211
     */
212
    private function retrieveUserFromToken(string $token)
213
    {
214
        try
215
        {
216
            $data = (array) \Firebase\JWT\JWT::decode($token, env('JWT_SECRET'), ['HS256']);
217
        }
218
        catch(\RuntimeException $e) {
219
            $this->logout();
220
221
            return null;
222
        }
223
224
        if(!$userId = Arr::get($data, 'userId')) {
225
            return null;
226
        }
227
228
        return $this->provider->retrieveByCredentials(['remote_id' => $userId]);
229
    }
230
231
    /**
232
     * Invalidate a cookie
233
     *
234
     * @return void
235
     */
236
    public function logout()
237
    {
238
        Cookie::queue(Cookie::forget($this->authCookie, null, $this->domain()));
239
    }
240
241
    /**
242
     * Get last error message from the server.
243
     *
244
     * @return string|null
245
     */
246
    public function getLastError(): ?string
247
    {
248
        return $this->lastError;
249
    }
250
251
    /**
252
     * Retrieve current domain
253
     *
254
     * @return string
255
     */
256
    protected function domain(): string
257
    {
258
        $parts = explode('.', $host = request()->getHost());
259
260
        if (count($parts) < 2) {
261
            return $host;
262
        }
263
264
        return $parts[count($parts) - 2] . '.' . last($parts);
265
    }
266
}