]> BookStack Code Mirror - bookstack/blobdiff - app/Auth/Access/Guards/LdapSessionGuard.php
Added a custom link context toolbar
[bookstack] / app / Auth / Access / Guards / LdapSessionGuard.php
index 6c416bf301621c31a8c887883b7470b2b0553557..5a902af7655aa021b37b9faa1425047f2a258005 100644 (file)
 namespace BookStack\Auth\Access\Guards;
 
 use BookStack\Auth\Access\LdapService;
+use BookStack\Auth\Access\RegistrationService;
 use BookStack\Auth\User;
-use BookStack\Auth\UserRepo;
 use BookStack\Exceptions\LdapException;
-use BookStack\Exceptions\LoginAttemptException;
 use BookStack\Exceptions\LoginAttemptEmailNeededException;
+use BookStack\Exceptions\LoginAttemptException;
+use BookStack\Exceptions\UserRegistrationException;
 use Illuminate\Contracts\Auth\UserProvider;
 use Illuminate\Contracts\Session\Session;
+use Illuminate\Support\Str;
 
 class LdapSessionGuard extends ExternalBaseSessionGuard
 {
-
     protected $ldapService;
 
     /**
      * LdapSessionGuard constructor.
      */
-    public function __construct($name,
+    public function __construct(
+        $name,
         UserProvider $provider,
         Session $session,
         LdapService $ldapService,
-        UserRepo $userRepo
-    )
-    {
+        RegistrationService $registrationService
+    ) {
         $this->ldapService = $ldapService;
-        parent::__construct($name, $provider, $session, $userRepo);
+        parent::__construct($name, $provider, $session, $registrationService);
     }
 
     /**
      * Validate a user's credentials.
      *
      * @param array $credentials
-     * @return bool
+     *
      * @throws LdapException
+     *
+     * @return bool
      */
     public function validate(array $credentials = [])
     {
         $userDetails = $this->ldapService->getUserDetails($credentials['username']);
-        $this->lastAttempted = $this->provider->retrieveByCredentials([
-            'external_auth_id' => $userDetails['uid']
-        ]);
 
-        return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']);
+        if (isset($userDetails['uid'])) {
+            $this->lastAttempted = $this->provider->retrieveByCredentials([
+                'external_auth_id' => $userDetails['uid'],
+            ]);
+        }
+
+        return $this->ldapService->validateUserCredentials($userDetails, $credentials['password']);
     }
 
     /**
      * Attempt to authenticate a user using the given credentials.
      *
      * @param array $credentials
-     * @param bool $remember
-     * @return bool
-     * @throws LoginAttemptEmailNeededException
+     * @param bool  $remember
+     *
      * @throws LoginAttemptException
      * @throws LdapException
+     *
+     * @return bool
      */
     public function attempt(array $credentials = [], $remember = false)
     {
         $username = $credentials['username'];
         $userDetails = $this->ldapService->getUserDetails($username);
-        $this->lastAttempted = $user = $this->provider->retrieveByCredentials([
-            'external_auth_id' => $userDetails['uid']
-        ]);
 
-        if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) {
+        $user = null;
+        if (isset($userDetails['uid'])) {
+            $this->lastAttempted = $user = $this->provider->retrieveByCredentials([
+                'external_auth_id' => $userDetails['uid'],
+            ]);
+        }
+
+        if (!$this->ldapService->validateUserCredentials($userDetails, $credentials['password'])) {
             return false;
         }
 
         if (is_null($user)) {
-            $user = $this->freshUserInstanceFromLdapUserDetails($userDetails);
+            try {
+                $user = $this->createNewFromLdapAndCreds($userDetails, $credentials);
+            } catch (UserRegistrationException $exception) {
+                throw new LoginAttemptException($exception->getMessage());
+            }
         }
 
-        $this->checkForUserEmail($user, $credentials['email'] ?? '');
-        $this->saveIfNew($user);
-
         // Sync LDAP groups if required
         if ($this->ldapService->shouldSyncGroups()) {
             $this->ldapService->syncGroups($user, $username);
         }
 
-        $this->login($user, $remember);
-        return true;
-    }
-
-    /**
-     * Save the give user if they don't yet existing in the system.
-     * @throws LoginAttemptException
-     */
-    protected function saveIfNew(User $user)
-    {
-        if ($user->exists) {
-            return;
+        // Attach avatar if non-existent
+        if (!$user->avatar()->exists()) {
+            $this->ldapService->saveAndAttachAvatar($user, $userDetails);
         }
 
-        // Check for existing users with same email
-        $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0;
-        if ($alreadyUser) {
-            throw new LoginAttemptException(trans('errors.error_user_exists_different_creds', ['email' => $user->email]));
-        }
+        $this->login($user, $remember);
 
-        $user->save();
-        $this->userRepo->attachDefaultRole($user);
-        $this->userRepo->downloadAndAssignUserAvatar($user);
+        return true;
     }
 
     /**
-     * Ensure the given user has an email.
-     * Takes the provided email in the request if a value is provided
-     * and the user does not have an existing email.
+     * Create a new user from the given ldap credentials and login credentials.
+     *
      * @throws LoginAttemptEmailNeededException
+     * @throws LoginAttemptException
+     * @throws UserRegistrationException
      */
-    protected function checkForUserEmail(User $user, string $providedEmail)
+    protected function createNewFromLdapAndCreds(array $ldapUserDetails, array $credentials): User
     {
-        // Request email if missing from user and missing from request
-        if (is_null($user->email) && !$providedEmail) {
+        $email = trim($ldapUserDetails['email'] ?: ($credentials['email'] ?? ''));
+
+        if (empty($email)) {
             throw new LoginAttemptEmailNeededException();
         }
 
-        // Add email to model if non-existing and email provided in request
-        if (!$user->exists && is_null($user->email) && $providedEmail) {
-            $user->email = $providedEmail;
-        }
-    }
+        $details = [
+            'name'             => $ldapUserDetails['name'],
+            'email'            => $ldapUserDetails['email'] ?: $credentials['email'],
+            'external_auth_id' => $ldapUserDetails['uid'],
+            'password'         => Str::random(32),
+        ];
 
-    /**
-     * Create a fresh user instance from details provided by a LDAP lookup.
-     */
-    protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User
-    {
-        $user = new User();
-
-        $user->name = $ldapUserDetails['name'];
-        $user->external_auth_id = $ldapUserDetails['uid'];
-        $user->email = $ldapUserDetails['email'];
-        $user->email_confirmed = false;
+        $user = $this->registrationService->registerUser($details, null, false);
+        $this->ldapService->saveAndAttachAvatar($user, $ldapUserDetails);
 
         return $user;
     }
-
 }