Version Description
- The "lost your password" process now validates passwords.
- Tested under WordPress 3.3.1 regular and 3.4beta2 multisite.
- Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
Download this release
Release Info
Developer | convissor |
Plugin | Login Security Solution |
Version | 0.7.0 |
Comparing to | |
See all releases |
Code changes from version 0.6.1 to 0.7.0
- login-security-solution.php +16 -2
- readme.txt +22 -14
- tests/LoginMessageTest.php +28 -2
- tests/PasswordChangeTest.php +32 -1
login-security-solution.php
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
* Description: Requires very strong passwords, repels brute force login attacks, prevents login information disclosures, expires idle sessions, notifies admins of attacks and breaches, permits administrators to disable logins for maintenance or emergency reasons and reset all passwords.
|
7 |
*
|
8 |
* Plugin URI: http://wordpress.org/extend/plugins/login-security-solution/
|
9 |
-
* Version: 0.
|
10 |
* Author: Daniel Convissor
|
11 |
* Author URI: http://www.analysisandsolutions.com/
|
12 |
* License: GPLv2
|
@@ -474,6 +474,10 @@ class login_security_solution {
|
|
474 |
$ours = __('Your password has expired. Please log and change it.', self::ID);
|
475 |
$ours .= ' ' . sprintf(__('We provide a %d minute grace period to do so.', self::ID), $this->options['pw_change_grace_period_minutes']);
|
476 |
break;
|
|
|
|
|
|
|
|
|
477 |
}
|
478 |
}
|
479 |
|
@@ -498,7 +502,7 @@ class login_security_solution {
|
|
498 |
*
|
499 |
* @param WP_User the user object being edited
|
500 |
* @param string $user_pass the unhashed new password
|
501 |
-
* @return
|
502 |
*
|
503 |
* @uses login_security_solution::process_pw_metadata() to update user
|
504 |
* metadata
|
@@ -507,6 +511,16 @@ class login_security_solution {
|
|
507 |
if (empty($user->ID)) {
|
508 |
return false;
|
509 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
510 |
$this->process_pw_metadata($user->ID, $user_pass);
|
511 |
}
|
512 |
|
6 |
* Description: Requires very strong passwords, repels brute force login attacks, prevents login information disclosures, expires idle sessions, notifies admins of attacks and breaches, permits administrators to disable logins for maintenance or emergency reasons and reset all passwords.
|
7 |
*
|
8 |
* Plugin URI: http://wordpress.org/extend/plugins/login-security-solution/
|
9 |
+
* Version: 0.7.0
|
10 |
* Author: Daniel Convissor
|
11 |
* Author URI: http://www.analysisandsolutions.com/
|
12 |
* License: GPLv2
|
474 |
$ours = __('Your password has expired. Please log and change it.', self::ID);
|
475 |
$ours .= ' ' . sprintf(__('We provide a %d minute grace period to do so.', self::ID), $this->options['pw_change_grace_period_minutes']);
|
476 |
break;
|
477 |
+
case 'pw_reset_bad':
|
478 |
+
$ours = __('The password you just created is not secure so must be changed. Use it now to log in then go to your profile page and create a new password.', self::ID);
|
479 |
+
$ours .= ' ' . sprintf(__('We provide a %d minute grace period to do so.', self::ID), $this->options['pw_change_grace_period_minutes']);
|
480 |
+
break;
|
481 |
}
|
482 |
}
|
483 |
|
502 |
*
|
503 |
* @param WP_User the user object being edited
|
504 |
* @param string $user_pass the unhashed new password
|
505 |
+
* @return mixed return values provided for unit testing
|
506 |
*
|
507 |
* @uses login_security_solution::process_pw_metadata() to update user
|
508 |
* metadata
|
511 |
if (empty($user->ID)) {
|
512 |
return false;
|
513 |
}
|
514 |
+
|
515 |
+
$user->user_pass = $user_pass;
|
516 |
+
if (!$this->validate_pw($user)) {
|
517 |
+
$this->process_pw_metadata($user->ID, $user_pass);
|
518 |
+
$this->set_pw_force_change($user->ID);
|
519 |
+
$this->set_pw_grace_period($user->ID);
|
520 |
+
$this->redirect_to_login('pw_reset_bad');
|
521 |
+
return -1;
|
522 |
+
}
|
523 |
+
|
524 |
$this->process_pw_metadata($user->ID, $user_pass);
|
525 |
}
|
526 |
|
readme.txt
CHANGED
@@ -4,14 +4,16 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=danie
|
|
4 |
Tags: login, password, idle, timeout, maintenance, security, attack, hack, lock, ban
|
5 |
Requires at least: 3.0
|
6 |
Tested up to: 3.4beta2
|
7 |
-
Stable tag:
|
|
|
|
|
|
|
|
|
8 |
|
9 |
-
Repels brute force attacks (by IP, name, password). Requires very strong passwords (complex, don't match site/user info, etc). Plus much more!
|
10 |
|
11 |
== Description ==
|
12 |
|
13 |
-
Locks down login
|
14 |
-
WordPress installations.
|
15 |
|
16 |
* Blocks brute force and dictionary attacks without inconveniencing
|
17 |
legitimate users or administrators
|
@@ -67,7 +69,8 @@ The tests have caught every password dictionary entry I've tried.
|
|
67 |
= Improvements Over Similar WordPress Plugins =
|
68 |
|
69 |
* Multisite network support
|
70 |
-
*
|
|
|
71 |
* Notice-free code means no information disclosures if `display_errors`
|
72 |
is on and `error_reporting` includes `E_NOTICE`
|
73 |
* Only loads files, actions, and filters needed for enabled options
|
@@ -104,8 +107,8 @@ clients and friends.
|
|
104 |
|
105 |
== Installation ==
|
106 |
|
107 |
-
1. Download the
|
108 |
-
|
109 |
|
110 |
1. Unzip the file.
|
111 |
|
@@ -170,7 +173,7 @@ clients and friends.
|
|
170 |
1. Adjust the settings as desired. This plugin's settings page can be
|
171 |
reached via a sub-menu entry under WordPress' "Settings" menu or this
|
172 |
plugin's entry on WordPress' "Plugins" page. Sites using WordPress'
|
173 |
-
multisite network
|
174 |
menus under "My Sites | Network Admin".
|
175 |
|
176 |
1. Run the "Change All Passwords" process. This is necessary to ensure
|
@@ -232,11 +235,11 @@ administrators from being inconvenienced. Plus it provides a quick sand
|
|
232 |
trap that ties up attackers' resources instead of immediately tipping them
|
233 |
off that the jig is up.
|
234 |
|
235 |
-
= Won't the slowdowns open my website to Denial of
|
236 |
|
237 |
Yeah, the DOS potential is there. I mitigated it for the most part by
|
238 |
-
disconnecting the database link (the most precious
|
239 |
-
situations) before sleeping. But remember, distributed
|
240 |
attacks are fairly easy to initiate these days. If someone really wants to
|
241 |
shut down your site, they'll be able to do it without even touching this
|
242 |
plugin's login failure process.
|
@@ -252,6 +255,11 @@ then `cd` into that directory and run:
|
|
252 |
|
253 |
== Changelog ==
|
254 |
|
|
|
|
|
|
|
|
|
|
|
255 |
= 0.6.1 =
|
256 |
* Minor wording adjustments.
|
257 |
|
@@ -301,15 +309,15 @@ problems under PHP 5.4.
|
|
301 |
* Initial import to `plugins.svn.wordpress.org`.
|
302 |
|
303 |
= 0.0.3 =
|
304 |
-
* Fix
|
305 |
* Adjust IdleTest so it doesn't radically change `wp_users` auto increment.
|
306 |
* Tested under WordPress 3.3.1.
|
307 |
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
308 |
|
309 |
= 0.0.2 =
|
310 |
* Use Unicode character properties to improve portability.
|
311 |
-
* Stop tests short if not in a
|
312 |
-
* Skip dict test if dict not available.
|
313 |
* Skip database tests if transactions are not available.
|
314 |
* Tested under WordPress 3.3.1.
|
315 |
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
4 |
Tags: login, password, idle, timeout, maintenance, security, attack, hack, lock, ban
|
5 |
Requires at least: 3.0
|
6 |
Tested up to: 3.4beta2
|
7 |
+
Stable tag: 0.7.0
|
8 |
+
|
9 |
+
Security against brute force attacks by tracking IP, name, password;
|
10 |
+
requiring very strong passwords. Idle timeout. Maintenance mode. Multisite
|
11 |
+
ready!
|
12 |
|
|
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
+
Locks down login security for multisite and regular WordPress installations.
|
|
|
17 |
|
18 |
* Blocks brute force and dictionary attacks without inconveniencing
|
19 |
legitimate users or administrators
|
69 |
= Improvements Over Similar WordPress Plugins =
|
70 |
|
71 |
* Multisite network support
|
72 |
+
* Takes security seriously so the plugin itself does not open your site
|
73 |
+
to SQL, HTML, or header injection vulnerabilities
|
74 |
* Notice-free code means no information disclosures if `display_errors`
|
75 |
is on and `error_reporting` includes `E_NOTICE`
|
76 |
* Only loads files, actions, and filters needed for enabled options
|
107 |
|
108 |
== Installation ==
|
109 |
|
110 |
+
1. Download the Login Security Solution zip file from WordPress' plugin
|
111 |
+
site: `http://wordpress.org/extend/plugins/login-security-solution/`
|
112 |
|
113 |
1. Unzip the file.
|
114 |
|
173 |
1. Adjust the settings as desired. This plugin's settings page can be
|
174 |
reached via a sub-menu entry under WordPress' "Settings" menu or this
|
175 |
plugin's entry on WordPress' "Plugins" page. Sites using WordPress'
|
176 |
+
multisite network capability will find the "Settings" and "Plugin"
|
177 |
menus under "My Sites | Network Admin".
|
178 |
|
179 |
1. Run the "Change All Passwords" process. This is necessary to ensure
|
235 |
trap that ties up attackers' resources instead of immediately tipping them
|
236 |
off that the jig is up.
|
237 |
|
238 |
+
= Won't the slowdowns open my website to Denial of Service (DOS) attacks? =
|
239 |
|
240 |
Yeah, the DOS potential is there. I mitigated it for the most part by
|
241 |
+
disconnecting the database link (the most precious resource in most
|
242 |
+
situations) before sleeping. But remember, distributed denial of service
|
243 |
attacks are fairly easy to initiate these days. If someone really wants to
|
244 |
shut down your site, they'll be able to do it without even touching this
|
245 |
plugin's login failure process.
|
255 |
|
256 |
== Changelog ==
|
257 |
|
258 |
+
= 0.7.0 =
|
259 |
+
* The "lost your password" process now validates passwords.
|
260 |
+
* Tested under WordPress 3.3.1 regular and 3.4beta2 multisite.
|
261 |
+
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
262 |
+
|
263 |
= 0.6.1 =
|
264 |
* Minor wording adjustments.
|
265 |
|
309 |
* Initial import to `plugins.svn.wordpress.org`.
|
310 |
|
311 |
= 0.0.3 =
|
312 |
+
* Fix mix ups in the code saving the "Change All Passwords" admin UI.
|
313 |
* Adjust IdleTest so it doesn't radically change `wp_users` auto increment.
|
314 |
* Tested under WordPress 3.3.1.
|
315 |
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
316 |
|
317 |
= 0.0.2 =
|
318 |
* Use Unicode character properties to improve portability.
|
319 |
+
* Stop tests short if not in a WordPress install.
|
320 |
+
* Skip `dict` test if `dict` not available.
|
321 |
* Skip database tests if transactions are not available.
|
322 |
* Tested under WordPress 3.3.1.
|
323 |
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
tests/LoginMessageTest.php
CHANGED
@@ -58,7 +58,12 @@ class LoginMessageTest extends TestCase {
|
|
58 |
public function test_login_message__idle() {
|
59 |
$_GET[self::$lss->key_login_msg] = 'idle';
|
60 |
|
61 |
-
$
|
|
|
|
|
|
|
|
|
|
|
62 |
$ours .= ' ' . __('Please log back in.', self::ID);
|
63 |
|
64 |
$actual = self::$lss->login_message('input');
|
@@ -91,8 +96,29 @@ class LoginMessageTest extends TestCase {
|
|
91 |
public function test_login_message__pw_grace() {
|
92 |
$_GET[self::$lss->key_login_msg] = 'pw_grace';
|
93 |
|
|
|
|
|
|
|
|
|
|
|
94 |
$ours = __('Your password has expired. Please log and change it.', self::ID);
|
95 |
-
$ours .= ' ' . sprintf(__('We provide a %d minute grace period to do so.', self::ID),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
$actual = self::$lss->login_message('input');
|
98 |
$this->assertEquals('input' . $this->ours($ours), $actual,
|
58 |
public function test_login_message__idle() {
|
59 |
$_GET[self::$lss->key_login_msg] = 'idle';
|
60 |
|
61 |
+
$value = 8;
|
62 |
+
$options = self::$lss->options;
|
63 |
+
$options['idle_timeout'] = $value;
|
64 |
+
self::$lss->options = $options;
|
65 |
+
|
66 |
+
$ours = sprintf(__('It has been over %d minutes since your last action.', self::ID), $value);
|
67 |
$ours .= ' ' . __('Please log back in.', self::ID);
|
68 |
|
69 |
$actual = self::$lss->login_message('input');
|
96 |
public function test_login_message__pw_grace() {
|
97 |
$_GET[self::$lss->key_login_msg] = 'pw_grace';
|
98 |
|
99 |
+
$value = 8;
|
100 |
+
$options = self::$lss->options;
|
101 |
+
$options['pw_change_grace_period_minutes'] = $value;
|
102 |
+
self::$lss->options = $options;
|
103 |
+
|
104 |
$ours = __('Your password has expired. Please log and change it.', self::ID);
|
105 |
+
$ours .= ' ' . sprintf(__('We provide a %d minute grace period to do so.', self::ID), $value);
|
106 |
+
|
107 |
+
$actual = self::$lss->login_message('input');
|
108 |
+
$this->assertEquals('input' . $this->ours($ours), $actual,
|
109 |
+
'Output should have been modified.');
|
110 |
+
}
|
111 |
+
|
112 |
+
public function test_login_message__pw_reset_bad() {
|
113 |
+
$_GET[self::$lss->key_login_msg] = 'pw_reset_bad';
|
114 |
+
|
115 |
+
$value = 8;
|
116 |
+
$options = self::$lss->options;
|
117 |
+
$options['pw_change_grace_period_minutes'] = $value;
|
118 |
+
self::$lss->options = $options;
|
119 |
+
|
120 |
+
$ours = __('The password you just created is not secure so must be changed. Use it now to log in then go to your profile page and create a new password.', self::ID);
|
121 |
+
$ours .= ' ' . sprintf(__('We provide a %d minute grace period to do so.', self::ID), $value);
|
122 |
|
123 |
$actual = self::$lss->login_message('input');
|
124 |
$this->assertEquals('input' . $this->ours($ours), $actual,
|
tests/PasswordChangeTest.php
CHANGED
@@ -188,7 +188,7 @@ class PasswordChangeTest extends TestCase {
|
|
188 |
|
189 |
// Check the outcome.
|
190 |
$actual = self::$lss->get_pw_changed_time($this->user->ID);
|
191 |
-
$this->assertGreaterThan(0, $actual, 'Changed time should be 0.');
|
192 |
|
193 |
$actual = self::$lss->is_pw_reused(self::$pass_1, $this->user->ID);
|
194 |
$this->assertTrue($actual, 'Password should show up as reused');
|
@@ -198,6 +198,37 @@ class PasswordChangeTest extends TestCase {
|
|
198 |
$wpdb->query('ROLLBACK TO empty');
|
199 |
}
|
200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
/*
|
202 |
* PROFILE UPDATE
|
203 |
*/
|
188 |
|
189 |
// Check the outcome.
|
190 |
$actual = self::$lss->get_pw_changed_time($this->user->ID);
|
191 |
+
$this->assertGreaterThan(0, $actual, 'Changed time should be > 0.');
|
192 |
|
193 |
$actual = self::$lss->is_pw_reused(self::$pass_1, $this->user->ID);
|
194 |
$this->assertTrue($actual, 'Password should show up as reused');
|
198 |
$wpdb->query('ROLLBACK TO empty');
|
199 |
}
|
200 |
|
201 |
+
public function test_password_reset__bad_pw() {
|
202 |
+
global $wpdb;
|
203 |
+
|
204 |
+
$bad_pw = 'too simple';
|
205 |
+
|
206 |
+
$expected_error = 'Cannot modify header information';
|
207 |
+
$this->expected_errors($expected_error);
|
208 |
+
self::$location_expected = get_option('siteurl')
|
209 |
+
. '/wp-login.php?action=login&'
|
210 |
+
. self::$lss->key_login_msg . '=pw_reset_bad';
|
211 |
+
|
212 |
+
$actual = self::$lss->password_reset($this->user, $bad_pw);
|
213 |
+
$this->assertEquals(-1, $actual, 'password_reset() return.');
|
214 |
+
|
215 |
+
// Check the outcome.
|
216 |
+
$actual = self::$lss->get_pw_changed_time($this->user->ID);
|
217 |
+
$this->assertGreaterThan(0, $actual, 'Changed time should be > 0.');
|
218 |
+
|
219 |
+
$actual = self::$lss->is_pw_reused($bad_pw, $this->user->ID);
|
220 |
+
$this->assertTrue($actual, 'Password should show up as reused');
|
221 |
+
|
222 |
+
$this->ensure_grace_and_force_are_populated();
|
223 |
+
|
224 |
+
$wpdb->query('ROLLBACK TO empty');
|
225 |
+
|
226 |
+
$this->assertTrue($this->were_expected_errors_found(),
|
227 |
+
"Expected error not found: '$expected_error'");
|
228 |
+
$this->assertEquals(self::$location_expected, self::$location_actual,
|
229 |
+
'wp_redirect() produced unexpected location header.');
|
230 |
+
}
|
231 |
+
|
232 |
/*
|
233 |
* PROFILE UPDATE
|
234 |
*/
|