]> BookStack Code Mirror - bookstack/blob - app/Auth/Access/Guards/LdapSessionGuard.php
Added files missed in previous commit
[bookstack] / app / Auth / Access / Guards / LdapSessionGuard.php
1 <?php
2
3 namespace BookStack\Auth\Access\Guards;
4
5 use BookStack\Auth\Access\LdapService;
6 use BookStack\Auth\User;
7 use BookStack\Auth\UserRepo;
8 use BookStack\Exceptions\LdapException;
9 use BookStack\Exceptions\LoginAttemptException;
10 use BookStack\Exceptions\LoginAttemptEmailNeededException;
11 use Illuminate\Contracts\Auth\UserProvider;
12 use Illuminate\Contracts\Session\Session;
13
14 class LdapSessionGuard extends ExternalBaseSessionGuard
15 {
16
17     protected $ldapService;
18
19     /**
20      * LdapSessionGuard constructor.
21      */
22     public function __construct($name,
23         UserProvider $provider,
24         Session $session,
25         LdapService $ldapService,
26         UserRepo $userRepo
27     )
28     {
29         $this->ldapService = $ldapService;
30         parent::__construct($name, $provider, $session, $userRepo);
31     }
32
33     /**
34      * Validate a user's credentials.
35      *
36      * @param array $credentials
37      * @return bool
38      * @throws LdapException
39      */
40     public function validate(array $credentials = [])
41     {
42         $userDetails = $this->ldapService->getUserDetails($credentials['username']);
43         $this->lastAttempted = $this->provider->retrieveByCredentials([
44             'external_auth_id' => $userDetails['uid']
45         ]);
46
47         return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']);
48     }
49
50     /**
51      * Attempt to authenticate a user using the given credentials.
52      *
53      * @param array $credentials
54      * @param bool $remember
55      * @return bool
56      * @throws LoginAttemptEmailNeededException
57      * @throws LoginAttemptException
58      * @throws LdapException
59      */
60     public function attempt(array $credentials = [], $remember = false)
61     {
62         $username = $credentials['username'];
63         $userDetails = $this->ldapService->getUserDetails($username);
64         $this->lastAttempted = $user = $this->provider->retrieveByCredentials([
65             'external_auth_id' => $userDetails['uid']
66         ]);
67
68         if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) {
69             return false;
70         }
71
72         if (is_null($user)) {
73             $user = $this->freshUserInstanceFromLdapUserDetails($userDetails);
74         }
75
76         $this->checkForUserEmail($user, $credentials['email'] ?? '');
77         $this->saveIfNew($user);
78
79         // Sync LDAP groups if required
80         if ($this->ldapService->shouldSyncGroups()) {
81             $this->ldapService->syncGroups($user, $username);
82         }
83
84         $this->login($user, $remember);
85         return true;
86     }
87
88     /**
89      * Save the give user if they don't yet existing in the system.
90      * @throws LoginAttemptException
91      */
92     protected function saveIfNew(User $user)
93     {
94         if ($user->exists) {
95             return;
96         }
97
98         // Check for existing users with same email
99         $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0;
100         if ($alreadyUser) {
101             throw new LoginAttemptException(trans('errors.error_user_exists_different_creds', ['email' => $user->email]));
102         }
103
104         $user->save();
105         $this->userRepo->attachDefaultRole($user);
106         $this->userRepo->downloadAndAssignUserAvatar($user);
107     }
108
109     /**
110      * Ensure the given user has an email.
111      * Takes the provided email in the request if a value is provided
112      * and the user does not have an existing email.
113      * @throws LoginAttemptEmailNeededException
114      */
115     protected function checkForUserEmail(User $user, string $providedEmail)
116     {
117         // Request email if missing from user and missing from request
118         if (is_null($user->email) && !$providedEmail) {
119             throw new LoginAttemptEmailNeededException();
120         }
121
122         // Add email to model if non-existing and email provided in request
123         if (!$user->exists && is_null($user->email) && $providedEmail) {
124             $user->email = $providedEmail;
125         }
126     }
127
128     /**
129      * Create a fresh user instance from details provided by a LDAP lookup.
130      */
131     protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User
132     {
133         $user = new User();
134
135         $user->name = $ldapUserDetails['name'];
136         $user->external_auth_id = $ldapUserDetails['uid'];
137         $user->email = $ldapUserDetails['email'];
138         $user->email_confirmed = false;
139
140         return $user;
141     }
142
143 }