Browse Source

Adding account blocked due number of wrong attempts see BT#6486

Julio Montoya 11 years ago
parent
commit
6773a8829b
3 changed files with 141 additions and 46 deletions
  1. 39 0
      main/inc/lib/main_api.lib.php
  2. 31 22
      main/inc/lib/userportal.lib.php
  3. 71 24
      main/inc/local.inc.php

+ 39 - 0
main/inc/lib/main_api.lib.php

@@ -6510,3 +6510,42 @@ function api_get_easy_password_list()
     }
     return $passwordList;
 }
+
+/**
+ *
+* create an user extra field called 'captcha_blocked_until_date'
+ */
+function api_block_account_captcha($username)
+{
+    $userInfo = api_get_user_info_from_username($username);
+    if (empty($userInfo)) {
+        return false;
+    }
+    global $_configuration;
+    $minutesToBlock = isset($_configuration['captcha_time_to_block']) ? $_configuration['captcha_time_to_block'] : 10;
+    $time = time() + $minutesToBlock*60;
+    Usermanager::update_extra_field_value($userInfo['user_id'], 'captcha_blocked_until_date', api_get_utc_datetime($time));
+}
+
+function api_clean_account_captcha($username)
+{
+    $userInfo = api_get_user_info_from_username($username);
+    if (empty($userInfo)) {
+        return false;
+    }
+    Session::erase('loginFailedCount');
+    Usermanager::update_extra_field_value($userInfo['user_id'], 'captcha_blocked_until_date', null);
+}
+
+function api_get_user_blocked_by_captcha($username)
+{
+    $userInfo = api_get_user_info_from_username($username);
+    if (empty($userInfo)) {
+        return false;
+    }
+    $data = Usermanager::get_extra_user_data_by_field($userInfo['user_id'], 'captcha_blocked_until_date');
+    if (isset($data)) {
+        return $data['captcha_blocked_until_date'];
+    }
+    return false;
+}

+ 31 - 22
main/inc/lib/userportal.lib.php

@@ -335,6 +335,9 @@ class IndexManager {
                 case 'wrong_captcha':
                     $message = get_lang('TheTextYouEnteredDoesNotMatchThePicture');
                     break;
+                case 'blocked_by_captcha':
+                    $message = get_lang('AccountBlockedByCaptcha');
+                    break;
                 case 'unrecognize_sso_origin':
                     //$message = get_lang('SSOError');
                     break;
@@ -646,37 +649,43 @@ class IndexManager {
 		$form = new FormValidator('formLogin', 'POST', null,  null, array('class'=>'form-vertical'));
 		$form->addElement('text', 'login', get_lang('UserName'), array('class' => 'span2 autocapitalize_off', 'autofocus' => 'autofocus'));
 		$form->addElement('password', 'password', get_lang('Pass'), array('class' => 'span2'));
+        global $_configuration;
 
         // Captcha
+        $allowCaptcha = isset($_configuration['allow_captcha']) ? $_configuration['allow_captcha'] : false;
+
+        if ($allowCaptcha) {
 
-        $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
+            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
 
-        if ($useCaptcha) {
+            if ($useCaptcha) {
 
-            $form->addElement('text', 'captcha', 'Enter the letters you see');
-            $form->addRule('captcha', 'Enter the characters you read in the image', 'required', null, 'client');
+                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
 
-            $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
+                $options = array(
+                    'width'        => 250,
+                    'height'       => 90,
+                    'callback'     => $ajax.'&var='.basename(__FILE__, '.php'),
+                    'sessionVar'   => basename(__FILE__, '.php'),
+                    'imageOptions' => array(
+                        'font_size' => 20,
+                        'font_path' => api_get_path(LIBRARY_PATH).'pchart/fonts/',
+                        'font_file' => 'tahoma.ttf',
+                        //'output' => 'gif'
+                    )
+                );
 
-            $options = array(
-                'width'        => 250,
-                'height'       => 90,
-                'callback'     => $ajax.'&var='.basename(__FILE__, '.php'),
-                'sessionVar'   => basename(__FILE__, '.php'),
-                'imageOptions' => array(
-                    'font_size' => 20,
-                    'font_path' => api_get_path(LIBRARY_PATH).'pchart/fonts/',
-                    'font_file' => 'tahoma.ttf',
-                    //'output' => 'gif'
-                )
-            );
+                // Minimum options using all defaults (including defaults for Image_Text):
+                //$options = array('callback' => 'qfcaptcha_image.php');
 
-            // Minimum options using all defaults (including defaults for Image_Text):
-            //$options = array('callback' => 'qfcaptcha_image.php');
+                $captcha_question =  $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
+                $form->addElement('static', null, null, get_lang('ClickOnTheImageForANewOne'));
 
-            $captcha_question =  $form->addElement('CAPTCHA_Image', 'captcha_question', 'Verification', $options);
-            $form->addElement('static', null, null, 'Click on the image for a new one');
-            $form->addRule('captcha', 'What you entered didn\'t match the picture', 'CAPTCHA', $captcha_question);
+                $form->addElement('text', 'captcha', get_lang('EnterTheLettersYouSee'));
+                $form->addRule('captcha', get_lang('EnterTheCharactersYouReadInTheImage'), 'required', null, 'client');
+
+                $form->addRule('captcha', 'What you entered didn\'t match the picture', 'CAPTCHA', $captcha_question);
+            }
         }
 
 		$form->addElement('style_submit_button','submitAuth', get_lang('LoginEnter'), array('class' => 'btn'));

+ 71 - 24
main/inc/local.inc.php

@@ -237,44 +237,69 @@ if (!empty($_SESSION['_user']['user_id']) && !($login || $logout)) {
                 WHERE username = '".Database::escape_string($login)."'";
         $result = Database::query($sql);
 
-        $catpchaValidated = true;
+        $captchaValidated = true;
+        $allowCaptcha = isset($_configuration['allow_captcha']) ? $_configuration['allow_captcha'] : false;
 
         if (Database::num_rows($result) > 0) {
             $uData = Database::fetch_array($result);
 
-            if (isset($_POST['captcha'])) {
-                // Check captcha
-                $captchaText = $_POST['captcha'];
-                /** @var Text_CAPTCHA $obj */
-                $obj = isset($_SESSION['userportal.lib']) ? $_SESSION['userportal.lib'] : null;
-                if ($obj) {
-                    $obj->getPhrase();
-                    if ($obj->getPhrase() != $captchaText) {
-                        $catpchaValidated = false;
-                    } else {
-                        $catpchaValidated = true;
+            if ($allowCaptcha) {
+
+                // Checking captcha
+                if (isset($_POST['captcha'])) {
+                    // Check captcha
+                    $captchaText = $_POST['captcha'];
+                    /** @var Text_CAPTCHA $obj */
+                    $obj = isset($_SESSION['userportal.lib']) ? $_SESSION['userportal.lib'] : null;
+                    if ($obj) {
+                        $obj->getPhrase();
+                        if ($obj->getPhrase() != $captchaText) {
+                            $captchaValidated = false;
+                        } else {
+                            $captchaValidated = true;
+                        }
+                    }
+                    if (isset($_SESSION['captcha_question'])) {
+                        $captcha_question = $_SESSION['captcha_question'];
+                        $captcha_question->destroy();
                     }
                 }
-                if (isset($_SESSION['captcha_question'])) {
-                    $captcha_question = $_SESSION['captcha_question'];
-                    $captcha_question->destroy();
+
+                // Redirect to login page
+                if ($captchaValidated == false) {
+                    $loginFailed = true;
+                    Session::erase('_uid');
+                    Session::write('loginFailed', '1');
+
+                    header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=wrong_captcha');
+                    exit;
                 }
-            }
 
-            if ($catpchaValidated == false) {
-                $loginFailed = true;
-                Session::erase('_uid');
-                Session::write('loginFailed', '1');
-                header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=wrong_captcha');
-                exit;
+                // Check if account is blocked by captcha user extra field see function api_block_account_captcha()
+                $blockedUntilDate = api_get_user_blocked_by_captcha($login);
+
+                if (isset($blockedUntilDate) && !empty($blockedUntilDate)) {
+                    if (time() > api_strtotime($blockedUntilDate, 'UTC')) {
+                        api_clean_account_captcha($login);
+
+                    } else {
+                        $loginFailed = true;
+                        Session::erase('_uid');
+                        Session::write('loginFailed', '1');
+
+                        header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=blocked_by_captcha');
+                        exit;
+                    }
+                }
             }
 
+
             if ($uData['auth_source'] == PLATFORM_AUTH_SOURCE || $uData['auth_source'] == CAS_AUTH_SOURCE) {
                 //The authentification of this user is managed by Chamilo itself
                 $password = api_get_encrypted_password(trim(stripslashes($password)));
 
                 // Check the user's password
-                if (($password == $uData['password']  OR $cas_login) AND (trim($login) == $uData['username'])) {
+                if (($password == $uData['password'] OR $cas_login) AND (trim($login) == $uData['username'])) {
                     $update_type = UserManager::get_extra_user_data_by_field($uData['user_id'], 'update_type');
                     $update_type= $update_type['update_type'];
                     if (!empty($extAuthSource[$update_type]['updateUser']) && file_exists($extAuthSource[$update_type]['updateUser'])) {
@@ -377,6 +402,24 @@ if (!empty($_SESSION['_user']['user_id']) && !($login || $logout)) {
                     $loginFailed = true;
                     Session::erase('_uid');
                     Session::write('loginFailed', '1');
+
+                    if ($allowCaptcha) {
+
+                        if (isset($_SESSION['loginFailedCount'])) {
+                            $_SESSION['loginFailedCount']++;
+                        } else {
+                            $_SESSION['loginFailedCount'] = 1;
+                        }
+
+                        $numberMistakesToBlockAccount = isset($_configuration['captcha_number_mistakes_to_block_account']) ? $_configuration['captcha_number_mistakes_to_block_account'] : 10;
+
+                        if (isset($_SESSION['loginFailedCount'])) {
+                            if ($_SESSION['loginFailedCount'] >= $numberMistakesToBlockAccount) {
+                                api_block_account_captcha($login);
+                            }
+                        }
+                    }
+
                     header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=user_password_incorrect');
                     exit;
                 }
@@ -618,8 +661,12 @@ if (isset($uidReset) && $uidReset) {    // session data refresh requested
     $is_allowedCreateCourse = false;
 
     if (isset($_user['user_id']) && $_user['user_id'] && ! api_is_anonymous()) {
-    // a uid is given (log in succeeded)
+        // a uid is given (log in succeeded)
+
         $_SESSION['loginFailed'] = false;
+        unset($_SESSION['loginFailedCount']);
+        unset($_SESSION['loginToBlock']);
+
         $user_table     = Database::get_main_table(TABLE_MAIN_USER);
         $admin_table    = Database::get_main_table(TABLE_MAIN_ADMIN);
         $track_e_login  = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LOGIN);