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

nette / security / 20848288786

09 Jan 2026 10:01AM UTC coverage: 92.919%. Remained the same
20848288786

push

github

dg
added CLAUDE.md

538 of 579 relevant lines covered (92.92%)

0.93 hits per line

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

92.68
/src/Security/User.php
1
<?php
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Nette\Security;
11

12
use Nette;
13
use Nette\Utils\Arrays;
14
use function func_get_args;
15

16

17
/**
18
 * User authentication and authorization.
19
 *
20
 * @property-read bool $loggedIn
21
 * @property-read IIdentity $identity
22
 * @property-read string|int $id
23
 * @property-read array $roles
24
 * @property-read int $logoutReason
25
 * @property   IAuthenticator $authenticator
26
 * @property   Authorizator $authorizator
27
 */
28
class User
29
{
30
        use Nette\SmartObject;
31

32
        /** Log-out reason */
33
        public const
34
                LogoutManual = 1,
35
                LogoutInactivity = 2;
36

37
        /** @deprecated use User::LogoutManual */
38
        public const LOGOUT_MANUAL = self::LogoutManual;
39

40
        /** @deprecated use User::LogoutManual */
41
        public const MANUAL = self::LogoutManual;
42

43
        /** @deprecated use User::LogoutInactivity */
44
        public const LOGOUT_INACTIVITY = self::LogoutInactivity;
45

46
        /** @deprecated use User::LogoutInactivity */
47
        public const INACTIVITY = self::LogoutInactivity;
48

49
        /** default role for unauthenticated user */
50
        public string $guestRole = 'guest';
51

52
        /** default role for authenticated user without own identity */
53
        public string $authenticatedRole = 'authenticated';
54

55
        /** @var array<callable(self): void>  Occurs when the user is successfully logged in */
56
        public array $onLoggedIn = [];
57

58
        /** @var array<callable(self): void>  Occurs when the user is logged out */
59
        public array $onLoggedOut = [];
60

61
        private ?IIdentity $identity = null;
62
        private ?bool $authenticated = null;
63
        private ?int $logoutReason = null;
64

65

66
        public function __construct(
1✔
67
                private UserStorage $storage,
68
                private ?IAuthenticator $authenticator = null,
69
                private ?Authorizator $authorizator = null,
70
        ) {
71
        }
1✔
72

73

74
        final public function getStorage(): UserStorage
75
        {
76
                return $this->storage;
×
77
        }
78

79

80
        /********************* Authentication ****************d*g**/
81

82

83
        /**
84
         * Conducts the authentication process. Parameters are optional.
85
         * @param  string|IIdentity  $username  name or Identity
86
         * @throws AuthenticationException if authentication was not successful
87
         */
88
        public function login(
1✔
89
                string|IIdentity $username,
90
                #[\SensitiveParameter]
91
                ?string $password = null,
92
        ): void
93
        {
94
                $this->logout(clearIdentity: true);
1✔
95
                if ($username instanceof IIdentity) {
1✔
96
                        $this->identity = $username;
1✔
97
                } else {
98
                        $authenticator = $this->getAuthenticator();
1✔
99
                        $this->identity = $authenticator instanceof Authenticator
1✔
100
                                ? $authenticator->authenticate(...func_get_args())
1✔
101
                                : $authenticator->authenticate(func_get_args());
×
102
                }
103

104
                $id = $this->authenticator instanceof IdentityHandler
1✔
105
                        ? $this->authenticator->sleepIdentity($this->identity)
1✔
106
                        : $this->identity;
1✔
107

108
                $this->storage->saveAuthentication($id);
1✔
109
                $this->authenticated = true;
1✔
110
                $this->logoutReason = null;
1✔
111
                Arrays::invoke($this->onLoggedIn, $this);
1✔
112
        }
1✔
113

114

115
        /**
116
         * Logs out the user from the current session.
117
         */
118
        final public function logout(bool $clearIdentity = false): void
1✔
119
        {
120
                $logged = $this->isLoggedIn();
1✔
121
                $this->storage->clearAuthentication($clearIdentity);
1✔
122
                $this->authenticated = false;
1✔
123
                $this->logoutReason = self::LogoutManual;
1✔
124
                if ($logged) {
1✔
125
                        Arrays::invoke($this->onLoggedOut, $this);
1✔
126
                }
127

128
                $this->identity = $clearIdentity ? null : $this->identity;
1✔
129
        }
1✔
130

131

132
        /**
133
         * Is this user authenticated?
134
         */
135
        final public function isLoggedIn(): bool
136
        {
137
                if ($this->authenticated === null) {
1✔
138
                        $this->getStoredData();
1✔
139
                }
140

141
                return $this->authenticated;
1✔
142
        }
143

144

145
        /**
146
         * Returns current user identity, if any.
147
         */
148
        final public function getIdentity(): ?IIdentity
149
        {
150
                if ($this->authenticated === null) {
1✔
151
                        $this->getStoredData();
1✔
152
                }
153

154
                return $this->identity;
1✔
155
        }
156

157

158
        private function getStoredData(): void
159
        {
160
                (function (bool $state, ?IIdentity $id, ?int $reason) use (&$identity) {
1✔
161
                        $identity = $id;
1✔
162
                        $this->authenticated = $state;
1✔
163
                        $this->logoutReason = $reason;
1✔
164
                })(...$this->storage->getState());
1✔
165

166
                $this->identity = $identity && $this->authenticator instanceof IdentityHandler
1✔
167
                        ? $this->authenticator->wakeupIdentity($identity)
1✔
168
                        : $identity;
1✔
169
                $this->authenticated = $this->authenticated && $this->identity;
1✔
170
        }
1✔
171

172

173
        /**
174
         * Returns current user ID, if any.
175
         */
176
        public function getId(): string|int|null
177
        {
178
                $identity = $this->getIdentity();
1✔
179
                return $identity ? $identity->getId() : null;
1✔
180
        }
181

182

183
        final public function refreshStorage(): void
184
        {
185
                $this->identity = $this->authenticated = $this->logoutReason = null;
1✔
186
        }
1✔
187

188

189
        /**
190
         * Sets authentication handler.
191
         */
192
        public function setAuthenticator(IAuthenticator $handler): static
1✔
193
        {
194
                $this->authenticator = $handler;
1✔
195
                return $this;
1✔
196
        }
197

198

199
        /**
200
         * Returns authentication handler.
201
         */
202
        final public function getAuthenticator(): IAuthenticator
203
        {
204
                if (!$this->authenticator) {
1✔
205
                        throw new Nette\InvalidStateException('Authenticator has not been set.');
1✔
206
                }
207

208
                return $this->authenticator;
1✔
209
        }
210

211

212
        /**
213
         * Returns authentication handler.
214
         */
215
        final public function getAuthenticatorIfExists(): ?IAuthenticator
216
        {
217
                return $this->authenticator;
×
218
        }
219

220

221
        /** @deprecated */
222
        final public function hasAuthenticator(): bool
223
        {
224
                return (bool) $this->authenticator;
×
225
        }
226

227

228
        /**
229
         * Enables log out after inactivity (like '20 minutes').
230
         */
231
        public function setExpiration(?string $expire, bool $clearIdentity = false): static
1✔
232
        {
233
                $this->storage->setExpiration($expire, $clearIdentity);
1✔
234
                return $this;
1✔
235
        }
236

237

238
        /**
239
         * Why was user logged out? Returns LOGOUT_MANUAL or LOGOUT_INACTIVITY.
240
         */
241
        final public function getLogoutReason(): ?int
242
        {
243
                return $this->logoutReason;
1✔
244
        }
245

246

247
        /********************* Authorization ****************d*g**/
248

249

250
        /**
251
         * Returns a list of effective roles that a user has been granted.
252
         * @return string[]
253
         */
254
        public function getRoles(): array
255
        {
256
                if (!$this->isLoggedIn()) {
1✔
257
                        return [$this->guestRole];
1✔
258
                }
259

260
                $identity = $this->getIdentity();
1✔
261
                return $identity?->getRoles() ?? [$this->authenticatedRole];
1✔
262
        }
263

264

265
        /**
266
         * Is a user in the specified effective role?
267
         */
268
        final public function isInRole(string $role): bool
1✔
269
        {
270
                foreach ($this->getRoles() as $r) {
1✔
271
                        if ($role === ($r instanceof Role ? $r->getRoleId() : $r)) {
1✔
272
                                return true;
1✔
273
                        }
274
                }
275

276
                return false;
1✔
277
        }
278

279

280
        /**
281
         * Has a user effective access to the Resource?
282
         * If $resource is null, then the query applies to all resources.
283
         */
284
        public function isAllowed($resource = Authorizator::All, $privilege = Authorizator::All): bool
1✔
285
        {
286
                foreach ($this->getRoles() as $role) {
1✔
287
                        if ($this->getAuthorizator()->isAllowed($role, $resource, $privilege)) {
1✔
288
                                return true;
1✔
289
                        }
290
                }
291

292
                return false;
1✔
293
        }
294

295

296
        /**
297
         * Sets authorization handler.
298
         */
299
        public function setAuthorizator(Authorizator $handler): static
1✔
300
        {
301
                $this->authorizator = $handler;
1✔
302
                return $this;
1✔
303
        }
304

305

306
        /**
307
         * Returns current authorization handler.
308
         */
309
        final public function getAuthorizator(): Authorizator
310
        {
311
                if (!$this->authorizator) {
1✔
312
                        throw new Nette\InvalidStateException('Authorizator has not been set.');
1✔
313
                }
314

315
                return $this->authorizator;
1✔
316
        }
317

318

319
        /**
320
         * Returns current authorization handler.
321
         */
322
        final public function getAuthorizatorIfExists(): ?Authorizator
323
        {
324
                return $this->authorizator;
×
325
        }
326

327

328
        /** @deprecated */
329
        final public function hasAuthorizator(): bool
330
        {
331
                return (bool) $this->authorizator;
×
332
        }
333
}
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