/** * Displays the login page * @param object $formModel * @param bool $isMobile Whether this was called from mobile site controller */ public function login(LoginForm $model, $isMobile = false) { $model->attributes = $_POST['LoginForm']; // get user input data Session::cleanUpSessions(); $ip = $this->owner->getRealIp(); $userModel = $model->getUser(); $isRealUser = $userModel instanceof User; $effectiveUsername = $isRealUser ? $userModel->username : $model->username; $isActiveUser = $isRealUser && $userModel->status == User::STATUS_ACTIVE; /* increment count on every session with this user/IP, to prevent brute force attacks using session_id spoofing or whatever */ Yii::app()->db->createCommand('UPDATE x2_sessions SET status=status-1,lastUpdated=:time WHERE user=:name AND CAST(IP AS CHAR)=:ip AND status BETWEEN -2 AND 0')->bindValues(array(':time' => time(), ':name' => $effectiveUsername, ':ip' => $ip))->execute(); $activeUser = Yii::app()->db->createCommand()->select('username')->from('x2_users')->where('username=:name AND status=1', array(':name' => $model->username))->limit(1)->queryScalar(); // get the correctly capitalized username if (isset($_SESSION['sessionId'])) { $sessionId = $_SESSION['sessionId']; } else { $sessionId = $_SESSION['sessionId'] = session_id(); } $session = X2Model::model('Session')->findByPk($sessionId); /* get the number of failed login attempts from this IP within timeout interval. If the number of login attempts exceeds maximum, display captcha */ $badAttemptsRefreshTimeout = 900; $maxFailedLoginAttemptsPerIP = 100; $maxLoginsBeforeCaptcha = 5; $this->pruneTimedOutBans($badAttemptsRefreshTimeout); $failedLoginRecord = FailedLogins::model()->findActiveByIp($ip); $badAttemptsWithThisIp = $failedLoginRecord ? $failedLoginRecord->attempts : 0; if ($badAttemptsWithThisIp >= $maxFailedLoginAttemptsPerIP) { $this->recordFailedLogin($ip); throw new CHttpException(403, Yii::t('app', 'You are not authorized to use this application')); } // if this client has already tried to log in, increment their attempt count if ($session === null) { $session = new Session(); $session->id = $sessionId; $session->user = $model->getSessionUserName(); $session->lastUpdated = time(); $session->status = 0; $session->IP = $ip; } else { $session->lastUpdated = time(); $session->user = $model->getSessionUserName(); } if ($isActiveUser === false) { $model->verifyCode = ''; // clear captcha code $model->validate(); // validate captcha if it's being used $this->recordFailedLogin($ip); $session->save(); if ($badAttemptsWithThisIp + 1 >= $maxFailedLoginAttemptsPerIP) { throw new CHttpException(403, Yii::t('app', 'You are not authorized to use this application')); } else { if ($badAttemptsWithThisIp >= $maxLoginsBeforeCaptcha - 1) { $model->useCaptcha = true; $model->setScenario('loginWithCaptcha'); $session->status = -2; } } } else { if ($model->validate() && $model->login()) { // user successfully logged in if ($model->rememberMe) { foreach (array('username', 'rememberMe') as $attr) { // Expires in 30 days AuxLib::setCookie(CHtml::resolveName($model, $attr), $model->{$attr}, 2592000); } } else { foreach (array('username', 'rememberMe') as $attr) { // Remove the cookie if they unchecked the box AuxLib::clearCookie(CHtml::resolveName($model, $attr)); } } // We're not using the isAdmin parameter of the application // here because isAdmin in this context hasn't been set yet. $isAdmin = Yii::app()->user->checkAccess('AdminIndex'); if ($isAdmin && !$isMobile) { $this->owner->attachBehavior('updaterBehavior', new UpdaterBehavior()); $this->owner->checkUpdates(); // check for updates if admin } else { Yii::app()->session['versionCheck'] = true; } // ...or don't $session->status = 1; $session->save(); SessionLog::logSession($model->username, $sessionId, 'login'); $_SESSION['playLoginSound'] = true; if (YII_UNIT_TESTING && defined('X2_DEBUG_EMAIL') && X2_DEBUG_EMAIL) { Yii::app()->session['debugEmailWarning'] = 1; } // if ( isset($_POST['themeName']) ) { // $profile = X2Model::model('Profile')->findByPk(Yii::app()->user->id); // $profile->theme = array_merge( // $profile->theme, // ThemeGenerator::loadDefault( $_POST['themeName']) // ); // $profile->save(); // } LoginThemeHelper::login(); if ($isMobile) { $this->owner->redirect($this->owner->createUrl('/mobile/home')); } else { if (Yii::app()->user->returnUrl == '/site/index') { $this->owner->redirect(array('/site/index')); } else { // after login, redirect to wherever $this->owner->redirect(Yii::app()->user->returnUrl); } } } else { // login failed $model->verifyCode = ''; // clear captcha code $this->recordFailedLogin($ip); $session->save(); if ($badAttemptsWithThisIp + 1 >= $maxFailedLoginAttemptsPerIP) { throw new CHttpException(403, Yii::t('app', 'You are not authorized to use this application')); } else { if ($badAttemptsWithThisIp >= $maxLoginsBeforeCaptcha - 1) { $model->useCaptcha = true; $model->setScenario('loginWithCaptcha'); $session->status = -2; } } } } $model->rememberMe = false; }
/** * An AJAX called function which will return HTML containing a full history * of a particular session, from login to logout. * @param $id The ID of the session */ public function actionViewSessionHistory($id) { $sessions = X2Model::model('SessionLog')->findAllByAttributes(array('sessionId' => $id)); $firstTimestamp = 0; $lastTimestamp = 0; $str = "<table class='items'><thead><tr><th>User</th><th>Status</th><th>Timestamp</th></tr></thead>"; foreach ($sessions as $session) { $str .= "<tr>"; $str .= "<td>" . User::getUserLinks($session->user) . "</td>"; $str .= "<td>" . SessionLog::parseStatus($session->status) . "</td>"; $str .= "<td>" . Formatter::formatCompleteDate($session->timestamp) . "</td>"; $str .= "</tr>"; } $str .= "</table>"; echo $str; }
/** * Load dynamic app configuration. * * Per the onBeginRequest key in the array returned by {@link events()}, * this method will be called when the request has begun. It allows for * many extra configuration tasks to be run on a per-request basis * without having to extend {@link Yii} and override its methods. */ public function beginRequest() { // About the "noSession" property/variable: // // This variable, if true, indicates that the application is running in // the context of either an API call or a console command, in which case // there would not be the typical authenticated user and session // variables one would need in a web request // // It's necessary because originally this method was written with // absolutely no regard for compatibility with the API or Yii console, // and thus certain lines of code that make references to the usual web // environment with cookie-based authentication (which would fail in // those cases) needed to be kept inside of conditional statements that // are skipped over if in the console/API. $this->owner->params->noSession = $this->owner->params->noSession || strpos($this->owner->request->getPathInfo(), 'api/') === 0 || strpos($this->owner->request->getPathInfo(), 'api2/') === 0; $noSession = $this->owner->params->noSession; if (!$noSession) { if ($this->owner->request->getPathInfo() == 'notifications/get') { // skip all the loading if this is a chat/notification update Yii::import('application.components.util.AuxLib'); Yii::import('application.models.Roles'); Yii::import('application.components.X2AuthManager'); Yii::import('application.components.X2Html'); Yii::import('application.components.X2WebUser'); Yii::import('application.components.sortableWidget.*'); Yii::import('application.components.sortableWidget.profileWidgets.*'); Yii::import('application.components.sortableWidget.recordViewWidgets.*'); Yii::import('application.components.X2Settings.*'); Yii::import('application.components.X2MessageSource'); Yii::import('application.components.Formatter'); Yii::import('application.components.X2Html'); Yii::import('application.components.JSONEmbeddedModelFieldsBehavior'); Yii::import('application.components.TransformedFieldStorageBehavior'); Yii::import('application.components.EncryptedFieldsBehavior'); Yii::import('application.components.permissions.*'); Yii::import('application.models.Modules'); if (!$this->owner->user->getIsGuest()) { $profData = $this->owner->db->createCommand()->select('timeZone, language')->from('x2_profile')->where('id=' . $this->owner->user->getId())->queryRow(); } // set the timezone to the admin's if (isset($profData)) { if (isset($profData['timeZone'])) { $timezone = $profData['timeZone']; } if (isset($profData['language'])) { $language = $profData['language']; } else { } } if (!isset($timezone)) { $timezone = 'UTC'; } if (!isset($language)) { $language = 'en'; } date_default_timezone_set($timezone); $this->owner->language = $language; Yii::import('application.models.X2Model'); Yii::import('application.models.Dropdowns'); Yii::import('application.models.Admin'); $this->cryptInit(); // Yii::import('application.models.*'); // foreach(scandir('protected/modules') as $module){ // if(file_exists('protected/modules/'.$module.'/register.php')) // Yii::import('application.modules.'.$module.'.models.*'); // } return; } } else { Yii::import('application.models.Profile'); Yii::import('application.components.sortableWidget.*'); Yii::import('application.components.X2Settings.*'); Yii::import('application.components.TransformedFieldStorageBehavior'); // Set time zone based on the default value date_default_timezone_set(Profile::model()->tableSchema->getColumn('timeZone')->defaultValue); } $this->importDirectories(); $this->cryptInit(); if (YII_DEBUG) { $this->owner->params->timer = new TimerUtil(); } $this->owner->messages->onMissingTranslation = array(new TranslationLogger(), 'log'); // Set profile // // Get the Administrator's and the current user's profile. $adminProf = Profile::model()->findByPk(1); $this->owner->params->adminProfile = $adminProf; if (!$noSession) { // Typical web session: $notGuest = !$this->owner->user->getIsGuest(); if ($notGuest) { $this->owner->params->profile = X2Model::model('Profile')->findByAttributes(array('username' => $this->owner->user->getName())); $this->setSuModel($this->owner->params->profile->user); } else { $this->owner->params->profile = Profile::model()->getGuestProfile(); } } else { // Use the admin profile as the user profile. // // If a different profile is desired in an API call or console // command, a different profile should be loaded. // // Using "admin" as the default profile should not affect // permissions (that's what the "suModel" property is for). It is // merely to account for cases where there is a reference to the // "profile" property of some model or component class that would // break the application outside the scope of a web request with a // session and cookie-based authentication. $notGuest = false; $this->owner->params->profile = $adminProf; $userModel = $this->owner->params->profile->user; $this->setSuModel($userModel instanceof User ? $userModel : User::model()->findByPk(1)); } // Set session variables if (!$noSession) { $sessionId = isset($_SESSION['sessionId']) ? $_SESSION['sessionId'] : session_id(); $session = X2Model::model('Session')->findByPk($sessionId); if (!empty($this->owner->params->profile)) { $_SESSION['fullscreen'] = $this->owner->params->profile->fullscreen; } if (!($this->owner->request->getPathInfo() == 'site/getEvents')) { if ($notGuest) { $this->owner->user->setReturnUrl($this->owner->request->requestUri); if ($session != null) { $timeout = Roles::getUserTimeout($this->owner->user->getId()); if ($session->lastUpdated + $timeout < time()) { SessionLog::logSession($this->owner->user->getName(), $sessionId, 'activeTimeout'); $session->delete(); $this->owner->user->logout(false); $this->_suModel = null; $this->_suID = null; $this->setUserAccessParameters(null); } else { // Print a warning message if ($this->owner->session['debugEmailWarning']) { $this->owner->session['debugEmailWarning'] = 0; $this->owner->user->setFlash('admin.debugEmailMode', Yii::t('app', 'Note, email debugging mode ' . 'is enabled. Emails will not ' . 'actually be delivered.')); } $session->lastUpdated = time(); $session->update(array('lastUpdated')); $this->owner->params->sessionStatus = $session->status; } } else { $this->owner->user->logout(false); } } else { // Guest $this->setUserAccessParameters(null); } } } // Configure logos if (!($logo = $this->owner->cache['x2Power'])) { $logo = 'data:image/png;base64,' . base64_encode(file_get_contents(implode(DIRECTORY_SEPARATOR, array(Yii::app()->basePath, '..', 'images', 'powered_by_x2engine.png')))); $this->owner->cache['x2Power'] = $logo; } $this->owner->params->x2Power = $logo; $logo = Media::model()->findByAttributes(array('associationId' => 1, 'associationType' => 'logo')); if (isset($logo)) { $this->owner->params->logo = $logo->fileName; } // Set currency and load currency symbols $this->owner->params->currency = $this->settings->currency; $locale = $this->owner->locale; $curSyms = array(); foreach ($this->owner->params->supportedCurrencies as $curCode) { $curSyms[$curCode] = $locale->getCurrencySymbol($curCode); } $this->owner->params->supportedCurrencySymbols = $curSyms; // Code to symbol // Set language if (!empty($this->owner->params->profile->language)) { $this->owner->language = $this->owner->params->profile->language; } else { if (isset($adminProf)) { $this->owner->language = $adminProf->language; } } // Set timezone if (!empty($this->owner->params->profile->timeZone)) { date_default_timezone_set($this->owner->params->profile->timeZone); } elseif (!empty($adminProf->timeZone)) { date_default_timezone_set($adminProf->timeZone); } else { date_default_timezone_set('UTC'); } setlocale(LC_ALL, 'en_US.UTF-8'); // Set base path and theme path globals for JS (web UI only) if (!$noSession) { $this->checkForMobileDevice(); $this->checkResponsiveLayout(); if ($notGuest) { $profile = $this->owner->params->profile; if (isset($profile)) { $yiiString = $this->getJSGlobalsSetupScript($profile); } else { $yiiString = $this->getJSGlobalsSetupScript(); } if (!$this->owner->request->isAjaxRequest) { Yii::app()->clientScript->registerScript(sprintf('%x', crc32(Yii::app()->name)), base64_decode('dmFyIF8weDFhNzk9WyJceDc1XHg2RVx4NjRceDY1XHg2Nlx4NjlceDZFXHg2NVx4NjQiLCJceDZDXHg2R' . 'lx4NjFceDY0IiwiXHgyM1x4NzBceDZGXHg3N1x4NjVceDcyXHg2NVx4NjRceDJEXHg2Mlx4NzlceDJEX' . 'Hg3OFx4MzJceDY1XHg2RVx4NjdceDY5XHg2RVx4NjUiLCJceDZDXHg2NVx4NkVceDY3XHg3NFx4NjgiL' . 'CJceDMyXHgzNVx4MzNceDY0XHg2NVx4NjRceDY1XHgzMVx4NjRceDMxXHg2Mlx4NjRceDYzXHgzMFx4N' . 'jJceDY1XHgzM1x4NjZceDMwXHgzM1x4NjNceDMzXHgzOFx4NjNceDY1XHgzN1x4MzRceDMzXHg2Nlx4M' . 'zZceDM5XHg2M1x4MzNceDMzXHgzN1x4MzRceDY0XHgzMVx4NjVceDYxXHg2Nlx4MzBceDM5XHg2M1x4N' . 'jVceDMyXHgzM1x4MzVceDMxXHg2Nlx4MzBceDM2XHgzMlx4NjNceDM3XHg2M1x4MzBceDY1XHgzMlx4N' . 'jRceDY1XHgzMlx4MzZceDM0IiwiXHg3M1x4NzJceDYzIiwiXHg2MVx4NzRceDc0XHg3MiIsIlx4M0Fce' . 'Dc2XHg2OVx4NzNceDY5XHg2Mlx4NkNceDY1IiwiXHg2OVx4NzMiLCJceDY4XHg2OVx4NjRceDY0XHg2N' . 'Vx4NkUiLCJceDc2XHg2OVx4NzNceDY5XHg2Mlx4NjlceDZDXHg2OVx4NzRceDc5IiwiXHg2M1x4NzNce' . 'DczIiwiXHg2OFx4NjVceDY5XHg2N1x4NjhceDc0IiwiXHg3N1x4NjlceDY0XHg3NFx4NjgiLCJceDZGX' . 'Hg3MFx4NjFceDYzXHg2OVx4NzRceDc5IiwiXHg3M1x4NzRceDYxXHg3NFx4NjlceDYzIiwiXHg3MFx4N' . 'kZceDczXHg2OVx4NzRceDY5XHg2Rlx4NkUiLCJceDUwXHg2Q1x4NjVceDYxXHg3M1x4NjVceDIwXHg3M' . 'Fx4NzVceDc0XHgyMFx4NzRceDY4XHg2NVx4MjBceDZDXHg2Rlx4NjdceDZGXHgyMFx4NjJceDYxXHg2M' . '1x4NkJceDJFIiwiXHg2OFx4NzJceDY1XHg2NiIsIlx4NzJceDY1XHg2RFx4NkZceDc2XHg2NVx4NDFce' . 'Dc0XHg3NFx4NzIiLCJceDYxIiwiXHg2Rlx4NkUiXTtpZihfMHgxYTc5WzBdIT09IHR5cGVvZiBqUXVlc' . 'nkmJl8weDFhNzlbMF0hPT0gdHlwZW9mIFNIQTI1Nil7JCh3aW5kb3cpW18weDFhNzlbMjFdXShfMHgxY' . 'Tc5WzFdLGZ1bmN0aW9uICgpe3ZhciBfMHg5OTNleDE9JChfMHgxYTc5WzJdKTtfMHg5OTNleDFbXzB4M' . 'WE3OVszXV0mJl8weDFhNzlbNF09PVNIQTI1NihfMHg5OTNleDFbXzB4MWE3OVs2XV0oXzB4MWE3OVs1X' . 'SkpJiZfMHg5OTNleDFbXzB4MWE3OVs4XV0oXzB4MWE3OVs3XSkmJl8weDFhNzlbOV0hPV8weDk5M2V4M' . 'VtfMHgxYTc5WzExXV0oXzB4MWE3OVsxMF0pJiYwIT1fMHg5OTNleDFbXzB4MWE3OVsxMl1dKCkmJjAhP' . 'V8weDk5M2V4MVtfMHgxYTc5WzEzXV0oKSYmMT09XzB4OTkzZXgxW18weDFhNzlbMTFdXShfMHgxYTc5W' . 'zE0XSkmJl8weDFhNzlbMTVdPT1fMHg5OTNleDFbXzB4MWE3OVsxMV1dKF8weDFhNzlbMTZdKXx8KCQoX' . 'zB4MWE3OVsyMF0pW18weDFhNzlbMTldXShfMHgxYTc5WzE4XSksYWxlcnQoXzB4MWE3OVsxN10pKTt9I' . 'Ck7fQo=')); } } else { $yiiString = $this->getJSGlobalsSetupScript(); } $this->owner->clientScript->registerScript('setParams', $yiiString, CClientScript::POS_HEAD); $cs = $this->owner->clientScript; $baseUrl = $this->owner->request->baseUrl; $jsVersion = '?' . $this->owner->params->buildDate; /** * To be restored when JavaScript minification is added to the build process: * $cs->scriptMap=array( * 'backgroundImage.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'json2.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'layout.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'media.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'modernizr.custom.66175.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'publisher.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * //'relationships.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'tags.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'translator.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'widgets.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * 'x2forms.js'=>$baseUrl.'/js/all.min.js'.$jsVersion, * ); */ } }
/** * Clear session records which have timed out. Log the timeout. */ public static function cleanUpSessions() { // Only select users with active sessions to clear out, in case there are // dozens of inactive users, to make things more efficient: $users = Yii::app()->db->createCommand()->select('x2_users.id,x2_users.username')->from('x2_users')->rightJoin('x2_sessions', 'x2_sessions.user = x2_users.username')->where('x2_users.username IS NOT NULL AND x2_users.username != ""')->queryAll(); foreach ($users as $user) { $timeout = Roles::getUserTimeout($user['id']); $sessions = X2Model::model('Session')->findAllByAttributes(array('user' => $user['username']), 'lastUpdated < :cutoff', array(':cutoff' => time() - $timeout)); foreach ($sessions as $session) { SessionLog::logSession($session->user, $session->id, 'passiveTimeout'); $session->delete(); } } // check timeout on sessions not corresponding to any existing user $defaultTimeout = 900; self::model()->deleteAll(array('condition' => 'lastUpdated < :cutoff and user not in (select distinct (username) from x2_users)', 'params' => array(':cutoff' => time() - $defaultTimeout))); }
public function actionToggleVisibility() { $id = $_SESSION['sessionId']; $session = Session::model()->findByAttributes(array('id' => $id)); if (isset($session)) { if ($session->status < 0) { $session->status = 0; } $session->status = !$session->status; $session->save(); SessionLog::logSession(Yii::app()->user->getName(), $id, $session->status ? "visible" : "invisible"); } $this->redirect($_GET['redirect']); }
public function actionPushSessionLogEnd() { $student_id = Yii::app()->request->getPost("student_id", NULL); $session_id = Yii::app()->request->getPost("session_id", NULL); $session_end_time = Yii::app()->request->getPost("session_end_time", NULL); $session = SessionLog::model()->find('student_id=:student_id AND session_id=:session_id', array(':student_id' => $student_id, ':session_id' => $session_id)); if ($session) { $session->session_end_time = $session_end_time; if (!$session->save()) { $this->renderJSON($session->getErrors()); } else { $this->renderJSON(array('status' => 1, 'message' => 'Successfully saved!')); } } else { $this->renderJSON(array('status' => 0, 'message' => 'Given Questionnaire could not be found!')); } }
public static function logSession($user, $sessionId, $status) { $sessionLog = Yii::app()->db->createCommand()->select('sessionLog')->from('x2_admin')->where('id=1')->queryScalar(); if ($sessionLog) { $model = new SessionLog(); $model->user = $user; $model->sessionId = $sessionId; $model->status = $status; $model->timestamp = time(); $model->save(); } }
/** * Logs out the current user and redirect to homepage. */ public function actionLogout() { $user = User::model()->findByPk(Yii::app()->user->getId()); if (isset($user)) { $user->lastLogin = time(); $user->save(); if (isset($_SESSION['sessionId'])) { SessionLog::logSession($user->username, $_SESSION['sessionId'], 'logout'); X2Model::model('Session')->deleteByPk($_SESSION['sessionId']); } else { X2Model::model('Session')->deleteAllByAttributes(array('IP' => $this->getRealIp())); } } if (isset($_SESSION['access_token'])) { unset($_SESSION['access_token']); } $this->redirect($this->createAbsoluteUrl('login')); }
protected function getSessionLogs($student_id) { $session_logs = SessionLog::model()->findAll('student_id=:student_id AND (session_end_time!=NULL or session_end_time!="")', array(':student_id' => $student_id)); return $session_logs; }