• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

valkyrjaio / valkyrja / 15659546660

15 Jun 2025 04:39AM UTC coverage: 47.202% (-0.4%) from 47.589%
15659546660

push

github

MelechMizrachi
Update Config.

5331 of 11294 relevant lines covered (47.2%)

16.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Valkyrja/Auth/Repository/TokenizedRepository.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <melechmizrachi@gmail.com>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13

14
namespace Valkyrja\Auth\Repository;
15

16
use Throwable;
17
use Valkyrja\Auth\Constant\HeaderValue;
18
use Valkyrja\Auth\Entity\Contract\TokenizableUser;
19
use Valkyrja\Auth\Entity\Contract\User;
20
use Valkyrja\Auth\Exception\AuthRuntimeException;
21
use Valkyrja\Auth\Exception\InvalidAuthenticationException;
22
use Valkyrja\Auth\Exception\InvalidCurrentAuthenticationException;
23
use Valkyrja\Auth\Exception\MissingTokenizableUserRequiredFieldsException;
24
use Valkyrja\Auth\Exception\TokenizationException;
25
use Valkyrja\Auth\Model\Contract\AuthenticatedUsers;
26
use Valkyrja\Auth\Repository\Contract\TokenizedRepository as Contract;
27
use Valkyrja\Exception\RuntimeException;
28
use Valkyrja\Http\Message\Constant\HeaderName;
29
use Valkyrja\Http\Message\Request\Contract\ServerRequest;
30

31
use function getType;
32
use function is_string;
33

34
/**
35
 * Abstract Class TokenizedRepository.
36
 *
37
 * @author Melech Mizrachi
38
 *
39
 * @property TokenizableUser               $user
40
 * @property class-string<TokenizableUser> $userEntityName
41
 */
42
abstract class TokenizedRepository extends Repository implements Contract
43
{
44
    /**
45
     * The token.
46
     *
47
     * @var string
48
     */
49
    protected string $token;
50

51
    /**
52
     * @inheritDoc
53
     *
54
     * @throws TokenizationException
55
     */
56
    public function setUser(User $user): static
57
    {
58
        parent::setUser($user);
×
59

60
        $this->resetToken();
×
61

62
        return $this;
×
63
    }
64

65
    /**
66
     * @inheritDoc
67
     *
68
     * @throws TokenizationException
69
     */
70
    public function setUsers(AuthenticatedUsers $users): static
71
    {
72
        parent::setUsers($users);
×
73

74
        $this->resetToken();
×
75

76
        return $this;
×
77
    }
78

79
    /**
80
     * @inheritDoc
81
     *
82
     * @throws TokenizationException
83
     */
84
    public function authenticate(User $user): static
85
    {
86
        parent::authenticate($user);
×
87

88
        $this->resetToken();
×
89

90
        return $this;
×
91
    }
92

93
    /**
94
     * @inheritDoc
95
     *
96
     * @throws Throwable
97
     */
98
    public function authenticateFromSession(): static
99
    {
100
        $token = $this->getTokenFromSession();
×
101

102
        if ($token === null) {
×
103
            throw new AuthRuntimeException('Invalid token provided.');
×
104
        }
105

106
        return $this->authenticateFromToken($token);
×
107
    }
108

109
    /**
110
     * @inheritDoc
111
     *
112
     * @throws Throwable
113
     */
114
    public function authenticateFromRequest(ServerRequest $request): static
115
    {
116
        $token = $this->getTokenFromRequest($request);
×
117

118
        return $this->authenticateFromToken($token);
×
119
    }
120

121
    /**
122
     * @inheritDoc
123
     *
124
     * @throws TokenizationException
125
     */
126
    public function setSession(): static
127
    {
128
        $this->session->set($this->user::getTokenSessionId(), $this->getToken());
×
129

130
        return $this;
×
131
    }
132

133
    /**
134
     * Get the user token.
135
     *
136
     * @throws TokenizationException
137
     *
138
     * @return string
139
     */
140
    public function getToken(): string
141
    {
142
        return $this->token ??= $this->getFreshToken();
×
143
    }
144

145
    /**
146
     * @inheritDoc
147
     *
148
     * @throws Throwable
149
     */
150
    public function authenticateFromToken(string $token): static
151
    {
152
        $user = $this->getUserFromToken($token);
×
153

154
        return $this->authenticateWithUser($user);
×
155
    }
156

157
    /**
158
     * Try tokenizing the users.
159
     *
160
     * @param AuthenticatedUsers $users The users
161
     *
162
     * @throws TokenizationException
163
     *
164
     * @return string
165
     */
166
    protected function tryTokenizingUsers(AuthenticatedUsers $users): string
167
    {
168
        return $this->tokenizeUsers($users);
×
169
    }
170

171
    /**
172
     * Get the required fields.
173
     *
174
     * @return string[]
175
     */
176
    protected function getRequiredFields(): array
177
    {
178
        $requiredFields = [
×
179
            $this->userEntityName::getIdField(),
×
180
        ];
×
181

182
        // If the always authenticate flag is on in the config we need the password and authentication fields to be part
183
        // of the tokenized user
184
        if ($this->config->shouldAlwaysAuthenticate) {
×
185
            $requiredFields[] = $this->userEntityName::getPasswordField();
×
186

187
            $requiredFields = array_merge($requiredFields, $this->user::getAuthenticationFields());
×
188
        }
189

190
        return $requiredFields;
×
191
    }
192

193
    /**
194
     * Ensure required fields for tokenization.
195
     *
196
     * @param AuthenticatedUsers $users The users
197
     *
198
     * @return void
199
     */
200
    protected function ensureRequiredFieldsForTokenization(AuthenticatedUsers $users): void
201
    {
202
        // Required fields that should exist within the tokenized user
203
        $requiredFields = $this->getRequiredFields();
×
204

205
        /** @var TokenizableUser $userFromCollection */
206
        foreach ($users->all() as $userFromCollection) {
×
207
            $userAsTokenizableArray = $userFromCollection->asTokenizableArray();
×
208

209
            foreach ($requiredFields as $requiredField) {
×
210
                if (! isset($userAsTokenizableArray[$requiredField])) {
×
211
                    $entityName = $this->userEntityName;
×
212

213
                    throw new MissingTokenizableUserRequiredFieldsException(
×
214
                        "Required field `$requiredField` is not being returned in $entityName::asTokenizableArray()"
×
215
                    );
×
216
                }
217
            }
218
        }
219
    }
220

221
    /**
222
     * Get the user token from session.
223
     *
224
     * @return string|null
225
     */
226
    protected function getTokenFromSession(): string|null
227
    {
228
        $token = $this->session->get($this->userEntityName::getTokenSessionId());
×
229

230
        if (! is_string($token)) {
×
231
            $type = gettype($token);
×
232

233
            throw new RuntimeException("Token should be a string $type provided");
×
234
        }
235

236
        return $token;
×
237
    }
238

239
    /**
240
     * Get the token from a request.
241
     *
242
     * @param ServerRequest $request The request
243
     *
244
     * @return string
245
     */
246
    protected function getTokenFromRequest(ServerRequest $request): string
247
    {
248
        [$bearer, $token] = explode(' ', $request->getHeaderLine(HeaderName::AUTHORIZATION));
×
249

250
        if ($bearer !== HeaderValue::BEARER || ! $token) {
×
251
            throw new InvalidAuthenticationException('Invalid token structure.');
×
252
        }
253

254
        return $token;
×
255
    }
256

257
    /**
258
     * Store the user token in session.
259
     *
260
     * @param string|null $token [optional] The token to store
261
     *
262
     * @throws TokenizationException
263
     *
264
     * @return static
265
     */
266
    protected function storeToken(string|null $token = null): static
267
    {
268
        $this->session->set($this->user::getTokenSessionId(), $token ?? $this->getToken());
×
269

270
        return $this;
×
271
    }
272

273
    /**
274
     * Get a user from a token.
275
     *
276
     * @param string $token The token
277
     *
278
     * @throws Throwable
279
     *
280
     * @return User
281
     */
282
    protected function getUserFromToken(string $token): User
283
    {
284
        try {
285
            $users = $this->tryUnTokenizingUsers($token);
×
286
        } catch (Throwable $exception) {
×
287
            $this->resetAfterUnAuthentication();
×
288

289
            throw $exception;
×
290
        }
291

292
        $this->users = $users;
×
293

294
        $current = $this->users->getCurrent();
×
295

296
        if (! $current) {
×
297
            throw new InvalidCurrentAuthenticationException('No current authenticated user.');
×
298
        }
299

300
        return $current;
×
301
    }
302

303
    /**
304
     * Attempt to get users from token.
305
     *
306
     * @param string $token The token
307
     *
308
     * @throws TokenizationException
309
     *
310
     * @return AuthenticatedUsers
311
     */
312
    protected function tryUnTokenizingUsers(string $token): AuthenticatedUsers
313
    {
314
        try {
315
            return $this->unTokenizeUsers($token);
×
316
        } catch (Throwable $exception) {
×
317
            throw new TokenizationException($exception->getMessage(), (int) $exception->getCode(), $exception);
×
318
        }
319
    }
320

321
    /**
322
     * Get a fresh token.
323
     *
324
     * @return string
325
     */
326
    protected function getFreshToken(): string
327
    {
328
        $user  = $this->user;
×
329
        $users = $this->users;
×
330

331
        $this->ensureRequiredFieldsForTokenization($users);
×
332
        $token = $this->tryTokenizingUsers($users);
×
333

334
        $user::setTokenized($token);
×
335

336
        return $token;
×
337
    }
338

339
    /**
340
     * Set the user token.
341
     *
342
     * @throws TokenizationException
343
     *
344
     * @return void
345
     */
346
    protected function resetToken(): void
347
    {
348
        $this->user::setTokenized($this->token = $this->getFreshToken());
×
349
    }
350

351
    /**
352
     * Tokenize the users.
353
     *
354
     * @param AuthenticatedUsers $users The users
355
     *
356
     * @return string
357
     */
358
    abstract protected function tokenizeUsers(AuthenticatedUsers $users): string;
359

360
    /**
361
     * Un-tokenize users.
362
     *
363
     * @param string $token The token
364
     *
365
     * @return AuthenticatedUsers
366
     */
367
    abstract protected function unTokenizeUsers(string $token): AuthenticatedUsers;
368
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc