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;
- protected $userRepo;
/**
* LdapSessionGuard constructor.
*/
- public function __construct($name,
+ public function __construct(
+ $name,
UserProvider $provider,
Session $session,
LdapService $ldapService,
- UserRepo $userRepo
- )
- {
+ RegistrationService $registrationService
+ ) {
$this->ldapService = $ldapService;
- $this->userRepo = $userRepo;
- parent::__construct($name, $provider, $session);
+ 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'])) {
- return false;
- }
-
- if (is_null($user)) {
- $user = $this->freshUserInstanceFromLdapUserDetails($userDetails);
+ $user = null;
+ if (isset($userDetails['uid'])) {
+ $this->lastAttempted = $user = $this->provider->retrieveByCredentials([
+ 'external_auth_id' => $userDetails['uid'],
+ ]);
}
- $providedEmail = ($credentials['email'] ?? false);
-
- // Request email if missing from LDAP and model and missing from request
- if (is_null($user->email) && !$providedEmail) {
- throw new LoginAttemptEmailNeededException();
- }
-
- // Add email to model if non-existing and email provided in request
- if (!$user->exists && $user->email === null && $providedEmail) {
- $user->email = $providedEmail;
+ if (!$this->ldapService->validateUserCredentials($userDetails, $credentials['password'])) {
+ return false;
}
- if (!$user->exists) {
- // 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]));
+ if (is_null($user)) {
+ try {
+ $user = $this->createNewFromLdapAndCreds($userDetails, $credentials);
+ } catch (UserRegistrationException $exception) {
+ throw new LoginAttemptException($exception->getMessage());
}
-
- $user->save();
- $this->userRepo->attachDefaultRole($user);
- $this->userRepo->downloadAndAssignUserAvatar($user);
}
// Sync LDAP groups if required
$this->ldapService->syncGroups($user, $username);
}
+ // Attach avatar if non-existent
+ if (!$user->avatar()->exists()) {
+ $this->ldapService->saveAndAttachAvatar($user, $userDetails);
+ }
+
$this->login($user, $remember);
+
return true;
}
/**
- * Create a fresh user instance from details provided by a LDAP lookup.
+ * Create a new user from the given ldap credentials and login credentials.
+ *
+ * @throws LoginAttemptEmailNeededException
+ * @throws LoginAttemptException
+ * @throws UserRegistrationException
*/
- protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User
+ protected function createNewFromLdapAndCreds(array $ldapUserDetails, array $credentials): User
{
- $user = new User();
+ $email = trim($ldapUserDetails['email'] ?: ($credentials['email'] ?? ''));
- $user->name = $ldapUserDetails['name'];
- $user->external_auth_id = $ldapUserDetails['uid'];
- $user->email = $ldapUserDetails['email'];
- $user->email_confirmed = false;
+ if (empty($email)) {
+ throw new LoginAttemptEmailNeededException();
+ }
+
+ $details = [
+ 'name' => $ldapUserDetails['name'],
+ 'email' => $ldapUserDetails['email'] ?: $credentials['email'],
+ 'external_auth_id' => $ldapUserDetails['uid'],
+ 'password' => Str::random(32),
+ ];
+
+ $user = $this->registrationService->registerUser($details, null, false);
+ $this->ldapService->saveAndAttachAvatar($user, $ldapUserDetails);
return $user;
}
-
}