user !== null) { return true; } $this->authenticateFromSession(); if ($this->user === null && ! $this->authExternal()) { return false; } return true; } public function setAuthenticated(User $user, $persist = true) { $this->setupUser($user); // Reload CSS if the theme changed $themingConfig = Icinga::app()->getConfig()->getSection('themes'); $userTheme = $user->getPreferences()->getValue('icingaweb', 'theme'); if (! (bool) $themingConfig->get('disabled', false) && $userTheme !== null) { $defaultTheme = $themingConfig->get('default', StyleSheet::DEFAULT_THEME); if ($userTheme !== $defaultTheme) { $this->getResponse()->setReloadCss(true); } } // Also reload CSS if the theme mode changed $themeMode = $user->getPreferences()->getValue('icingaweb', 'theme_mode'); if ($themeMode && $themeMode !== StyleSheet::DEFAULT_MODE) { $this->getResponse()->setReloadCss(true); } // Reload entire layout if the locale changed if (($locale = $user->getPreferences()->getValue('icingaweb', 'language')) !== null) { if (setlocale(LC_ALL, 0) !== $locale && $this->getRequest()->isXmlHttpRequest()) { $this->getResponse()->setHeader('X-Icinga-Redirect-Http', 'yes'); } } $this->user = $user; if ($persist) { $this->persistCurrentUser(); } AuditHook::logActivity('login', 'User logged in'); } /** * Getter for groups belonged to authenticated user * * @return array * @see User::getGroups */ public function getGroups() { return $this->user->getGroups(); } /** * Get the request * * @return \Icinga\Web\Request */ public function getRequest() { if ($this->request === null) { $this->request = Icinga::app()->getRequest(); } return $this->request; } /** * Get the response * * @return \Icinga\Web\Response */ public function getResponse() { if ($this->response === null) { $this->response = Icinga::app()->getResponse(); } return $this->response; } /** * Get applied restrictions matching a given restriction name * * Returns a list of applied restrictions, empty if no user is * authenticated * * @param string $restriction Restriction name * @return array */ public function getRestrictions($restriction) { if (! $this->isAuthenticated()) { return array(); } return $this->user->getRestrictions($restriction); } /** * Returns the current user or null if no user is authenticated * * @return User|null */ public function getUser() { return $this->user; } /** * Set the authenticated user * * Note that this method just sets the authenticated user and thus bypasses our default authentication process in * {@link setAuthenticated()}. * * @param User $user * * @return $this */ public function setUser(User $user) { $this->user = $user; return $this; } /** * Try to authenticate the user with the current session * * Authentication for externally-authenticated users will be revoked if the username changed or external * authentication is no longer in effect */ public function authenticateFromSession() { $this->user = Session::getSession()->get('user'); if ($this->user !== null && $this->user->isExternalUser()) { list($originUsername, $field) = $this->user->getExternalUserInformation(); $username = ExternalBackend::getRemoteUser($field); if ($username === null || $username !== $originUsername) { $this->removeAuthorization(); } } } /** * Attempt to authenticate a user from external user backends * * @return bool */ protected function authExternal() { $user = new User(''); foreach ($this->getAuthChain() as $userBackend) { if ($userBackend instanceof ExternalBackend) { if ($userBackend->authenticate($user)) { if (! $user->hasDomain()) { $user->setDomain(Config::app()->get('authentication', 'default_domain')); } $this->setAuthenticated($user); return true; } } } return false; } /** * Attempt to authenticate a user using HTTP authentication on API requests only * * Supports only the Basic HTTP authentication scheme. XHR will be ignored. * * @return bool */ public function authHttp() { $request = $this->getRequest(); $header = $request->getHeader('Authorization'); if (empty($header)) { return false; } list($scheme) = explode(' ', $header, 2); if ($scheme !== 'Basic') { return false; } $authorization = substr($header, strlen('Basic ')); $credentials = base64_decode($authorization); $credentials = array_filter(explode(':', $credentials, 2)); if (count($credentials) !== 2) { // Deny empty username and/or password return false; } $user = new User($credentials[0]); if (! $user->hasDomain()) { $user->setDomain(Config::app()->get('authentication', 'default_domain')); } $password = $credentials[1]; if ($this->getAuthChain()->setSkipExternalBackends(true)->authenticate($user, $password)) { $this->setAuthenticated($user, false); $user->setIsHttpUser(true); return true; } else { return false; } } /** * Challenge client immediately for HTTP authentication * * Sends the response w/ the 401 Unauthorized status code and WWW-Authenticate header. */ public function challengeHttp() { $response = $this->getResponse(); $response->setHttpResponseCode(401); $response->setHeader('WWW-Authenticate', 'Basic realm="Icinga Web 2"'); $response->sendHeaders(); exit(); } /** * Whether an authenticated user has a given permission * * @param string $permission Permission name * * @return bool True if the user owns the given permission, false if not or if not authenticated */ public function hasPermission($permission) { if (! $this->isAuthenticated()) { return false; } return $this->user->can($permission); } /** * Writes the current user to the session */ public function persistCurrentUser() { // @TODO(el): https://dev.icinga.com/issues/10646 $params = session_get_cookie_params(); setcookie( 'icingaweb2-session', time(), 0, $params['path'], $params['domain'], $params['secure'], $params['httponly'] ); Session::getSession()->set('user', $this->user)->refreshId(); } /** * Purges the current authorization information and session */ public function removeAuthorization() { AuditHook::logActivity('logout', 'User logged out'); $this->user = null; Session::getSession()->purge(); } /** * Setup the given user * * This loads preferences, groups and roles. * * @param User $user * * @return void */ public function setupUser(User $user) { // Load the user's preferences try { $config = Config::app(); } catch (NotReadableError $e) { Logger::error( new IcingaException( 'Cannot load preferences for user "%s". An exception was thrown: %s', $user->getUsername(), $e ) ); $config = new Config(); } $preferencesConfig = new ConfigObject([ 'resource' => $config->get('global', 'config_resource') ]); try { $preferencesStore = PreferencesStore::create($preferencesConfig, $user); $preferences = new Preferences($preferencesStore->load()); } catch (Exception $e) { Logger::error( new IcingaException( 'Cannot load preferences for user "%s". An exception was thrown: %s', $user->getUsername(), $e ) ); $preferences = new Preferences(); } $user->setPreferences($preferences); // Load the user's groups $groups = $user->getGroups(); $userBackendName = $user->getAdditional('backend_name'); foreach (Config::app('groups') as $name => $config) { $groupsUserBackend = $config->user_backend; if ($groupsUserBackend && $groupsUserBackend !== 'none' && $userBackendName !== null && $groupsUserBackend !== $userBackendName ) { // Do not ask for Group membership if a specific User Backend // has been assigned to that Group Backend, and the user has // been authenticated by another User Backend continue; } try { $groupBackend = UserGroupBackend::create($name, $config); $groupsFromBackend = $groupBackend->getMemberships($user); } catch (Exception $e) { Logger::error( 'Can\'t get group memberships for user \'%s\' from backend \'%s\'. An exception was thrown: %s', $user->getUsername(), $name, $e ); continue; } if (empty($groupsFromBackend)) { Logger::debug( 'No groups found in backend "%s" which the user "%s" is a member of.', $name, $user->getUsername() ); continue; } $groupsFromBackend = array_values($groupsFromBackend); Logger::debug( 'Groups found in backend "%s" for user "%s": %s', $name, $user->getUsername(), join(', ', $groupsFromBackend) ); $groups = array_merge($groups, array_combine($groupsFromBackend, $groupsFromBackend)); } $user->setGroups($groups); // Load the user's roles $admissionLoader = new AdmissionLoader(); $admissionLoader->applyRoles($user); } }