Lockdown WP Admin - Version 2.1

Version Description

  • Unit Testing! Unit Testing ensure more reliable code going forward
  • Support for WordPress 3.6
  • General Cleaning
Download this release

Release Info

Developer sean212
Plugin Icon wp plugin Lockdown WP Admin
Version 2.1
Comparing to
See all releases

Code changes from version 2.0.2 to 2.1

Files changed (5) hide show
  1. README.md +8 -1
  2. admin.php +13 -5
  3. lockdown-wp-admin.php +81 -37
  4. no-wpmu.php +8 -28
  5. readme.txt +7 -2
README.md CHANGED
@@ -18,6 +18,8 @@ If you enable HTTP authentication, it will add HTTP authentication to the PHP fi
18
  2. Activate the plugin through the 'Plugins' menu in WordPress
19
  3. Navigate to the "Lockdown WP" menu
20
 
 
 
21
  ### FAQ
22
  **How can we add files to the white list to hide from the public eye? We want to have AJAX and use a custom file, but we can't because it hides it from the public.**
23
 
@@ -91,4 +93,9 @@ A very late update, sorry! Worked to fix many issues with the admin bar and the
91
 
92
  2.0.2
93
  * Query string detection bug fix by [James Bonham](http://wordpress.org/support/profile/jamesbonham)
94
- * Issues with WordPress in a sub-directory
 
 
 
 
 
18
  2. Activate the plugin through the 'Plugins' menu in WordPress
19
  3. Navigate to the "Lockdown WP" menu
20
 
21
+ *Composer is not required to be setup for installation of this plugin! It is simply used for development purposes to provide unit testing.*
22
+
23
  ### FAQ
24
  **How can we add files to the white list to hide from the public eye? We want to have AJAX and use a custom file, but we can't because it hides it from the public.**
25
 
93
 
94
  2.0.2
95
  * Query string detection bug fix by [James Bonham](http://wordpress.org/support/profile/jamesbonham)
96
+ * Issues with WordPress in a sub-directory
97
+
98
+ 2.1
99
+ * Unit Testing! Unit Testing ensure more reliable code going forward
100
+ * Support for WordPress 3.6
101
+ * General Cleaning
admin.php CHANGED
@@ -8,7 +8,7 @@
8
  </div>
9
  <?php endif;
10
  if ( defined('LD_DIS_BASE') && LD_DIS_BASE == TRUE ) : ?>
11
- <div class="updated fade">
12
  <p>You can't make that your URL Base! </p>
13
  </div>
14
  <?php endif; ?>
@@ -17,7 +17,7 @@ if ( defined('LD_DIS_BASE') && LD_DIS_BASE == TRUE ) : ?>
17
  <p><a href="https://twitter.com/srtfisher" class="twitter-follow-button" data-show-count="false">Follow @srtfisher</a>
18
  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script><br />
19
  I tweet a lot of things and often post whenever I update this plugin. You should follow me <a href="http://twitter.com/srtfisher">@srtfisher</a></p>
20
-
21
  <form method="POST" action="<?php echo admin_url('admin.php?page=lockdown-wp-admin'); ?>">
22
 
23
  <?php wp_nonce_field('lockdown-wp-admin'); ?>
@@ -32,13 +32,21 @@ if ( defined('LD_DIS_BASE') && LD_DIS_BASE == TRUE ) : ?>
32
  <label> Change the WordPress Login URL? <?php echo wp_guess_url().'/'; ?>
33
  <input type="text" name="login_base" value="<?php echo $this->login_base; ?>" />
34
  <br />
35
- <em>This will change it from <?php echo wp_guess_url(); ?>/wp-login.php to whatever you put in this box. If you leave it <strong>black</strong>, it will be disabled.<br />
36
- Say if you put "login" into the box, your new login URL will be <?php echo home_url(); ?>/login/.</em></label>
37
  <?php
38
  global $auth_obj;
39
  $url = home_url() . '/'. $this->login_base;
40
  ?>
41
  <p>Your current login URL is <code><a href="<?php echo $url; ?>"><?php echo $url; ?></a></code>.</p>
 
 
 
 
 
 
 
 
42
  <blockquote>
43
  <h4>Please Note Something!</h4>
44
  <p>If you are using a cache plugin (WTC, WP Super Cache, etc), you need to enable it
@@ -66,4 +74,4 @@ $url = home_url() . '/'. $this->login_base;
66
  <input type="hidden" name="did_update" value="yes_we_did">
67
  <input class='button-primary' type='submit' name='Save' value='<?php _e('Save Options'); ?>' id='submitbutton' />
68
  </form>
69
- </div>
8
  </div>
9
  <?php endif;
10
  if ( defined('LD_DIS_BASE') && LD_DIS_BASE == TRUE ) : ?>
11
+ <div class="updated error fade">
12
  <p>You can't make that your URL Base! </p>
13
  </div>
14
  <?php endif; ?>
17
  <p><a href="https://twitter.com/srtfisher" class="twitter-follow-button" data-show-count="false">Follow @srtfisher</a>
18
  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script><br />
19
  I tweet a lot of things and often post whenever I update this plugin. You should follow me <a href="http://twitter.com/srtfisher">@srtfisher</a></p>
20
+
21
  <form method="POST" action="<?php echo admin_url('admin.php?page=lockdown-wp-admin'); ?>">
22
 
23
  <?php wp_nonce_field('lockdown-wp-admin'); ?>
32
  <label> Change the WordPress Login URL? <?php echo wp_guess_url().'/'; ?>
33
  <input type="text" name="login_base" value="<?php echo $this->login_base; ?>" />
34
  <br />
35
+ <em>This will change it from <?php echo wp_guess_url(); ?>/wp-login.php to whatever you put in this box. If you leave it <strong>blank</strong>, it will be disabled.<br />
36
+ Say if you put "<strong>login</strong>" into the box, your new login URL will be <?php echo home_url(); ?>/login/.</em></label>
37
  <?php
38
  global $auth_obj;
39
  $url = home_url() . '/'. $this->login_base;
40
  ?>
41
  <p>Your current login URL is <code><a href="<?php echo $url; ?>"><?php echo $url; ?></a></code>.</p>
42
+
43
+ <?php if ($this->isSuggestedAgainst()) : ?>
44
+ <div class="updated error"><p>
45
+ Your login base <strong><?php echo $this->login_base; ?></strong> is highly insecure!
46
+ We strongly reccomend using another login URL to ensure maximum security.
47
+ </p>
48
+ </div>
49
+ <?php endif; ?>
50
  <blockquote>
51
  <h4>Please Note Something!</h4>
52
  <p>If you are using a cache plugin (WTC, WP Super Cache, etc), you need to enable it
74
  <input type="hidden" name="did_update" value="yes_we_did">
75
  <input class='button-primary' type='submit' name='Save' value='<?php _e('Save Options'); ?>' id='submitbutton' />
76
  </form>
77
+ </div>
lockdown-wp-admin.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Lockdown WP Admin
4
  Plugin URI: http://seanfisher.co/lockdown-wp-admin/
5
  Donate link: http://seanfisher.co/donate/
6
  Description: Securing the WordPress Administration interface by concealing the administration dashboard and changing the login page URL.
7
- Version: 2.0.2
8
  Author: Sean Fisher
9
  Author URI: http://seanfisher.co/
10
  License: GPL
@@ -17,7 +17,7 @@ define('LD_FILE_NAME', __FILE__ );
17
  * This is the plugin that will add security to our site
18
  *
19
  * @author Sean Fisher <me@seanfisher.co>
20
- * @version 2.0.2
21
  * @license GPL
22
  **/
23
  class WP_LockAuth
@@ -28,7 +28,7 @@ class WP_LockAuth
28
  * @global string
29
  * @access private
30
  **/
31
- public $ld_admin_version = '2.0.2';
32
 
33
  /**
34
  * The HTTP Auth name for the protected area
@@ -53,6 +53,20 @@ class WP_LockAuth
53
  **/
54
  protected $login_base = FALSE;
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  public function __construct()
57
  {
58
  // We don't like adding network wide WordPress plugins.
@@ -109,14 +123,14 @@ class WP_LockAuth
109
  **/
110
  public function update_users()
111
  {
112
- if (! isset( $_GET['page'] ) )
113
  return;
114
 
115
  if ( $_GET['page'] !== 'lockdown-private-users' )
116
  return;
117
 
118
  // Nonce
119
- if ( !isset( $_REQUEST['_wpnonce'] ) )
120
  return;
121
 
122
  $nonce = $_REQUEST['_wpnonce'];
@@ -198,7 +212,7 @@ class WP_LockAuth
198
 
199
  // Nonce
200
  $nonce = $_POST['_wpnonce'];
201
- if (! wp_verify_nonce($nonce, 'lockdown-wp-admin') )
202
  wp_die('Security error, please try again.');
203
 
204
  // ---------------------------------------------------
@@ -209,7 +223,7 @@ class WP_LockAuth
209
  else
210
  update_option('ld_http_auth', 'none' );
211
 
212
- if ( !isset( $_POST['hide_wp_admin'] ) )
213
  {
214
  update_option('ld_hide_wp_admin', 'nope');
215
  }
@@ -223,17 +237,16 @@ class WP_LockAuth
223
 
224
  if ( isset( $_POST['login_base'] ) )
225
  {
226
- $exp = explode('/', $_POST['login_base'], 2);
227
- $base = reset( $exp );
228
- $base = sanitize_title_with_dashes( $base);
229
  $base = str_replace('/', '', $base);
230
 
231
  $disallowed = array(
232
  'user', 'wp-admin', 'wp-content', 'wp-includes', 'wp-feed.php', 'index', 'feed', 'rss', 'robots', 'robots.txt', 'wp-login.php',
 
233
  );
234
  if ( in_array( $base, $disallowed ) )
235
  {
236
- define('LD_DIS_BASE', TRUE);
237
  }
238
  else
239
  {
@@ -283,16 +296,13 @@ class WP_LockAuth
283
 
284
  /**
285
  * Setup hiding wp-admin
286
- *
287
- * @access void
288
  **/
289
  protected function setup_hide_admin()
290
  {
291
  $opt = get_option('ld_hide_wp_admin');
292
-
293
  // Nope, they didn't enable it.
294
- if ( $opt !== 'yep' )
295
- return $this->setup_http_area();
296
 
297
  // We're gonna hide it.
298
  $no_check_files = array('async-upload.php', 'admin-ajax.php', 'wp-app.php');
@@ -304,18 +314,12 @@ class WP_LockAuth
304
  $explode = explode('/', $script_filename);
305
  $file = end( $explode );
306
 
307
- if ( in_array( $file, $no_check_files ) )
308
- {
309
- define('INTERNAL_AUTH_PASSED', TRUE);
310
- return;
311
- }
312
-
313
- // Disable for WP-CLI
314
  if ( defined('WP_CLI') AND WP_CLI )
315
- {
316
- define('INTERNAL_AUTH_PASSED', TRUE);
317
- return;
318
- }
319
 
320
  // We only will hide it if we are in admin (/wp-admin/)
321
  if ( is_admin() )
@@ -349,7 +353,6 @@ class WP_LockAuth
349
 
350
  /**
351
  * Setting up the HTTP Auth
352
- *
353
  * Here, we only check if it's enabled
354
  *
355
  * @access protected
@@ -383,10 +386,7 @@ class WP_LockAuth
383
 
384
  // Already logged in?
385
  if ( $current_uid === $requested_uid )
386
- {
387
- define('INTERNAL_AUTH_PASSED', TRUE);
388
- return;
389
- }
390
 
391
  // Attempt to sign them in if they aren't already
392
  if (! is_user_logged_in() ) :
@@ -403,7 +403,7 @@ class WP_LockAuth
403
  endif;
404
 
405
  // They passed!
406
- define('INTERNAL_AUTH_PASSED', TRUE);
407
  break;
408
 
409
  // Private list of users to check
@@ -429,7 +429,7 @@ class WP_LockAuth
429
  // Did they enter a valid user?
430
  if ( $this->user_array_check( $users, $creds['username'], $creds['password'] ) )
431
  {
432
- define('INTERNAL_AUTH_PASSED', TRUE);
433
  $this->set_current_user( $users, $creds['username'] );
434
  return;
435
  }
@@ -551,7 +551,7 @@ class WP_LockAuth
551
  public function redo_login_form()
552
  {
553
  $login_base = get_option('ld_login_base');
554
-
555
  // It's not enabled.
556
  if ( $login_base == NULL || ! $login_base || $login_base == '' )
557
  return;
@@ -665,14 +665,56 @@ class WP_LockAuth
665
  // Either way, it's gonna stop right here.
666
  exit;
667
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
  }
669
 
670
  /**
671
  * The function called at 'init'.
672
- *
673
  * Sets up the object
674
  *
675
- * @return void
676
  * @access private
677
  * @since 1.0
678
  * @see do_action() Called by the 'init' action.
@@ -682,6 +724,8 @@ function ld_setup_auth()
682
  // Instantiate the object
683
  $class = apply_filters('ld_class', 'WP_LockAuth');
684
  $auth_obj = new $class();
 
 
685
  }
686
 
687
  add_action('init', 'ld_setup_auth');
4
  Plugin URI: http://seanfisher.co/lockdown-wp-admin/
5
  Donate link: http://seanfisher.co/donate/
6
  Description: Securing the WordPress Administration interface by concealing the administration dashboard and changing the login page URL.
7
+ Version: 2.1
8
  Author: Sean Fisher
9
  Author URI: http://seanfisher.co/
10
  License: GPL
17
  * This is the plugin that will add security to our site
18
  *
19
  * @author Sean Fisher <me@seanfisher.co>
20
+ * @version 2.1
21
  * @license GPL
22
  **/
23
  class WP_LockAuth
28
  * @global string
29
  * @access private
30
  **/
31
+ public $ld_admin_version = '2.1';
32
 
33
  /**
34
  * The HTTP Auth name for the protected area
53
  **/
54
  protected $login_base = FALSE;
55
 
56
+ /**
57
+ * Check if the Auth passed
58
+ *
59
+ * See {@link WP_LockAuth::getAuthPassed()}
60
+ *
61
+ * @var boolean
62
+ */
63
+ protected $passed = FALSE;
64
+
65
+ /**
66
+ * Constructor
67
+ *
68
+ * @return void
69
+ */
70
  public function __construct()
71
  {
72
  // We don't like adding network wide WordPress plugins.
123
  **/
124
  public function update_users()
125
  {
126
+ if ( ! isset( $_GET['page'] ) )
127
  return;
128
 
129
  if ( $_GET['page'] !== 'lockdown-private-users' )
130
  return;
131
 
132
  // Nonce
133
+ if ( ! isset( $_REQUEST['_wpnonce'] ) )
134
  return;
135
 
136
  $nonce = $_REQUEST['_wpnonce'];
212
 
213
  // Nonce
214
  $nonce = $_POST['_wpnonce'];
215
+ if ( ! wp_verify_nonce($nonce, 'lockdown-wp-admin') )
216
  wp_die('Security error, please try again.');
217
 
218
  // ---------------------------------------------------
223
  else
224
  update_option('ld_http_auth', 'none' );
225
 
226
+ if ( ! isset( $_POST['hide_wp_admin'] ) )
227
  {
228
  update_option('ld_hide_wp_admin', 'nope');
229
  }
237
 
238
  if ( isset( $_POST['login_base'] ) )
239
  {
240
+ $base = sanitize_title_with_dashes( $_POST['login_base']);
 
 
241
  $base = str_replace('/', '', $base);
242
 
243
  $disallowed = array(
244
  'user', 'wp-admin', 'wp-content', 'wp-includes', 'wp-feed.php', 'index', 'feed', 'rss', 'robots', 'robots.txt', 'wp-login.php',
245
+ 'wp-login', 'wp-config', 'blog', 'sitemap', 'sitemap.xml',
246
  );
247
  if ( in_array( $base, $disallowed ) )
248
  {
249
+ return define('LD_DIS_BASE', TRUE);
250
  }
251
  else
252
  {
296
 
297
  /**
298
  * Setup hiding wp-admin
 
 
299
  **/
300
  protected function setup_hide_admin()
301
  {
302
  $opt = get_option('ld_hide_wp_admin');
303
+
304
  // Nope, they didn't enable it.
305
+ if ( $opt !== 'yep' ) return;
 
306
 
307
  // We're gonna hide it.
308
  $no_check_files = array('async-upload.php', 'admin-ajax.php', 'wp-app.php');
314
  $explode = explode('/', $script_filename);
315
  $file = end( $explode );
316
 
317
+ // Disable for WP-CLI
 
 
 
 
 
 
318
  if ( defined('WP_CLI') AND WP_CLI )
319
+ return $this->passed(true);
320
+
321
+ if ( in_array( $file, $no_check_files ) )
322
+ return $this->passed(true);
323
 
324
  // We only will hide it if we are in admin (/wp-admin/)
325
  if ( is_admin() )
353
 
354
  /**
355
  * Setting up the HTTP Auth
 
356
  * Here, we only check if it's enabled
357
  *
358
  * @access protected
386
 
387
  // Already logged in?
388
  if ( $current_uid === $requested_uid )
389
+ return $this->passed(true);
 
 
 
390
 
391
  // Attempt to sign them in if they aren't already
392
  if (! is_user_logged_in() ) :
403
  endif;
404
 
405
  // They passed!
406
+ $this->passed(true);
407
  break;
408
 
409
  // Private list of users to check
429
  // Did they enter a valid user?
430
  if ( $this->user_array_check( $users, $creds['username'], $creds['password'] ) )
431
  {
432
+ $this->passed(true);
433
  $this->set_current_user( $users, $creds['username'] );
434
  return;
435
  }
551
  public function redo_login_form()
552
  {
553
  $login_base = get_option('ld_login_base');
554
+
555
  // It's not enabled.
556
  if ( $login_base == NULL || ! $login_base || $login_base == '' )
557
  return;
665
  // Either way, it's gonna stop right here.
666
  exit;
667
  }
668
+
669
+ /**
670
+ * See if a login base is suggested against
671
+ *
672
+ * @return boolean
673
+ */
674
+ public function isSuggestedAgainst()
675
+ {
676
+ return (in_array($this->login_base, array(
677
+ 'login',
678
+ 'admin',
679
+ 'user-login',
680
+ )));
681
+ }
682
+
683
+ /**
684
+ * Retrieve the Login Base
685
+ *
686
+ * @return string
687
+ */
688
+ public function getLoginBase()
689
+ {
690
+ return $this->login_base;
691
+ }
692
+
693
+ /**
694
+ * See if the auth passed
695
+ *
696
+ * @return boolean
697
+ */
698
+ public function getAuthPassed() { return $this->passed; }
699
+
700
+ /**
701
+ * Update the Passed Auth Value
702
+ * See {@link WP_LockAuth::getAuthPassed()}
703
+ *
704
+ * @access protected
705
+ * @param boolean
706
+ */
707
+ protected function passed($value)
708
+ {
709
+ $this->passed = (bool) $value;
710
+ }
711
  }
712
 
713
  /**
714
  * The function called at 'init'.
 
715
  * Sets up the object
716
  *
717
+ * @return object
718
  * @access private
719
  * @since 1.0
720
  * @see do_action() Called by the 'init' action.
724
  // Instantiate the object
725
  $class = apply_filters('ld_class', 'WP_LockAuth');
726
  $auth_obj = new $class();
727
+
728
+ return $auth_obj;
729
  }
730
 
731
  add_action('init', 'ld_setup_auth');
no-wpmu.php CHANGED
@@ -7,12 +7,11 @@
7
  class Disable_WPMS_Plugin_LD
8
  {
9
  /**
10
- * PHP 4 style constructor
11
  *
12
- * @access private
13
  * @return void
14
  **/
15
- function Disable_WPMS_Plugin_LD()
16
  {
17
  register_activation_hook(LD_FILE_NAME, array( &$this, 'on_activate') );
18
  }
@@ -24,12 +23,9 @@ class Disable_WPMS_Plugin_LD
24
  **/
25
  function on_activate()
26
  {
27
- /**
28
- * Disable buggy sitewide activation in WPMU and WP 3.0
29
- */
30
- if ((is_multisite() && isset($_GET['sitewide'])) || ($this->is_network_mode() && isset($_GET['networkwide']))) {
31
- $this->network_activate_error();
32
- }
33
 
34
  // Default options
35
  update_option('ld_http_auth', 'none');
@@ -41,7 +37,7 @@ class Disable_WPMS_Plugin_LD
41
  *
42
  * @access private
43
  **/
44
- function network_activate_error()
45
  {
46
  // De-activate the plugin
47
  $active_plugins = (array) get_option('active_plugins');
@@ -66,23 +62,7 @@ class Disable_WPMS_Plugin_LD
66
  update_option('active_plugins', $active_plugins);
67
  update_site_option('active_sitewide_plugins', $active_plugins_network);
68
 
69
- ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
70
- <html xmlns="http://www.w3.org/1999/xhtml">
71
- <head>
72
- <title>Network Activation Error</title>
73
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
74
- </head>
75
- <body>
76
- <p>
77
- <strong>Error:</strong> This plugin cannot be activated network-wide.
78
- </p>
79
- <p>
80
- <a href="javascript:history.back(-1);">Back</a>
81
- </p>
82
- </body>
83
- </html>
84
- <?php
85
- exit();
86
  }
87
 
88
  /**
@@ -104,6 +84,6 @@ class Disable_WPMS_Plugin_LD
104
  }
105
 
106
  // The object.
107
- $setup_no_wpmu = new Disable_WPMS_Plugin_LD();
108
 
109
  /* End of file: no-wpmu.php */
7
  class Disable_WPMS_Plugin_LD
8
  {
9
  /**
10
+ * Object Constructor
11
  *
 
12
  * @return void
13
  **/
14
+ function __construct()
15
  {
16
  register_activation_hook(LD_FILE_NAME, array( &$this, 'on_activate') );
17
  }
23
  **/
24
  function on_activate()
25
  {
26
+ // Disable buggy sitewide activation in WPMU and WP 3.0
27
+ if ((is_multisite() && isset($_GET['sitewide'])) || ($this->is_network_mode() && isset($_GET['networkwide'])))
28
+ $this->network_activate_error();
 
 
 
29
 
30
  // Default options
31
  update_option('ld_http_auth', 'none');
37
  *
38
  * @access private
39
  **/
40
+ public function network_activate_error()
41
  {
42
  // De-activate the plugin
43
  $active_plugins = (array) get_option('active_plugins');
62
  update_option('active_plugins', $active_plugins);
63
  update_site_option('active_sitewide_plugins', $active_plugins_network);
64
 
65
+ wp_die('The plugin cannot be activate network-wide.');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
 
68
  /**
84
  }
85
 
86
  // The object.
87
+ $setup_no_wpmu = new Disable_WPMS_Plugin_LD;
88
 
89
  /* End of file: no-wpmu.php */
readme.txt CHANGED
@@ -4,8 +4,8 @@ Donate link: http://seanfisher.co/donate/
4
  Link: http://seanfisher.co/lockdown-wp-admin/
5
  Tags: security, secure, lockdown, vulnerability, website security, wp-admin, login, hide login, rename login, http auth, 404, lockdown, srtfisher, secure
6
  Requires at least: 3.3
7
- Tested up to: 3.5.1
8
- Stable tag: 2.0.2
9
 
10
  Lockdown WP Admin conceals the administration and login screen from intruders. It can hide WordPress Admin (/wp-admin/) and and login (/wp-login.php) as well as add HTTP authentication to the login system. We can also change the login URL from wp-login.php to whatever you'd like: /login, /log-in-here, etc.
11
 
@@ -97,3 +97,8 @@ A very late update, sorry! Worked to fix many issues with the admin bar and the
97
  = 2.0.2 =
98
  * Query string detection bug fix by [James Bonham](http://wordpress.org/support/profile/jamesbonham)
99
  * Issues with WordPress in a sub-directory
 
 
 
 
 
4
  Link: http://seanfisher.co/lockdown-wp-admin/
5
  Tags: security, secure, lockdown, vulnerability, website security, wp-admin, login, hide login, rename login, http auth, 404, lockdown, srtfisher, secure
6
  Requires at least: 3.3
7
+ Tested up to: 3.6
8
+ Stable tag: 2.1
9
 
10
  Lockdown WP Admin conceals the administration and login screen from intruders. It can hide WordPress Admin (/wp-admin/) and and login (/wp-login.php) as well as add HTTP authentication to the login system. We can also change the login URL from wp-login.php to whatever you'd like: /login, /log-in-here, etc.
11
 
97
  = 2.0.2 =
98
  * Query string detection bug fix by [James Bonham](http://wordpress.org/support/profile/jamesbonham)
99
  * Issues with WordPress in a sub-directory
100
+
101
+ = 2.1 =
102
+ * Unit Testing! Unit Testing ensure more reliable code going forward
103
+ * Support for WordPress 3.6
104
+ * General Cleaning