]> BookStack Code Mirror - bookstack/blob - app/Access/Guards/ExternalBaseSessionGuard.php
Maintenance: Updated larastan target level, fixed issues from tests
[bookstack] / app / Access / Guards / ExternalBaseSessionGuard.php
1 <?php
2
3 namespace BookStack\Access\Guards;
4
5 use BookStack\Access\RegistrationService;
6 use Illuminate\Auth\GuardHelpers;
7 use Illuminate\Contracts\Auth\Authenticatable;
8 use Illuminate\Contracts\Auth\StatefulGuard;
9 use Illuminate\Contracts\Auth\UserProvider;
10 use Illuminate\Contracts\Session\Session;
11
12 /**
13  * Class BaseSessionGuard
14  * A base implementation of a session guard. Is a copy of the default Laravel
15  * guard with 'remember' functionality removed. Basic auth and event emission
16  * has also been removed to keep this simple. Designed to be extended by external
17  * Auth Guards.
18  */
19 class ExternalBaseSessionGuard implements StatefulGuard
20 {
21     use GuardHelpers;
22
23     /**
24      * The name of the Guard. Typically "session".
25      *
26      * Corresponds to guard name in authentication configuration.
27      */
28     protected readonly string $name;
29
30     /**
31      * The user we last attempted to retrieve.
32      */
33     protected Authenticatable|null $lastAttempted;
34
35     /**
36      * The session used by the guard.
37      */
38     protected Session $session;
39
40     /**
41      * Indicates if the logout method has been called.
42      */
43     protected bool $loggedOut = false;
44
45     /**
46      * Service to handle common registration actions.
47      */
48     protected RegistrationService $registrationService;
49
50     /**
51      * Create a new authentication guard.
52      */
53     public function __construct(string $name, UserProvider $provider, Session $session, RegistrationService $registrationService)
54     {
55         $this->name = $name;
56         $this->session = $session;
57         $this->provider = $provider;
58         $this->registrationService = $registrationService;
59     }
60
61     /**
62      * Get the currently authenticated user.
63      */
64     public function user(): Authenticatable|null
65     {
66         if ($this->loggedOut) {
67             return null;
68         }
69
70         // If we've already retrieved the user for the current request we can just
71         // return it back immediately. We do not want to fetch the user data on
72         // every call to this method because that would be tremendously slow.
73         if (!is_null($this->user)) {
74             return $this->user;
75         }
76
77         $id = $this->session->get($this->getName());
78
79         // First we will try to load the user using the
80         // identifier in the session if one exists.
81         if (!is_null($id)) {
82             $this->user = $this->provider->retrieveById($id);
83         }
84
85         return $this->user;
86     }
87
88     /**
89      * Get the ID for the currently authenticated user.
90      */
91     public function id(): int|null
92     {
93         if ($this->loggedOut) {
94             return null;
95         }
96
97         return $this->user()
98             ? $this->user()->getAuthIdentifier()
99             : $this->session->get($this->getName());
100     }
101
102     /**
103      * Log a user into the application without sessions or cookies.
104      */
105     public function once(array $credentials = []): bool
106     {
107         if ($this->validate($credentials)) {
108             $this->setUser($this->lastAttempted);
109
110             return true;
111         }
112
113         return false;
114     }
115
116     /**
117      * Log the given user ID into the application without sessions or cookies.
118      */
119     public function onceUsingId($id): Authenticatable|false
120     {
121         if (!is_null($user = $this->provider->retrieveById($id))) {
122             $this->setUser($user);
123
124             return $user;
125         }
126
127         return false;
128     }
129
130     /**
131      * Validate a user's credentials.
132      */
133     public function validate(array $credentials = []): bool
134     {
135         return false;
136     }
137
138     /**
139      * Attempt to authenticate a user using the given credentials.
140      * @param bool $remember
141      */
142     public function attempt(array $credentials = [], $remember = false): bool
143     {
144         return false;
145     }
146
147     /**
148      * Log the given user ID into the application.
149      * @param bool  $remember
150      */
151     public function loginUsingId(mixed $id, $remember = false): Authenticatable|false
152     {
153         // Always return false as to disable this method,
154         // Logins should route through LoginService.
155         return false;
156     }
157
158     /**
159      * Log a user into the application.
160      *
161      * @param bool $remember
162      */
163     public function login(Authenticatable $user, $remember = false): void
164     {
165         $this->updateSession($user->getAuthIdentifier());
166
167         $this->setUser($user);
168     }
169
170     /**
171      * Update the session with the given ID.
172      */
173     protected function updateSession(string|int $id): void
174     {
175         $this->session->put($this->getName(), $id);
176
177         $this->session->migrate(true);
178     }
179
180     /**
181      * Log the user out of the application.
182      */
183     public function logout(): void
184     {
185         $this->clearUserDataFromStorage();
186
187         // Now we will clear the users out of memory so they are no longer available
188         // as the user is no longer considered as being signed into this
189         // application and should not be available here.
190         $this->user = null;
191
192         $this->loggedOut = true;
193     }
194
195     /**
196      * Remove the user data from the session and cookies.
197      */
198     protected function clearUserDataFromStorage(): void
199     {
200         $this->session->remove($this->getName());
201     }
202
203     /**
204      * Get the last user we attempted to authenticate.
205      */
206     public function getLastAttempted(): Authenticatable
207     {
208         return $this->lastAttempted;
209     }
210
211     /**
212      * Get a unique identifier for the auth session value.
213      */
214     public function getName(): string
215     {
216         return 'login_' . $this->name . '_' . sha1(static::class);
217     }
218
219     /**
220      * Determine if the user was authenticated via "remember me" cookie.
221      */
222     public function viaRemember(): bool
223     {
224         return false;
225     }
226
227     /**
228      * Return the currently cached user.
229      */
230     public function getUser(): Authenticatable|null
231     {
232         return $this->user;
233     }
234
235     /**
236      * Set the current user.
237      */
238     public function setUser(Authenticatable $user): self
239     {
240         $this->user = $user;
241
242         $this->loggedOut = false;
243
244         return $this;
245     }
246 }