config = Config::app(static::AUTHENTICATION_CONFIG); } catch (NotReadableError $e) { $this->config = new Config(); $this->error = static::EPERM; } } else { $this->config = $config; } } /** * {@inheritdoc} */ public function authenticate(User $user, $password) { $this->error = null; $backendsTried = 0; $backendsWithError = 0; foreach ($this as $backend) { ++$backendsTried; try { $authenticated = $backend->authenticate($user, $password); } catch (AuthenticationException $e) { Logger::error($e); ++$backendsWithError; continue; } if ($authenticated) { $user->setAdditional('backend_name', $backend->getName()); $user->setAdditional('backend_type', $this->config->current()->get('backend')); return true; } } if ($backendsTried === 0) { $this->error = static::EEMPTY; } elseif ($backendsTried === $backendsWithError) { $this->error = static::EFAIL; } elseif ($backendsWithError) { $this->error = static::ENOTALL; } else { AuditHook::logActivity('login-failed', 'User failed to authenticate', null, $user->getUsername()); } return false; } /** * Get the last error code * * @return int|null */ public function getError() { return $this->error; } /** * Whether authentication had errors * * @return bool */ public function hasError() { return $this->error !== null; } /** * Get whether to skip external user backends on iteration * * @return bool */ public function getSkipExternalBackends() { return $this->skipExternalBackends; } /** * Set whether to skip external user backends on iteration * * @param bool $skipExternalBackends * * @return $this */ public function setSkipExternalBackends($skipExternalBackends = true) { $this->skipExternalBackends = (bool) $skipExternalBackends; return $this; } /** * Rewind the chain * * @return void */ public function rewind(): void { $this->currentBackend = null; $this->config->rewind(); } /** * Get the current user backend * * @return UserBackendInterface */ public function current(): UserBackendInterface { return $this->currentBackend; } /** * Get the key of the current user backend config * * @return string */ public function key(): string { return $this->config->key(); } /** * Move forward to the next user backend config * * @return void */ public function next(): void { $this->config->next(); } /** * Check whether the current user backend is valid, i.e. it's enabled, not an external user backend and whether its * config is valid * * @return bool */ public function valid(): bool { if (! $this->config->valid()) { // Stop when there are no more backends to check return false; } $backendConfig = $this->config->current(); if ((bool) $backendConfig->get('disabled', false)) { $this->next(); return $this->valid(); } $name = $this->key(); try { $backend = UserBackend::create($name, $backendConfig); } catch (ConfigurationError $e) { Logger::error( new ConfigurationError( 'Can\'t create authentication backend "%s". An exception was thrown:', $name, $e ) ); $this->next(); return $this->valid(); } if ($this->getSkipExternalBackends() && $backend instanceof ExternalBackend ) { $this->next(); return $this->valid(); } $this->currentBackend = $backend; return true; } }