Version Description
- Fixing issues with other plugins
- Support tested for 3.9
- Large code structure changes. If you are extending the
WP_LockAuth
at all, you should basically check the class anew since it was seperated into Admin and Application services.
Download this release
Release Info
Developer | sean212 |
Plugin | Lockdown WP Admin |
Version | 2.2 |
Comparing to | |
See all releases |
Code changes from version 2.1 to 2.2
- README.md +8 -0
- bin/install-wp-tests.sh +78 -0
- composer.json +22 -0
- lockdown-wp-admin.php +37 -607
- no-wpmu.php +2 -2
- phpunit.xml +14 -0
- readme.txt +8 -3
- src/Lockdown/Admin.php +193 -0
- src/Lockdown/Application.php +472 -0
- tests/bootstrap.php +14 -0
- tests/test-application.php +63 -0
- tests/test-core.php +89 -0
- tests/test-hideadmin.php +34 -0
- tests/test-sample.php +10 -0
- views/settings.php +110 -0
README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1 |
Lockdown WP Admin
|
2 |
=============
|
3 |
|
|
|
|
|
|
|
4 |
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.
|
5 |
|
6 |
### Description
|
@@ -99,3 +102,8 @@ A very late update, sorry! Worked to fix many issues with the admin bar and the
|
|
99 |
* Unit Testing! Unit Testing ensure more reliable code going forward
|
100 |
* Support for WordPress 3.6
|
101 |
* General Cleaning
|
|
|
|
|
|
|
|
|
|
1 |
Lockdown WP Admin
|
2 |
=============
|
3 |
|
4 |
+
[![Build Status](https://api.travis-ci.org/srtfisher/Lockdown-WPAdmin.png?branch=master)](https://travis-ci.org/srtfisher/Lockdown-WPAdmin)
|
5 |
+
|
6 |
+
|
7 |
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.
|
8 |
|
9 |
### Description
|
102 |
* Unit Testing! Unit Testing ensure more reliable code going forward
|
103 |
* Support for WordPress 3.6
|
104 |
* General Cleaning
|
105 |
+
|
106 |
+
2.2
|
107 |
+
* Fixing issues with other plugins
|
108 |
+
* Support tested for 3.9
|
109 |
+
* Large code structure changes. If you are extending the `WP_LockAuth` at all, you should basically check the class anew since it was seperated into Admin and Application services.
|
bin/install-wp-tests.sh
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env bash
|
2 |
+
|
3 |
+
if [ $# -lt 3 ]; then
|
4 |
+
echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version]"
|
5 |
+
exit 1
|
6 |
+
fi
|
7 |
+
|
8 |
+
DB_NAME=$1
|
9 |
+
DB_USER=$2
|
10 |
+
DB_PASS=$3
|
11 |
+
DB_HOST=${4-localhost}
|
12 |
+
WP_VERSION=${5-latest}
|
13 |
+
|
14 |
+
WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
|
15 |
+
WP_CORE_DIR=/tmp/wordpress/
|
16 |
+
|
17 |
+
set -ex
|
18 |
+
|
19 |
+
install_wp() {
|
20 |
+
mkdir -p $WP_CORE_DIR
|
21 |
+
|
22 |
+
if [ $WP_VERSION == 'latest' ]; then
|
23 |
+
local ARCHIVE_NAME='latest'
|
24 |
+
else
|
25 |
+
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
26 |
+
fi
|
27 |
+
|
28 |
+
wget -nv -O /tmp/wordpress.tar.gz http://wordpress.org/${ARCHIVE_NAME}.tar.gz
|
29 |
+
tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
|
30 |
+
|
31 |
+
wget -nv -O $WP_CORE_DIR/wp-content/db.php https://raw.github.com/markoheijnen/wp-mysqli/master/db.php
|
32 |
+
}
|
33 |
+
|
34 |
+
install_test_suite() {
|
35 |
+
# portable in-place argument for both GNU sed and Mac OSX sed
|
36 |
+
if [[ $(uname -s) == 'Darwin' ]]; then
|
37 |
+
local ioption='-i .bak'
|
38 |
+
else
|
39 |
+
local ioption='-i'
|
40 |
+
fi
|
41 |
+
|
42 |
+
# set up testing suite
|
43 |
+
mkdir -p $WP_TESTS_DIR
|
44 |
+
cd $WP_TESTS_DIR
|
45 |
+
svn co --quiet http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/
|
46 |
+
|
47 |
+
wget -nv -O wp-tests-config.php http://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php
|
48 |
+
sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" wp-tests-config.php
|
49 |
+
sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" wp-tests-config.php
|
50 |
+
sed $ioption "s/yourusernamehere/$DB_USER/" wp-tests-config.php
|
51 |
+
sed $ioption "s/yourpasswordhere/$DB_PASS/" wp-tests-config.php
|
52 |
+
sed $ioption "s|localhost|${DB_HOST}|" wp-tests-config.php
|
53 |
+
}
|
54 |
+
|
55 |
+
install_db() {
|
56 |
+
# parse DB_HOST for port or socket references
|
57 |
+
local PARTS=(${DB_HOST//\:/ })
|
58 |
+
local DB_HOSTNAME=${PARTS[0]};
|
59 |
+
local DB_SOCK_OR_PORT=${PARTS[1]};
|
60 |
+
local EXTRA=""
|
61 |
+
|
62 |
+
if ! [ -z $DB_HOSTNAME ] ; then
|
63 |
+
if [[ "$DB_SOCK_OR_PORT" =~ ^[0-9]+$ ]] ; then
|
64 |
+
EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
|
65 |
+
elif ! [ -z $DB_SOCK_OR_PORT ] ; then
|
66 |
+
EXTRA=" --socket=$DB_SOCK_OR_PORT"
|
67 |
+
elif ! [ -z $DB_HOSTNAME ] ; then
|
68 |
+
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
|
69 |
+
fi
|
70 |
+
fi
|
71 |
+
|
72 |
+
# create database
|
73 |
+
mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
|
74 |
+
}
|
75 |
+
|
76 |
+
install_wp
|
77 |
+
install_test_suite
|
78 |
+
install_db
|
composer.json
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "srtfisher/lockdown-wp-admin",
|
3 |
+
"description": "WordPress Plugin to hide login and admin URLs when not logged into WordPress.",
|
4 |
+
"homepage": "http://wordpress.org/plugins/lockdown-wp-admin/",
|
5 |
+
"license": "GPL-2.0",
|
6 |
+
"type": "wp-cli",
|
7 |
+
"keywords": ["wordpress", "admin", "security"],
|
8 |
+
|
9 |
+
"authors": [
|
10 |
+
{
|
11 |
+
"name": "Sean Fisher",
|
12 |
+
"homepage": "http://seanfisher.co/"
|
13 |
+
}
|
14 |
+
],
|
15 |
+
"minimum-stability": "dev",
|
16 |
+
"config": {
|
17 |
+
"preferred-install": "dist"
|
18 |
+
},
|
19 |
+
"require-dev": {
|
20 |
+
"phpunit/phpunit": "3.7.*"
|
21 |
+
}
|
22 |
+
}
|
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.
|
8 |
Author: Sean Fisher
|
9 |
Author URI: http://seanfisher.co/
|
10 |
License: GPL
|
@@ -12,6 +12,7 @@ License: GPL
|
|
12 |
|
13 |
// This file name
|
14 |
define('LD_FILE_NAME', __FILE__ );
|
|
|
15 |
|
16 |
/**
|
17 |
* This is the plugin that will add security to our site
|
@@ -28,14 +29,14 @@ class WP_LockAuth
|
|
28 |
* @global string
|
29 |
* @access private
|
30 |
**/
|
31 |
-
public $ld_admin_version = '2.
|
32 |
|
33 |
/**
|
34 |
* The HTTP Auth name for the protected area
|
35 |
* Change this via calling the object, not by editing the file.
|
36 |
*
|
37 |
* @access public
|
38 |
-
* @
|
39 |
**/
|
40 |
public $relm = 'Secure Area';
|
41 |
|
@@ -46,648 +47,74 @@ class WP_LockAuth
|
|
46 |
**/
|
47 |
protected $current_user = FALSE;
|
48 |
|
49 |
-
/**
|
50 |
-
* The base to get the login url
|
51 |
-
*
|
52 |
-
* @access private
|
53 |
-
**/
|
54 |
-
protected $login_base = FALSE;
|
55 |
-
|
56 |
/**
|
57 |
* Check if the Auth passed
|
58 |
-
*
|
59 |
* See {@link WP_LockAuth::getAuthPassed()}
|
60 |
*
|
61 |
-
* @
|
62 |
*/
|
63 |
protected $passed = FALSE;
|
64 |
|
65 |
/**
|
66 |
-
*
|
67 |
*
|
68 |
-
* @
|
69 |
*/
|
70 |
-
public
|
71 |
-
{
|
72 |
-
// We don't like adding network wide WordPress plugins.
|
73 |
-
if (! class_exists('Disable_WPMS_Plugin_LD'))
|
74 |
-
require_once( dirname( __FILE__ ) .'/no-wpmu.php' );
|
75 |
-
|
76 |
-
// Add the action to setup the menu.
|
77 |
-
add_action('admin_menu', array( $this, 'add_admin_menu'));
|
78 |
-
|
79 |
-
// Setup the plugin.
|
80 |
-
$this->setup_hide_admin();
|
81 |
-
|
82 |
-
// Hide the login form
|
83 |
-
$this->redo_login_form();
|
84 |
-
}
|
85 |
-
|
86 |
-
/**
|
87 |
-
* Get a username and password from the HTTP auth
|
88 |
-
*
|
89 |
-
* @return array|bool
|
90 |
-
**/
|
91 |
-
public function get_http_auth_creds()
|
92 |
-
{
|
93 |
-
// Since PHP saves the HTTP Password in a bunch of places, we have to be able to test for all of them
|
94 |
-
$username = $password = NULL;
|
95 |
-
|
96 |
-
// mod_php
|
97 |
-
if (isset($_SERVER['PHP_AUTH_USER']))
|
98 |
-
{
|
99 |
-
$username = (isset($_SERVER['PHP_AUTH_USER'])) ? $_SERVER['PHP_AUTH_USER'] : NULL;
|
100 |
-
$password = (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW'] : NULL;
|
101 |
-
}
|
102 |
|
103 |
-
// most other servers
|
104 |
-
elseif ($_SERVER['HTTP_AUTHENTICATION'])
|
105 |
-
{
|
106 |
-
if (strpos(strtolower($_SERVER['HTTP_AUTHENTICATION']),'basic') === 0)
|
107 |
-
{
|
108 |
-
list($username,$password) = explode(':',base64_decode(substr($_SERVER['HTTP_AUTHENTICATION'], 6)));
|
109 |
-
}
|
110 |
-
}
|
111 |
-
|
112 |
-
// Check them - if they're null a/o empty, they're invalid.
|
113 |
-
if ( is_null($username) OR is_null($password) OR empty($username) OR empty($password))
|
114 |
-
return FALSE;
|
115 |
-
else
|
116 |
-
return array('username' => $username, 'password' => $password);
|
117 |
-
}
|
118 |
-
|
119 |
/**
|
120 |
-
*
|
121 |
*
|
122 |
-
* @
|
123 |
-
|
124 |
-
public
|
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'];
|
137 |
-
if ( !wp_verify_nonce( $nonce, 'lockdown-wp-admin' ) )
|
138 |
-
wp_die('Security error, please try again.');
|
139 |
-
|
140 |
-
// Add a user
|
141 |
-
if ( isset( $_POST['private_username'] ) && isset( $_POST['private_password'] ) )
|
142 |
-
{
|
143 |
-
if ( $_POST['private_username'] !== '' && $_POST['private_password'] !== '' )
|
144 |
-
{
|
145 |
-
// Adding a user
|
146 |
-
$users = $this->get_private_users();
|
147 |
-
$add['user'] = sanitize_user( $_POST['private_username'] );
|
148 |
-
$add['pass'] = trim( md5( $_POST['private_password'] ) );
|
149 |
-
|
150 |
-
// See if it exists
|
151 |
-
if ($this->user_exists($users, $add['user'])) :
|
152 |
-
define('LD_ERROR', 'username-exists');
|
153 |
-
return;
|
154 |
-
endif;
|
155 |
|
156 |
-
$users[] = $add;
|
157 |
-
|
158 |
-
update_option('ld_private_users', $users);
|
159 |
-
|
160 |
-
define('LD_WP_ADMIN', TRUE);
|
161 |
-
return;
|
162 |
-
}
|
163 |
-
}
|
164 |
-
|
165 |
-
// Deleting a user.
|
166 |
-
if ( isset( $_GET['delete'] ) )
|
167 |
-
{
|
168 |
-
// Delete the user.
|
169 |
-
unset( $users );
|
170 |
-
$users = $this->get_private_users();
|
171 |
-
$to_delete = (int) $_GET['delete'];
|
172 |
-
|
173 |
-
if ( count( $users ) > 0 )
|
174 |
-
{
|
175 |
-
foreach( $users as $key => $val )
|
176 |
-
{
|
177 |
-
if ( $key === $to_delete ) :
|
178 |
-
if( $this->current_user !== '' && $to_delete === $this->current_user )
|
179 |
-
{
|
180 |
-
// They can't delete themselves!
|
181 |
-
define('LD_ERROR', 'delete-self');
|
182 |
-
return;
|
183 |
-
}
|
184 |
-
|
185 |
-
unset( $users[$key] );
|
186 |
-
endif;
|
187 |
-
}
|
188 |
-
}
|
189 |
-
|
190 |
-
update_option('ld_private_users', $users);
|
191 |
-
|
192 |
-
define('LD_WP_ADMIN', TRUE);
|
193 |
-
return;
|
194 |
-
}
|
195 |
-
}
|
196 |
-
|
197 |
/**
|
198 |
-
*
|
199 |
-
*
|
200 |
-
* @access private
|
201 |
-
**/
|
202 |
-
public function update_options()
|
203 |
-
{
|
204 |
-
if ( !isset( $_GET['page'] ) )
|
205 |
-
return;
|
206 |
-
|
207 |
-
if ( $_GET['page'] !== 'lockdown-wp-admin' )
|
208 |
-
return;
|
209 |
-
|
210 |
-
if ( !isset( $_POST['did_update'] ) )
|
211 |
-
return;
|
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 |
-
// ---------------------------------------------------
|
219 |
-
// They're updating.
|
220 |
-
// ---------------------------------------------------
|
221 |
-
if ( isset( $_POST['http_auth'] ) )
|
222 |
-
update_option('ld_http_auth', trim( strtolower( $_POST['http_auth'] ) ) );
|
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 |
-
}
|
230 |
-
else
|
231 |
-
{
|
232 |
-
if ( $_POST['hide_wp_admin'] === 'yep' )
|
233 |
-
update_option('ld_hide_wp_admin', 'yep');
|
234 |
-
else
|
235 |
-
update_option('ld_hide_wp_admin', 'nope');
|
236 |
-
}
|
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 |
-
{
|
253 |
-
|
254 |
-
update_option('ld_login_base', $base);
|
255 |
-
$this->login_base = sanitize_title_with_dashes ( $base );
|
256 |
-
}
|
257 |
-
}
|
258 |
-
|
259 |
-
// Redirect
|
260 |
-
define('LD_WP_ADMIN', TRUE);
|
261 |
-
return;
|
262 |
-
}
|
263 |
-
|
264 |
-
/**
|
265 |
-
* Send headers to the browser that are going to ask for a username/pass
|
266 |
-
* from the browser.
|
267 |
*
|
268 |
-
* @access private
|
269 |
* @return void
|
270 |
-
|
271 |
-
|
272 |
{
|
273 |
-
//
|
274 |
-
if (
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
|
|
|
|
281 |
}
|
282 |
|
283 |
/**
|
284 |
* Get the users for the private creds
|
285 |
*
|
286 |
-
* @
|
287 |
**/
|
288 |
public function get_private_users()
|
289 |
{
|
290 |
-
$
|
291 |
-
if ( !is_array( $opt ) )
|
292 |
-
return array();
|
293 |
-
|
294 |
-
return $opt;
|
295 |
-
}
|
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');
|
309 |
-
$no_check_files = apply_filters('no_check_files', $no_check_files);
|
310 |
-
|
311 |
-
$script_filename = empty($_SERVER['SCRIPT_FILENAME'])
|
312 |
-
? $_SERVER['PATH_TRANSLATED']
|
313 |
-
: $_SERVER['SCRIPT_FILENAME'];
|
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() )
|
326 |
-
{
|
327 |
-
// Non logged in users.
|
328 |
-
if ( ! is_user_logged_in() )
|
329 |
-
$this->throw_404();
|
330 |
-
|
331 |
-
// Setup HTTP auth.
|
332 |
-
$this->setup_http_area();
|
333 |
-
}
|
334 |
-
}
|
335 |
-
|
336 |
-
/**
|
337 |
-
* Get the current file name
|
338 |
-
*
|
339 |
-
* @return string JUST the file name
|
340 |
-
**/
|
341 |
-
public function get_file()
|
342 |
-
{
|
343 |
-
// We're gonna hide it.
|
344 |
-
$no_check_files = array('async-upload.php');
|
345 |
-
$no_check_files = apply_filters('no_check_files', $no_check_files);
|
346 |
-
|
347 |
-
$script_filename = empty($_SERVER['SCRIPT_FILENAME'])
|
348 |
-
? $_SERVER['PATH_TRANSLATED']
|
349 |
-
: $_SERVER['SCRIPT_FILENAME'];
|
350 |
-
$explode = explode('/', $script_filename );
|
351 |
-
return end( $explode );
|
352 |
-
}
|
353 |
-
|
354 |
-
/**
|
355 |
-
* Setting up the HTTP Auth
|
356 |
-
* Here, we only check if it's enabled
|
357 |
-
*
|
358 |
-
* @access protected
|
359 |
-
**/
|
360 |
-
protected function setup_http_area()
|
361 |
-
{
|
362 |
-
// We save what type of auth we're doing here.
|
363 |
-
$opt = get_option('ld_http_auth');
|
364 |
-
|
365 |
-
// What type of auth are we doing?
|
366 |
-
switch( $opt )
|
367 |
-
{
|
368 |
-
// HTTP auth is going to ask for their WordPress creds.
|
369 |
-
case 'wp_creds' :
|
370 |
-
$creds = $this->get_http_auth_creds();
|
371 |
-
if (! $creds )
|
372 |
-
$this->inauth_headers(); // Invalid credentials
|
373 |
-
|
374 |
-
// Are they already logged in as this?
|
375 |
-
$current_uid = get_current_user_id();
|
376 |
-
|
377 |
-
// We fixed this for use with non WP-MS sites
|
378 |
-
$requested_user = get_user_by('login', $creds['username']);
|
379 |
-
|
380 |
-
// Not a valid user.
|
381 |
-
if (! $requested_user )
|
382 |
-
$this->inauth_headers();
|
383 |
-
|
384 |
-
// The correct User ID.
|
385 |
-
$requested_uid = (int) $requested_user->ID;
|
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() ) :
|
393 |
-
// Try it via wp_signon
|
394 |
-
$creds = array();
|
395 |
-
$creds['user_login'] = $creds['username'];
|
396 |
-
$creds['user_password'] = $creds['password'];
|
397 |
-
$creds['remember'] = true;
|
398 |
-
$user = wp_signon( $creds, false );
|
399 |
-
|
400 |
-
// In error
|
401 |
-
if ( is_wp_error($user) )
|
402 |
-
$this->inauth_headers();
|
403 |
-
endif;
|
404 |
-
|
405 |
-
// They passed!
|
406 |
-
$this->passed(true);
|
407 |
-
break;
|
408 |
-
|
409 |
-
// Private list of users to check
|
410 |
-
case 'private' :
|
411 |
-
$users = $this->get_private_users();
|
412 |
-
|
413 |
-
// We want a user to exist.
|
414 |
-
// If nobody is found, we won't lock them out!
|
415 |
-
if ( ! $users || ! is_array( $users ) )
|
416 |
-
return;
|
417 |
-
|
418 |
-
// Let's NOT lock everybody out
|
419 |
-
if ( count( $users ) < 1 )
|
420 |
-
return;
|
421 |
-
|
422 |
-
// Get the HTTP auth creds
|
423 |
-
$creds = $this->get_http_auth_creds();
|
424 |
-
|
425 |
-
// Invalid creds
|
426 |
-
if (! $creds )
|
427 |
-
$this->inauth_headers();
|
428 |
-
|
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 |
-
}
|
436 |
-
else
|
437 |
-
{
|
438 |
-
return $this->inauth_headers();
|
439 |
-
}
|
440 |
-
|
441 |
-
break;
|
442 |
-
|
443 |
-
// Unknown type of auth
|
444 |
-
default :
|
445 |
-
return FALSE;
|
446 |
-
}
|
447 |
-
|
448 |
-
}
|
449 |
-
/**
|
450 |
-
* Check an internal array of users against a passed user and pass
|
451 |
-
*
|
452 |
-
* @access protected
|
453 |
-
* @return bool
|
454 |
-
*
|
455 |
-
* @param array $array The array of users
|
456 |
-
* @param string $user The username to check for
|
457 |
-
* @param string $pass The password to check for (plain text)
|
458 |
-
**/
|
459 |
-
protected function user_array_check( $array, $user, $pass )
|
460 |
-
{
|
461 |
-
foreach( $array as $key => $val )
|
462 |
-
{
|
463 |
-
if ( $val['user'] === $user && md5( $pass ) === $val['pass'] )
|
464 |
-
return TRUE;
|
465 |
-
}
|
466 |
-
|
467 |
-
return FALSE;
|
468 |
-
}
|
469 |
-
|
470 |
-
/**
|
471 |
-
* See if a user exists in the array
|
472 |
-
*
|
473 |
-
* @access protected
|
474 |
-
* @return boolean
|
475 |
-
* @param array Array of users
|
476 |
-
* @param string
|
477 |
-
*/
|
478 |
-
protected function user_exists($array, $user)
|
479 |
-
{
|
480 |
-
if (count($array) == 0) return FALSE;
|
481 |
-
|
482 |
-
foreach ($array as $k => $v) :
|
483 |
-
if ($v['user'] == $user)
|
484 |
-
return TRUE;
|
485 |
-
endforeach;
|
486 |
-
|
487 |
-
return FALSE;
|
488 |
}
|
489 |
|
490 |
/**
|
491 |
* Set the current user
|
492 |
*
|
493 |
-
* @
|
494 |
-
* @param array
|
495 |
-
* @param integer
|
496 |
**/
|
497 |
protected function set_current_user( $array, $user )
|
498 |
{
|
499 |
-
|
500 |
-
{
|
501 |
-
if ( $val['user'] === $user )
|
502 |
-
$this->current_user = $key;
|
503 |
-
}
|
504 |
-
}
|
505 |
-
|
506 |
-
/**
|
507 |
-
* Adds the admin menu
|
508 |
-
*
|
509 |
-
* @acces private
|
510 |
-
**/
|
511 |
-
public function add_admin_menu()
|
512 |
-
{
|
513 |
-
add_menu_page('Lockdown WP', 'Lockdown WP', 'manage_options', 'lockdown-wp-admin', array( $this, 'admin_callback'));
|
514 |
-
add_submenu_page( 'lockdown-wp-admin', 'Private Users', 'Private Users', 'manage_options', 'lockdown-private-users', array( $this, 'sub_admin_callback'));
|
515 |
-
}
|
516 |
-
|
517 |
-
/**
|
518 |
-
* The callback for the admin area
|
519 |
-
*
|
520 |
-
* You need the 'manage_options' capability to get here.
|
521 |
-
**/
|
522 |
-
public function admin_callback()
|
523 |
-
{
|
524 |
-
// Update the options
|
525 |
-
$this->update_options();
|
526 |
-
|
527 |
-
// The UI
|
528 |
-
require_once( dirname( __FILE__ ) . '/admin.php' );
|
529 |
-
}
|
530 |
-
|
531 |
-
/**
|
532 |
-
* The callback for ther private users management.
|
533 |
-
*
|
534 |
-
* You need the 'manage_options' capability to get here.
|
535 |
-
**/
|
536 |
-
public function sub_admin_callback()
|
537 |
-
{
|
538 |
-
// Update the users options
|
539 |
-
$this->update_users();
|
540 |
-
|
541 |
-
// The UI
|
542 |
-
$private_users = $this->get_private_users();
|
543 |
-
require_once( dirname( __FILE__ ) . '/admin-private-users.php' );
|
544 |
-
}
|
545 |
-
|
546 |
-
/**
|
547 |
-
* Rename the login URL
|
548 |
-
*
|
549 |
-
* @access public
|
550 |
-
**/
|
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;
|
558 |
-
|
559 |
-
$this->login_base = $login_base;
|
560 |
-
unset( $login_base );
|
561 |
-
|
562 |
-
// Setup the filters for the new login form
|
563 |
-
add_filter('wp_redirect', array( &$this, 'filter_wp_login'));
|
564 |
-
add_filter('network_site_url', array( &$this, 'filter_wp_login'));
|
565 |
-
add_filter('site_url', array( &$this, 'filter_wp_login'));
|
566 |
-
|
567 |
-
// We need to get the URL
|
568 |
-
// This means we need to take the current URL,
|
569 |
-
// strip it of an WordPress path (if the blog is located @ /blog/)
|
570 |
-
// And then remove the query string
|
571 |
-
// We also need to remove the index.php from the URL if it exists
|
572 |
-
|
573 |
-
// The blog's URL
|
574 |
-
$blog_url = trailingslashit( get_bloginfo('url') );
|
575 |
-
|
576 |
-
// The Current URL
|
577 |
-
$schema = is_ssl() ? 'https://' : 'http://';
|
578 |
-
$current_url = $schema . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
579 |
-
|
580 |
-
$request_url = str_replace( $blog_url, '', $current_url );
|
581 |
-
$request_url = str_replace('index.php/', '', $request_url);
|
582 |
-
|
583 |
-
$url_parts = explode( '?', $request_url, 2 );
|
584 |
-
$base = $url_parts[0];
|
585 |
-
|
586 |
-
// Remove trailing slash
|
587 |
-
$base = rtrim($base,"/");
|
588 |
-
$exp = explode( '/', $base, 2 );
|
589 |
-
$super_base = end( $exp );
|
590 |
-
|
591 |
-
// Are they visiting wp-login.php?
|
592 |
-
if ( $super_base == 'wp-login.php')
|
593 |
-
$this->throw_404();
|
594 |
-
|
595 |
-
// Is this the "login" url?
|
596 |
-
if ( $base !== $this->login_base )
|
597 |
-
return FALSE;
|
598 |
-
|
599 |
-
// We dont' want a WP plugin caching this page
|
600 |
-
@define('NO_CACHE', TRUE);
|
601 |
-
@define('WTC_IN_MINIFY', TRUE);
|
602 |
-
@define('WP_CACHE', FALSE);
|
603 |
-
|
604 |
-
// Hook onto this
|
605 |
-
do_action('ld_login_page');
|
606 |
-
|
607 |
-
include ABSPATH . '/wp-login.php';
|
608 |
-
exit;
|
609 |
-
}
|
610 |
-
|
611 |
-
/**
|
612 |
-
* Filters out wp-login to whatever they named it
|
613 |
-
*
|
614 |
-
* @access public
|
615 |
-
**/
|
616 |
-
public function filter_wp_login( $str )
|
617 |
-
{
|
618 |
-
return str_replace('wp-login.php', $this->login_base, $str);
|
619 |
-
}
|
620 |
-
|
621 |
-
/**
|
622 |
-
* Launch and display the 404 page depending upon the template
|
623 |
-
*
|
624 |
-
* @param void
|
625 |
-
* @return void
|
626 |
-
**/
|
627 |
-
public function throw_404()
|
628 |
-
{
|
629 |
-
// Change WP Query
|
630 |
-
global $wp_query;
|
631 |
-
$wp_query->set_404();
|
632 |
-
status_header(404);
|
633 |
-
|
634 |
-
// Disable that pesky Admin Bar
|
635 |
-
add_filter('show_admin_bar', '__return_false', 900);
|
636 |
-
remove_action( 'admin_footer', 'wp_admin_bar_render', 10);
|
637 |
-
remove_action('wp_head', 'wp_admin_bar_header', 10);
|
638 |
-
remove_action('wp_head', '_admin_bar_bump_cb', 10);
|
639 |
-
wp_dequeue_script( 'admin-bar' );
|
640 |
-
wp_dequeue_style( 'admin-bar' );
|
641 |
-
|
642 |
-
// Template
|
643 |
-
$four_tpl = apply_filters('LD_404', get_404_template());
|
644 |
-
|
645 |
-
// Handle the admin bar
|
646 |
-
@define('APP_REQUEST', TRUE);
|
647 |
-
@define('DOING_AJAX', TRUE);
|
648 |
-
|
649 |
-
if ( empty($four_tpl) OR ! file_exists($four_tpl) )
|
650 |
-
{
|
651 |
-
// We're gonna try and get TwentyTen's one
|
652 |
-
$twenty_ten_tpl = apply_filters('LD_404_FALLBACK', WP_CONTENT_DIR . '/themes/twentythirteen/404.php');
|
653 |
-
|
654 |
-
if (file_exists($twenty_ten_tpl))
|
655 |
-
require($twenty_ten_tpl);
|
656 |
-
else
|
657 |
-
wp_die('404 - File not found!', '', array('response' => 404));
|
658 |
-
}
|
659 |
-
else
|
660 |
-
{
|
661 |
-
// Their theme has a template!
|
662 |
-
require( $four_tpl );
|
663 |
-
}
|
664 |
-
|
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->
|
691 |
}
|
692 |
|
693 |
/**
|
@@ -695,16 +122,19 @@ class WP_LockAuth
|
|
695 |
*
|
696 |
* @return boolean
|
697 |
*/
|
698 |
-
public function getAuthPassed()
|
|
|
|
|
|
|
699 |
|
700 |
/**
|
701 |
* Update the Passed Auth Value
|
702 |
* See {@link WP_LockAuth::getAuthPassed()}
|
703 |
*
|
704 |
-
* @access
|
705 |
* @param boolean
|
706 |
*/
|
707 |
-
|
708 |
{
|
709 |
$this->passed = (bool) $value;
|
710 |
}
|
@@ -728,7 +158,7 @@ function ld_setup_auth()
|
|
728 |
return $auth_obj;
|
729 |
}
|
730 |
|
731 |
-
add_action('init', 'ld_setup_auth');
|
732 |
|
733 |
/* End of file: lockdown-wp-admin.php */
|
734 |
/* Code is poetry. */
|
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.2
|
8 |
Author: Sean Fisher
|
9 |
Author URI: http://seanfisher.co/
|
10 |
License: GPL
|
12 |
|
13 |
// This file name
|
14 |
define('LD_FILE_NAME', __FILE__ );
|
15 |
+
define('LD_PLUGIN_DIR', dirname(__FILE__));
|
16 |
|
17 |
/**
|
18 |
* This is the plugin that will add security to our site
|
29 |
* @global string
|
30 |
* @access private
|
31 |
**/
|
32 |
+
public static $ld_admin_version = '2.2';
|
33 |
|
34 |
/**
|
35 |
* The HTTP Auth name for the protected area
|
36 |
* Change this via calling the object, not by editing the file.
|
37 |
*
|
38 |
* @access public
|
39 |
+
* @type string
|
40 |
**/
|
41 |
public $relm = 'Secure Area';
|
42 |
|
47 |
**/
|
48 |
protected $current_user = FALSE;
|
49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
/**
|
51 |
* Check if the Auth passed
|
|
|
52 |
* See {@link WP_LockAuth::getAuthPassed()}
|
53 |
*
|
54 |
+
* @type boolean
|
55 |
*/
|
56 |
protected $passed = FALSE;
|
57 |
|
58 |
/**
|
59 |
+
* Admin Instance
|
60 |
*
|
61 |
+
* @type Lockdown_Admin
|
62 |
*/
|
63 |
+
public $admin;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
/**
|
66 |
+
* Application Instance
|
67 |
*
|
68 |
+
* @type Lockdown_Application
|
69 |
+
*/
|
70 |
+
public $application;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
/**
|
73 |
+
* Constructor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
*
|
|
|
75 |
* @return void
|
76 |
+
*/
|
77 |
+
public function __construct()
|
78 |
{
|
79 |
+
// We don't like adding network wide WordPress plugins.
|
80 |
+
if (! class_exists('Disable_WPMS_Plugin_LD'))
|
81 |
+
require_once( dirname( __FILE__ ) .'/no-wpmu.php' );
|
82 |
+
|
83 |
+
require_once(LD_PLUGIN_DIR.'/src/Lockdown/Application.php');
|
84 |
+
require_once(LD_PLUGIN_DIR.'/src/Lockdown/Admin.php');
|
85 |
+
|
86 |
+
// Instantiate objects
|
87 |
+
$this->admin = new Lockdown_Admin($this);
|
88 |
+
$this->application = new Lockdown_Application($this);
|
89 |
}
|
90 |
|
91 |
/**
|
92 |
* Get the users for the private creds
|
93 |
*
|
94 |
+
* @deprecated Moved to `Lockdown_Application::getPrivateUsers()`
|
95 |
**/
|
96 |
public function get_private_users()
|
97 |
{
|
98 |
+
return $this->application->getPrivateUsers();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
|
101 |
/**
|
102 |
* Set the current user
|
103 |
*
|
104 |
+
* @deprecated Moved to {@see Lockdown_Application::setUser()}
|
|
|
|
|
105 |
**/
|
106 |
protected function set_current_user( $array, $user )
|
107 |
{
|
108 |
+
return $this->application->setUser($array, $user);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
}
|
110 |
|
111 |
/**
|
112 |
* Retrieve the Login Base
|
|
|
113 |
* @return string
|
114 |
*/
|
115 |
public function getLoginBase()
|
116 |
{
|
117 |
+
return $this->application->getLoginBase();
|
118 |
}
|
119 |
|
120 |
/**
|
122 |
*
|
123 |
* @return boolean
|
124 |
*/
|
125 |
+
public function getAuthPassed()
|
126 |
+
{
|
127 |
+
return (bool) $this->passed;
|
128 |
+
}
|
129 |
|
130 |
/**
|
131 |
* Update the Passed Auth Value
|
132 |
* See {@link WP_LockAuth::getAuthPassed()}
|
133 |
*
|
134 |
+
* @access public
|
135 |
* @param boolean
|
136 |
*/
|
137 |
+
public function passed($value)
|
138 |
{
|
139 |
$this->passed = (bool) $value;
|
140 |
}
|
158 |
return $auth_obj;
|
159 |
}
|
160 |
|
161 |
+
add_action('init', 'ld_setup_auth', 20);
|
162 |
|
163 |
/* End of file: lockdown-wp-admin.php */
|
164 |
/* Code is poetry. */
|
no-wpmu.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
/**
|
3 |
* We don't want to allow for this plugin to be used in WP-MS or network wide.
|
4 |
*
|
@@ -84,6 +84,6 @@ class Disable_WPMS_Plugin_LD
|
|
84 |
}
|
85 |
|
86 |
// The object.
|
87 |
-
|
88 |
|
89 |
/* End of file: no-wpmu.php */
|
1 |
+
<?php
|
2 |
/**
|
3 |
* We don't want to allow for this plugin to be used in WP-MS or network wide.
|
4 |
*
|
84 |
}
|
85 |
|
86 |
// The object.
|
87 |
+
new Disable_WPMS_Plugin_LD;
|
88 |
|
89 |
/* End of file: no-wpmu.php */
|
phpunit.xml
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<phpunit
|
2 |
+
bootstrap="tests/bootstrap.php"
|
3 |
+
backupGlobals="false"
|
4 |
+
colors="true"
|
5 |
+
convertErrorsToExceptions="true"
|
6 |
+
convertNoticesToExceptions="true"
|
7 |
+
convertWarningsToExceptions="true"
|
8 |
+
>
|
9 |
+
<testsuites>
|
10 |
+
<testsuite>
|
11 |
+
<directory prefix="test-" suffix=".php">./tests/</directory>
|
12 |
+
</testsuite>
|
13 |
+
</testsuites>
|
14 |
+
</phpunit>
|
readme.txt
CHANGED
@@ -3,9 +3,9 @@ Contributors: sean212
|
|
3 |
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.
|
7 |
-
Tested up to: 3.
|
8 |
-
Stable tag: 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 |
|
@@ -102,3 +102,8 @@ A very late update, sorry! Worked to fix many issues with the admin bar and the
|
|
102 |
* Unit Testing! Unit Testing ensure more reliable code going forward
|
103 |
* Support for WordPress 3.6
|
104 |
* General Cleaning
|
|
|
|
|
|
|
|
|
|
3 |
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.6
|
7 |
+
Tested up to: 3.8
|
8 |
+
Stable tag: 2.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 |
|
102 |
* Unit Testing! Unit Testing ensure more reliable code going forward
|
103 |
* Support for WordPress 3.6
|
104 |
* General Cleaning
|
105 |
+
|
106 |
+
= 2.2 =
|
107 |
+
* Fixing issues with other plugins
|
108 |
+
* Support tested for 3.9
|
109 |
+
* Large code structure changes. If you are extending the `WP_LockAuth` at all, you should basically check the class anew since it was seperated into Admin and Application services.
|
src/Lockdown/Admin.php
ADDED
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Lockdown_Admin {
|
3 |
+
/**
|
4 |
+
* Main Instance Storage
|
5 |
+
*
|
6 |
+
* @var WP_LockAuth
|
7 |
+
*/
|
8 |
+
protected $instance;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Admin Constructor
|
12 |
+
*
|
13 |
+
* @param WP_LockAuth
|
14 |
+
*/
|
15 |
+
public function __construct(WP_LockAuth $instance)
|
16 |
+
{
|
17 |
+
$this->instance = $instance;
|
18 |
+
|
19 |
+
// Add the action to setup the menu.
|
20 |
+
add_action('admin_menu', array( $this, 'add_admin_menu'));
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Adds the admin menu
|
25 |
+
*
|
26 |
+
* @acces private
|
27 |
+
**/
|
28 |
+
public function add_admin_menu()
|
29 |
+
{
|
30 |
+
add_menu_page('Lockdown WP', 'Lockdown WP', 'manage_options', 'lockdown-wp-admin', array( $this, 'admin_callback'));
|
31 |
+
add_submenu_page( 'lockdown-wp-admin', 'Private Users', 'Private Users', 'manage_options', 'lockdown-private-users', array( $this, 'sub_admin_callback'));
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* The callback for the admin area
|
36 |
+
*
|
37 |
+
* You need the 'manage_options' capability to get here.
|
38 |
+
**/
|
39 |
+
public function admin_callback()
|
40 |
+
{
|
41 |
+
// Update the options
|
42 |
+
$this->updateSettings();
|
43 |
+
|
44 |
+
// The UI
|
45 |
+
require_once( LD_PLUGIN_DIR . '/views/settings.php' );
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* The callback for ther private users management.
|
50 |
+
*
|
51 |
+
* You need the 'manage_options' capability to get here.
|
52 |
+
**/
|
53 |
+
public function sub_admin_callback()
|
54 |
+
{
|
55 |
+
// Update the users options
|
56 |
+
$this->update_users();
|
57 |
+
|
58 |
+
// The UI
|
59 |
+
$private_users = $this->instance->application->getPrivateUsers();
|
60 |
+
require_once( LD_PLUGIN_DIR . '/admin-private-users.php' );
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Update the options
|
65 |
+
*
|
66 |
+
* @access private
|
67 |
+
**/
|
68 |
+
public function updateSettings()
|
69 |
+
{
|
70 |
+
if ( !isset( $_GET['page'] ) || $_GET['page'] !== 'lockdown-wp-admin' || !isset( $_POST['did_update'] ))
|
71 |
+
return;
|
72 |
+
|
73 |
+
// Nonce
|
74 |
+
$nonce = $_POST['_wpnonce'];
|
75 |
+
if ( ! wp_verify_nonce($nonce, 'lockdown-wp-admin') )
|
76 |
+
wp_die('Security error, please try again.');
|
77 |
+
|
78 |
+
// ---------------------------------------------------
|
79 |
+
// They're updating.
|
80 |
+
// ---------------------------------------------------
|
81 |
+
if ( isset( $_POST['http_auth'] ) )
|
82 |
+
update_option('ld_http_auth', trim( strtolower( $_POST['http_auth'] ) ) );
|
83 |
+
else
|
84 |
+
update_option('ld_http_auth', 'none' );
|
85 |
+
|
86 |
+
if ( ! isset( $_POST['hide_wp_admin'] ) )
|
87 |
+
{
|
88 |
+
update_option('ld_hide_wp_admin', 'nope');
|
89 |
+
}
|
90 |
+
else
|
91 |
+
{
|
92 |
+
if ( $_POST['hide_wp_admin'] === 'yep' )
|
93 |
+
update_option('ld_hide_wp_admin', 'yep');
|
94 |
+
else
|
95 |
+
update_option('ld_hide_wp_admin', 'nope');
|
96 |
+
}
|
97 |
+
|
98 |
+
if ( isset( $_POST['login_base'] ) )
|
99 |
+
{
|
100 |
+
$base = sanitize_title_with_dashes( $_POST['login_base']);
|
101 |
+
$base = str_replace('/', '', $base);
|
102 |
+
|
103 |
+
$disallowed = array(
|
104 |
+
'user', 'wp-admin', 'wp-content', 'wp-includes', 'wp-feed.php', 'index', 'feed', 'rss', 'robots', 'robots.txt', 'wp-login.php',
|
105 |
+
'wp-login', 'wp-config', 'blog', 'sitemap', 'sitemap.xml',
|
106 |
+
);
|
107 |
+
if ( in_array( $base, $disallowed ) )
|
108 |
+
{
|
109 |
+
return define('LD_DIS_BASE', TRUE);
|
110 |
+
}
|
111 |
+
else
|
112 |
+
{
|
113 |
+
|
114 |
+
update_option('ld_login_base', $base);
|
115 |
+
$this->instance->application->setLoginBase(sanitize_title_with_dashes ( $base ));
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
// Redirect
|
120 |
+
return define('LD_WP_ADMIN', TRUE);
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Update the users
|
125 |
+
*
|
126 |
+
* @access private
|
127 |
+
**/
|
128 |
+
public function update_users()
|
129 |
+
{
|
130 |
+
if ( ! isset( $_GET['page'] ) || $_GET['page'] !== 'lockdown-private-users')
|
131 |
+
return;
|
132 |
+
|
133 |
+
// Nonce
|
134 |
+
if ( ! isset( $_REQUEST['_wpnonce'] ) )
|
135 |
+
return;
|
136 |
+
|
137 |
+
$nonce = $_REQUEST['_wpnonce'];
|
138 |
+
if ( ! wp_verify_nonce( $nonce, 'lockdown-wp-admin' ) )
|
139 |
+
wp_die('Security error, please try again.');
|
140 |
+
|
141 |
+
// Add a user
|
142 |
+
if ( isset( $_POST['private_username'] ) && isset( $_POST['private_password'] ) )
|
143 |
+
{
|
144 |
+
if ( $_POST['private_username'] !== '' && $_POST['private_password'] !== '' )
|
145 |
+
{
|
146 |
+
// Adding a user
|
147 |
+
$users = $this->instance->application->getPrivateUsers();
|
148 |
+
$add['user'] = sanitize_user( $_POST['private_username'] );
|
149 |
+
$add['pass'] = trim( md5( $_POST['private_password'] ) );
|
150 |
+
|
151 |
+
// See if it exists
|
152 |
+
if ($this->instance->application->userExists($users, $add['user']))
|
153 |
+
return define('LD_ERROR', 'username-exists');
|
154 |
+
else
|
155 |
+
$users[] = $add;
|
156 |
+
|
157 |
+
update_option('ld_private_users', $users);
|
158 |
+
|
159 |
+
return define('LD_WP_ADMIN', TRUE);
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
// Deleting a user.
|
164 |
+
if ( isset( $_GET['delete'] ) )
|
165 |
+
{
|
166 |
+
// Delete the user.
|
167 |
+
unset( $users );
|
168 |
+
$users = $this->instance->application->getPrivateUsers();
|
169 |
+
$to_delete = (int) $_GET['delete'];
|
170 |
+
|
171 |
+
if ( count( $users ) > 0 )
|
172 |
+
{
|
173 |
+
foreach( $users as $key => $val )
|
174 |
+
{
|
175 |
+
if ( $key === $to_delete ) :
|
176 |
+
if( $this->current_user !== '' && $to_delete === $this->current_user )
|
177 |
+
{
|
178 |
+
// They can't delete themselves!
|
179 |
+
return define('LD_ERROR', 'delete-self');
|
180 |
+
}
|
181 |
+
|
182 |
+
unset( $users[$key] );
|
183 |
+
endif;
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
update_option('ld_private_users', $users);
|
188 |
+
|
189 |
+
define('LD_WP_ADMIN', TRUE);
|
190 |
+
return;
|
191 |
+
}
|
192 |
+
}
|
193 |
+
}
|
src/Lockdown/Application.php
ADDED
@@ -0,0 +1,472 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class Lockdown_Application {
|
3 |
+
/**
|
4 |
+
* Main Instance Storage
|
5 |
+
*
|
6 |
+
* @var WP_LockAuth
|
7 |
+
*/
|
8 |
+
protected $instance;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* The base to get the login url
|
12 |
+
*
|
13 |
+
* @access private
|
14 |
+
**/
|
15 |
+
protected $login_base;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Admin Constructor
|
19 |
+
*
|
20 |
+
* @param WP_LockAuth
|
21 |
+
*/
|
22 |
+
public function __construct(WP_LockAuth $instance)
|
23 |
+
{
|
24 |
+
$this->instance = $instance;
|
25 |
+
|
26 |
+
// Setup the plugin.
|
27 |
+
$this->ininitializeConceal();
|
28 |
+
|
29 |
+
// Hide the login form
|
30 |
+
$this->renameLogin();
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Setup hiding wp-admin
|
35 |
+
*/
|
36 |
+
protected function ininitializeConceal()
|
37 |
+
{
|
38 |
+
$opt = get_option('ld_hide_wp_admin');
|
39 |
+
|
40 |
+
// Nope, they didn't enable it.
|
41 |
+
if ( $opt !== 'yep' ) return;
|
42 |
+
|
43 |
+
// We're gonna hide it.
|
44 |
+
$no_check_files = array('async-upload.php', 'admin-ajax.php', 'wp-app.php');
|
45 |
+
$no_check_files = apply_filters('no_check_files', $no_check_files);
|
46 |
+
|
47 |
+
$script_filename = empty($_SERVER['SCRIPT_FILENAME'])
|
48 |
+
? $_SERVER['PATH_TRANSLATED']
|
49 |
+
: $_SERVER['SCRIPT_FILENAME'];
|
50 |
+
$explode = explode('/', $script_filename);
|
51 |
+
$file = end( $explode );
|
52 |
+
|
53 |
+
// Disable for WP-CLI
|
54 |
+
if ( defined('WP_CLI') AND WP_CLI )
|
55 |
+
return $this->instance->passed(true);
|
56 |
+
|
57 |
+
if ( in_array( $file, $no_check_files ) )
|
58 |
+
return $this->instance->passed(true);
|
59 |
+
|
60 |
+
// We only will hide it if we are in admin (/wp-admin/)
|
61 |
+
if ( is_admin() )
|
62 |
+
{
|
63 |
+
// Non logged in users.
|
64 |
+
if ( ! is_user_logged_in() )
|
65 |
+
$this->throw404();
|
66 |
+
|
67 |
+
// Setup HTTP auth.
|
68 |
+
$this->setupHttpCheck();
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Launch and display the 404 page depending upon the template
|
74 |
+
*
|
75 |
+
* @param void
|
76 |
+
* @return void
|
77 |
+
**/
|
78 |
+
public function throw404()
|
79 |
+
{
|
80 |
+
// Change WP Query
|
81 |
+
global $wp_query;
|
82 |
+
$wp_query->set_404();
|
83 |
+
status_header(404);
|
84 |
+
|
85 |
+
// Disable that pesky Admin Bar
|
86 |
+
add_filter('show_admin_bar', '__return_false', 900);
|
87 |
+
remove_action( 'admin_footer', 'wp_admin_bar_render', 10);
|
88 |
+
remove_action('wp_head', 'wp_admin_bar_header', 10);
|
89 |
+
remove_action('wp_head', '_admin_bar_bump_cb', 10);
|
90 |
+
wp_dequeue_script( 'admin-bar' );
|
91 |
+
wp_dequeue_style( 'admin-bar' );
|
92 |
+
|
93 |
+
// Template
|
94 |
+
$four_tpl = apply_filters('LD_404', get_404_template());
|
95 |
+
|
96 |
+
// Handle the admin bar
|
97 |
+
@define('APP_REQUEST', TRUE);
|
98 |
+
@define('DOING_AJAX', TRUE);
|
99 |
+
|
100 |
+
if ( empty($four_tpl) OR ! file_exists($four_tpl) )
|
101 |
+
{
|
102 |
+
// We're gonna try and get TwentyTen's one
|
103 |
+
$twenty_ten_tpl = apply_filters('LD_404_FALLBACK', WP_CONTENT_DIR . '/themes/twentyfourteen/404.php');
|
104 |
+
|
105 |
+
if (file_exists($twenty_ten_tpl))
|
106 |
+
require($twenty_ten_tpl);
|
107 |
+
else
|
108 |
+
wp_die('404 - File not found!', '', array('response' => 404));
|
109 |
+
}
|
110 |
+
else
|
111 |
+
{
|
112 |
+
// Their theme has a template!
|
113 |
+
require( $four_tpl );
|
114 |
+
}
|
115 |
+
|
116 |
+
// Either way, it's gonna stop right here.
|
117 |
+
exit;
|
118 |
+
}
|
119 |
+
|
120 |
+
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Rename the login URL
|
124 |
+
*
|
125 |
+
*
|
126 |
+
* @see do_action() Calls `ld_login_page` right before we call `wp-login.php`
|
127 |
+
* @access public
|
128 |
+
**/
|
129 |
+
public function renameLogin()
|
130 |
+
{
|
131 |
+
$this->login_base = get_option('ld_login_base');
|
132 |
+
|
133 |
+
// It's not enabled.
|
134 |
+
if ( $this->login_base == NULL || ! $this->login_base || $this->login_base == '' )
|
135 |
+
return;
|
136 |
+
|
137 |
+
// Setup the filters for the new login form
|
138 |
+
add_filter('wp_redirect', array( &$this, 'filterWpLogin'));
|
139 |
+
add_filter('network_site_url', array( &$this, 'filterWpLogin'));
|
140 |
+
add_filter('site_url', array( &$this, 'filterWpLogin'));
|
141 |
+
|
142 |
+
// We need to get the URL
|
143 |
+
// This means we need to take the current URL,
|
144 |
+
// strip it of an WordPress path (if the blog is located @ /blog/)
|
145 |
+
// And then remove the query string
|
146 |
+
// We also need to remove the index.php from the URL if it exists
|
147 |
+
|
148 |
+
// The blog's URL
|
149 |
+
$blog_url = trailingslashit( get_bloginfo('url') );
|
150 |
+
|
151 |
+
// The Current URL
|
152 |
+
$schema = is_ssl() ? 'https://' : 'http://';
|
153 |
+
$current_url = $schema . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
154 |
+
|
155 |
+
$request_url = str_replace( $blog_url, '', $current_url );
|
156 |
+
$request_url = str_replace('index.php/', '', $request_url);
|
157 |
+
|
158 |
+
$url_parts = explode( '?', $request_url, 2 );
|
159 |
+
$base = $url_parts[0];
|
160 |
+
|
161 |
+
// Remove trailing slash
|
162 |
+
$base = rtrim($base,"/");
|
163 |
+
$exp = explode( '/', $base, 2 );
|
164 |
+
$super_base = end( $exp );
|
165 |
+
|
166 |
+
// Are they visiting wp-login.php?
|
167 |
+
if ( $super_base == 'wp-login.php')
|
168 |
+
$this->throw404();
|
169 |
+
|
170 |
+
// Is this the "login" url?
|
171 |
+
if ( $base !== $this->getLoginBase() )
|
172 |
+
return FALSE;
|
173 |
+
|
174 |
+
// We dont' want a WP plugin caching this page
|
175 |
+
@define('NO_CACHE', TRUE);
|
176 |
+
@define('WTC_IN_MINIFY', TRUE);
|
177 |
+
@define('WP_CACHE', FALSE);
|
178 |
+
|
179 |
+
// Hook onto this
|
180 |
+
do_action('ld_login_page');
|
181 |
+
|
182 |
+
include ABSPATH . '/wp-login.php';
|
183 |
+
exit;
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
* Filters out wp-login to whatever they named it
|
188 |
+
*
|
189 |
+
* @access public
|
190 |
+
**/
|
191 |
+
public function filterWpLogin( $str )
|
192 |
+
{
|
193 |
+
return str_replace('wp-login.php', $this->getLoginBase(), $str);
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* Setting up the HTTP Auth
|
198 |
+
* Here, we only check if it's enabled
|
199 |
+
*
|
200 |
+
* @access protected
|
201 |
+
**/
|
202 |
+
protected function setupHttpCheck($option = NULL)
|
203 |
+
{
|
204 |
+
// We save what type of auth we're doing here.
|
205 |
+
if (! $option)
|
206 |
+
$option = get_option('ld_http_auth');
|
207 |
+
|
208 |
+
// What type of auth are we doing?
|
209 |
+
switch( $option )
|
210 |
+
{
|
211 |
+
// HTTP auth is going to ask for their WordPress creds.
|
212 |
+
case 'wp_creds' :
|
213 |
+
$creds = $this->retrieveAuthCredentials();
|
214 |
+
|
215 |
+
if (! $creds )
|
216 |
+
$this->unauthorizedArea(); // Invalid credentials
|
217 |
+
|
218 |
+
// Are they already logged in as this?
|
219 |
+
$current_uid = get_current_user_id();
|
220 |
+
|
221 |
+
// We fixed this for use with non WP-MS sites
|
222 |
+
$requested_user = get_user_by('login', $creds['username']);
|
223 |
+
|
224 |
+
// Not a valid user.
|
225 |
+
if (! $requested_user )
|
226 |
+
$this->unauthorizedArea();
|
227 |
+
|
228 |
+
// The correct User ID.
|
229 |
+
$requested_uid = (int) $requested_user->ID;
|
230 |
+
|
231 |
+
// Already logged in?
|
232 |
+
if ( $current_uid === $requested_uid )
|
233 |
+
return $this->instance->passed(true);
|
234 |
+
|
235 |
+
// Attempt to sign them in if they aren't already
|
236 |
+
if (! is_user_logged_in() ) :
|
237 |
+
// Try it via wp_signon
|
238 |
+
$creds = array();
|
239 |
+
$creds['user_login'] = $creds['username'];
|
240 |
+
$creds['user_password'] = $creds['password'];
|
241 |
+
$creds['remember'] = true;
|
242 |
+
$user = wp_signon( $creds, false );
|
243 |
+
|
244 |
+
// In error
|
245 |
+
if ( is_wp_error($user) )
|
246 |
+
return $this->unauthorizedArea();
|
247 |
+
endif;
|
248 |
+
|
249 |
+
// They passed!
|
250 |
+
$this->passed(true);
|
251 |
+
break;
|
252 |
+
|
253 |
+
// Private list of users to check
|
254 |
+
case 'private' :
|
255 |
+
$users = $this->getPrivateUsers();
|
256 |
+
|
257 |
+
// We want a user to exist.
|
258 |
+
// If nobody is found, we won't lock them out!
|
259 |
+
if ( ! $users || ! is_array( $users ) )
|
260 |
+
return;
|
261 |
+
|
262 |
+
// Let's NOT lock everybody out
|
263 |
+
if ( count( $users ) < 1 )
|
264 |
+
return;
|
265 |
+
|
266 |
+
// Get the HTTP auth creds
|
267 |
+
$creds = $this->retrieveAuthCredentials();
|
268 |
+
|
269 |
+
// Invalid creds
|
270 |
+
if (! $creds )
|
271 |
+
$this->unauthorizedArea();
|
272 |
+
|
273 |
+
// Did they enter a valid user?
|
274 |
+
if ( $this->matchUserToArray( $users, $creds['username'], $creds['password'] ) )
|
275 |
+
{
|
276 |
+
$this->instance->passed(true);
|
277 |
+
return $this->setUser( $users, $creds['username'] );
|
278 |
+
}
|
279 |
+
else
|
280 |
+
{
|
281 |
+
return $this->unauthorizedArea();
|
282 |
+
}
|
283 |
+
|
284 |
+
break;
|
285 |
+
|
286 |
+
// Unknown type of auth
|
287 |
+
default :
|
288 |
+
$this->instance->passed(true);
|
289 |
+
return FALSE;
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Send headers to the browser that are going to ask for a username/pass
|
295 |
+
* from the browser.
|
296 |
+
*
|
297 |
+
* @access private
|
298 |
+
* @return void
|
299 |
+
**/
|
300 |
+
protected function unauthorizedArea()
|
301 |
+
{
|
302 |
+
// Disable if there is a text file there.
|
303 |
+
if ( file_exists(LD_PLUGIN_DIR.'/disable_auth.txt'))
|
304 |
+
return;
|
305 |
+
|
306 |
+
header('WWW-Authenticate: Basic realm="'. $this->instance->relm.'"');
|
307 |
+
header('HTTP/1.0 401 Unauthorized');
|
308 |
+
echo '<h1>Authorization Required.</h1>';
|
309 |
+
exit;
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Set the current user
|
314 |
+
*
|
315 |
+
* @access private
|
316 |
+
* @param array
|
317 |
+
* @param integer
|
318 |
+
**/
|
319 |
+
public function setUser( $array, $user )
|
320 |
+
{
|
321 |
+
foreach( $array as $key => $val )
|
322 |
+
{
|
323 |
+
if ( $val['user'] === $user )
|
324 |
+
$this->current_user = $key;
|
325 |
+
}
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Get the current file name
|
330 |
+
*
|
331 |
+
* @return string JUST the file name
|
332 |
+
**/
|
333 |
+
public function retrieveFile()
|
334 |
+
{
|
335 |
+
// We're gonna hide it.
|
336 |
+
$no_check_files = array('async-upload.php');
|
337 |
+
$no_check_files = apply_filters('no_check_files', $no_check_files);
|
338 |
+
|
339 |
+
$script_filename = empty($_SERVER['SCRIPT_FILENAME'])
|
340 |
+
? $_SERVER['PATH_TRANSLATED']
|
341 |
+
: $_SERVER['SCRIPT_FILENAME'];
|
342 |
+
$explode = explode('/', $script_filename );
|
343 |
+
return end( $explode );
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Check an internal array of users against a passed user and pass
|
348 |
+
*
|
349 |
+
* @access protected
|
350 |
+
* @return bool
|
351 |
+
*
|
352 |
+
* @param array $array The array of users
|
353 |
+
* @param string $user The username to check for
|
354 |
+
* @param string $pass The password to check for (plain text)
|
355 |
+
**/
|
356 |
+
protected function matchUserToArray( $array, $user, $pass )
|
357 |
+
{
|
358 |
+
foreach( $array as $key => $val )
|
359 |
+
{
|
360 |
+
if (! isset($val['user']) || ! isset($val['pass']))
|
361 |
+
continue;
|
362 |
+
|
363 |
+
if ( $val['user'] === $user && md5( $pass ) === $val['pass'] )
|
364 |
+
return TRUE;
|
365 |
+
}
|
366 |
+
|
367 |
+
return FALSE;
|
368 |
+
}
|
369 |
+
|
370 |
+
/**
|
371 |
+
* See if a user exists in the array
|
372 |
+
*
|
373 |
+
* @access public
|
374 |
+
* @return boolean
|
375 |
+
* @param array Array of users
|
376 |
+
* @param string
|
377 |
+
*/
|
378 |
+
public function userExists($array, $user)
|
379 |
+
{
|
380 |
+
if (count($array) == 0) return FALSE;
|
381 |
+
|
382 |
+
foreach ($array as $k => $v) :
|
383 |
+
if ($v['user'] == $user)
|
384 |
+
return TRUE;
|
385 |
+
endforeach;
|
386 |
+
|
387 |
+
return FALSE;
|
388 |
+
}
|
389 |
+
|
390 |
+
/**
|
391 |
+
* See if a login base is suggested against
|
392 |
+
*
|
393 |
+
* @return boolean
|
394 |
+
*/
|
395 |
+
public function isSuggestedAgainst()
|
396 |
+
{
|
397 |
+
return (in_array($this->login_base, array(
|
398 |
+
'login',
|
399 |
+
'admin',
|
400 |
+
'user-login',
|
401 |
+
)));
|
402 |
+
}
|
403 |
+
|
404 |
+
/**
|
405 |
+
* Retrieve the login base
|
406 |
+
*
|
407 |
+
* @return string
|
408 |
+
* @param string Default
|
409 |
+
*/
|
410 |
+
public function getLoginBase($default = '')
|
411 |
+
{
|
412 |
+
return ($this->login_base) ? $this->login_base : $default;
|
413 |
+
}
|
414 |
+
|
415 |
+
/**
|
416 |
+
* Set the login base
|
417 |
+
*
|
418 |
+
* @param string
|
419 |
+
*/
|
420 |
+
public function setLoginBase($base = '')
|
421 |
+
{
|
422 |
+
$this->login_base = $base;
|
423 |
+
return $this;
|
424 |
+
}
|
425 |
+
|
426 |
+
/**
|
427 |
+
* Get a username and password from the Basic HTTP auth
|
428 |
+
*
|
429 |
+
* @return array|bool
|
430 |
+
**/
|
431 |
+
public function retrieveAuthCredentials()
|
432 |
+
{
|
433 |
+
// Since PHP saves the HTTP Password in a bunch of places, we have to be able to test for all of them
|
434 |
+
$username = $password = NULL;
|
435 |
+
|
436 |
+
// mod_php
|
437 |
+
if (isset($_SERVER['PHP_AUTH_USER']))
|
438 |
+
{
|
439 |
+
$username = (isset($_SERVER['PHP_AUTH_USER'])) ? $_SERVER['PHP_AUTH_USER'] : NULL;
|
440 |
+
$password = (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW'] : NULL;
|
441 |
+
}
|
442 |
+
|
443 |
+
// most other servers
|
444 |
+
elseif ($_SERVER['HTTP_AUTHENTICATION'])
|
445 |
+
{
|
446 |
+
if (strpos(strtolower($_SERVER['HTTP_AUTHENTICATION']),'basic') === 0)
|
447 |
+
{
|
448 |
+
list($username,$password) = explode(':',base64_decode(substr($_SERVER['HTTP_AUTHENTICATION'], 6)));
|
449 |
+
}
|
450 |
+
}
|
451 |
+
|
452 |
+
// Check them - if they're null a/o empty, they're invalid.
|
453 |
+
if ( is_null($username) OR is_null($password) OR empty($username) OR empty($password))
|
454 |
+
return FALSE;
|
455 |
+
else
|
456 |
+
return array('username' => $username, 'password' => $password);
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Get the users for the private creds
|
461 |
+
*
|
462 |
+
* @access private
|
463 |
+
**/
|
464 |
+
public function getPrivateUsers()
|
465 |
+
{
|
466 |
+
$opt = get_option('ld_private_users');
|
467 |
+
if ( !is_array( $opt ) )
|
468 |
+
return array();
|
469 |
+
|
470 |
+
return $opt;
|
471 |
+
}
|
472 |
+
}
|
tests/bootstrap.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
$_tests_dir = getenv('WP_TESTS_DIR');
|
4 |
+
if ( !$_tests_dir ) $_tests_dir = '/tmp/wordpress-tests-lib';
|
5 |
+
|
6 |
+
require_once $_tests_dir . '/includes/functions.php';
|
7 |
+
|
8 |
+
function _manually_load_plugin() {
|
9 |
+
require dirname( __FILE__ ) . '/../lockdown-wp-admin.php';
|
10 |
+
}
|
11 |
+
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
|
12 |
+
|
13 |
+
require $_tests_dir . '/includes/bootstrap.php';
|
14 |
+
|
tests/test-application.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class LockdownApplicationTest extends PHPUnit_Framework_TestCase {
|
3 |
+
protected $object;
|
4 |
+
|
5 |
+
protected function setUp()
|
6 |
+
{
|
7 |
+
$this->object = ld_setup_auth();
|
8 |
+
}
|
9 |
+
|
10 |
+
public function testMatchUserToArray()
|
11 |
+
{
|
12 |
+
$users = array(
|
13 |
+
array(
|
14 |
+
'user' => 'admin',
|
15 |
+
'pass' => md5('password')
|
16 |
+
),
|
17 |
+
|
18 |
+
array(
|
19 |
+
'user' => 'stan',
|
20 |
+
'pass' => md5('marsh')
|
21 |
+
)
|
22 |
+
);
|
23 |
+
|
24 |
+
// Should pass
|
25 |
+
$this->assertTrue(
|
26 |
+
$this->invokeMethod($this->object->application, 'matchUserToArray', array($users, 'admin', 'password'))
|
27 |
+
);
|
28 |
+
|
29 |
+
// Both should fail
|
30 |
+
$this->assertFalse(
|
31 |
+
$this->invokeMethod($this->object->application, 'matchUserToArray', array($users, 'admin', 'notpassword'))
|
32 |
+
);
|
33 |
+
|
34 |
+
$this->assertFalse(
|
35 |
+
$this->invokeMethod($this->object->application, 'matchUserToArray', array(array(), 'admin', 'notpassword'))
|
36 |
+
);
|
37 |
+
}
|
38 |
+
|
39 |
+
public function testNoSettingsPassed()
|
40 |
+
{
|
41 |
+
$this->invokeMethod($this->object->application, 'setupHttpCheck', array(null));
|
42 |
+
|
43 |
+
$this->assertTrue($this->object->getAuthPassed());
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Call protected/private method of a class.
|
48 |
+
*
|
49 |
+
* @param object &$object Instantiated object that we will run method on.
|
50 |
+
* @param string $methodName Method name to call
|
51 |
+
* @param array $parameters Array of parameters to pass into method.
|
52 |
+
*
|
53 |
+
* @return mixed Method return.
|
54 |
+
*/
|
55 |
+
public function invokeMethod(&$object, $methodName, array $parameters = array())
|
56 |
+
{
|
57 |
+
$reflection = new \ReflectionClass(get_class($object));
|
58 |
+
$method = $reflection->getMethod($methodName);
|
59 |
+
$method->setAccessible(true);
|
60 |
+
|
61 |
+
return $method->invokeArgs($object, $parameters);
|
62 |
+
}
|
63 |
+
}
|
tests/test-core.php
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class LockdownTest extends PHPUnit_Framework_TestCase {
|
3 |
+
protected $object;
|
4 |
+
|
5 |
+
protected function setUp()
|
6 |
+
{
|
7 |
+
$this->object = ld_setup_auth();
|
8 |
+
}
|
9 |
+
|
10 |
+
public function testApplicationSetup()
|
11 |
+
{
|
12 |
+
$this->assertInstanceOf('Lockdown_Application', $this->object->application);
|
13 |
+
}
|
14 |
+
|
15 |
+
public function testAdminSetup()
|
16 |
+
{
|
17 |
+
$this->assertInstanceOf('Lockdown_Admin', $this->object->admin);
|
18 |
+
}
|
19 |
+
|
20 |
+
public function testRelm()
|
21 |
+
{
|
22 |
+
$this->assertTrue(is_string($this->object->relm));
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Test that the application has added an action to init
|
27 |
+
*/
|
28 |
+
public function testActionAdded()
|
29 |
+
{
|
30 |
+
$this->assertTrue(has_action('init'));
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* The ability to overwrite the Lockdown WP Admin Object
|
35 |
+
*/
|
36 |
+
public function testOverwriteLdObject()
|
37 |
+
{
|
38 |
+
add_filter('ld_class', function() { return 'LdProxyObject'; });
|
39 |
+
$setup = ld_setup_auth();
|
40 |
+
$this->assertEquals('LdProxyObject', get_class($setup));
|
41 |
+
$this->assertEquals('WP_LockAuth', get_class($this->object));
|
42 |
+
}
|
43 |
+
|
44 |
+
public function testFiltersWithoutBase()
|
45 |
+
{
|
46 |
+
remove_all_actions('wp_redirect');
|
47 |
+
remove_all_actions('network_site_url');
|
48 |
+
remove_all_actions('site_url');
|
49 |
+
|
50 |
+
update_option('ld_login_base', null);
|
51 |
+
$this->object->application->renameLogin();
|
52 |
+
|
53 |
+
$this->assertFalse(has_action('wp_redirect'));
|
54 |
+
$this->assertFalse(has_action('network_site_url'));
|
55 |
+
$this->assertFalse(has_action('site_url'));
|
56 |
+
}
|
57 |
+
|
58 |
+
public function testFiltersWithBase()
|
59 |
+
{
|
60 |
+
remove_all_actions('wp_redirect');
|
61 |
+
remove_all_actions('network_site_url');
|
62 |
+
remove_all_actions('site_url');
|
63 |
+
|
64 |
+
update_option('ld_login_base', 'login');
|
65 |
+
$this->object->application->renameLogin();
|
66 |
+
|
67 |
+
$this->assertTrue(has_action('wp_redirect'));
|
68 |
+
$this->assertTrue(has_action('network_site_url'));
|
69 |
+
$this->assertTrue(has_action('site_url'));
|
70 |
+
}
|
71 |
+
|
72 |
+
public function testLoginBase()
|
73 |
+
{
|
74 |
+
update_option('ld_login_base', 'login');
|
75 |
+
$this->object->application->renameLogin();
|
76 |
+
|
77 |
+
$this->assertEquals('login', $this->object->getLoginBase());
|
78 |
+
}
|
79 |
+
|
80 |
+
public function testRewriteUrl()
|
81 |
+
{
|
82 |
+
$this->assertEquals('http://localhost/login', $this->object->application->filterWpLogin('http://localhost/wp-login.php'));
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
* @ignore
|
88 |
+
*/
|
89 |
+
class LdProxyObject extends WP_LockAuth { }
|
tests/test-hideadmin.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
class LockdownAdminTest extends PHPUnit_Framework_TestCase {
|
3 |
+
protected $object;
|
4 |
+
|
5 |
+
protected function setUp()
|
6 |
+
{
|
7 |
+
$this->object = ld_setup_auth();
|
8 |
+
}
|
9 |
+
|
10 |
+
public function testWhitelist()
|
11 |
+
{
|
12 |
+
add_filter('no_check_files', function($a) { $a[] = 'wp-activate.php'; return $a; });
|
13 |
+
update_option('ld_hide_wp_admin', 'yep');
|
14 |
+
|
15 |
+
// Mocking a request to wp-activate.php
|
16 |
+
$_SERVER['SCRIPT_FILENAME'] = ABSPATH.'/wp-activate.php';
|
17 |
+
|
18 |
+
// Set it back up again so we can test if it passed
|
19 |
+
$this->setUp();
|
20 |
+
$this->assertTrue($this->object->getAuthPassed());
|
21 |
+
}
|
22 |
+
|
23 |
+
public function testWhitelistToBlock()
|
24 |
+
{
|
25 |
+
update_option('ld_hide_wp_admin', 'yep');
|
26 |
+
|
27 |
+
// Mocking a request to wp-activate.php
|
28 |
+
$_SERVER['SCRIPT_FILENAME'] = ABSPATH.'/wp-login.php';
|
29 |
+
|
30 |
+
// Set it back up again so we can test if it passed
|
31 |
+
$this->setUp();
|
32 |
+
$this->assertFalse($this->object->getAuthPassed());
|
33 |
+
}
|
34 |
+
}
|
tests/test-sample.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class SampleTest extends WP_UnitTestCase {
|
4 |
+
|
5 |
+
function testSample() {
|
6 |
+
// replace this with some actual testing code
|
7 |
+
$this->assertTrue( true );
|
8 |
+
}
|
9 |
+
}
|
10 |
+
|
views/settings.php
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if (! defined('ABSPATH')) exit; ?>
|
2 |
+
<div class="wrap">
|
3 |
+
<div id="icon-options-general" class="icon32"></div>
|
4 |
+
<h2>Lockdown WordPress Admin</h2>
|
5 |
+
<?php if ( defined('LD_WP_ADMIN') && LD_WP_ADMIN == TRUE ) : ?>
|
6 |
+
<div class="updated fade">
|
7 |
+
<p>Options updated!</p>
|
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; ?>
|
15 |
+
|
16 |
+
<p>
|
17 |
+
We are going to help make WordPress a bit more secure.
|
18 |
+
</p>
|
19 |
+
<p>
|
20 |
+
<a href="https://twitter.com/srtfisher" class="twitter-follow-button" data-show-count="false">Follow @srtfisher</a>
|
21 |
+
<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 />
|
22 |
+
I tweet a lot of things and often post whenever I update this plugin. Follow me <a href="http://twitter.com/srtfisher">@srtfisher</a>.
|
23 |
+
<br>
|
24 |
+
<em>
|
25 |
+
(Also, I am a freelancer and would love to <a href="http://seanfisher.co/contact">hear from you about your project</a>!)
|
26 |
+
</em>
|
27 |
+
</p>
|
28 |
+
|
29 |
+
<p>
|
30 |
+
Follow Lockdown WP-Admin development on <a href="https://github.com/srtfisher/Lockdown-WPAdmin" target="_blank">GitHub</a>
|
31 |
+
</p>
|
32 |
+
|
33 |
+
<form method="POST" action="<?php echo admin_url('admin.php?page=lockdown-wp-admin'); ?>">
|
34 |
+
|
35 |
+
<?php wp_nonce_field('lockdown-wp-admin'); ?>
|
36 |
+
<h3>
|
37 |
+
Hide WP Admin
|
38 |
+
</h3>
|
39 |
+
<p>
|
40 |
+
We can "hide" WordPress's administration interface from the public.
|
41 |
+
If you enable this, when you access
|
42 |
+
<code><?php echo admin_url(); ?></code> when you
|
43 |
+
<strong>aren't</strong> logged in, you will recieve a
|
44 |
+
<a href="http://en.wikipedia.org/wiki/HTTP_404">404 error page</a>
|
45 |
+
instead of redirecting to the login page.
|
46 |
+
</p>
|
47 |
+
<label>
|
48 |
+
<input type="checkbox" name="hide_wp_admin" value="yep"
|
49 |
+
<?php if ( get_option('ld_hide_wp_admin') === 'yep' ) { ?>
|
50 |
+
checked<?php
|
51 |
+
} ?>>
|
52 |
+
Yes, please hide WP Admin from the user when they aren't logged in.
|
53 |
+
</label>
|
54 |
+
|
55 |
+
<h3 style="margin-top: 30px;">
|
56 |
+
WordPress Login URL
|
57 |
+
</h3>
|
58 |
+
<label>
|
59 |
+
Change the WordPress Login URL?
|
60 |
+
<?php echo wp_guess_url().'/'; ?>
|
61 |
+
<input type="text" name="login_base" value="<?php echo $this->instance->application->getLoginBase(); ?>" />
|
62 |
+
<br>
|
63 |
+
<em>
|
64 |
+
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 />
|
65 |
+
Say if you put "<strong>login</strong>" into the box, your new login URL will be <?php echo home_url(); ?>/login/.
|
66 |
+
</em>
|
67 |
+
</label>
|
68 |
+
<?php
|
69 |
+
global $auth_obj;
|
70 |
+
$url = home_url() . '/'. $this->instance->application->getLoginBase();
|
71 |
+
?>
|
72 |
+
<p>
|
73 |
+
Your current login URL is <code><a href="<?php echo $url; ?>"><?php echo $url; ?></a></code>.
|
74 |
+
</p>
|
75 |
+
|
76 |
+
<?php if ($this->instance->application->isSuggestedAgainst()) : ?>
|
77 |
+
<div class="updated error"><p>
|
78 |
+
Your login base <strong><?php echo $this->login_base; ?></strong> is highly insecure!
|
79 |
+
We strongly reccomend using another login URL to ensure maximum security.
|
80 |
+
</p>
|
81 |
+
</div>
|
82 |
+
<?php endif; ?>
|
83 |
+
<blockquote>
|
84 |
+
<h4>Please Note Something!</h4>
|
85 |
+
<p>If you are using a cache plugin (WTC, WP Super Cache, etc), you need to enable it
|
86 |
+
to not cache the above base. That means (for most caching plugins) adding
|
87 |
+
whatever you enter into the box above into your plugins Caching Whitelist, that
|
88 |
+
is the list of URLs that your plugin doesn't cache. If you have any questions, tweet
|
89 |
+
me <a href="http://twitter.com/srtfisher">@srtfisher</a>.</p>
|
90 |
+
</blockquote>
|
91 |
+
<h3>HTTP Authentication</h3>
|
92 |
+
<p>Please read about HTTP Authentication on <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">http://en.wikipedia.org/wiki/Basic_access_authentication</a>.</p>
|
93 |
+
<?php $http_auth_type = get_option('ld_http_auth'); ?>
|
94 |
+
<label>
|
95 |
+
<input name="http_auth" type="radio" value="none" <?php if ( $http_auth_type === '' || $http_auth_type === 'none' || !$http_auth_type ) { ?>checked<?php } ?>>
|
96 |
+
Disable HTTP Auth.</label>
|
97 |
+
<div class="clear"></div>
|
98 |
+
<label>
|
99 |
+
<input type="radio" name="http_auth" <?php if ( $http_auth_type === 'wp_creds' ) { ?>checked<?php } ?> value="wp_creds">
|
100 |
+
WordPress Login Credentials</label>
|
101 |
+
<div class="clear"></div>
|
102 |
+
<label>
|
103 |
+
<input type="radio" name="http_auth" <?php if ( $http_auth_type === 'private' ) { ?>checked<?php } ?> value="private">
|
104 |
+
Private Usernames/Passwords</label>
|
105 |
+
<div class="clear"></div>
|
106 |
+
<br>
|
107 |
+
<input type="hidden" name="did_update" value="yes_we_did">
|
108 |
+
<input class='button-primary' type='submit' name='Save' value='<?php _e('Save Options'); ?>' id='submitbutton' />
|
109 |
+
</form>
|
110 |
+
</div>
|