]> BookStack Code Mirror - bookstack/blob - app/Access/Guards/ExternalBaseSessionGuard.php
Add optional OIDC avatar fetching from the “picture” claim
[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 as AuthenticatableContract;
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      * @var string
29      */
30     protected $name;
31
32     /**
33      * The user we last attempted to retrieve.
34      *
35      * @var \Illuminate\Contracts\Auth\Authenticatable
36      */
37     protected $lastAttempted;
38
39     /**
40      * The session used by the guard.
41      *
42      * @var \Illuminate\Contracts\Session\Session
43      */
44     protected $session;
45
46     /**
47      * Indicates if the logout method has been called.
48      *
49      * @var bool
50      */
51     protected $loggedOut = false;
52
53     /**
54      * Service to handle common registration actions.
55      *
56      * @var RegistrationService
57      */
58     protected $registrationService;
59
60     /**
61      * Create a new authentication guard.
62      *
63      * @return void
64      */
65     public function __construct(string $name, UserProvider $provider, Session $session, RegistrationService $registrationService)
66     {
67         $this->name = $name;
68         $this->session = $session;
69         $this->provider = $provider;
70         $this->registrationService = $registrationService;
71     }
72
73     /**
74      * Get the currently authenticated user.
75      *
76      * @return \Illuminate\Contracts\Auth\Authenticatable|null
77      */
78     public function user()
79     {
80         if ($this->loggedOut) {
81             return;
82         }
83
84         // If we've already retrieved the user for the current request we can just
85         // return it back immediately. We do not want to fetch the user data on
86         // every call to this method because that would be tremendously slow.
87         if (!is_null($this->user)) {
88             return $this->user;
89         }
90
91         $id = $this->session->get($this->getName());
92
93         // First we will try to load the user using the
94         // identifier in the session if one exists.
95         if (!is_null($id)) {
96             $this->user = $this->provider->retrieveById($id);
97         }
98
99         return $this->user;
100     }
101
102     /**
103      * Get the ID for the currently authenticated user.
104      *
105      * @return int|null
106      */
107     public function id()
108     {
109         if ($this->loggedOut) {
110             return;
111         }
112
113         return $this->user()
114             ? $this->user()->getAuthIdentifier()
115             : $this->session->get($this->getName());
116     }
117
118     /**
119      * Log a user into the application without sessions or cookies.
120      *
121      * @param array $credentials
122      *
123      * @return bool
124      */
125     public function once(array $credentials = [])
126     {
127         if ($this->validate($credentials)) {
128             $this->setUser($this->lastAttempted);
129
130             return true;
131         }
132
133         return false;
134     }
135
136     /**
137      * Log the given user ID into the application without sessions or cookies.
138      *
139      * @param mixed $id
140      *
141      * @return \Illuminate\Contracts\Auth\Authenticatable|false
142      */
143     public function onceUsingId($id)
144     {
145         if (!is_null($user = $this->provider->retrieveById($id))) {
146             $this->setUser($user);
147
148             return $user;
149         }
150
151         return false;
152     }
153
154     /**
155      * Validate a user's credentials.
156      *
157      * @param array $credentials
158      *
159      * @return bool
160      */
161     public function validate(array $credentials = [])
162     {
163         return false;
164     }
165
166     /**
167      * Attempt to authenticate a user using the given credentials.
168      *
169      * @param array $credentials
170      * @param bool  $remember
171      *
172      * @return bool
173      */
174     public function attempt(array $credentials = [], $remember = false)
175     {
176         return false;
177     }
178
179     /**
180      * Log the given user ID into the application.
181      *
182      * @param mixed $id
183      * @param bool  $remember
184      *
185      * @return \Illuminate\Contracts\Auth\Authenticatable|false
186      */
187     public function loginUsingId($id, $remember = false)
188     {
189         // Always return false as to disable this method,
190         // Logins should route through LoginService.
191         return false;
192     }
193
194     /**
195      * Log a user into the application.
196      *
197      * @param \Illuminate\Contracts\Auth\Authenticatable $user
198      * @param bool                                       $remember
199      *
200      * @return void
201      */
202     public function login(AuthenticatableContract $user, $remember = false)
203     {
204         $this->updateSession($user->getAuthIdentifier());
205
206         $this->setUser($user);
207     }
208
209     /**
210      * Update the session with the given ID.
211      *
212      * @param string $id
213      *
214      * @return void
215      */
216     protected function updateSession($id)
217     {
218         $this->session->put($this->getName(), $id);
219
220         $this->session->migrate(true);
221     }
222
223     /**
224      * Log the user out of the application.
225      *
226      * @return void
227      */
228     public function logout()
229     {
230         $this->clearUserDataFromStorage();
231
232         // Now we will clear the users out of memory so they are no longer available
233         // as the user is no longer considered as being signed into this
234         // application and should not be available here.
235         $this->user = null;
236
237         $this->loggedOut = true;
238     }
239
240     /**
241      * Remove the user data from the session and cookies.
242      *
243      * @return void
244      */
245     protected function clearUserDataFromStorage()
246     {
247         $this->session->remove($this->getName());
248     }
249
250     /**
251      * Get the last user we attempted to authenticate.
252      *
253      * @return \Illuminate\Contracts\Auth\Authenticatable
254      */
255     public function getLastAttempted()
256     {
257         return $this->lastAttempted;
258     }
259
260     /**
261      * Get a unique identifier for the auth session value.
262      *
263      * @return string
264      */
265     public function getName()
266     {
267         return 'login_' . $this->name . '_' . sha1(static::class);
268     }
269
270     /**
271      * Determine if the user was authenticated via "remember me" cookie.
272      *
273      * @return bool
274      */
275     public function viaRemember()
276     {
277         return false;
278     }
279
280     /**
281      * Return the currently cached user.
282      *
283      * @return \Illuminate\Contracts\Auth\Authenticatable|null
284      */
285     public function getUser()
286     {
287         return $this->user;
288     }
289
290     /**
291      * Set the current user.
292      *
293      * @param \Illuminate\Contracts\Auth\Authenticatable $user
294      *
295      * @return $this
296      */
297     public function setUser(AuthenticatableContract $user)
298     {
299         $this->user = $user;
300
301         $this->loggedOut = false;
302
303         return $this;
304     }
305 }