Adding apihighlimits permission. Users with this permission can request 10 times...
[lhc/web/wiklou.git] / includes / api / ApiLogin.php
index 1caac14..7d78124 100644 (file)
@@ -37,16 +37,16 @@ if (!defined('MEDIAWIKI')) {
 class ApiLogin extends ApiBase {
        
        /**
-        * The amount of time a user must wait after submitting
+        * Time (in seconds) a user must wait after submitting
         * a bad login (will be multiplied by the THROTTLE_FACTOR for each bad attempt)
         */
-       const THROTTLE_TIME = 10;
+       const THROTTLE_TIME = 5;
 
        /**
         * The factor by which the wait-time in between authentication
         * attempts is increased every failed attempt.
         */
-       const THROTTLE_FACTOR = 1.5;
+       const THROTTLE_FACTOR = 2;
        
        /**
         * The maximum number of failed logins after which the wait increase stops. 
@@ -72,15 +72,9 @@ class ApiLogin extends ApiBase {
                $name = $password = $domain = null;
                extract($this->extractRequestParams());
 
-               $params = new FauxRequest(array (
-                       'wpName' => $name,
-                       'wpPassword' => $password,
-                       'wpDomain' => $domain,
-                       'wpRemember' => ''
-               ));
-
                $result = array ();
 
+               // Make sure noone is trying to guess the password brut-force
                $nextLoginIn = $this->getNextLoginTimeout();
                if ($nextLoginIn > 0) {
                        $result['result']  = 'NeedToWait';
@@ -90,10 +84,17 @@ class ApiLogin extends ApiBase {
                        return;
                }
 
+               $params = new FauxRequest(array (
+                       'wpName' => $name,
+                       'wpPassword' => $password,
+                       'wpDomain' => $domain,
+                       'wpRemember' => ''
+               ));
+
                $loginForm = new LoginForm($params);
                switch ($loginForm->authenticateUserData()) {
                        case LoginForm :: SUCCESS :
-                               global $wgUser;
+                               global $wgUser, $wgCookiePrefix;
 
                                $wgUser->setOption('rememberpassword', 1);
                                $wgUser->setCookies();
@@ -102,6 +103,8 @@ class ApiLogin extends ApiBase {
                                $result['lguserid'] = $_SESSION['wsUserID'];
                                $result['lgusername'] = $_SESSION['wsUserName'];
                                $result['lgtoken'] = $_SESSION['wsToken'];
+                               $result['cookieprefix'] = $wgCookiePrefix;
+                               $result['sessionid'] = $_COOKIE["{$wgCookiePrefix}_session"];
                                break;
 
                        case LoginForm :: NO_NAME :
@@ -128,6 +131,7 @@ class ApiLogin extends ApiBase {
 
                if ($result['result'] != 'Success') {
                        $result['wait'] = $this->cacheBadLogin();
+                       $result['details'] = "Please wait " . self::THROTTLE_TIME . " seconds before next log-in attempt";
                }
                // if we were allowed to try to login, memcache is fine
                
@@ -150,7 +154,7 @@ class ApiLogin extends ApiBase {
                global $wgMemc;
                
                $key = $this->getMemCacheKey();
-               $val =& $wgMemc->get( $key );
+               $val = $wgMemc->get( $key );
 
                $val['lastReqTime'] = time();
                if (!isset($val['count'])) {
@@ -159,10 +163,11 @@ class ApiLogin extends ApiBase {
                        $val['count'] = 1 + $val['count'];
                }
                
-               $delay = ApiLogin::calculateDelay($val);
+               $delay = ApiLogin::calculateDelay($val['count']);
                
                $wgMemc->delete($key);
-               $wgMemc->add( $key, $val, $delay );
+               // Cache expiration should be the maximum timeout - to prevent a "try and wait" attack
+               $wgMemc->add( $key, $val, ApiLogin::calculateDelay(ApiLogin::THOTTLE_MAX_COUNT) );      
                
                return $delay;
        }
@@ -177,20 +182,19 @@ class ApiLogin extends ApiBase {
                
                $val = $wgMemc->get($this->getMemCacheKey());
 
-               $elapse = (time() - $val['lastReqTime']) / 1000;  // in seconds
-               $canRetryIn = ApiLogin::calculateDelay($val) - $elapse;
-               $canRetryIn = $canRetryIn < 0 ? 0 : $canRetryIn; 
+               $elapse = (time() - $val['lastReqTime']);  // in seconds
+               $canRetryIn = ApiLogin::calculateDelay($val['count']) - $elapse;
 
-               return $canRetryIn;
+               return $canRetryIn < 0 ? 0 : $canRetryIn;
        }
        
        /**
         * Based on the number of previously attempted logins, returns
         * the delay (in seconds) when the next login attempt will be allowed.
         */
-       private static function calculateDelay($val) {
+       private static function calculateDelay($count) {
                // Defensive programming
-               $count = $val['count'];
+               $count = intval($count);
                $count = $count < 1 ? 1 : $count;
                $count = $count > self::THOTTLE_MAX_COUNT ? self::THOTTLE_MAX_COUNT : $count;
 
@@ -227,12 +231,11 @@ class ApiLogin extends ApiBase {
 
        protected function getDescription() {
                return array (
-                       'This module is used to login and get the authentication tokens. ' .
-                       'In the event of a successful log-in, a cookie will be attached ' .
-                       'to your session. In the event of a failed log-in, you will not ' .
-                       'be able to attempt another log-in through this method for 60 ' .
-                       'seconds--this is to prevent its use in aiding automated password ' .
-                       'crackers.'
+                       'This module is used to login and get the authentication tokens. ',
+                       'In the event of a successful log-in, a cookie will be attached',
+                       'to your session. In the event of a failed log-in, you will not ',
+                       'be able to attempt another log-in through this method for 60 seconds.',
+                       'This is to prevent password guessing by automated password crackers.'
                );
        }
        
@@ -246,4 +249,4 @@ class ApiLogin extends ApiBase {
                return __CLASS__ . ': $Id$';
        }
 }
-?>
+