From f8ae6f9885cbf267c948b5d81906081f4f284351 Mon Sep 17 00:00:00 2001
From: misol
Date: Mon, 25 Jun 2012 14:49:18 +0000
Subject: [PATCH] Issue 1816 Defence infinite loop of ID/Password insertion
test.
git-svn-id: http://xe-core.googlecode.com/svn/branches/1.5.0@10793 201d5d3c-b55e-5fd7-737f-ddc643e51545
---
modules/member/lang/lang.xml | 33 +++++
modules/member/member.admin.controller.php | 1 +
modules/member/member.class.php | 53 +++++++-
modules/member/member.controller.php | 138 +++++++++++++++------
modules/member/member.model.php | 3 +
modules/member/ruleset/insertConfig.xml | 2 +
modules/member/tpl/member_config.html | 8 ++
7 files changed, 200 insertions(+), 38 deletions(-)
diff --git a/modules/member/lang/lang.xml b/modules/member/lang/lang.xml
index fcee32d4e..1d2d8cf8e 100644
--- a/modules/member/lang/lang.xml
+++ b/modules/member/lang/lang.xml
@@ -155,6 +155,10 @@
+
+
+
+
@@ -2234,6 +2238,22 @@ Bạn có thể quản lý thành viên bằng cách tạo những nhóm mới,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2467,9 +2487,22 @@ Bạn có thể quản lý thành viên bằng cách tạo những nhóm mới,
+
+
+
+
+
+
+
+
+
+
+ 확인하지 않은 로그인 실패 기록이 있습니다.
%1$s
* 이 알림은 한번만 보입니다. * 이 메시지는 쪽지와 이메일로 발송됩니다. * 이 메시지는 로그인이 성공한 순간, 로그인 성공 이전 실패 기록을 모아서 발송합니다. 발송 시각: %2$s
]]>
+ There is unfolded sign in failure report
%1$s
* This notification is shown once. * This message will be send to your email and message. * This message contains sign in failure records, before a ID sign in success. Sending: %2$s
]]>
+
diff --git a/modules/member/member.admin.controller.php b/modules/member/member.admin.controller.php
index f79d83b74..f7ed1944e 100644
--- a/modules/member/member.admin.controller.php
+++ b/modules/member/member.admin.controller.php
@@ -133,6 +133,7 @@
'webmaster_email',
'limit_day',
'change_password_date',
+ 'max_error_count','max_error_count_time',
'agreement',
'after_login_url',
'after_logout_url',
diff --git a/modules/member/member.class.php b/modules/member/member.class.php
index ee17290ad..7fa87869a 100644
--- a/modules/member/member.class.php
+++ b/modules/member/member.class.php
@@ -337,5 +337,56 @@
$store = new Auth_OpenID_XEStore();
$store->reset();
}
- }
+
+ /**
+ * @brief Record login error and return the error, about IPaddress.
+ **/
+ function recordLoginError($error = 0, $message = 'success')
+ {
+ if($error == 0) return new Object($error, $message);
+
+ $args->ipaddress = $_SERVER['REMOTE_ADDR'];
+
+ $output = executeQuery('member.getLoginCountByIp', $args);
+ if($output->data && $output->data->count)
+ {
+ //update
+ $args->count = $output->data->count + 1;
+ $output = executeQuery('member.updateLoginCountByIp', $args);
+ }
+ else
+ {
+ //insert
+ $args->count = 1;
+ $output = executeQuery('member.insertLoginCountByIp', $args);
+ }
+ return new Object($error, $message);
+ }
+
+ /**
+ * @brief Record login error and return the error, about MemberSrl.
+ **/
+ function recordMemberLoginError($error = 0, $message = 'success', $args = NULL)
+ {
+ if($error == 0 || !$args->member_srl) return new Object($error, $message);
+
+ $output = executeQuery('member.getLoginCountHistoryByMemberSrl', $args);
+ if($output->data && $output->data->content)
+ {
+ //update
+ $content = unserialize($output->data->content);
+ $content[] = array($_SERVER['REMOTE_ADDR'],Context::getLang($message),time());
+ $args->content = serialize($content);
+ $output = executeQuery('member.updateLoginCountHistoryByMemberSrl', $args);
+ }
+ else
+ {
+ //insert
+ $content[0] = array($_SERVER['REMOTE_ADDR'],Context::getLang($message),time());
+ $args->content = serialize($content);
+ $output = executeQuery('member.insertLoginCountHistoryByMemberSrl', $args);
+ }
+ return $this->recordLoginError($error, $message);
+ }
+ }
?>
diff --git a/modules/member/member.controller.php b/modules/member/member.controller.php
index 00f67de00..c1200271c 100644
--- a/modules/member/member.controller.php
+++ b/modules/member/member.controller.php
@@ -1516,47 +1516,111 @@
}
}
- /**
- * @brief Log-in
- **/
- function doLogin($user_id, $password = '', $keep_signed = false) {
- $user_id = strtolower($user_id);
- // Call a trigger before log-in (before)
- $trigger_obj->user_id = $user_id;
- $trigger_obj->password = $password;
- $trigger_output = ModuleHandler::triggerCall('member.doLogin', 'before', $trigger_obj);
- if(!$trigger_output->toBool()) return $trigger_output;
- // Create a member model object
- $oMemberModel = &getModel('member');
+ /**
+ * @brief Log-in
+ **/
+ function doLogin($user_id, $password = '', $keep_signed = false) {
+ $user_id = strtolower($user_id);
+ if(!$user_id) return new Object(-1, 'null_user_id');
+ // Call a trigger before log-in (before)
+ $trigger_obj->user_id = $user_id;
+ $trigger_obj->password = $password;
+ $trigger_output = ModuleHandler::triggerCall('member.doLogin', 'before', $trigger_obj);
+ if(!$trigger_output->toBool()) return $trigger_output;
+ // Create a member model object
+ $oMemberModel = &getModel('member');
- // check identifier
- $config = $oMemberModel->getMemberConfig();
- if ($config->identifier == 'email_address'){
- // Get user_id information
- $this->memberInfo = $oMemberModel->getMemberInfoByEmailAddress($user_id);
- // Set an invalid user if no value returned
- if(!$user_id || strtolower($this->memberInfo->email_address) != strtolower($user_id)) return new Object(-1, 'invalid_email_address');
+ // check IP access count.
+ $config = $oMemberModel->getMemberConfig();
+ $args->ipaddress = $_SERVER['REMOTE_ADDR'];
+ $output = executeQuery('member.getLoginCountByIp', $args);
+ $count = (int)$output->data->count;
+ if($config->max_error_count < $count)
+ {
+ $last_update = $output->data->last_update;
+ $year = substr($last_update,0,4);
+ $month = substr($last_update,4,2);
+ $day = substr($last_update,6,2);
+ $hour = substr($last_update,8,2);
+ $min = substr($last_update,10,2);
+ $sec = substr($last_update,12,2);
+ $last_update = mktime($hour,$min,$sec,$month,$day,$year);
+ $term = intval(time()-$last_update);
+ if($term < $config->max_error_count_time)
+ {
+ $term = $config->max_error_count_time - $term;
+ if($term < 60) $term = intval($term).Context::getLang('unit_sec');
+ elseif(60 <= $term && $term < 3600) $term = intval($term/60).Context::getLang('unit_min');
+ elseif(3600 <= $term && $term < 86400) $term = intval($term/3600).Context::getLang('unit_hour');
+ else $term = intval($term/86400).Context::getLang('unit_day');
+ return new Object(-1, sprintf(Context::getLang('excess_ip_access_count'),$term));
+ }
+ else
+ {
+ $args->ipaddress = $_SERVER['REMOTE_ADDR'];
+ $output = executeQuery('member.deleteLoginCountByIp', $args);
+ }
+ }
- }else{
- // Get user_id information
- $this->memberInfo = $oMemberModel->getMemberInfoByUserID($user_id);
- // Set an invalid user if no value returned
- if(!$user_id || strtolower($this->memberInfo->user_id) != strtolower($user_id)) return new Object(-1, 'invalid_user_id');
- }
- // Password Check
- if($password && !$oMemberModel->isValidPassword($this->memberInfo->password, $password, $this->memberInfo->member_srl)) return new Object(-1, 'invalid_password');
- // If denied == 'Y', notify
- if($this->memberInfo->denied == 'Y') {
- $args->member_srl = $this->memberInfo->member_srl;
- $output = executeQuery('member.chkAuthMail', $args);
- if ($output->toBool() && $output->data->count != '0') return new Object(-1,'msg_user_not_confirmed');
- return new Object(-1,'msg_user_denied');
- }
- // Notify if denied_date is less than the current time
- if($this->memberInfo->limit_date && substr($this->memberInfo->limit_date,0,8) >= date("Ymd")) return new Object(-1,sprintf(Context::getLang('msg_user_limited'),zdate($this->memberInfo->limit_date,"Y-m-d")));
+ // check identifier
+ if ($config->identifier == 'email_address'){
+ // Get user_id information
+ $this->memberInfo = $oMemberModel->getMemberInfoByEmailAddress($user_id);
+ // Set an invalid user if no value returned
+ if(!$user_id || strtolower($this->memberInfo->email_address) != strtolower($user_id)) return $this->recordLoginError(-1, 'invalid_email_address');
+
+ }else{
+ // Get user_id information
+ $this->memberInfo = $oMemberModel->getMemberInfoByUserID($user_id);
+ // Set an invalid user if no value returned
+ if(!$user_id || strtolower($this->memberInfo->user_id) != strtolower($user_id)) return $this->recordLoginError(-1, 'invalid_user_id');
+ }
+ // Password Check
+ if($password && !$oMemberModel->isValidPassword($this->memberInfo->password, $password, $this->memberInfo->member_srl)) return $this->recordMemberLoginError(-1, 'invalid_password',$this->memberInfo);
+ // If denied == 'Y', notify
+ if($this->memberInfo->denied == 'Y') {
+ $args->member_srl = $this->memberInfo->member_srl;
+ $output = executeQuery('member.chkAuthMail', $args);
+ if ($output->toBool() && $output->data->count != '0') return new Object(-1,'msg_user_not_confirmed');
+ return new Object(-1,'msg_user_denied');
+ }
+ // Notify if denied_date is less than the current time
+ if($this->memberInfo->limit_date && substr($this->memberInfo->limit_date,0,8) >= date("Ymd")) return new Object(-1,sprintf(Context::getLang('msg_user_limited'),zdate($this->memberInfo->limit_date,"Y-m-d")));
// Update the latest login time
$args->member_srl = $this->memberInfo->member_srl;
$output = executeQuery('member.updateLastLogin', $args);
+ // check if there is login fail records.
+ $output = executeQuery('member.getLoginCountHistoryByMemberSrl', $args);
+ if($output->data && $output->data->content)
+ {
+ $title = Context::getLang('login_fail_report');
+ $message = '