Version Description
- Have multisite network mode use the saved options instead of the defaults.
- Close more HTML injection vectors. (One would think WordPress' built in functions would already do this. Alas...)
- Get the success/error messages to work when saving settings via the Network Admin page.
- Improve unit tests by ensuring the fail table uses InnoDB.
- 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.5.0 |
Comparing to | |
See all releases |
Code changes from version 0.4.0 to 0.5.0
- admin.inc +32 -18
- login-security-solution.php +8 -2
- readme.txt +19 -4
- tests/TestCase.php +9 -3
admin.inc
CHANGED
@@ -391,19 +391,19 @@ class login_security_solution_admin extends login_security_solution {
|
|
391 |
|
392 |
add_settings_section(
|
393 |
self::ID . '-login',
|
394 |
-
__(
|
395 |
array(&$this, 'section_login'),
|
396 |
self::ID
|
397 |
);
|
398 |
add_settings_section(
|
399 |
self::ID . '-pw',
|
400 |
-
__(
|
401 |
array(&$this, 'section_blank'),
|
402 |
self::ID
|
403 |
);
|
404 |
add_settings_section(
|
405 |
self::ID . '-misc',
|
406 |
-
__(
|
407 |
array(&$this, 'section_blank'),
|
408 |
self::ID
|
409 |
);
|
@@ -412,7 +412,7 @@ class login_security_solution_admin extends login_security_solution {
|
|
412 |
foreach ($this->fields as $id => $field) {
|
413 |
add_settings_field(
|
414 |
$id,
|
415 |
-
$field['label'],
|
416 |
array(&$this, $id),
|
417 |
self::ID,
|
418 |
self::ID . '-' . $field['group']
|
@@ -425,6 +425,13 @@ class login_security_solution_admin extends login_security_solution {
|
|
425 |
* @return void
|
426 |
*/
|
427 |
public function page_settings() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
echo '<h2>' . $this->hsc_utf8($this->text_settings) . '</h2>';
|
429 |
echo '<form action="' . $this->hsc_utf8($this->form_action) . '" method="post">' . "\n";
|
430 |
settings_fields($this->option_name);
|
@@ -532,7 +539,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
532 |
$out = $this->options_default;
|
533 |
if (!is_array($in)) {
|
534 |
// Not translating this since only hackers will see it.
|
535 |
-
add_settings_error($this->option_name,
|
|
|
536 |
'Input must be an array.');
|
537 |
return $out;
|
538 |
}
|
@@ -548,7 +556,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
548 |
|
549 |
if (!is_scalar($in[$name])) {
|
550 |
// Not translating this since only hackers will see it.
|
551 |
-
add_settings_error($this->option_name,
|
|
|
552 |
$this->hsc_utf8("'" . $field['label'])
|
553 |
. "' was not a scalar, $default");
|
554 |
continue;
|
@@ -558,7 +567,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
558 |
case 'bool':
|
559 |
if ($in[$name] != 0 && $in[$name] != 1) {
|
560 |
// Not translating this since only hackers will see it.
|
561 |
-
add_settings_error($this->option_name,
|
|
|
562 |
$this->hsc_utf8("'" . $field['label']
|
563 |
. "' must be '0' or '1', $default"));
|
564 |
continue 2;
|
@@ -566,7 +576,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
566 |
break;
|
567 |
case 'int':
|
568 |
if (!ctype_digit($in[$name])) {
|
569 |
-
add_settings_error($this->option_name,
|
|
|
570 |
$this->hsc_utf8("'" . $field['label'] . "' "
|
571 |
. __("must be an integer,", self::ID)
|
572 |
. ' ' . $default));
|
@@ -575,7 +586,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
575 |
if (array_key_exists('greater_than', $field)
|
576 |
&& $in[$name] < $field['greater_than'])
|
577 |
{
|
578 |
-
add_settings_error($this->option_name,
|
|
|
579 |
$this->hsc_utf8("'" . $field['label'] . "' "
|
580 |
. sprintf($gt_format, $field['greater_than'])
|
581 |
. ' ' . $default));
|
@@ -589,7 +601,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
589 |
// Special check to make sure Delay Tier 3 > Delay Tier 2.
|
590 |
$name = 'login_fail_tier_3';
|
591 |
if ($out[$name] <= $out['login_fail_tier_2']) {
|
592 |
-
add_settings_error($this->option_name,
|
|
|
593 |
$this->hsc_utf8("'" . $this->fields[$name]['label'] . "' "
|
594 |
. sprintf($gt_format, $this->fields['login_fail_tier_2']['label'])
|
595 |
. ' ' . $default));
|
@@ -600,7 +613,8 @@ class login_security_solution_admin extends login_security_solution {
|
|
600 |
// Speical check to ensure reuse count is set if aging is enabled.
|
601 |
$name = 'pw_reuse_count';
|
602 |
if ($out['pw_change_days'] && !$out[$name]) {
|
603 |
-
add_settings_error($this->option_name,
|
|
|
604 |
$this->hsc_utf8("'" . $this->fields[$name]['label'] . "' "
|
605 |
. sprintf($gt_format, 1)
|
606 |
. ' ' . $default));
|
@@ -747,16 +761,16 @@ class login_security_solution_admin extends login_security_solution {
|
|
747 |
case $this->text_button_remind:
|
748 |
if (!empty($in[$this->key_checkbox_require])) {
|
749 |
add_settings_error($this->option_pw_force_change_name,
|
750 |
-
$this->option_pw_force_change_name,
|
751 |
$crossed);
|
752 |
} elseif (empty($in[$this->key_checkbox_remind])) {
|
753 |
add_settings_error($this->option_pw_force_change_name,
|
754 |
-
$this->option_pw_force_change_name,
|
755 |
$this->hsc_utf8(sprintf($confirm, "No thanks")));
|
756 |
} else {
|
757 |
// Translaton already in WP.
|
758 |
add_settings_error($this->option_pw_force_change_name,
|
759 |
-
$this->option_pw_force_change_name,
|
760 |
$this->hsc_utf8(__("Success!")),
|
761 |
'updated');
|
762 |
$out = 1;
|
@@ -765,23 +779,23 @@ class login_security_solution_admin extends login_security_solution {
|
|
765 |
case $this->text_button_require:
|
766 |
if (!empty($in[$this->key_checkbox_remind])) {
|
767 |
add_settings_error($this->option_pw_force_change_name,
|
768 |
-
$this->option_pw_force_change_name,
|
769 |
$crossed);
|
770 |
} elseif (empty($in[$this->key_checkbox_require])) {
|
771 |
add_settings_error($this->option_pw_force_change_name,
|
772 |
-
$this->option_pw_force_change_name,
|
773 |
$this->hsc_utf8(sprintf($confirm, "Confirm")));
|
774 |
} else {
|
775 |
$result = $this->force_change_for_all();
|
776 |
if ($result === true) {
|
777 |
// Translaton already in WP.
|
778 |
add_settings_error($this->option_pw_force_change_name,
|
779 |
-
$this->option_pw_force_change_name,
|
780 |
$this->hsc_utf8(__("Success!")), 'updated');
|
781 |
$out = 1;
|
782 |
} else {
|
783 |
add_settings_error($this->option_pw_force_change_name,
|
784 |
-
$this->option_pw_force_change_name,
|
785 |
$this->hsc_utf8($result));
|
786 |
}
|
787 |
}
|
391 |
|
392 |
add_settings_section(
|
393 |
self::ID . '-login',
|
394 |
+
$this->hsc_utf8(__("Login Failure Policies", self::ID)),
|
395 |
array(&$this, 'section_login'),
|
396 |
self::ID
|
397 |
);
|
398 |
add_settings_section(
|
399 |
self::ID . '-pw',
|
400 |
+
$this->hsc_utf8(__("Password Policies", self::ID)),
|
401 |
array(&$this, 'section_blank'),
|
402 |
self::ID
|
403 |
);
|
404 |
add_settings_section(
|
405 |
self::ID . '-misc',
|
406 |
+
$this->hsc_utf8(__("Miscellaneous Policies", self::ID)),
|
407 |
array(&$this, 'section_blank'),
|
408 |
self::ID
|
409 |
);
|
412 |
foreach ($this->fields as $id => $field) {
|
413 |
add_settings_field(
|
414 |
$id,
|
415 |
+
$this->hsc_utf8($field['label']),
|
416 |
array(&$this, $id),
|
417 |
self::ID,
|
418 |
self::ID . '-' . $field['group']
|
425 |
* @return void
|
426 |
*/
|
427 |
public function page_settings() {
|
428 |
+
if (is_multisite()) {
|
429 |
+
// WordPress doesn't show the successs/error messages on
|
430 |
+
// the Network Admin screen, at least in version 3.3.1,
|
431 |
+
// so force it to happen for now.
|
432 |
+
include_once ABSPATH . 'wp-admin/options-head.php';
|
433 |
+
}
|
434 |
+
|
435 |
echo '<h2>' . $this->hsc_utf8($this->text_settings) . '</h2>';
|
436 |
echo '<form action="' . $this->hsc_utf8($this->form_action) . '" method="post">' . "\n";
|
437 |
settings_fields($this->option_name);
|
539 |
$out = $this->options_default;
|
540 |
if (!is_array($in)) {
|
541 |
// Not translating this since only hackers will see it.
|
542 |
+
add_settings_error($this->option_name,
|
543 |
+
$this->hsc_utf8($this->option_name),
|
544 |
'Input must be an array.');
|
545 |
return $out;
|
546 |
}
|
556 |
|
557 |
if (!is_scalar($in[$name])) {
|
558 |
// Not translating this since only hackers will see it.
|
559 |
+
add_settings_error($this->option_name,
|
560 |
+
$this->hsc_utf8($name),
|
561 |
$this->hsc_utf8("'" . $field['label'])
|
562 |
. "' was not a scalar, $default");
|
563 |
continue;
|
567 |
case 'bool':
|
568 |
if ($in[$name] != 0 && $in[$name] != 1) {
|
569 |
// Not translating this since only hackers will see it.
|
570 |
+
add_settings_error($this->option_name,
|
571 |
+
$this->hsc_utf8($name),
|
572 |
$this->hsc_utf8("'" . $field['label']
|
573 |
. "' must be '0' or '1', $default"));
|
574 |
continue 2;
|
576 |
break;
|
577 |
case 'int':
|
578 |
if (!ctype_digit($in[$name])) {
|
579 |
+
add_settings_error($this->option_name,
|
580 |
+
$this->hsc_utf8($name),
|
581 |
$this->hsc_utf8("'" . $field['label'] . "' "
|
582 |
. __("must be an integer,", self::ID)
|
583 |
. ' ' . $default));
|
586 |
if (array_key_exists('greater_than', $field)
|
587 |
&& $in[$name] < $field['greater_than'])
|
588 |
{
|
589 |
+
add_settings_error($this->option_name,
|
590 |
+
$this->hsc_utf8($name),
|
591 |
$this->hsc_utf8("'" . $field['label'] . "' "
|
592 |
. sprintf($gt_format, $field['greater_than'])
|
593 |
. ' ' . $default));
|
601 |
// Special check to make sure Delay Tier 3 > Delay Tier 2.
|
602 |
$name = 'login_fail_tier_3';
|
603 |
if ($out[$name] <= $out['login_fail_tier_2']) {
|
604 |
+
add_settings_error($this->option_name,
|
605 |
+
$this->hsc_utf8($name),
|
606 |
$this->hsc_utf8("'" . $this->fields[$name]['label'] . "' "
|
607 |
. sprintf($gt_format, $this->fields['login_fail_tier_2']['label'])
|
608 |
. ' ' . $default));
|
613 |
// Speical check to ensure reuse count is set if aging is enabled.
|
614 |
$name = 'pw_reuse_count';
|
615 |
if ($out['pw_change_days'] && !$out[$name]) {
|
616 |
+
add_settings_error($this->option_name,
|
617 |
+
$this->hsc_utf8($name),
|
618 |
$this->hsc_utf8("'" . $this->fields[$name]['label'] . "' "
|
619 |
. sprintf($gt_format, 1)
|
620 |
. ' ' . $default));
|
761 |
case $this->text_button_remind:
|
762 |
if (!empty($in[$this->key_checkbox_require])) {
|
763 |
add_settings_error($this->option_pw_force_change_name,
|
764 |
+
$this->hsc_utf8($this->option_pw_force_change_name),
|
765 |
$crossed);
|
766 |
} elseif (empty($in[$this->key_checkbox_remind])) {
|
767 |
add_settings_error($this->option_pw_force_change_name,
|
768 |
+
$this->hsc_utf8($this->option_pw_force_change_name),
|
769 |
$this->hsc_utf8(sprintf($confirm, "No thanks")));
|
770 |
} else {
|
771 |
// Translaton already in WP.
|
772 |
add_settings_error($this->option_pw_force_change_name,
|
773 |
+
$this->hsc_utf8($this->option_pw_force_change_name),
|
774 |
$this->hsc_utf8(__("Success!")),
|
775 |
'updated');
|
776 |
$out = 1;
|
779 |
case $this->text_button_require:
|
780 |
if (!empty($in[$this->key_checkbox_remind])) {
|
781 |
add_settings_error($this->option_pw_force_change_name,
|
782 |
+
$this->hsc_utf8($this->option_pw_force_change_name),
|
783 |
$crossed);
|
784 |
} elseif (empty($in[$this->key_checkbox_require])) {
|
785 |
add_settings_error($this->option_pw_force_change_name,
|
786 |
+
$this->hsc_utf8($this->option_pw_force_change_name),
|
787 |
$this->hsc_utf8(sprintf($confirm, "Confirm")));
|
788 |
} else {
|
789 |
$result = $this->force_change_for_all();
|
790 |
if ($result === true) {
|
791 |
// Translaton already in WP.
|
792 |
add_settings_error($this->option_pw_force_change_name,
|
793 |
+
$this->hsc_utf8($this->option_pw_force_change_name),
|
794 |
$this->hsc_utf8(__("Success!")), 'updated');
|
795 |
$out = 1;
|
796 |
} else {
|
797 |
add_settings_error($this->option_pw_force_change_name,
|
798 |
+
$this->hsc_utf8($this->option_pw_force_change_name),
|
799 |
$this->hsc_utf8($result));
|
800 |
}
|
801 |
}
|
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
|
@@ -1829,7 +1829,13 @@ class login_security_solution {
|
|
1829 |
* @uses login_security_solution::$options to hold the data
|
1830 |
*/
|
1831 |
protected function set_options() {
|
1832 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1833 |
if (!is_array($options)) {
|
1834 |
$options = array();
|
1835 |
}
|
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.5.0
|
10 |
* Author: Daniel Convissor
|
11 |
* Author URI: http://www.analysisandsolutions.com/
|
12 |
* License: GPLv2
|
1829 |
* @uses login_security_solution::$options to hold the data
|
1830 |
*/
|
1831 |
protected function set_options() {
|
1832 |
+
if (is_multisite()) {
|
1833 |
+
switch_to_blog(1);
|
1834 |
+
$options = get_option($this->option_name);
|
1835 |
+
restore_current_blog();
|
1836 |
+
} else {
|
1837 |
+
$options = get_option($this->option_name);
|
1838 |
+
}
|
1839 |
if (!is_array($options)) {
|
1840 |
$options = array();
|
1841 |
}
|
readme.txt
CHANGED
@@ -3,13 +3,16 @@ Contributors: convissor
|
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=danielc%40analysisandsolutions%2ecom&lc=US&item_name=Donate%3a%20Login%20Security%20Solution¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
|
4 |
Tags: login, password, idle, timeout, maintenance, security, attack, hack, lock, ban
|
5 |
Requires at least: 3.0
|
6 |
-
Tested up to: 3.
|
7 |
Stable tag: trunk
|
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 |
* Blocks brute force and dictionary attacks without inconveniencing
|
14 |
legitimate users or administrators
|
15 |
+ Tracks IP addresses, usernames, and passwords
|
@@ -185,7 +188,7 @@ A thorough set of unit tests are found in the `tests` directory.
|
|
185 |
The plugin needs to be installed and activated before running the tests.
|
186 |
|
187 |
To execute the tests, `cd` into this plugin's directory and
|
188 |
-
call `phpunit tests`
|
189 |
|
190 |
Please note that the tests make extensive use of database transactions.
|
191 |
Many tests will be skipped if your `wp_options` and `wp_usermeta` tables
|
@@ -211,8 +214,8 @@ are not using the `InnoDB` storage engine.
|
|
211 |
|
212 |
A link to the page is found in this plugin's entry in the "Plugins" admin
|
213 |
interface:
|
214 |
-
* Regular sites: Plugins
|
215 |
-
* Sites using multisite networks: My Sites | Network Admin | Plugins
|
216 |
|
217 |
= How do I generate the POT translation file? =
|
218 |
|
@@ -225,10 +228,22 @@ then `cd` into that directory and run:
|
|
225 |
|
226 |
== Changelog ==
|
227 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
= 0.4.0 =
|
229 |
* Add multisite network support.
|
230 |
* Keep unit tests from deleting settings. Note: removes the ability to
|
231 |
run the unit tests without activating the plugin.
|
|
|
|
|
232 |
|
233 |
= 0.3.0 =
|
234 |
* Use UTF-8 encoding for `htmlspecialchars()` instead of `DB_CHARSET`.
|
3 |
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=danielc%40analysisandsolutions%2ecom&lc=US&item_name=Donate%3a%20Login%20Security%20Solution¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted
|
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: trunk
|
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 related security matters for regular and multisite
|
14 |
+
WordPress installations.
|
15 |
+
|
16 |
* Blocks brute force and dictionary attacks without inconveniencing
|
17 |
legitimate users or administrators
|
18 |
+ Tracks IP addresses, usernames, and passwords
|
188 |
The plugin needs to be installed and activated before running the tests.
|
189 |
|
190 |
To execute the tests, `cd` into this plugin's directory and
|
191 |
+
call `phpunit tests`
|
192 |
|
193 |
Please note that the tests make extensive use of database transactions.
|
194 |
Many tests will be skipped if your `wp_options` and `wp_usermeta` tables
|
214 |
|
215 |
A link to the page is found in this plugin's entry in the "Plugins" admin
|
216 |
interface:
|
217 |
+
* Regular sites: Plugins
|
218 |
+
* Sites using multisite networks: My Sites | Network Admin | Plugins
|
219 |
|
220 |
= How do I generate the POT translation file? =
|
221 |
|
228 |
|
229 |
== Changelog ==
|
230 |
|
231 |
+
= 0.5.0 =
|
232 |
+
* Have multisite network mode use the saved options instead of the defaults.
|
233 |
+
* Close more HTML injection vectors. (One would think WordPress' built in
|
234 |
+
functions would already do this. Alas...)
|
235 |
+
* Get the success/error messages to work when saving settings via the
|
236 |
+
Network Admin page.
|
237 |
+
* Improve unit tests by ensuring the fail table uses InnoDB.
|
238 |
+
* Tested under WordPress 3.3.1 regular and 3.4beta2 multisite.
|
239 |
+
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
240 |
+
|
241 |
= 0.4.0 =
|
242 |
* Add multisite network support.
|
243 |
* Keep unit tests from deleting settings. Note: removes the ability to
|
244 |
run the unit tests without activating the plugin.
|
245 |
+
* Tested under WordPress 3.3.1 regular and 3.4beta2 multisite.
|
246 |
+
* Unit tests pass using PHP 5.4.0RC8-dev, 5.3.11-dev, and 5.2.18-dev.
|
247 |
|
248 |
= 0.3.0 =
|
249 |
* Use UTF-8 encoding for `htmlspecialchars()` instead of `DB_CHARSET`.
|
tests/TestCase.php
CHANGED
@@ -258,9 +258,15 @@ abstract class TestCase extends PHPUnit_Framework_TestCase {
|
|
258 |
|
259 |
$opt = $wpdb->get_row("SHOW CREATE TABLE `$wpdb->options`", ARRAY_N);
|
260 |
$usr = $wpdb->get_row("SHOW CREATE TABLE `$wpdb->usermeta`", ARRAY_N);
|
261 |
-
|
262 |
-
|
263 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
}
|
265 |
|
266 |
/**
|
258 |
|
259 |
$opt = $wpdb->get_row("SHOW CREATE TABLE `$wpdb->options`", ARRAY_N);
|
260 |
$usr = $wpdb->get_row("SHOW CREATE TABLE `$wpdb->usermeta`", ARRAY_N);
|
261 |
+
$fail = $wpdb->get_row("SHOW CREATE TABLE `"
|
262 |
+
. self::$lss->table_fail . "`", ARRAY_N);
|
263 |
+
|
264 |
+
return (
|
265 |
+
strpos($opt[1], 'ENGINE=InnoDB')
|
266 |
+
&& strpos($usr[1], 'ENGINE=InnoDB')
|
267 |
+
&& !empty($fail)
|
268 |
+
&& strpos($fail[1], 'ENGINE=InnoDB')
|
269 |
+
);
|
270 |
}
|
271 |
|
272 |
/**
|