Changeset 730189
- Timestamp:
- 06/23/2013 02:09:12 AM (13 years ago)
- Location:
- login-security-solution/trunk
- Files:
-
- 5 edited
-
login-security-solution.php (modified) (10 diffs)
-
readme.txt (modified) (1 diff)
-
tests/Accessor.php (modified) (2 diffs)
-
tests/LoginFailTest.php (modified) (5 diffs)
-
tests/VerifiedIpTest.php (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
login-security-solution/trunk/login-security-solution.php
r719657 r730189 7 7 * 8 8 * Plugin URI: http://wordpress.org/extend/plugins/login-security-solution/ 9 * Version: 0. 39.09 * Version: 0.40.0 10 10 * (Remember to change the VERSION constant, below, as well!) 11 11 * Author: Daniel Convissor … … 43 43 * This plugin's version 44 44 */ 45 const VERSION = '0. 39.0';45 const VERSION = '0.40.0'; 46 46 47 47 /** … … 69 69 const LOGIN_FORCE_PW_CHANGE = 2; 70 70 const LOGIN_NOTIFY = 4; 71 const LOGIN_VERIFIED_IP = 8;71 const LOGIN_VERIFIED_IP_SAFE = 8; 72 72 const LOGIN_UNKNOWN_IP = 16; 73 73 const LOGIN_CLEAN = 32; 74 const LOGIN_VERIFIED_IP_NEW = 64; 75 const LOGIN_VERIFIED_IP_OLD = 128; 74 76 75 77 /** … … 847 849 */ 848 850 public function wp_login($user_name, $user) { 849 ###$this->log(__FUNCTION__, $user_name);851 ###$this->log(__FUNCTION__, is_object($user) ? $user->user_name : 'ERROR: non-object'); 850 852 return $this->process_login_success($user); 851 853 } … … 995 997 */ 996 998 protected function delete_pw_force_change($user_ID) { 999 ###$this->log(__FUNCTION__, $user_ID); 997 1000 return delete_user_meta($user_ID, $this->umk_pw_force_change); 998 1001 } … … 1192 1195 */ 1193 1196 protected function get_pw_force_change($user_ID) { 1197 ###$this->log(__FUNCTION__, $user_ID); 1194 1198 return (bool) get_user_meta($user_ID, $this->umk_pw_force_change, true); 1199 } 1200 1201 /** 1202 * Gets the server's request time 1203 * 1204 * Provided for overloading by unit tests so they can create multiple 1205 * entries in one request. 1206 * 1207 * @return int $_SERVER['REQUEST_TIME'] 1208 */ 1209 protected function get_time() { 1210 return $_SERVER['REQUEST_TIME']; 1195 1211 } 1196 1212 … … 2279 2295 * recent failed logins and the current IP address has been verified. 2280 2296 */ 2281 if ($fails['network_ip'] <= $this->options['login_fail_breach_pw_force_change'] 2282 && in_array($ip, $this->get_verified_ips($user->ID))) 2283 { 2284 // Use <= instead of <, above, in case 2285 // login_fail_breach_pw_force_change = 0. 2286 2287 ###$this->log(__FUNCTION__, "$user->user_login verified IP"); 2288 $flag += self::LOGIN_VERIFIED_IP; 2289 $verified_ip = true; 2297 2298 $ip_time = array_search($ip, $this->get_verified_ips($user->ID)); 2299 ###$this->log(__FUNCTION__, 'ip_time', $ip_time ? $ip_time : 'false'); 2300 if ($ip_time !== false) { 2301 if ($fails['network_ip'] <= $this->options['login_fail_breach_pw_force_change']) 2302 { 2303 // Use <= instead of <, above, in case 2304 // login_fail_breach_pw_force_change = 0. 2305 2306 // Not part of attack. 2307 ###$this->log(__FUNCTION__, "$user->user_login verified IP, not part of attack"); 2308 $flag += self::LOGIN_VERIFIED_IP_SAFE; 2309 $verified_ip = true; 2310 } else { 2311 $age = $this->get_time() - $ip_time; 2312 $max_age_permitted = $this->options['login_fail_minutes'] * 60; 2313 if ($age < $max_age_permitted) { 2314 // Same IP as "attacker," but IP verified recently. 2315 ###$this->log(__FUNCTION__, "$user->user_login, part of attack, but newly verified IP ($age < $max_age_permitted)"); 2316 $flag += self::LOGIN_VERIFIED_IP_NEW; 2317 $verified_ip = true; 2318 } else { 2319 // Same IP as "attacker," and IP verified a while ago. 2320 ###$this->log(__FUNCTION__, "$user->user_login, part of attack, old verified IP ($age >= $max_age_permitted)"); 2321 $flag += self::LOGIN_VERIFIED_IP_OLD; 2322 $verified_ip = false; 2323 } 2324 } 2290 2325 } else { 2291 2326 ###$this->log(__FUNCTION__, "$user->user_login non-verified IP"); … … 2444 2479 * Stores the user's current IP address 2445 2480 * 2446 * Note: saves up to 10 adddresses, duplicates are not stored. 2481 * Note: saves up to 20 adddresses, duplicates are not stored. 2482 * 2483 * Note: storing IP's in array values for backwards compatibility. 2447 2484 * 2448 2485 * @param int $user_ID the user's id number 2449 2486 * @param string $new_ip the ip address to add 2450 * @return mixed true on success, 1 if IP is already stored,-1 if IP empty2487 * @return mixed true on success, -1 if IP empty 2451 2488 */ 2452 2489 protected function save_verified_ip($user_ID, $new_ip) { … … 2456 2493 2457 2494 $ips = $this->get_verified_ips($user_ID); 2458 2459 if (in_array($new_ip, $ips)) { 2460 return 1; 2461 } 2462 2463 $ips[] = $new_ip; 2464 2465 $cut = count($ips) - 10; 2466 if ($cut > 0) { 2467 array_splice($ips, 0, $cut); 2495 $time = array_search($new_ip, $ips); 2496 2497 if ($time !== false) { 2498 // Replace time stamp. 2499 unset($ips[$time]); 2500 } 2501 $ips[$this->get_time()] = $new_ip; 2502 2503 if (count($ips) > 20) { 2504 // Drop oldest (first) element to keep array from getting to big. 2505 // Can't use array_shift() because it reindexes the array 2506 $first_key = key($ips); 2507 unset($ips[$first_key]); 2468 2508 } 2469 2509 … … 2521 2561 */ 2522 2562 protected function set_pw_force_change($user_ID) { 2563 ###$this->log(__FUNCTION__, $user_ID); 2523 2564 return update_user_meta($user_ID, $this->umk_pw_force_change, 1); 2524 2565 } -
login-security-solution/trunk/readme.txt
r719657 r730189 445 445 446 446 == Changelog == 447 448 = 0.40.0 (2013-06-22) = 449 * Track the age of verified IP's and use that to prevent users being locked 450 out by "attacks" from one's own IP address. 451 * Unit tests pass using PHP 5.3.27-dev, 5.4.17-dev, 5.5.0-dev 452 * Tested under WordPress 3.4.2, 3.5.2 and 3.6beta4 using regular and multisite. 447 453 448 454 = 0.39.0 (2013-05-29) = -
login-security-solution/trunk/tests/Accessor.php
r705187 r730189 33 33 */ 34 34 class Accessor extends login_security_solution_admin { 35 public $time_overload = 10; 36 35 37 public function __call($method, $args) { 36 38 return call_user_func_array(array($this, $method), $args); … … 45 47 return $this->data[$key]; 46 48 } 49 protected function get_time() { 50 return $this->time_overload++; 51 } 47 52 } -
login-security-solution/trunk/tests/LoginFailTest.php
r705187 r730189 336 336 * @depends test_wp_login__post_breach_threshold 337 337 */ 338 public function test_wp_login__post_breach_threshold_verified_ip () {338 public function test_wp_login__post_breach_threshold_verified_ip_safe() { 339 339 global $wpdb; 340 340 … … 353 353 $this->fail($e->getMessage()); 354 354 } 355 $flag = login_security_solution::LOGIN_VERIFIED_IP ;355 $flag = login_security_solution::LOGIN_VERIFIED_IP_SAFE; 356 356 $this->assertSame($flag + 1, $actual, 'wp_login() return value...'); 357 357 $this->assertNull(self::$lss->sleep, 'Sleep should be unset.'); … … 359 359 $actual = self::$lss->get_pw_force_change($this->user->ID); 360 360 $this->assertFalse($actual, 'get_pw_force_change() return value...'); 361 361 } 362 363 /** 364 * @depends test_wp_login__post_breach_threshold_verified_ip_safe 365 */ 366 public function test_wp_login__post_breach_threshold_verified_ip_new() { 367 self::$lss->delete_pw_force_change($this->user->ID); 368 369 $options = self::$lss->options; 370 $options['login_fail_breach_pw_force_change'] = 1; 371 $options['login_fail_minutes'] = 1; 372 self::$lss->options = $options; 373 374 self::$lss->time_overload = 10; 375 self::$lss->save_verified_ip($this->user->ID, $this->ip); 376 self::$lss->time_overload = 20; 377 378 try { 379 // Do THE deed. 380 $actual = self::$lss->wp_login(null, $this->user); 381 } catch (Exception $e) { 382 $this->fail($e->getMessage()); 383 } 384 $flag = login_security_solution::LOGIN_VERIFIED_IP_NEW; 385 $this->assertSame($flag + 1, $actual, 'wp_login() return value...'); 386 $this->assertNull(self::$lss->sleep, 'Sleep should be unset.'); 387 388 $actual = self::$lss->get_pw_force_change($this->user->ID); 389 $this->assertFalse($actual, 'get_pw_force_change() return value...'); 390 } 391 392 /** 393 * @depends test_wp_login__post_breach_threshold_verified_ip_new 394 */ 395 public function test_wp_login__post_breach_threshold_verified_ip_old() { 396 global $wpdb; 397 398 self::$lss->delete_pw_force_change($this->user->ID); 399 400 $options = self::$lss->options; 401 $options['login_fail_breach_notify'] = 0; 402 $options['login_fail_breach_pw_force_change'] = 1; 403 $options['login_fail_minutes'] = 1; 404 self::$lss->options = $options; 405 406 self::$lss->time_overload = 10; 407 self::$lss->save_verified_ip($this->user->ID, $this->ip); 408 self::$lss->time_overload = 100; 409 410 try { 411 // Do THE deed. 412 $actual = self::$lss->wp_login(null, $this->user); 413 } catch (Exception $e) { 414 $this->fail($e->getMessage()); 415 } 416 $flag = login_security_solution::LOGIN_VERIFIED_IP_OLD 417 + login_security_solution::LOGIN_FORCE_PW_CHANGE; 418 $this->assertSame($flag + 1, $actual, 'wp_login() return value...'); 419 $this->assertGreaterThan(0, self::$lss->sleep, 'Sleep not set.'); 420 421 $actual = self::$lss->get_pw_force_change($this->user->ID); 422 $this->assertTrue($actual, 'get_pw_force_change() return value...'); 423 424 self::$lss->delete_pw_force_change($this->user->ID); 362 425 $wpdb->query('ROLLBACK TO pre_verified_ip'); 363 426 } 364 427 365 428 /** 366 * @depends test_wp_login__post_breach_threshold_verified_ip 429 * @depends test_wp_login__post_breach_threshold_verified_ip_old 367 430 */ 368 431 public function test_wp_login__post_breach_threshold_only_notify() { … … 372 435 $options['login_fail_breach_pw_force_change'] = 0; 373 436 self::$lss->options = $options; 374 375 self::$lss->delete_pw_force_change($this->user->ID);376 437 377 438 try { … … 405 466 406 467 self::$lss->delete_pw_force_change($this->user->ID); 468 $actual = self::$lss->get_pw_force_change($this->user->ID); 469 $this->assertFalse($actual, 'pw_force_change should be empty to start with'); 470 delete_user_meta($this->user->ID, self::$lss->umk_verified_ips); 407 471 408 472 try { -
login-security-solution/trunk/tests/VerifiedIpTest.php
r615063 r730189 35 35 public function setUp() { 36 36 parent::setUp(); 37 // Because arrays naturally start at index 0, force our IP array to 38 // start indexing at 10 to ensure tests do what we really expect 39 // than passing by getting lucky. 40 self::$lss->time_overload = 10; 37 41 } 38 42 … … 66 70 public function test_save_verified_ip__exists() { 67 71 $actual = self::$lss->save_verified_ip($this->user->ID, self::$ip_1); 68 $this->assert Same(1,$actual);72 $this->assertTrue($actual); 69 73 } 70 74 … … 76 80 77 81 $actual = self::$lss->get_verified_ips($this->user->ID); 78 $this->assertEquals(array( self::$ip_1), $actual);82 $this->assertEquals(array(10 => self::$ip_1), $actual); 79 83 80 84 $wpdb->query('ROLLBACK TO empty'); … … 102 106 self::$lss->save_verified_ip($this->user->ID, 'j'); 103 107 self::$lss->save_verified_ip($this->user->ID, 'k'); 108 self::$lss->save_verified_ip($this->user->ID, 'l'); 109 self::$lss->save_verified_ip($this->user->ID, 'm'); 110 self::$lss->save_verified_ip($this->user->ID, 'n'); 111 self::$lss->save_verified_ip($this->user->ID, 'o'); 112 self::$lss->save_verified_ip($this->user->ID, 'p'); 113 self::$lss->save_verified_ip($this->user->ID, 'q'); 114 self::$lss->save_verified_ip($this->user->ID, 'r'); 115 self::$lss->save_verified_ip($this->user->ID, 's'); 116 self::$lss->save_verified_ip($this->user->ID, 't'); 117 self::$lss->save_verified_ip($this->user->ID, 'u'); 104 118 105 $expected = range('b', 'k'); 119 $expected_keys = range(11, 30); 120 $expected_values = range('b', 'u'); 121 $expected = array_combine($expected_keys, $expected_values); 106 122 $actual = self::$lss->get_verified_ips($this->user->ID); 107 123 $this->assertEquals($expected, $actual); … … 125 141 // Check the outcome. 126 142 $actual = self::$lss->get_verified_ips($this->user->ID); 127 $this->assertSame(array( $ip), $actual, 'Expected IP was not found.');143 $this->assertSame(array(10 => $ip), $actual, 'Expected IP was not found.'); 128 144 129 145 $wpdb->query('ROLLBACK TO empty'); … … 152 168 // Check the outcome. 153 169 $actual = self::$lss->get_verified_ips($this->user->ID); 154 $this->assertSame(array( $ip), $actual, 'Expected IP was not found.');170 $this->assertSame(array(10 => $ip), $actual, 'Expected IP was not found.'); 155 171 } 156 172 }
Note: See TracChangeset
for help on using the changeset viewer.