PluginProbe
Authorizer / 2.8.0
Authorizer v2.8.0
3.15.3 3.15.2 3.15.1 3.15.0 3.14.3 3.14.4 3.14.2 3.14.1 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.9.0 2.9.1 2.9.10 2.9.11 2.9.12 2.9.13 2.9.2 2.9.3 2.9.6 All 126 releases
authorizer / authorizer.php

authorizer.php in Authorizer 2.8.0, at authorizer.php

7,989 lines 356.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Authorizer
4 * Description: Authorizer limits login attempts, restricts access to specified users, and authenticates against external sources (e.g., Google, LDAP, or CAS).
5 * Author: Paul Ryan <prar@hawaii.edu>
6 * Plugin URI: https://github.com/uhm-coe/authorizer
7 * Text Domain: authorizer
8 * Domain Path: /languages
9 * License: GPL2
10 * Version: 2.8.0
11 *
12 * @package authorizer
13 */
14
15 /**
16 * Portions forked from Restricted Site Access plugin: http://wordpress.org/plugins/restricted-site-access/
17 * Portions forked from wpCAS plugin: http://wordpress.org/extend/plugins/cas-authentication/
18 * Portions forked from Limit Login Attempts: http://wordpress.org/plugins/limit-login-attempts/
19 */
20
21 /**
22 * Add phpCAS library if it's not included.
23 *
24 * @see https://wiki.jasig.org/display/CASC/phpCAS+installation+guide
25 */
26 if ( ! defined( 'PHPCAS_VERSION' ) ) {
27 require_once dirname( __FILE__ ) . '/vendor/CAS-1.3.5/CAS.php';
28 }
29
30
31 if ( ! class_exists( 'WP_Plugin_Authorizer' ) ) {
32 /**
33 * Define class for plugin: Authorizer.
34 *
35 * @category Authentication
36 * @package Authorizer
37 * @author Paul Ryan <prar@hawaii.edu>
38 * @license http://www.gnu.org/licenses/gpl-2.0.html GPL2
39 * @link http://hawaii.edu/coe/dcdc/wordpress/authorizer/doc/
40 */
41 class WP_Plugin_Authorizer {
42
43 /**
44 * Constants for determining our admin context (network or individual site).
45 */
46 const NETWORK_CONTEXT = 'multisite_admin';
47 const SINGLE_CONTEXT = 'single_admin';
48
49 /**
50 * Current site ID (Multisite).
51 *
52 * @var string
53 */
54 public $current_site_blog_id = 1;
55
56 /**
57 * HTML allowed when rendering translatable strings in the Authorizer UI.
58 * This is passed to wp_kses() when sanitizing HMTL strings.
59 *
60 * @var array
61 */
62 private $allowed_html = array(
63 'a' => array(
64 'class' => array(),
65 'href' => array(),
66 'style' => array(),
67 'target' => array(),
68 'title' => array(),
69 ),
70 'b' => array(),
71 'br' => array(),
72 'div' => array(
73 'class' => array(),
74 ),
75 'em' => array(),
76 'hr' => array(),
77 'i' => array(),
78 'input' => array(
79 'aria-describedby' => array(),
80 'class' => array(),
81 'id' => array(),
82 'name' => array(),
83 'size' => array(),
84 'type' => array(),
85 'value' => array(),
86 ),
87 'label' => array(
88 'class' => array(),
89 'for' => array(),
90 ),
91 'p' => array(
92 'style' => array(),
93 ),
94 'span' => array(
95 'aria-hidden' => array(),
96 'class' => array(),
97 'id' => array(),
98 'style' => array(),
99 ),
100 'strong' => array(),
101 );
102
103 /**
104 * Constructor.
105 */
106 public function __construct() {
107 // Save reference to current blog id in the network (support deprecated
108 // constant BLOGID_CURRENT_SITE).
109 if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {
110 $this->current_site_blog_id = BLOG_ID_CURRENT_SITE;
111 } elseif ( defined( 'BLOGID_CURRENT_SITE' ) ) { // deprecated.
112 $this->current_site_blog_id = BLOGID_CURRENT_SITE;
113 }
114
115 // Installation and uninstallation hooks.
116 register_activation_hook( __FILE__, array( $this, 'activate' ) );
117 register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
118
119 /**
120 * Register filters.
121 */
122
123 // Custom wp authentication routine using external service.
124 add_filter( 'authenticate', array( $this, 'custom_authenticate' ), 1, 3 );
125
126 // Custom logout action using external service.
127 add_action( 'wp_logout', array( $this, 'custom_logout' ) );
128
129 // Create settings link on Plugins page.
130 add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_settings_link' ) );
131 add_filter( 'network_admin_plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'network_admin_plugin_settings_link' ) );
132
133 // Modify login page with a custom password url (if option is set).
134 add_filter( 'lostpassword_url', array( $this, 'custom_lostpassword_url' ) );
135
136 // If we have a custom login error, add the filter to show it.
137 $error = get_option( 'auth_settings_advanced_login_error' );
138 if ( $error && strlen( $error ) > 0 ) {
139 add_filter( 'login_errors', array( $this, 'show_advanced_login_error' ) );
140 }
141
142 /**
143 * Register actions.
144 */
145
146 // Enable localization. Translation files stored in /languages.
147 add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
148
149 // Perform plugin updates if newer version installed.
150 add_action( 'plugins_loaded', array( $this, 'auth_update_check' ) );
151
152 // Update the user meta with this user's failed login attempt.
153 add_action( 'wp_login_failed', array( $this, 'update_login_failed_count' ) );
154
155 // Add users who successfully login to the approved list.
156 add_action( 'wp_login', array( $this, 'ensure_wordpress_user_in_approved_list_on_login' ), 10, 2 );
157
158 // Create menu item in Settings.
159 add_action( 'admin_menu', array( $this, 'add_plugin_page' ) );
160
161 // Create options page.
162 add_action( 'admin_init', array( $this, 'page_init' ) );
163
164 // Update user role in approved list if it's changed in the WordPress edit user page.
165 add_action( 'user_profile_update_errors', array( $this, 'edit_user_profile_update_role' ), 10, 3 );
166
167 // Update user email in approved list if it's changed in the WordPress edit user page.
168 add_filter( 'send_email_change_email', array( $this, 'edit_user_profile_update_email' ), 10, 3 );
169
170 // Enqueue javascript and css on the plugin's options page, the
171 // dashboard (for the widget), and the network admin.
172 add_action( 'load-settings_page_authorizer', array( $this, 'load_options_page' ) );
173 add_action( 'admin_head-index.php', array( $this, 'load_options_page' ) );
174 add_action( 'load-toplevel_page_authorizer', array( $this, 'load_options_page' ) );
175
176 // Add custom css and js to wp-login.php.
177 add_action( 'login_enqueue_scripts', array( $this, 'login_enqueue_scripts_and_styles' ) );
178 add_action( 'login_footer', array( $this, 'load_login_footer_js' ) );
179
180 // Create google nonce cookie when loading wp-login.php if Google is enabled.
181 add_action( 'login_init', array( $this, 'login_init__maybe_set_google_nonce_cookie' ) );
182
183 // Modify login page with external auth links (if enabled; e.g., google or cas).
184 add_action( 'login_form', array( $this, 'login_form_add_external_service_links' ) );
185
186 // Redirect to CAS login when visiting login page (only if option is
187 // enabled, CAS is the only service, and WordPress logins are hidden).
188 // Note: hook into wp_login_errors filter so this fires after the
189 // authenticate hook (where the redirect to CAS happens), but before html
190 // output is started (so the redirect header doesn't complain about data
191 // already being sent).
192 add_filter( 'wp_login_errors', array( $this, 'wp_login_errors__maybe_redirect_to_cas' ), 10, 2 );
193
194 // Verify current user has access to page they are visiting.
195 add_action( 'parse_request', array( $this, 'restrict_access' ), 9 );
196 add_action( 'init', array( $this, 'init__maybe_add_network_approved_user' ) );
197
198 // AJAX: Save options from dashboard widget.
199 add_action( 'wp_ajax_update_auth_user', array( $this, 'ajax_update_auth_user' ) );
200
201 // AJAX: Save options from multisite options page.
202 add_action( 'wp_ajax_save_auth_multisite_settings', array( $this, 'ajax_save_auth_multisite_settings' ) );
203
204 // AJAX: Save usermeta from options page.
205 add_action( 'wp_ajax_update_auth_usermeta', array( $this, 'ajax_update_auth_usermeta' ) );
206
207 // AJAX: Verify google login.
208 add_action( 'wp_ajax_process_google_login', array( $this, 'ajax_process_google_login' ) );
209 add_action( 'wp_ajax_nopriv_process_google_login', array( $this, 'ajax_process_google_login' ) );
210
211 // AJAX: Refresh approved user list.
212 add_action( 'wp_ajax_refresh_approved_user_list', array( $this, 'ajax_refresh_approved_user_list' ) );
213
214 // Add dashboard widget so instructors can add/edit users with access.
215 // Hint: For Multisite Network Admin Dashboard use wp_network_dashboard_setup instead of wp_dashboard_setup.
216 add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widgets' ) );
217
218 // If we have a custom admin message, add the action to show it.
219 $notice = get_option( 'auth_settings_advanced_admin_notice' );
220 if ( $notice && strlen( $notice ) > 0 ) {
221 add_action( 'admin_notices', array( $this, 'show_advanced_admin_notice' ) );
222 add_action( 'network_admin_notices', array( $this, 'show_advanced_admin_notice' ) );
223 }
224
225 // Load custom javascript for the main site (e.g., for displaying alerts).
226 add_action( 'wp_enqueue_scripts', array( $this, 'auth_public_scripts' ), 20 );
227
228 // Multisite-specific actions.
229 if ( is_multisite() ) {
230 // Add network admin options page (global settings for all sites).
231 add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ) );
232 }
233
234 // Remove user from authorizer lists when that user is deleted in WordPress.
235 add_action( 'delete_user', array( $this, 'remove_user_from_authorizer_when_deleted' ) );
236 if ( is_multisite() ) {
237 // Remove multisite user from authorizer lists when that user is deleted from Network Users.
238 add_action( 'remove_user_from_blog', array( $this, 'remove_network_user_from_site_when_removed' ), 10, 2 );
239 add_action( 'wpmu_delete_user', array( $this, 'remove_network_user_from_authorizer_when_deleted' ) );
240 }
241
242 // Add user to authorizer approved list when that user is added to a blog from the Users screen.
243 // Multisite: invite_user action fired when adding (inviting) an existing network user to the current site (with email confirmation).
244 add_action( 'invite_user', array( $this, 'add_existing_user_to_authorizer_when_created' ), 10, 3 );
245 // Multisite: added_existing_user action fired when adding an existing network user to the current site (without email confirmation).
246 add_action( 'added_existing_user', array( $this, 'add_existing_user_to_authorizer_when_created_noconfirmation' ), 10, 2 );
247 // Multisite: after_signup_user action fired when adding a new user to the site (with or without email confirmation).
248 add_action( 'after_signup_user', array( $this, 'add_new_user_to_authorizer_when_created' ), 10, 4 );
249 // Single site: edit_user_created_user action fired when adding a new user to the site (with or without email notification).
250 add_action( 'edit_user_created_user', array( $this, 'add_new_user_to_authorizer_when_created_single_site' ), 10, 2 );
251
252 // Add user to network approved users (and remove from individual sites)
253 // when user is elevated to super admin status.
254 add_action( 'grant_super_admin', array( $this, 'grant_super_admin__add_to_network_approved' ) );
255 // Remove user from network approved users (and add them to the approved
256 // list on sites they are already on) when super admin status is removed.
257 add_action( 'revoke_super_admin', array( $this, 'revoke_super_admin__remove_from_network_approved' ) );
258
259 }
260
261
262 /**
263 * Plugin activation hook.
264 * Will also activate the plugin for all sites/blogs if this is a "Network enable."
265 *
266 * @return void
267 */
268 public function activate() {
269 global $wpdb;
270
271 // Nonce check.
272 if (
273 ! isset( $_REQUEST['_wpnonce'], $_REQUEST['plugin'] ) ||
274 ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'activate-plugin_' . sanitize_text_field( wp_unslash( $_REQUEST['plugin'] ) ) )
275 ) {
276 die( '' );
277 }
278
279 // If we're in a multisite environment, run the plugin activation for each site when network enabling.
280 if ( is_multisite() && isset( $_GET['networkwide'] ) && 1 === intval( $_GET['networkwide'] ) ) {
281
282 // Add super admins to the multisite approved list.
283 $auth_multisite_settings_access_users_approved = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', array() );
284 $should_update_auth_multisite_settings_access_users_approved = false;
285 foreach ( get_super_admins() as $super_admin ) {
286 $user = get_user_by( 'login', $super_admin );
287 // Add to approved list if not there.
288 if ( ! $this->in_multi_array( $user->user_email, $auth_multisite_settings_access_users_approved ) ) {
289 $approved_user = array(
290 'email' => $this->lowercase( $user->user_email ),
291 'role' => count( $user->roles ) > 0 ? $user->roles[0] : 'administrator',
292 'date_added' => date( 'M Y', strtotime( $user->user_registered ) ),
293 'local_user' => true,
294 );
295 array_push( $auth_multisite_settings_access_users_approved, $approved_user );
296 $should_update_auth_multisite_settings_access_users_approved = true;
297 }
298 }
299 if ( $should_update_auth_multisite_settings_access_users_approved ) {
300 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
301 }
302
303 // Run plugin activation on each site in the network.
304 $current_blog_id = $wpdb->blogid;
305 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
306 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
307 foreach ( $sites as $site ) {
308 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
309 switch_to_blog( $blog_id );
310 // Set default plugin options and add current users to approved list.
311 $this->set_default_options();
312 $this->add_wp_users_to_approved_list();
313 }
314 switch_to_blog( $current_blog_id );
315
316 } else {
317 // Set default plugin options and add current users to approved list.
318 $this->set_default_options();
319 $this->add_wp_users_to_approved_list();
320 }
321
322 }
323
324
325 /**
326 * Adds all WordPress users in the current site to the approved list,
327 * unless they are already in the blocked list. Also removes them
328 * from the pending list if they are there.
329 *
330 * Runs in plugin activation hook.
331 *
332 * @return void
333 */
334 private function add_wp_users_to_approved_list() {
335 // Add current WordPress users to the approved list.
336 $auth_multisite_settings_access_users_approved = is_multisite() ? get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', array() ) : array();
337 $auth_settings_access_users_pending = $this->get_plugin_option( 'access_users_pending', WP_Plugin_Authorizer::SINGLE_CONTEXT );
338 $auth_settings_access_users_approved = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
339 $auth_settings_access_users_blocked = $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT );
340 $updated = false;
341 foreach ( get_users() as $user ) {
342 // Skip if user is in blocked list.
343 if ( $this->in_multi_array( $user->user_email, $auth_settings_access_users_blocked ) ) {
344 continue;
345 }
346 // Remove from pending list if there.
347 foreach ( $auth_settings_access_users_pending as $key => $pending_user ) {
348 if ( 0 === strcasecmp( $pending_user['email'], $user->user_email ) ) {
349 unset( $auth_settings_access_users_pending[ $key ] );
350 $updated = true;
351 }
352 }
353 // Skip if user is in multisite approved list.
354 if ( $this->in_multi_array( $user->user_email, $auth_multisite_settings_access_users_approved ) ) {
355 continue;
356 }
357 // Add to approved list if not there.
358 if ( ! $this->in_multi_array( $user->user_email, $auth_settings_access_users_approved ) ) {
359 $approved_user = array(
360 'email' => $this->lowercase( $user->user_email ),
361 'role' => count( $user->roles ) > 0 ? $user->roles[0] : '',
362 'date_added' => date( 'M Y', strtotime( $user->user_registered ) ),
363 'local_user' => true,
364 );
365 array_push( $auth_settings_access_users_approved, $approved_user );
366 $updated = true;
367 }
368 }
369 if ( $updated ) {
370 update_option( 'auth_settings_access_users_pending', $auth_settings_access_users_pending );
371 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
372 }
373 }
374
375
376 /**
377 * Plugin deactivation.
378 *
379 * @return void
380 */
381 public function deactivate() {
382 // Do nothing.
383 }
384
385
386
387 /**
388 * ***************************
389 * External Authentication
390 * ***************************
391 */
392
393
394
395 /**
396 * Authenticate against an external service.
397 *
398 * Filter: authenticate
399 *
400 * @param WP_User $user user to authenticate.
401 * @param string $username optional username to authenticate.
402 * @param string $password optional password to authenticate.
403 * @return WP_User|WP_Error WP_User on success, WP_Error on failure.
404 */
405 public function custom_authenticate( $user, $username, $password ) {
406 // Pass through if already authenticated.
407 if ( is_a( $user, 'WP_User' ) ) {
408 return $user;
409 } else {
410 $user = null;
411 }
412
413 // If username and password are blank, this isn't a log in attempt.
414 $is_login_attempt = strlen( $username ) > 0 && strlen( $password ) > 0;
415
416 // Check to make sure that $username is not locked out due to too
417 // many invalid login attempts. If it is, tell the user how much
418 // time remains until they can try again.
419 $unauthenticated_user = $is_login_attempt ? get_user_by( 'login', $username ) : false;
420 $unauthenticated_user_is_blocked = false;
421 if ( $is_login_attempt && false !== $unauthenticated_user ) {
422 $last_attempt = get_user_meta( $unauthenticated_user->ID, 'auth_settings_advanced_lockouts_time_last_failed', true );
423 $num_attempts = get_user_meta( $unauthenticated_user->ID, 'auth_settings_advanced_lockouts_failed_attempts', true );
424 // Also check the auth_blocked user_meta flag (users in blocked list will get this flag).
425 $unauthenticated_user_is_blocked = get_user_meta( $unauthenticated_user->ID, 'auth_blocked', true ) === 'yes';
426 } else {
427 $last_attempt = get_option( 'auth_settings_advanced_lockouts_time_last_failed' );
428 $num_attempts = get_option( 'auth_settings_advanced_lockouts_failed_attempts' );
429 }
430
431 // Inactive users should be treated like deleted users (we just
432 // do this to preserve any content they created, but here we should
433 // pretend they don't exist).
434 if ( $unauthenticated_user_is_blocked ) {
435 remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
436 return new WP_Error( 'empty_password', __( '<strong>ERROR</strong>: Incorrect username or password.', 'authorizer' ) );
437 }
438
439 // Grab plugin settings.
440 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
441
442 // Make sure $last_attempt (time) and $num_attempts are positive integers.
443 // Note: this addresses resetting them if either is unset from above.
444 $last_attempt = abs( intval( $last_attempt ) );
445 $num_attempts = abs( intval( $num_attempts ) );
446
447 // Create semantic lockout variables.
448 $lockouts = $auth_settings['advanced_lockouts'];
449 $time_since_last_fail = time() - $last_attempt;
450 $reset_duration = $lockouts['reset_duration'] * 60; // minutes to seconds.
451 $num_attempts_long_lockout = $lockouts['attempts_1'] + $lockouts['attempts_2'];
452 $num_attempts_short_lockout = $lockouts['attempts_1'];
453 $seconds_remaining_long_lockout = $lockouts['duration_2'] * 60 - $time_since_last_fail;
454 $seconds_remaining_short_lockout = $lockouts['duration_1'] * 60 - $time_since_last_fail;
455
456 // Check if we need to institute a lockout delay.
457 if ( $is_login_attempt && $time_since_last_fail > $reset_duration ) {
458 // Enough time has passed since the last invalid attempt and
459 // now that we can reset the failed attempt count, and let this
460 // login attempt go through.
461 $num_attempts = 0; // This does nothing, but include it for semantic meaning.
462 } elseif ( $is_login_attempt && $num_attempts > $num_attempts_long_lockout && $seconds_remaining_long_lockout > 0 ) {
463 // Stronger lockout (1st/2nd round of invalid attempts reached)
464 // Note: set the error code to 'empty_password' so it doesn't
465 // trigger the wp_login_failed hook, which would continue to
466 // increment the failed attempt count.
467 remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
468 return new WP_Error(
469 'empty_password',
470 sprintf(
471 /* TRANSLATORS: 1: username 2: duration of lockout in seconds 3: duration of lockout as a phrase 4: lost password URL */
472 __( '<strong>ERROR</strong>: There have been too many invalid login attempts for the username <strong>%1$s</strong>. Please wait <strong id="seconds_remaining" data-seconds="%2$s">%3$s</strong> before trying again. <a href="%4$s" title="Password Lost and Found">Lost your password</a>?', 'authorizer' ),
473 $username,
474 $seconds_remaining_long_lockout,
475 $this->seconds_as_sentence( $seconds_remaining_long_lockout ),
476 wp_lostpassword_url()
477 )
478 );
479 } elseif ( $is_login_attempt && $num_attempts > $num_attempts_short_lockout && $seconds_remaining_short_lockout > 0 ) {
480 // Normal lockout (1st round of invalid attempts reached)
481 // Note: set the error code to 'empty_password' so it doesn't
482 // trigger the wp_login_failed hook, which would continue to
483 // increment the failed attempt count.
484 remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
485 return new WP_Error(
486 'empty_password',
487 sprintf(
488 /* TRANSLATORS: 1: username 2: duration of lockout in seconds 3: duration of lockout as a phrase 4: lost password URL */
489 __( '<strong>ERROR</strong>: There have been too many invalid login attempts for the username <strong>%1$s</strong>. Please wait <strong id="seconds_remaining" data-seconds="%2$s">%3$s</strong> before trying again. <a href="%4$s" title="Password Lost and Found">Lost your password</a>?', 'authorizer' ),
490 $username,
491 $seconds_remaining_short_lockout,
492 $this->seconds_as_sentence( $seconds_remaining_short_lockout ),
493 wp_lostpassword_url()
494 )
495 );
496 }
497
498 // Start external authentication.
499 $externally_authenticated_emails = array();
500 $authenticated_by = '';
501 $result = null;
502
503 // Try Google authentication if it's enabled and we don't have a
504 // successful login yet.
505 if (
506 '1' === $auth_settings['google'] &&
507 0 === count( $externally_authenticated_emails ) &&
508 ! is_wp_error( $result )
509 ) {
510 $result = $this->custom_authenticate_google( $auth_settings );
511 if ( ! is_null( $result ) && ! is_wp_error( $result ) ) {
512 if ( is_array( $result['email'] ) ) {
513 $externally_authenticated_emails = $result['email'];
514 } else {
515 $externally_authenticated_emails[] = $result['email'];
516 }
517 $authenticated_by = $result['authenticated_by'];
518 }
519 }
520
521 // Try CAS authentication if it's enabled and we don't have a
522 // successful login yet.
523 if (
524 '1' === $auth_settings['cas'] &&
525 0 === count( $externally_authenticated_emails ) &&
526 ! is_wp_error( $result )
527 ) {
528 $result = $this->custom_authenticate_cas( $auth_settings );
529 if ( ! is_null( $result ) && ! is_wp_error( $result ) ) {
530 if ( is_array( $result['email'] ) ) {
531 $externally_authenticated_emails = $result['email'];
532 } else {
533 $externally_authenticated_emails[] = $result['email'];
534 }
535 $authenticated_by = $result['authenticated_by'];
536 }
537 }
538
539 // Try LDAP authentication if it's enabled and we don't have an
540 // authenticated user yet.
541 if (
542 '1' === $auth_settings['ldap'] &&
543 0 === count( $externally_authenticated_emails ) &&
544 ! is_wp_error( $result )
545 ) {
546 $result = $this->custom_authenticate_ldap( $auth_settings, $username, $password );
547 if ( ! is_null( $result ) && ! is_wp_error( $result ) ) {
548 if ( is_array( $result['email'] ) ) {
549 $externally_authenticated_emails = $result['email'];
550 } else {
551 $externally_authenticated_emails[] = $result['email'];
552 }
553 $authenticated_by = $result['authenticated_by'];
554 }
555 }
556
557 // Skip to WordPress authentication if we don't have an externally
558 // authenticated user.
559 if ( count( array_filter( $externally_authenticated_emails ) ) < 1 ) {
560 return $result;
561 }
562
563 // Remove duplicate and blank emails, if any.
564 $externally_authenticated_emails = array_filter( array_unique( $externally_authenticated_emails ) );
565
566 /**
567 * If we've made it this far, we should have an externally
568 * authenticated user. The following should be set:
569 * $externally_authenticated_emails
570 * $authenticated_by
571 */
572
573 // Get the external user's WordPress account by email address.
574 foreach ( $externally_authenticated_emails as $externally_authenticated_email ) {
575 $user = get_user_by( 'email', $this->lowercase( $externally_authenticated_email ) );
576
577 // If we've already found a WordPress user associated with one
578 // of the supplied email addresses, don't keep examining other
579 // email addresses associated with the externally authenticated user.
580 if ( false !== $user ) {
581 break;
582 }
583 }
584
585 // Check this external user's access against the access lists
586 // (pending, approved, blocked).
587 $result = $this->check_user_access( $user, $externally_authenticated_emails, $result );
588
589 // Fail with message if there was an error creating/adding the user.
590 if ( is_wp_error( $result ) || 0 === $result ) {
591 return $result;
592 }
593
594 // If we created a new user in check_user_access(), log that user in.
595 if ( get_class( $result ) === 'WP_User' ) {
596 $user = $result;
597 }
598
599 // We'll track how this user was authenticated in user meta.
600 if ( $user ) {
601 update_user_meta( $user->ID, 'authenticated_by', $authenticated_by );
602 }
603
604 // If we haven't exited yet, we have a valid/approved user, so authenticate them.
605 return $user;
606 }
607
608
609 /**
610 * This function will fail with a wp_die() message to the user if they
611 * don't have access.
612 *
613 * @param WP_User $user User to check.
614 * @param array $user_emails Array of user's plaintext emails (in case current user doesn't have a WP account).
615 * @param array $user_data Array of keys for email, username, first_name, last_name,
616 * authenticated_by, google_attributes, cas_attributes, ldap_attributes.
617 * @return WP_Error|void|null|WP_User
618 * WP_Error if there was an error on user creation / adding user to blog.
619 * wp_die() if user does not have access.
620 * null if user has access (success).
621 * WP_User if user has access and a new account was created for them.
622 */
623 private function check_user_access( $user, $user_emails, $user_data = array() ) {
624 // Grab plugin settings.
625 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
626 $auth_settings_access_users_pending = $this->sanitize_user_list(
627 $this->get_plugin_option( 'access_users_pending', WP_Plugin_Authorizer::SINGLE_CONTEXT )
628 );
629 $auth_settings_access_users_approved_single = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
630 $auth_settings_access_users_approved_multi = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT );
631 $auth_settings_access_users_approved = $this->sanitize_user_list(
632 array_merge(
633 $auth_settings_access_users_approved_single,
634 $auth_settings_access_users_approved_multi
635 )
636 );
637
638 /**
639 * Filter whether to block the currently logging in user based on any of
640 * their user attributes.
641 *
642 * @param bool $allow_login Whether to block the currently logging in user.
643 * @param array $user_data User data returned from external service.
644 */
645 $allow_login = apply_filters( 'authorizer_allow_login', true, $user_data );
646 $blocked_by_filter = ! $allow_login; // Use this for better readability.
647
648 // Check our externally authenticated user against the block list.
649 // If any of their email addresses are blocked, set the relevant user
650 // meta field, and show them an error screen.
651 foreach ( $user_emails as $user_email ) {
652 if ( $blocked_by_filter || $this->is_email_in_list( $user_email, 'blocked' ) ) {
653
654 // Add user to blocked list if it was blocked via the filter.
655 if ( $blocked_by_filter && ! $this->is_email_in_list( $user_email, 'blocked' ) ) {
656 $auth_settings_access_users_blocked = $this->sanitize_user_list(
657 $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT )
658 );
659 array_push(
660 $auth_settings_access_users_blocked, array(
661 'email' => $this->lowercase( $user_email ),
662 'date_added' => date( 'M Y' ),
663 )
664 );
665 update_option( 'auth_settings_access_users_blocked', $auth_settings_access_users_blocked );
666 }
667
668 // If the blocked external user has a WordPress account, mark it as
669 // blocked (enforce block in this->authenticate()).
670 if ( $user ) {
671 update_user_meta( $user->ID, 'auth_blocked', 'yes' );
672 }
673
674 // Notify user about blocked status and return without authenticating them.
675 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
676 $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ) : home_url();
677 $page_title = sprintf(
678 /* TRANSLATORS: %s: Name of blog */
679 __( '%s - Access Restricted', 'authorizer' ),
680 get_bloginfo( 'name' )
681 );
682 $error_message =
683 apply_filters( 'the_content', $auth_settings['access_blocked_redirect_to_message'] ) .
684 '<hr />' .
685 '<p style="text-align: center;">' .
686 '<a class="button" href="' . wp_logout_url( $redirect_to ) . '">' .
687 __( 'Back', 'authorizer' ) .
688 '</a></p>';
689 update_option( 'auth_settings_advanced_login_error', $error_message );
690 wp_die( wp_kses( $error_message, $this->allowed_html ), esc_html( $page_title ) );
691 }
692 }
693
694 // Get the default role for this user (or their current role, if they
695 // already have an account).
696 $default_role = $user && is_array( $user->roles ) && count( $user->roles ) > 0 ? $user->roles[0] : $auth_settings['access_default_role'];
697 /**
698 * Filter the role of the user currently logging in. The role will be
699 * set to the default (specified in Authorizer options) for new users,
700 * or the user's current role for existing users. This filter allows
701 * changing user roles based on custom CAS/LDAP attributes.
702 *
703 * @param bool $role Role of the user currently logging in.
704 * @param array $user_data User data returned from external service.
705 */
706 $approved_role = apply_filters( 'authorizer_custom_role', $default_role, $user_data );
707
708 /**
709 * Filter whether to automatically approve the currently logging in user
710 * based on any of their user attributes.
711 *
712 * @param bool $automatically_approve_login
713 * Whether to automatically approve the currently logging in user.
714 * @param array $user_data User data returned from external service.
715 */
716 $automatically_approve_login = apply_filters( 'authorizer_automatically_approve_login', false, $user_data );
717
718 // Iterate through each of the email addresses provided by the external
719 // service and determine if any of them have access.
720 $last_email = end( $user_emails );
721 reset( $user_emails );
722 foreach ( $user_emails as $user_email ) {
723 $is_newly_approved_user = false;
724
725 // If this externally authenticated user is an existing administrator
726 // (administrator in single site mode, or super admin in network mode),
727 // and is not in the blocked list, let them in.
728 if ( $user && is_super_admin( $user->ID ) ) {
729 return;
730 }
731
732 // If this externally authenticated user isn't in the approved list
733 // and login access is set to "All authenticated users," or if they were
734 // automatically approved in the "authorizer_approve_login" filter
735 // above, then add them to the approved list (they'll get an account
736 // created below if they don't have one yet).
737 if (
738 ! $this->is_email_in_list( $user_email, 'approved' ) &&
739 ( 'external_users' === $auth_settings['access_who_can_login'] || $automatically_approve_login )
740 ) {
741 $is_newly_approved_user = true;
742
743 // If this user happens to be in the pending list (rare),
744 // remove them from pending before adding them to approved.
745 if ( $this->is_email_in_list( $user_email, 'pending' ) ) {
746 foreach ( $auth_settings_access_users_pending as $key => $pending_user ) {
747 if ( 0 === strcasecmp( $pending_user['email'], $user_email ) ) {
748 unset( $auth_settings_access_users_pending[ $key ] );
749 update_option( 'auth_settings_access_users_pending', $auth_settings_access_users_pending );
750 break;
751 }
752 }
753 }
754
755 // Add this user to the approved list.
756 $approved_user = array(
757 'email' => $this->lowercase( $user_email ),
758 'role' => $approved_role,
759 'date_added' => date( 'Y-m-d H:i:s' ),
760 );
761 array_push( $auth_settings_access_users_approved, $approved_user );
762 array_push( $auth_settings_access_users_approved_single, $approved_user );
763 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved_single );
764 }
765
766 // Check our externally authenticated user against the approved
767 // list. If they are approved, log them in (and create their account
768 // if necessary).
769 if ( $is_newly_approved_user || $this->is_email_in_list( $user_email, 'approved' ) ) {
770 $user_info = $is_newly_approved_user ? $approved_user : $this->get_user_info_from_list( $user_email, $auth_settings_access_users_approved );
771
772 // If this user's role was modified above (in the
773 // authorizer_custom_role filter), use that value instead of
774 // whatever is specified in the approved list.
775 if ( $default_role !== $approved_role ) {
776 $user_info['role'] = $approved_role;
777 }
778
779 // If the approved external user does not have a WordPress account, create it.
780 if ( ! $user ) {
781 // If there's already a user with this username (e.g.,
782 // johndoe/johndoe@gmail.com exists, and we're trying to add
783 // johndoe/johndoe@example.com), use the full email address
784 // as the username.
785 if ( array_key_exists( 'username', $user_data ) ) {
786 $username = $user_data['username'];
787 } else {
788 $username = explode( '@', $user_info['email'] );
789 $username = $username[0];
790 }
791 if ( get_user_by( 'login', $username ) !== false ) {
792 $username = $user_info['email'];
793 }
794 $result = wp_insert_user(
795 array(
796 'user_login' => strtolower( $username ),
797 'user_pass' => wp_generate_password(), // random password.
798 'first_name' => array_key_exists( 'first_name', $user_data ) ? $user_data['first_name'] : '',
799 'last_name' => array_key_exists( 'last_name', $user_data ) ? $user_data['last_name'] : '',
800 'user_email' => $this->lowercase( $user_info['email'] ),
801 'user_registered' => date( 'Y-m-d H:i:s' ),
802 'role' => $user_info['role'],
803 )
804 );
805
806 // Fail with message if error.
807 if ( is_wp_error( $result ) || 0 === $result ) {
808 return $result;
809 }
810
811 // Authenticate as new user.
812 $user = new WP_User( $result );
813
814 /**
815 * Fires after an external user is authenticated for the first time
816 * and a new WordPress account is created for them.
817 *
818 * @since 2.8.0
819 *
820 * @param WP_User $user User object.
821 * @param array $user_data User data from external service.
822 *
823 * Example $user_data:
824 * array(
825 * 'email' => 'user@example.edu',
826 * 'username' => 'user',
827 * 'first_name' => 'First',
828 * 'last_name' => 'Last',
829 * 'authenticated_by' => 'cas',
830 * 'cas_attributes' => array( ... ),
831 * );
832 */
833 do_action( 'authorizer_user_register', $user, $user_data );
834
835 // If multisite, iterate through all sites in the network and add the user
836 // currently logging in to any of them that have the user on the approved list.
837 // Note: this is useful for first-time logins--some users will have access
838 // to multiple sites, and this prevents them from having to log into each
839 // site individually to get access.
840 if ( is_multisite() ) {
841 $site_ids_of_user = array_map(
842 function ( $site_of_user ) {
843 return intval( $site_of_user->userblog_id );
844 },
845 get_blogs_of_user( $user->ID )
846 );
847
848 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
849 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
850 foreach ( $sites as $site ) {
851 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
852
853 // Skip if user is already added to this site.
854 if ( in_array( intval( $blog_id ), $site_ids_of_user, true ) ) {
855 continue;
856 }
857
858 // Check if user is on the approved list of this site they are not added to.
859 $other_auth_settings_access_users_approved = get_blog_option( $blog_id, 'auth_settings_access_users_approved', array() );
860 if ( $this->in_multi_array( $user->user_email, $other_auth_settings_access_users_approved ) ) {
861 $other_user_info = $this->get_user_info_from_list( $user->user_email, $other_auth_settings_access_users_approved );
862 // Add user to other site.
863 add_user_to_blog( $blog_id, $user->ID, $other_user_info['role'] );
864 }
865 }
866 }
867
868 // Check if this new user has any preassigned usermeta
869 // values in their approved list entry, and apply them to
870 // their new WordPress account.
871 if ( array_key_exists( 'usermeta', $user_info ) && is_array( $user_info['usermeta'] ) ) {
872 $meta_key = $this->get_plugin_option( 'advanced_usermeta' );
873
874 if ( array_key_exists( 'meta_key', $user_info['usermeta'] ) && array_key_exists( 'meta_value', $user_info['usermeta'] ) ) {
875 // Only update the usermeta if the stored value matches
876 // the option set in authorizer settings (if they don't
877 // match it's probably old data).
878 if ( $meta_key === $user_info['usermeta']['meta_key'] ) {
879 // Update user's usermeta value for usermeta key stored in authorizer options.
880 if ( strpos( $meta_key, 'acf___' ) === 0 && class_exists( 'acf' ) ) {
881 // We have an ACF field value, so use the ACF function to update it.
882 update_field( str_replace( 'acf___', '', $meta_key ), $user_info['usermeta']['meta_value'], 'user_' . $user->ID );
883 } else {
884 // We have a normal usermeta value, so just update it via the WordPress function.
885 update_user_meta( $user->ID, $meta_key, $user_info['usermeta']['meta_value'] );
886 }
887 }
888 } elseif ( is_multisite() && count( $user_info['usermeta'] ) > 0 ) {
889 // Update usermeta for each multisite blog defined for this user.
890 foreach ( $user_info['usermeta'] as $blog_id => $usermeta ) {
891 if ( array_key_exists( 'meta_key', $usermeta ) && array_key_exists( 'meta_value', $usermeta ) ) {
892 // Add this new user to the blog before we create their user meta (this step typically happens below, but we need it to happen early so we can create user meta here).
893 if ( ! is_user_member_of_blog( $user->ID, $blog_id ) ) {
894 add_user_to_blog( $blog_id, $user->ID, $user_info['role'] );
895 }
896 switch_to_blog( $blog_id );
897 // Update user's usermeta value for usermeta key stored in authorizer options.
898 if ( strpos( $meta_key, 'acf___' ) === 0 && class_exists( 'acf' ) ) {
899 // We have an ACF field value, so use the ACF function to update it.
900 update_field( str_replace( 'acf___', '', $meta_key ), $usermeta['meta_value'], 'user_' . $user->ID );
901 } else {
902 // We have a normal usermeta value, so just update it via the WordPress function.
903 update_user_meta( $user->ID, $meta_key, $usermeta['meta_value'] );
904 }
905 restore_current_blog();
906 }
907 }
908 }
909 }
910 } else {
911 // Update first/last names of WordPress user from external
912 // service if that option is set.
913 if ( ( array_key_exists( 'authenticated_by', $user_data ) && 'cas' === $user_data['authenticated_by'] && array_key_exists( 'cas_attr_update_on_login', $auth_settings ) && 1 === intval( $auth_settings['cas_attr_update_on_login'] ) ) || ( array_key_exists( 'authenticated_by', $user_data ) && 'ldap' === $user_data['authenticated_by'] && array_key_exists( 'ldap_attr_update_on_login', $auth_settings ) && 1 === intval( $auth_settings['ldap_attr_update_on_login'] ) ) ) {
914 if ( array_key_exists( 'first_name', $user_data ) && 0 < strlen( $user_data['first_name'] ) ) {
915 wp_update_user(
916 array(
917 'ID' => $user->ID,
918 'first_name' => $user_data['first_name'],
919 )
920 );
921 }
922 if ( array_key_exists( 'last_name', $user_data ) && strlen( $user_data['last_name'] ) > 0 ) {
923 wp_update_user(
924 array(
925 'ID' => $user->ID,
926 'last_name' => $user_data['last_name'],
927 )
928 );
929 }
930 }
931
932 // Update this user's role if it was modified in the
933 // authorizer_custom_role filter.
934 if ( $default_role !== $approved_role ) {
935 // Update user's role in WordPress.
936 $user->set_role( $approved_role );
937
938 // Update user's role in this site's approved list and save.
939 foreach ( $auth_settings_access_users_approved_single as $key => $existing_user ) {
940 if ( 0 === strcasecmp( $user->user_email, $existing_user['email'] ) ) {
941 $auth_settings_access_users_approved_single[ $key ]['role'] = $approved_role;
942 break;
943 }
944 }
945 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved_single );
946 }
947 }
948
949 // If this is multisite, add new user to current blog.
950 if ( is_multisite() && ! is_user_member_of_blog( $user->ID ) ) {
951 $result = add_user_to_blog( get_current_blog_id(), $user->ID, $user_info['role'] );
952
953 // Fail with message if error.
954 if ( is_wp_error( $result ) ) {
955 return $result;
956 }
957 }
958
959 // Ensure user has the same role as their entry in the approved list.
960 if ( $user_info && ! in_array( $user_info['role'], $user->roles, true ) ) {
961 $user->set_role( $user_info['role'] );
962 }
963
964 return $user;
965
966 } elseif ( 0 === strcasecmp( $user_email, $last_email ) ) {
967 /**
968 * Note: only do this for the last email address we are checking (we need
969 * to iterate through them all to make sure one of them isn't approved).
970 */
971
972 // User isn't an admin, is not blocked, and is not approved.
973 // Add them to the pending list and notify them and their instructor.
974 if ( strlen( $user_email ) > 0 && ! $this->is_email_in_list( $user_email, 'pending' ) ) {
975 $pending_user = array();
976 $pending_user['email'] = $this->lowercase( $user_email );
977 $pending_user['role'] = $approved_role;
978 $pending_user['date_added'] = '';
979 array_push( $auth_settings_access_users_pending, $pending_user );
980 update_option( 'auth_settings_access_users_pending', $auth_settings_access_users_pending );
981
982 // Create strings used in the email notification.
983 $site_name = get_bloginfo( 'name' );
984 $site_url = get_bloginfo( 'url' );
985 $authorizer_options_url = 'settings' === $auth_settings['advanced_admin_menu'] ? admin_url( 'options-general.php?page=authorizer' ) : admin_url( '?page=authorizer' );
986
987 // Notify users with the role specified in "Which role should
988 // receive email notifications about pending users?".
989 if ( strlen( $auth_settings['access_role_receive_pending_emails'] ) > 0 ) {
990 foreach ( get_users( array( 'role' => $auth_settings['access_role_receive_pending_emails'] ) ) as $user_recipient ) {
991 wp_mail(
992 $user_recipient->user_email,
993 sprintf(
994 /* TRANSLATORS: 1: User email 2: Name of site */
995 __( 'Action required: Pending user %1$s at %2$s', 'authorizer' ),
996 $pending_user['email'],
997 $site_name
998 ),
999 sprintf(
1000 /* TRANSLATORS: 1: Name of site 2: URL of site 3: URL of authorizer */
1001 __( "A new user has tried to access the %1\$s site you manage at:\n%2\$s\n\nPlease log in to approve or deny their request:\n%3\$s\n", 'authorizer' ),
1002 $site_name,
1003 $site_url,
1004 $authorizer_options_url
1005 )
1006 );
1007 }
1008 }
1009 }
1010
1011 // Notify user about pending status and return without authenticating them.
1012 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
1013 $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ) : home_url();
1014 $page_title = get_bloginfo( 'name' ) . ' - Access Pending';
1015 $error_message =
1016 apply_filters( 'the_content', $auth_settings['access_pending_redirect_to_message'] ) .
1017 '<hr />' .
1018 '<p style="text-align: center;">' .
1019 '<a class="button" href="' . wp_logout_url( $redirect_to ) . '">' .
1020 __( 'Back', 'authorizer' ) .
1021 '</a></p>';
1022 update_option( 'auth_settings_advanced_login_error', $error_message );
1023 wp_die( wp_kses( $error_message, $this->allowed_html ), esc_html( $page_title ) );
1024 }
1025 }
1026
1027 // Sanity check: if we made it here without returning, something has gone wrong.
1028 return new WP_Error( 'invalid_login', __( 'Invalid login attempted.', 'authorizer' ) );
1029
1030 }
1031
1032
1033 /**
1034 * Verify the Google login and set a session token.
1035 *
1036 * Flow: "Sign in with Google" button clicked; JS Google library
1037 * called; JS function signInCallback() fired with results from Google;
1038 * signInCallback() posts code and nonce (via AJAX) to this function;
1039 * This function checks the token using the Google PHP library, and
1040 * saves it to a session variable if it's authentic; control passes
1041 * back to signInCallback(), which will reload the current page
1042 * (wp-login.php) on success; wp-login.php reloads; custom_authenticate
1043 * hooked into authenticate action fires again, and
1044 * custom_authenticate_google() runs to verify the token; once verified
1045 * custom_authenticate proceeds as normal with the google email address
1046 * as a successfully authenticated external user.
1047 *
1048 * Action: wp_ajax_process_google_login
1049 * Action: wp_ajax_nopriv_process_google_login
1050 *
1051 * @return void, but die with the value to return to the success() function in AJAX call signInCallback().
1052 */
1053 public function ajax_process_google_login() {
1054 // Nonce check.
1055 if (
1056 ! isset( $_POST['nonce'] ) ||
1057 ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'google_csrf_nonce' )
1058 ) {
1059 die( '' );
1060 }
1061
1062 // Google authentication token.
1063 // phpcs:ignore WordPress.VIP.ValidatedSanitizedInput.InputNotSanitized
1064 $code = isset( $_POST['code'] ) ? wp_unslash( $_POST['code'] ) : null;
1065
1066 // Grab plugin settings.
1067 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
1068
1069 /**
1070 * Add Google API PHP Client.
1071 *
1072 * @see https://github.com/google/google-api-php-client branch:v1-master
1073 */
1074 require_once dirname( __FILE__ ) . '/vendor/google-api-php-client/src/Google/autoload.php';
1075
1076 // Build the Google Client.
1077 $client = new Google_Client();
1078 $client->setApplicationName( 'WordPress' );
1079 $client->setClientId( $auth_settings['google_clientid'] );
1080 $client->setClientSecret( $auth_settings['google_clientsecret'] );
1081 $client->setRedirectUri( 'postmessage' );
1082
1083 /**
1084 * If the hosted domain parameter is set, restrict logins to that domain.
1085 *
1086 * Note: Will have to upgrade to google-api-php-client v2 or higher for
1087 * this to function server-side; it's not complete in v1, so this check
1088 * is performed manually below.
1089 *
1090 * if (
1091 * array_key_exists( 'google_hosteddomain', $auth_settings ) &&
1092 * strlen( $auth_settings['google_hosteddomain'] ) > 0
1093 * ) {
1094 * $google_hosteddomains = explode( "\n", str_replace( "\r", '', $auth_settings['google_hosteddomain'] ) );
1095 * $google_hosteddomain = trim( $google_hosteddomains[0] );
1096 * $client->setHostedDomain( $google_hosteddomain );
1097 * }
1098 */
1099
1100 // Get one time use token (if it doesn't exist, we'll create one below).
1101 session_start();
1102 $token = array_key_exists( 'token', $_SESSION ) ? json_decode( $_SESSION['token'] ) : null;
1103
1104 if ( empty( $token ) ) {
1105 // Exchange the OAuth 2.0 authorization code for user credentials.
1106 $client->authenticate( $code );
1107 $token = json_decode( $client->getAccessToken() );
1108
1109 // Store the token in the session for later use.
1110 $_SESSION['token'] = wp_json_encode( $token );
1111
1112 $response = 'Successfully authenticated.';
1113 } else {
1114 $client->setAccessToken( wp_json_encode( $token ) );
1115
1116 $response = 'Already authenticated.';
1117 }
1118
1119 die( esc_html( $response ) );
1120 }
1121
1122
1123 /**
1124 * Validate this user's credentials against Google.
1125 *
1126 * @param array $auth_settings Plugin settings.
1127 * @return array|WP_Error Array containing email, authenticated_by, first_name,
1128 * last_name, and username strings for the successfully
1129 * authenticated user, or WP_Error() object on failure,
1130 * or null if not attempting a google login.
1131 */
1132 private function custom_authenticate_google( $auth_settings ) {
1133 // Move on if Google auth hasn't been requested here.
1134 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
1135 if ( empty( $_GET['external'] ) || 'google' !== $_GET['external'] ) {
1136 return null;
1137 }
1138
1139 // Get one time use token.
1140 session_start();
1141 $token = array_key_exists( 'token', $_SESSION ) ? json_decode( $_SESSION['token'] ) : null;
1142
1143 // No token, so this is not a succesful Google login.
1144 if ( is_null( $token ) ) {
1145 return null;
1146 }
1147
1148 /**
1149 * Add Google API PHP Client.
1150 *
1151 * @see https://github.com/google/google-api-php-client branch:v1-master
1152 */
1153 require_once dirname( __FILE__ ) . '/vendor/google-api-php-client/src/Google/autoload.php';
1154
1155 // Build the Google Client.
1156 $client = new Google_Client();
1157 $client->setApplicationName( 'WordPress' );
1158 $client->setClientId( $auth_settings['google_clientid'] );
1159 $client->setClientSecret( $auth_settings['google_clientsecret'] );
1160 $client->setRedirectUri( 'postmessage' );
1161
1162 /**
1163 * If the hosted domain parameter is set, restrict logins to that domain.
1164 * Note: Will have to upgrade to google-api-php-client v2 or higher for
1165 * this to function server-side; it's not complete in v1, so this check
1166 * is performed manually later.
1167 * if (
1168 * array_key_exists( 'google_hosteddomain', $auth_settings ) &&
1169 * strlen( $auth_settings['google_hosteddomain'] ) > 0
1170 * ) {
1171 * $google_hosteddomains = explode( "\n", str_replace( "\r", '', $auth_settings['google_hosteddomain'] ) );
1172 * $google_hosteddomain = trim( $google_hosteddomains[0] );
1173 * $client->setHostedDomain( $google_hosteddomain );
1174 * }
1175 */
1176
1177 // Verify this is a successful Google authentication.
1178 try {
1179 $ticket = $client->verifyIdToken( $token->id_token, $auth_settings['google_clientid'] );
1180 } catch ( Google_Auth_Exception $e ) {
1181 // Invalid ticket, so this in not a successful Google login.
1182 return new WP_Error( 'invalid_google_login', __( 'Invalid Google credentials provided.', 'authorizer' ) );
1183 }
1184
1185 // Invalid ticket, so this in not a successful Google login.
1186 if ( ! $ticket ) {
1187 return new WP_Error( 'invalid_google_login', __( 'Invalid Google credentials provided.', 'authorizer' ) );
1188 }
1189
1190 // Get email address.
1191 $attributes = $ticket->getAttributes();
1192 $email = $this->lowercase( $attributes['payload']['email'] );
1193 $email_domain = substr( strrchr( $email, '@' ), 1 );
1194 $username = current( explode( '@', $email ) );
1195
1196 /**
1197 * Fail if hd param is set and the logging in user's email address doesn't
1198 * match the allowed hosted domain.
1199 *
1200 * See: https://developers.google.com/identity/protocols/OpenIDConnect#hd-param
1201 * See: https://github.com/google/google-api-php-client/blob/v1-master/src/Google/Client.php#L407-L416
1202 *
1203 * Note: Will have to upgrade to google-api-php-client v2 or higher for
1204 * this to function server-side; it's not complete in v1, so this check
1205 * is only performed here.
1206 */
1207 if ( array_key_exists( 'google_hosteddomain', $auth_settings ) && strlen( $auth_settings['google_hosteddomain'] ) > 0 ) {
1208 // Allow multiple whitelisted domains.
1209 $google_hosteddomains = explode( "\n", str_replace( "\r", '', $auth_settings['google_hosteddomain'] ) );
1210 if ( ! in_array( $email_domain, $google_hosteddomains, true ) ) {
1211 $this->custom_logout();
1212 return new WP_Error( 'invalid_google_login', __( 'Google credentials do not match the allowed hosted domain', 'authorizer' ) );
1213 }
1214 }
1215
1216 return array(
1217 'email' => $email,
1218 'username' => $username,
1219 'first_name' => '',
1220 'last_name' => '',
1221 'authenticated_by' => 'google',
1222 'google_attributes' => $attributes,
1223 );
1224 }
1225
1226
1227 /**
1228 * Validate this user's credentials against CAS.
1229 *
1230 * @param array $auth_settings Plugin settings.
1231 * @return array|WP_Error Array containing 'email' and 'authenticated_by' strings
1232 * for the successfully authenticated user, or WP_Error()
1233 * object on failure, or null if not attempting a CAS login.
1234 */
1235 private function custom_authenticate_cas( $auth_settings ) {
1236 // Move on if CAS hasn't been requested here.
1237 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
1238 if ( empty( $_GET['external'] ) || 'cas' !== $_GET['external'] ) {
1239 return null;
1240 }
1241
1242 /**
1243 * Get the CAS server version (default to SAML_VERSION_1_1).
1244 *
1245 * @see: https://developer.jasig.org/cas-clients/php/1.3.4/docs/api/group__public.html
1246 */
1247 $cas_version = SAML_VERSION_1_1;
1248 if ( 'CAS_VERSION_3_0' === $auth_settings['cas_version'] ) {
1249 $cas_version = CAS_VERSION_3_0;
1250 } elseif ( 'CAS_VERSION_2_0' === $auth_settings['cas_version'] ) {
1251 $cas_version = CAS_VERSION_2_0;
1252 } elseif ( 'CAS_VERSION_1_0' === $auth_settings['cas_version'] ) {
1253 $cas_version = CAS_VERSION_1_0;
1254 }
1255
1256 // Set the CAS client configuration.
1257 phpCAS::client( $cas_version, $auth_settings['cas_host'], intval( $auth_settings['cas_port'] ), $auth_settings['cas_path'] );
1258
1259 // Allow redirects at the CAS server endpoint (e.g., allow connections
1260 // at an old CAS URL that redirects to a newer CAS URL).
1261 phpCAS::setExtraCurlOption( CURLOPT_FOLLOWLOCATION, true );
1262
1263 // Update server certificate bundle if it doesn't exist or is older
1264 // than 6 months, then use it to ensure CAS server is legitimate.
1265 // Note: only try to update if the system has the php_openssl extension.
1266 $cacert_url = 'https://curl.haxx.se/ca/cacert.pem';
1267 $cacert_path = plugin_dir_path( __FILE__ ) . 'vendor/cacert.pem';
1268 $time_180_days = 180 * 24 * 60 * 60; // days * hours * minutes * seconds.
1269 $time_180_days_ago = time() - $time_180_days;
1270 if (
1271 extension_loaded( 'openssl' ) &&
1272 ( ! file_exists( $cacert_path ) || filemtime( $cacert_path ) < $time_180_days_ago )
1273 ) {
1274 // Get new cacert.pem file from https://curl.haxx.se/ca/cacert.pem.
1275 $response = wp_safe_remote_get( $cacert_url );
1276 if (
1277 is_wp_error( $response ) ||
1278 200 !== wp_remote_retrieve_response_code( $response ) ||
1279 ! array_key_exists( 'body', $response )
1280 ) {
1281 new WP_Error( 'cannot_update_cacert', __( 'Unable to update outdated server certificates from https://curl.haxx.se/ca/cacert.pem.', 'authorizer' ) );
1282 }
1283 $cacert_contents = $response['body'];
1284
1285 // Write out the updated certs to the plugin directory.
1286 // Note: Don't use WP_Filesystem because we are not in an admin context
1287 // and don't want to potentially prompt the end user for credentials.
1288 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
1289 file_put_contents( $cacert_path, $cacert_contents );
1290 }
1291 phpCAS::setCasServerCACert( $cacert_path );
1292
1293 // Set the CAS service URL (including the redirect URL for WordPress when it comes back from CAS).
1294 $cas_service_url = site_url( '/wp-login.php?external=cas' );
1295 $login_querystring = array();
1296 if ( isset( $_SERVER['QUERY_STRING'] ) ) {
1297 parse_str( wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['QUERY_STRING'] ) ), PHP_URL_HOST ), $login_querystring );
1298 }
1299 if ( isset( $login_querystring['redirect_to'] ) ) {
1300 $cas_service_url .= '&redirect_to=' . rawurlencode( $login_querystring['redirect_to'] );
1301 }
1302 phpCAS::setFixedServiceURL( $cas_service_url );
1303
1304 // Authenticate against CAS.
1305 try {
1306 phpCAS::forceAuthentication();
1307 } catch ( CAS_AuthenticationException $e ) {
1308 // CAS server threw an error in isAuthenticated(), potentially because
1309 // the cached ticket is outdated. Try renewing the authentication.
1310 error_log( __( 'CAS server returned an Authentication Exception. Details:', 'authorizer' ) ); // phpcs:ignore
1311 error_log( print_r( $e, true ) ); // phpcs:ignore
1312
1313 // CAS server is throwing errors on this login, so try logging the
1314 // user out of CAS and redirecting them to the login page.
1315 phpCAS::logoutWithRedirectService( wp_login_url() );
1316 die();
1317 }
1318
1319 // Get username (as specified by the CAS server).
1320 $username = phpCAS::getUser();
1321
1322 // Get email that successfully authenticated against the external service (CAS).
1323 $externally_authenticated_email = strtolower( $username );
1324 if ( ! filter_var( $externally_authenticated_email, FILTER_VALIDATE_EMAIL ) ) {
1325 // If we can't get the user's email address from a CAS attribute,
1326 // try to guess the domain from the CAS server hostname. This will only
1327 // be used if we can't discover the email address from CAS attributes.
1328 $domain_guess = preg_match( '/[^.]*\.[^.]*$/', $auth_settings['cas_host'], $matches ) === 1 ? $matches[0] : '';
1329 $externally_authenticated_email = $this->lowercase( $username ) . '@' . $domain_guess;
1330 }
1331
1332 // Retrieve the user attributes (e.g., email address, first name, last name) from the CAS server.
1333 $cas_attributes = phpCAS::getAttributes();
1334
1335 // Get user email if it is specified in another field.
1336 if ( array_key_exists( 'cas_attr_email', $auth_settings ) && strlen( $auth_settings['cas_attr_email'] ) > 0 ) {
1337 // If the email attribute starts with an at symbol (@), assume that the
1338 // email domain is manually entered there (instead of a reference to a
1339 // CAS attribute), and combine that with the username to create the email.
1340 // Otherwise, look up the CAS attribute for email.
1341 if ( substr( $auth_settings['cas_attr_email'], 0, 1 ) === '@' ) {
1342 $externally_authenticated_email = $this->lowercase( $username . $auth_settings['cas_attr_email'] );
1343 } elseif (
1344 // If a CAS attribute has been specified as containing the email address, use that instead.
1345 // Email attribute can be a string or an array of strings.
1346 array_key_exists( $auth_settings['cas_attr_email'], $cas_attributes ) && (
1347 (
1348 is_array( $cas_attributes[ $auth_settings['cas_attr_email'] ] ) &&
1349 count( $cas_attributes[ $auth_settings['cas_attr_email'] ] ) > 0
1350 ) || (
1351 is_string( $cas_attributes[ $auth_settings['cas_attr_email'] ] ) &&
1352 strlen( $cas_attributes[ $auth_settings['cas_attr_email'] ] ) > 0
1353 )
1354 )
1355 ) {
1356 // Each of the emails in the array needs to be set to lowercase.
1357 if ( is_array( $cas_attributes[ $auth_settings['cas_attr_email'] ] ) ) {
1358 $externally_authenticated_email = array();
1359 foreach ( $cas_attributes[ $auth_settings['cas_attr_email'] ] as $external_email ) {
1360 $externally_authenticated_email[] = $this->lowercase( $external_email );
1361 }
1362 } else {
1363 $externally_authenticated_email = $this->lowercase( $cas_attributes[ $auth_settings['cas_attr_email'] ] );
1364 }
1365 }
1366 }
1367
1368 // Get user first name and last name.
1369 $first_name = array_key_exists( 'cas_attr_first_name', $auth_settings ) && strlen( $auth_settings['cas_attr_first_name'] ) > 0 && array_key_exists( $auth_settings['cas_attr_first_name'], $cas_attributes ) && strlen( $cas_attributes[ $auth_settings['cas_attr_first_name'] ] ) > 0 ? $cas_attributes[ $auth_settings['cas_attr_first_name'] ] : '';
1370 $last_name = array_key_exists( 'cas_attr_last_name', $auth_settings ) && strlen( $auth_settings['cas_attr_last_name'] ) > 0 && array_key_exists( $auth_settings['cas_attr_last_name'], $cas_attributes ) && strlen( $cas_attributes[ $auth_settings['cas_attr_last_name'] ] ) > 0 ? $cas_attributes[ $auth_settings['cas_attr_last_name'] ] : '';
1371
1372 return array(
1373 'email' => $externally_authenticated_email,
1374 'username' => $username,
1375 'first_name' => $first_name,
1376 'last_name' => $last_name,
1377 'authenticated_by' => 'cas',
1378 'cas_attributes' => $cas_attributes,
1379 );
1380 }
1381
1382
1383 /**
1384 * Validate this user's credentials against LDAP.
1385 *
1386 * @param array $auth_settings Plugin settings.
1387 * @param string $username Attempted username from authenticate action.
1388 * @param string $password Attempted password from authenticate action.
1389 * @return array|WP_Error Array containing 'email' and 'authenticated_by' strings
1390 * for the successfully authenticated user, or WP_Error()
1391 * object on failure, or null if skipping LDAP auth and
1392 * falling back to WP auth.
1393 */
1394 private function custom_authenticate_ldap( $auth_settings, $username, $password ) {
1395 // Get LDAP search base(s).
1396 $search_bases = explode( "\n", str_replace( "\r", '', trim( $auth_settings['ldap_search_base'] ) ) );
1397
1398 // Fail silently (fall back to WordPress authentication) if no search base specified.
1399 if ( count( $search_bases ) < 1 ) {
1400 return null;
1401 }
1402
1403 // Get the FQDN from the first LDAP search base domain components (dc). For
1404 // example, ou=people,dc=example,dc=edu,dc=uk would yield user@example.edu.uk.
1405 $search_base_components = explode( ',', trim( $search_bases[0] ) );
1406 $domain = array();
1407 foreach ( $search_base_components as $search_base_component ) {
1408 $component = explode( '=', $search_base_component );
1409 if ( 2 === count( $component ) && 'dc' === $component[0] ) {
1410 $domain[] = $component[1];
1411 }
1412 }
1413 $domain = implode( '.', $domain );
1414
1415 // If we can't get the logging in user's email address from an LDAP attribute,
1416 // just use the domain from the LDAP host. This will only be used if we
1417 // can't discover the email address from an LDAP attribute.
1418 if ( empty( $domain ) ) {
1419 $domain = preg_match( '/[^.]*\.[^.]*$/', $auth_settings['ldap_host'], $matches ) === 1 ? $matches[0] : '';
1420 }
1421
1422 // remove @domain if it exists in the username (i.e., if user entered their email).
1423 $username = str_replace( '@' . $domain, '', $username );
1424
1425 // Fail silently (fall back to WordPress authentication) if both username
1426 // and password are empty (this will be the case when visiting wp-login.php
1427 // for the first time, or when clicking the Log In button without filling
1428 // out either field.
1429 if ( empty( $username ) && empty( $password ) ) {
1430 return null;
1431 }
1432
1433 // Fail with error message if username or password is blank.
1434 if ( empty( $username ) ) {
1435 return new WP_Error( 'empty_username', __( 'You must provide a username or email.', 'authorizer' ) );
1436 }
1437 if ( empty( $password ) ) {
1438 return new WP_Error( 'empty_password', __( 'You must provide a password.', 'authorizer' ) );
1439 }
1440
1441 // If php5-ldap extension isn't installed on server, fall back to WP auth.
1442 if ( ! function_exists( 'ldap_connect' ) ) {
1443 return null;
1444 }
1445
1446 // Authenticate against LDAP using options provided in plugin settings.
1447 $result = false;
1448 $ldap_user_dn = '';
1449 $first_name = '';
1450 $last_name = '';
1451 $email = '';
1452
1453 // Construct LDAP connection parameters. ldap_connect() takes either a
1454 // hostname or a full LDAP URI as its first parameter (works with OpenLDAP
1455 // 2.x.x or later). If it's an LDAP URI, the second parameter, $port, is
1456 // ignored, and port must be specified in the full URI. An LDAP URI is of
1457 // the form ldap://hostname:port or ldaps://hostname:port.
1458 $ldap_host = $auth_settings['ldap_host'];
1459 $ldap_port = intval( $auth_settings['ldap_port'] );
1460 $parsed_host = wp_parse_url( $ldap_host );
1461 // Fail (fall back to WordPress auth) if invalid host is specified.
1462 if ( false === $parsed_host ) {
1463 return null;
1464 }
1465 // If a scheme is in the LDAP host, use full LDAP URI instead of just hostname.
1466 if ( array_key_exists( 'scheme', $parsed_host ) ) {
1467 // If the port isn't in the LDAP URI, use the one in the LDAP port field.
1468 if ( ! array_key_exists( 'port', $parsed_host ) ) {
1469 $parsed_host['port'] = $ldap_port;
1470 }
1471 $ldap_host = $this->build_url( $parsed_host );
1472 }
1473
1474 // Establish LDAP connection.
1475 $ldap = ldap_connect( $ldap_host, $ldap_port );
1476 ldap_set_option( $ldap, LDAP_OPT_PROTOCOL_VERSION, 3 );
1477 if ( 1 === intval( $auth_settings['ldap_tls'] ) ) {
1478 if ( ! ldap_start_tls( $ldap ) ) {
1479 return null;
1480 }
1481 }
1482
1483 // Set bind credentials; attempt an anonymous bind if not provided.
1484 $bind_rdn = null;
1485 $bind_password = null;
1486 if ( strlen( $auth_settings['ldap_user'] ) > 0 ) {
1487 $bind_rdn = $auth_settings['ldap_user'];
1488 $bind_password = $this->decrypt( $auth_settings['ldap_password'] );
1489 }
1490
1491 // Attempt LDAP bind.
1492 $result = @ldap_bind( $ldap, $bind_rdn, stripslashes( $bind_password ) ); // phpcs:ignore
1493 if ( ! $result ) {
1494 // Can't connect to LDAP, so fall back to WordPress authentication.
1495 return null;
1496 }
1497 // Look up the bind DN (and first/last name) of the user trying to
1498 // log in by performing an LDAP search for the login username in
1499 // the field specified in the LDAP settings. This setup is common.
1500 $ldap_attributes_to_retrieve = array( 'dn' );
1501 if ( array_key_exists( 'ldap_attr_first_name', $auth_settings ) && strlen( $auth_settings['ldap_attr_first_name'] ) > 0 ) {
1502 array_push( $ldap_attributes_to_retrieve, $auth_settings['ldap_attr_first_name'] );
1503 }
1504 if ( array_key_exists( 'ldap_attr_last_name', $auth_settings ) && strlen( $auth_settings['ldap_attr_last_name'] ) > 0 ) {
1505 array_push( $ldap_attributes_to_retrieve, $auth_settings['ldap_attr_last_name'] );
1506 }
1507 if ( array_key_exists( 'ldap_attr_email', $auth_settings ) && strlen( $auth_settings['ldap_attr_email'] ) > 0 && substr( $auth_settings['ldap_attr_email'], 0, 1 ) !== '@' ) {
1508 array_push( $ldap_attributes_to_retrieve, $this->lowercase( $auth_settings['ldap_attr_email'] ) );
1509 }
1510
1511 // Create default LDAP search filter (uid=$username).
1512 $search_filter = '(' . $auth_settings['ldap_uid'] . '=' . $username . ')';
1513
1514 /**
1515 * Filter LDAP search filter.
1516 *
1517 * Allows for custom LDAP authentication rules (e.g., restricting login
1518 * access to users in multiple groups, or having certain attributes).
1519 *
1520 * @param string $search_filter The filter to pass to ldap_search().
1521 * @param string $ldap_uid The attribute to compare username against (from Authorizer Settings).
1522 * @param string $username The username attempting to log in.
1523 */
1524 $search_filter = apply_filters( 'authorizer_ldap_search_filter', $search_filter, $auth_settings['ldap_uid'], $username );
1525
1526 // Multiple search bases can be provided, so iterate through them until a match is found.
1527 foreach ( $search_bases as $search_base ) {
1528 $ldap_search = ldap_search(
1529 $ldap,
1530 $search_base,
1531 $search_filter,
1532 $ldap_attributes_to_retrieve
1533 );
1534 $ldap_entries = ldap_get_entries( $ldap, $ldap_search );
1535 if ( $ldap_entries['count'] > 0 ) {
1536 break;
1537 }
1538 }
1539
1540 // If we didn't find any users in ldap, fall back to WordPress authentication.
1541 if ( $ldap_entries['count'] < 1 ) {
1542 return null;
1543 }
1544
1545 // Get the bind dn and first/last names; if there are multiple results returned, just get the last one.
1546 for ( $i = 0; $i < $ldap_entries['count']; $i++ ) {
1547 $ldap_user_dn = $ldap_entries[ $i ]['dn'];
1548
1549 // Get user first name and last name.
1550 $ldap_attr_first_name = array_key_exists( 'ldap_attr_first_name', $auth_settings ) ? $this->lowercase( $auth_settings['ldap_attr_first_name'] ) : '';
1551 if ( strlen( $ldap_attr_first_name ) > 0 && array_key_exists( $ldap_attr_first_name, $ldap_entries[ $i ] ) && $ldap_entries[ $i ][ $ldap_attr_first_name ]['count'] > 0 && strlen( $ldap_entries[ $i ][ $ldap_attr_first_name ][0] ) > 0 ) {
1552 $first_name = $ldap_entries[ $i ][ $ldap_attr_first_name ][0];
1553 }
1554 $ldap_attr_last_name = array_key_exists( 'ldap_attr_last_name', $auth_settings ) ? $this->lowercase( $auth_settings['ldap_attr_last_name'] ) : '';
1555 if ( strlen( $ldap_attr_last_name ) > 0 && array_key_exists( $ldap_attr_last_name, $ldap_entries[ $i ] ) && $ldap_entries[ $i ][ $ldap_attr_last_name ]['count'] > 0 && strlen( $ldap_entries[ $i ][ $ldap_attr_last_name ][0] ) > 0 ) {
1556 $last_name = $ldap_entries[ $i ][ $ldap_attr_last_name ][0];
1557 }
1558 // Get user email if it is specified in another field.
1559 $ldap_attr_email = array_key_exists( 'ldap_attr_email', $auth_settings ) ? $this->lowercase( $auth_settings['ldap_attr_email'] ) : '';
1560 if ( strlen( $ldap_attr_email ) > 0 ) {
1561 // If the email attribute starts with an at symbol (@), assume that the
1562 // email domain is manually entered there (instead of a reference to an
1563 // LDAP attribute), and combine that with the username to create the email.
1564 // Otherwise, look up the LDAP attribute for email.
1565 if ( substr( $ldap_attr_email, 0, 1 ) === '@' ) {
1566 $email = $this->lowercase( $username . $ldap_attr_email );
1567 } elseif ( array_key_exists( $ldap_attr_email, $ldap_entries[ $i ] ) && $ldap_entries[ $i ][ $ldap_attr_email ]['count'] > 0 && strlen( $ldap_entries[ $i ][ $ldap_attr_email ][0] ) > 0 ) {
1568 $email = $this->lowercase( $ldap_entries[ $i ][ $ldap_attr_email ][0] );
1569 }
1570 }
1571 }
1572
1573 $result = @ldap_bind( $ldap, $ldap_user_dn, stripslashes( $password ) ); // phpcs:ignore
1574 if ( ! $result ) {
1575 // We have a real ldap user, but an invalid password. Pass
1576 // through to wp authentication after failing LDAP (since
1577 // this could be a local account that happens to be the
1578 // same name as an LDAP user).
1579 return null;
1580 }
1581
1582 // User successfully authenticated against LDAP, so set the relevant variables.
1583 $externally_authenticated_email = $this->lowercase( $username . '@' . $domain );
1584
1585 // If an LDAP attribute has been specified as containing the email address, use that instead.
1586 if ( strlen( $email ) > 0 ) {
1587 $externally_authenticated_email = $this->lowercase( $email );
1588 }
1589
1590 return array(
1591 'email' => $externally_authenticated_email,
1592 'username' => $username,
1593 'first_name' => $first_name,
1594 'last_name' => $last_name,
1595 'authenticated_by' => 'ldap',
1596 'ldap_attributes' => $ldap_entries,
1597 );
1598 }
1599
1600
1601 /**
1602 * Log out of the attached external service.
1603 *
1604 * Action: wp_logout
1605 *
1606 * @return void
1607 */
1608 public function custom_logout() {
1609 // Grab plugin settings.
1610 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
1611
1612 // Reset option containing old error messages.
1613 delete_option( 'auth_settings_advanced_login_error' );
1614
1615 if ( session_id() === '' ) {
1616 session_start();
1617 }
1618
1619 $current_user_authenticated_by = get_user_meta( get_current_user_id(), 'authenticated_by', true );
1620
1621 // If logged in to CAS, Log out of CAS.
1622 if ( 'cas' === $current_user_authenticated_by && '1' === $auth_settings['cas'] ) {
1623 if ( ! array_key_exists( 'PHPCAS_CLIENT', $GLOBALS ) || ! array_key_exists( 'phpCAS', $_SESSION ) ) {
1624
1625 /**
1626 * Get the CAS server version (default to SAML_VERSION_1_1).
1627 *
1628 * @see: https://developer.jasig.org/cas-clients/php/1.3.4/docs/api/group__public.html
1629 */
1630 $cas_version = SAML_VERSION_1_1;
1631 if ( 'CAS_VERSION_3_0' === $auth_settings['cas_version'] ) {
1632 $cas_version = CAS_VERSION_3_0;
1633 } elseif ( 'CAS_VERSION_2_0' === $auth_settings['cas_version'] ) {
1634 $cas_version = CAS_VERSION_2_0;
1635 } elseif ( 'CAS_VERSION_1_0' === $auth_settings['cas_version'] ) {
1636 $cas_version = CAS_VERSION_1_0;
1637 }
1638
1639 // Set the CAS client configuration if it hasn't been set already.
1640 phpCAS::client( $cas_version, $auth_settings['cas_host'], intval( $auth_settings['cas_port'] ), $auth_settings['cas_path'] );
1641 // Allow redirects at the CAS server endpoint (e.g., allow connections
1642 // at an old CAS URL that redirects to a newer CAS URL).
1643 phpCAS::setExtraCurlOption( CURLOPT_FOLLOWLOCATION, true );
1644 // Restrict logout request origin to the CAS server only (prevent DDOS).
1645 phpCAS::handleLogoutRequests( true, array( $auth_settings['cas_host'] ) );
1646 }
1647 if ( phpCAS::isAuthenticated() || phpCAS::isInitialized() ) {
1648 // Redirect to home page, or specified page if it's been provided.
1649 $redirect_to = site_url( '/' );
1650 if ( ! empty( $_REQUEST['redirect_to'] ) && isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'log-out' ) ) {
1651 $redirect_to = esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) );
1652 }
1653
1654 phpCAS::logoutWithRedirectService( $redirect_to );
1655 }
1656 }
1657
1658 // If session token set, log out of Google.
1659 if ( 'google' === $current_user_authenticated_by || array_key_exists( 'token', $_SESSION ) ) {
1660 $token = json_decode( $_SESSION['token'] )->access_token;
1661
1662 /**
1663 * Add Google API PHP Client.
1664 *
1665 * @see https://github.com/google/google-api-php-client branch:v1-master
1666 */
1667 require_once dirname( __FILE__ ) . '/vendor/google-api-php-client/src/Google/autoload.php';
1668
1669 // Build the Google Client.
1670 $client = new Google_Client();
1671 $client->setApplicationName( 'WordPress' );
1672 $client->setClientId( $auth_settings['google_clientid'] );
1673 $client->setClientSecret( $auth_settings['google_clientsecret'] );
1674 $client->setRedirectUri( 'postmessage' );
1675
1676 // Revoke the token.
1677 $client->revokeToken( $token );
1678
1679 // Remove the credentials from the user's session.
1680 unset( $_SESSION['token'] );
1681 }
1682
1683 }
1684
1685
1686
1687 /**
1688 * ***************************
1689 * Access Restriction
1690 * ***************************
1691 */
1692
1693
1694
1695 /**
1696 * Restrict access to WordPress site based on settings (everyone, logged_in_users).
1697 *
1698 * Action: parse_request
1699 *
1700 * @param array $wp WordPress object.
1701 * @return WP|void WP object when passing through to WordPress authentication, or void.
1702 */
1703 public function restrict_access( $wp ) {
1704 // Grab plugin settings.
1705 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
1706
1707 // Grab current user.
1708 $current_user = wp_get_current_user();
1709
1710 $has_access = (
1711 // Always allow access if WordPress is installing.
1712 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
1713 ( defined( 'WP_INSTALLING' ) && isset( $_GET['key'] ) ) ||
1714 // Always allow access to admins.
1715 ( current_user_can( 'create_users' ) ) ||
1716 // Allow access if option is set to 'everyone'.
1717 ( 'everyone' === $auth_settings['access_who_can_view'] ) ||
1718 // Allow access to approved external users and logged in users if option is set to 'logged_in_users'.
1719 ( 'logged_in_users' === $auth_settings['access_who_can_view'] && $this->is_user_logged_in_and_blog_user() && $this->is_email_in_list( $current_user->user_email, 'approved' ) ) ||
1720 // Allow access for requests to /wp-json/oauth1 so oauth clients can authenticate to use the REST API.
1721 ( property_exists( $wp, 'matched_query' ) && stripos( $wp->matched_query, 'rest_oauth1=' ) === 0 ) ||
1722 // Allow access for non-GET requests to /wp-json/*, since REST API authentication already covers them.
1723 ( property_exists( $wp, 'matched_query' ) && 0 === stripos( $wp->matched_query, 'rest_route=' ) && isset( $_SERVER['REQUEST_METHOD'] ) && 'GET' !== $_SERVER['REQUEST_METHOD'] ) ||
1724 // Allow access for GET requests to /wp-json/ (root), since REST API discovery calls rely on this.
1725 ( property_exists( $wp, 'matched_query' ) && 'rest_route=/' === $wp->matched_query )
1726 // Note that GET requests to a rest endpoint will be restricted by authorizer. In that case, error messages will be returned as JSON.
1727 );
1728
1729 /**
1730 * Developers can use the `authorizer_has_access` filter
1731 * to override restricted access on certain pages. Note that the
1732 * restriction checks happens before WordPress executes any queries, so
1733 * use the global `$wp` variable to investigate what the visitor is
1734 * trying to load.
1735 *
1736 * For example, to unblock an RSS feed, place the following PHP code in
1737 * the theme's functions.php file or in a simple plug-in:
1738 *
1739 * function my_rsa_feed_access_override( $has_access ) {
1740 * global $wp;
1741 * // check query variables to see if this is the feed
1742 * if ( ! empty( $wp->query_vars['feed'] ) )
1743 * $has_access = true;
1744 * return $has_access;
1745 * }
1746 * add_filter( 'authorizer_has_access', 'my_rsa_feed_access_override' );
1747 */
1748 if ( apply_filters( 'authorizer_has_access', $has_access, $wp ) === true ) {
1749 // Turn off the public notice about browsing anonymously.
1750 update_option( 'auth_settings_advanced_public_notice', false );
1751
1752 // We've determined that the current user has access, so simply return to grant access.
1753 return $wp;
1754 }
1755
1756 // Allow HEAD requests to the root (usually discovery from a REST client).
1757 if ( 'HEAD' === $_SERVER['REQUEST_METHOD'] && empty( $wp->request ) && empty( $wp->matched_query ) ) {
1758 return $wp;
1759 }
1760
1761 /* We've determined that the current user doesn't have access, so we deal with them now. */
1762
1763 // Fringe case: In a multisite, a user of a different blog can successfully
1764 // log in, but they aren't on the 'approved' whitelist for this blog.
1765 // If that's the case, add them to the pending list for this blog.
1766 if ( is_multisite() && is_user_logged_in() && ! $has_access ) {
1767 $current_user = wp_get_current_user();
1768
1769 // Check user access; block if not, add them to pending list if open, let them through otherwise.
1770 $result = $this->check_user_access( $current_user, array( $current_user->user_email ) );
1771 }
1772
1773 // Check to see if the requested page is public. If so, show it.
1774 if ( empty( $wp->request ) ) {
1775 $current_page_id = 'home';
1776 } else {
1777 $request_query = isset( $wp->query_vars ) ? new WP_Query( $wp->query_vars ) : null;
1778 $current_page_id = isset( $request_query->post_count ) && $request_query->post_count > 0 ? $request_query->post->ID : '';
1779 }
1780 if ( ! array_key_exists( 'access_public_pages', $auth_settings ) || ! is_array( $auth_settings['access_public_pages'] ) ) {
1781 $auth_settings['access_public_pages'] = array();
1782 }
1783 if ( in_array( strval( $current_page_id ), $auth_settings['access_public_pages'], true ) ) {
1784 if ( 'no_warning' === $auth_settings['access_public_warning'] ) {
1785 update_option( 'auth_settings_advanced_public_notice', false );
1786 } else {
1787 update_option( 'auth_settings_advanced_public_notice', true );
1788 }
1789 return $wp;
1790 }
1791
1792 // Check to see if any category assigned to the requested page is public. If so, show it.
1793 $current_page_categories = wp_get_post_categories( $current_page_id, array( 'fields' => 'slugs' ) );
1794 foreach ( $current_page_categories as $current_page_category ) {
1795 if ( in_array( 'cat_' . $current_page_category, $auth_settings['access_public_pages'], true ) ) {
1796 if ( 'no_warning' === $auth_settings['access_public_warning'] ) {
1797 update_option( 'auth_settings_advanced_public_notice', false );
1798 } else {
1799 update_option( 'auth_settings_advanced_public_notice', true );
1800 }
1801 return $wp;
1802 }
1803 }
1804
1805 // Check to see if this page can't be found. If so, allow showing the 404 page.
1806 if ( strlen( $current_page_id ) < 1 ) {
1807 if ( in_array( 'auth_public_404', $auth_settings['access_public_pages'], true ) ) {
1808 if ( 'no_warning' === $auth_settings['access_public_warning'] ) {
1809 update_option( 'auth_settings_advanced_public_notice', false );
1810 } else {
1811 update_option( 'auth_settings_advanced_public_notice', true );
1812 }
1813 return $wp;
1814 }
1815 }
1816
1817 // Check to see if the requested category is public. If so, show it.
1818 $current_category_name = property_exists( $wp, 'query_vars' ) && array_key_exists( 'category_name', $wp->query_vars ) && strlen( $wp->query_vars['category_name'] ) > 0 ? $wp->query_vars['category_name'] : '';
1819 if ( $current_category_name ) {
1820 $current_category_name = end( explode( '/', $current_category_name ) );
1821 if ( in_array( 'cat_' . $current_category_name, $auth_settings['access_public_pages'], true ) ) {
1822 if ( 'no_warning' === $auth_settings['access_public_warning'] ) {
1823 update_option( 'auth_settings_advanced_public_notice', false );
1824 } else {
1825 update_option( 'auth_settings_advanced_public_notice', true );
1826 }
1827 return $wp;
1828 }
1829 }
1830
1831 // User is denied access, so show them the error message. Render as JSON
1832 // if this is a REST API call; otherwise, show the error message via
1833 // wp_die() (rendered html), or redirect to the login URL.
1834 $current_path = ! empty( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : home_url();
1835 if ( property_exists( $wp, 'matched_query' ) && stripos( $wp->matched_query, 'rest_route=' ) === 0 && 'GET' === $_SERVER['REQUEST_METHOD'] ) {
1836 wp_send_json(
1837 array(
1838 'code' => 'rest_cannot_view',
1839 'message' => strip_tags( $auth_settings['access_redirect_to_message'] ),
1840 'data' => array(
1841 'status' => 401,
1842 ),
1843 )
1844 );
1845 } elseif ( 'message' === $auth_settings['access_redirect'] ) {
1846 $page_title = sprintf(
1847 /* TRANSLATORS: %s: Name of blog */
1848 __( '%s - Access Restricted', 'authorizer' ),
1849 get_bloginfo( 'name' )
1850 );
1851 $error_message =
1852 apply_filters( 'the_content', $auth_settings['access_redirect_to_message'] ) .
1853 '<hr />' .
1854 '<p style="text-align: center;margin-bottom: -15px;">' .
1855 '<a class="button" href="' . wp_login_url( $current_path ) . '">' .
1856 __( 'Log In', 'authorizer' ) .
1857 '</a></p>';
1858 wp_die( wp_kses( $error_message, $this->allowed_html ), esc_html( $page_title ) );
1859 } else {
1860 wp_redirect( wp_login_url( $current_path ), 302 );
1861 exit;
1862 }
1863
1864 // Sanity check: we should never get here.
1865 wp_die( '<p>Access denied.</p>', 'Site Access Restricted' );
1866 }
1867
1868
1869 /**
1870 * On an admin page load, check for edge case (network-approved user who has
1871 * not yet been added to this particular blog in a multisite). Note: we do
1872 * this because check_user_access() runs on the parse_request hook, which
1873 * does not fire on wp-admin pages.
1874 *
1875 * Action: init
1876 *
1877 * @return void
1878 */
1879 public function init__maybe_add_network_approved_user() {
1880 global $current_user;
1881
1882 // If this is a multisite install and we have a logged in user that's not
1883 // a member of this blog, but is (network) approved, add them to this blog.
1884 if (
1885 is_admin() &&
1886 is_multisite() &&
1887 is_user_logged_in() &&
1888 ! is_user_member_of_blog() &&
1889 $this->is_email_in_list( $current_user->user_email, 'approved' )
1890 ) {
1891 // Get all approved users.
1892 $auth_settings_access_users_approved = $this->sanitize_user_list(
1893 array_merge(
1894 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT ),
1895 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
1896 )
1897 );
1898
1899 // Get user info (we need user role).
1900 $user_info = $this->get_user_info_from_list(
1901 $current_user->user_email,
1902 $auth_settings_access_users_approved
1903 );
1904
1905 // Add user to blog.
1906 add_user_to_blog( get_current_blog_id(), $current_user->ID, $user_info['role'] );
1907
1908 // Refresh user permissions.
1909 $current_user = new WP_User( $current_user->ID ); // phpcs:ignore WordPress.Variables.GlobalVariables.OverrideProhibited
1910 }
1911 }
1912
1913
1914
1915 /**
1916 * ***************************
1917 * Login page (wp-login.php)
1918 * ***************************
1919 */
1920
1921
1922
1923 /**
1924 * Add custom error message to login screen.
1925 *
1926 * Filter: login_errors
1927 *
1928 * @param string $errors Error description.
1929 * @return string Error description with Authorizer errors added.
1930 */
1931 public function show_advanced_login_error( $errors ) {
1932 $error = get_option( 'auth_settings_advanced_login_error' );
1933 delete_option( 'auth_settings_advanced_login_error' );
1934 $errors = ' ' . $error . "<br />\n";
1935 return $errors;
1936 }
1937
1938
1939 /**
1940 * Load external resources for the public-facing site.
1941 *
1942 * Action: wp_enqueue_scripts
1943 */
1944 public function auth_public_scripts() {
1945 // Load (and localize) public scripts.
1946 $current_path = ! empty( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : home_url();
1947 wp_enqueue_script( 'auth_public_scripts', plugins_url( '/js/authorizer-public.js', __FILE__ ), array( 'jquery' ), '2.3.2' );
1948 $auth_localized = array(
1949 'wpLoginUrl' => wp_login_url( $current_path ),
1950 'publicWarning' => get_option( 'auth_settings_advanced_public_notice' ),
1951 'anonymousNotice' => $this->get_plugin_option( 'access_redirect_to_message' ),
1952 'logIn' => esc_html__( 'Log In', 'authorizer' ),
1953 );
1954 wp_localize_script( 'auth_public_scripts', 'auth', $auth_localized );
1955
1956 // Load public css.
1957 wp_register_style( 'authorizer-public-css', plugins_url( 'css/authorizer-public.css', __FILE__ ), array(), '2.3.2' );
1958 wp_enqueue_style( 'authorizer-public-css' );
1959 }
1960
1961
1962 /**
1963 * Enqueue JS scripts and CSS styles appearing on wp-login.php.
1964 *
1965 * Action: login_enqueue_scripts
1966 *
1967 * @return void
1968 */
1969 public function login_enqueue_scripts_and_styles() {
1970 // Grab plugin settings.
1971 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
1972
1973 // Enqueue scripts appearing on wp-login.php.
1974 wp_enqueue_script( 'auth_login_scripts', plugins_url( '/js/authorizer-login.js', __FILE__ ), array( 'jquery' ), '2.3.2' );
1975
1976 // Enqueue styles appearing on wp-login.php.
1977 wp_register_style( 'authorizer-login-css', plugins_url( '/css/authorizer-login.css', __FILE__ ), array(), '2.3.2' );
1978 wp_enqueue_style( 'authorizer-login-css' );
1979
1980 /**
1981 * Developers can use the `authorizer_add_branding_option` filter
1982 * to add a radio button for "Custom WordPress login branding"
1983 * under the "Advanced" tab in Authorizer options. Example:
1984 * function my_authorizer_add_branding_option( $branding_options ) {
1985 * $new_branding_option = array(
1986 * 'value' => 'your_brand'
1987 * 'description' => 'Custom Your Brand Login Screen',
1988 * 'css_url' => 'http://url/to/your_brand.css',
1989 * 'js_url' => 'http://url/to/your_brand.js',
1990 * );
1991 * array_push( $branding_options, $new_branding_option );
1992 * return $branding_options;
1993 * }
1994 * add_filter( 'authorizer_add_branding_option', 'my_authorizer_add_branding_option' );
1995 */
1996 $branding_options = array();
1997 $branding_options = apply_filters( 'authorizer_add_branding_option', $branding_options );
1998 foreach ( $branding_options as $branding_option ) {
1999 // Make sure the custom brands have the required values.
2000 if ( ! ( is_array( $branding_option ) && array_key_exists( 'value', $branding_option ) && array_key_exists( 'css_url', $branding_option ) && array_key_exists( 'js_url', $branding_option ) ) ) {
2001 continue;
2002 }
2003 if ( $auth_settings['advanced_branding'] === $branding_option['value'] ) {
2004 wp_enqueue_script( 'auth_login_custom_scripts-' . sanitize_title( $branding_option['value'] ), $branding_option['js_url'], array( 'jquery' ), '2.3.2' );
2005 wp_register_style( 'authorizer-login-custom-css-' . sanitize_title( $branding_option['value'] ), $branding_option['css_url'], array(), '2.3.2' );
2006 wp_enqueue_style( 'authorizer-login-custom-css-' . sanitize_title( $branding_option['value'] ) );
2007 }
2008 }
2009
2010 // If we're using Google logins, load those resources.
2011 if ( '1' === $auth_settings['google'] ) {
2012 wp_enqueue_script( 'authorizer-login-custom-google', plugins_url( '/js/authorizer-login-custom_google.js', __FILE__ ), array( 'jquery' ), '2.3.2' ); ?>
2013 <meta name="google-signin-clientid" content="<?php echo esc_attr( $auth_settings['google_clientid'] ); ?>" />
2014 <meta name="google-signin-scope" content="email" />
2015 <meta name="google-signin-cookiepolicy" content="single_host_origin" />
2016 <?php
2017 }
2018 }
2019
2020
2021 /**
2022 * Load external resources in the footer of the wp-login.php page.
2023 *
2024 * Action: login_footer
2025 */
2026 public function load_login_footer_js() {
2027 // Grab plugin settings.
2028 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
2029 $ajaxurl = admin_url( 'admin-ajax.php' );
2030 if ( '1' === $auth_settings['google'] ) :
2031 ?>
2032 <script type="text/javascript">
2033 /* global location, window */
2034 // Reload login page if reauth querystring param exists,
2035 // since reauth interrupts external logins (e.g., google).
2036 if ( location.search.indexOf( 'reauth=1' ) >= 0 ) {
2037 location.href = location.href.replace( 'reauth=1', '' );
2038 }
2039
2040 // eslint-disable-next-line no-implicit-globals
2041 function authUpdateQuerystringParam( uri, key, value ) {
2042 var re = new RegExp( '([?&])' + key + '=.*?(&|$)', 'i' );
2043 var separator = uri.indexOf( '?' ) !== -1 ? '&' : '?';
2044 if ( uri.match( re ) ) {
2045 return uri.replace( re, '$1' + key + '=' + value + '$2' );
2046 } else {
2047 return uri + separator + key + '=' + value;
2048 }
2049 }
2050
2051 // eslint-disable-next-line
2052 function signInCallback( authResult ) { // jshint ignore:line
2053 var $ = jQuery;
2054 if ( authResult.status && authResult.status.signed_in ) {
2055 // Hide the sign-in button now that the user is authorized, for example:
2056 $( '#googleplus_button' ).attr( 'style', 'display: none' );
2057
2058 // Send the code to the server
2059 var ajaxurl = '<?php echo esc_attr( $ajaxurl ); ?>';
2060 $.post(ajaxurl, {
2061 action: 'process_google_login',
2062 code: authResult.code,
2063 nonce: $('#nonce_google_auth-<?php echo esc_attr( $this->get_cookie_value() ); ?>' ).val(),
2064 }, function() {
2065 // Handle or verify the server response if necessary.
2066 // console.log( response );
2067
2068 // Reload wp-login.php to continue the authentication process.
2069 var newHref = authUpdateQuerystringParam( location.href, 'external', 'google' );
2070 if ( location.href === newHref ) {
2071 location.reload();
2072 } else {
2073 location.href = newHref;
2074 }
2075 });
2076 } else {
2077 // Update the app to reflect a signed out user
2078 // Possible error values:
2079 // "user_signed_out" - User is signed-out
2080 // "access_denied" - User denied access to your app
2081 // "immediate_failed" - Could not automatically log in the user
2082 // console.log('Sign-in state: ' + authResult['error']);
2083
2084 // If user denies access, reload the login page.
2085 if ( authResult.error === 'access_denied' || authResult.error === 'user_signed_out' ) {
2086 window.location.reload();
2087 }
2088 }
2089 }
2090 </script>
2091 <?php
2092 endif;
2093 }
2094
2095
2096 /**
2097 * Create links for any external authentication services that are enabled.
2098 *
2099 * Action: login_form
2100 */
2101 public function login_form_add_external_service_links() {
2102 // Grab plugin settings.
2103 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
2104 ?>
2105 <div id="auth-external-service-login">
2106 <?php if ( '1' === $auth_settings['google'] ) : ?>
2107 <p><a id="googleplus_button" class="button button-primary button-external button-google"><span class="dashicons dashicons-googleplus"></span><span class="label"><?php esc_html_e( 'Sign in with Google', 'authorizer' ); ?></span></a></p>
2108 <?php wp_nonce_field( 'google_csrf_nonce', 'nonce_google_auth-' . $this->get_cookie_value() ); ?>
2109 <?php endif; ?>
2110
2111 <?php if ( '1' === $auth_settings['cas'] ) : ?>
2112 <p><a class="button button-primary button-external button-cas" href="<?php echo esc_attr( $this->modify_current_url_for_cas_login() ); ?>">
2113 <span class="dashicons dashicons-lock"></span>
2114 <span class="label">
2115 <?php
2116 echo esc_html(
2117 sprintf(
2118 /* TRANSLATORS: %s: Custom CAS label from authorizer options */
2119 __( 'Sign in with %s', 'authorizer' ),
2120 $auth_settings['cas_custom_label']
2121 )
2122 );
2123 ?>
2124 </span>
2125 </a></p>
2126 <?php endif; ?>
2127
2128 <?php if ( '1' === $auth_settings['advanced_hide_wp_login'] && isset( $_SERVER['QUERY_STRING'] ) && false === strpos( wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['QUERY_STRING'] ) ), PHP_URL_HOST ), 'external=wordpress' ) ) : ?>
2129 <style type="text/css">
2130 body.login-action-login form {
2131 padding-bottom: 8px;
2132 }
2133 body.login-action-login form p > label,
2134 body.login-action-login form .forgetmenot,
2135 body.login-action-login form .submit,
2136 body.login-action-login #nav { /* csslint allow: ids */
2137 display: none;
2138 }
2139 </style>
2140 <?php elseif ( '1' === $auth_settings['cas'] || '1' === $auth_settings['google'] ) : ?>
2141 <h3> &mdash; <?php esc_html_e( 'or', 'authorizer' ); ?> &mdash; </h3>
2142 <?php endif; ?>
2143 </div>
2144 <?php
2145
2146 }
2147
2148
2149 /**
2150 * Redirect to CAS login when visiting login page (only if option is
2151 * enabled, CAS is the only service, and WordPress logins are hidden).
2152 * Note: hook into wp_login_errors filter so this fires after the
2153 * authenticate hook (where the redirect to CAS happens), but before html
2154 * output is started (so the redirect header doesn't complain about data
2155 * already being sent).
2156 *
2157 * Filter: wp_login_errors
2158 *
2159 * @param object $errors WP Error object.
2160 * @param string $redirect_to Where to redirect on error.
2161 * @return WP_Error|void WP Error object or void on redirect.
2162 */
2163 public function wp_login_errors__maybe_redirect_to_cas( $errors, $redirect_to ) {
2164 // Grab plugin settings.
2165 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
2166
2167 // Check whether we should redirect to CAS.
2168 if (
2169 isset( $_SERVER['QUERY_STRING'] ) &&
2170 strpos( wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['QUERY_STRING'] ) ), PHP_URL_HOST ), 'external=wordpress' ) === false &&
2171 array_key_exists( 'cas_auto_login', $auth_settings ) && '1' === $auth_settings['cas_auto_login'] &&
2172 array_key_exists( 'cas', $auth_settings ) && '1' === $auth_settings['cas'] &&
2173 ( ! array_key_exists( 'ldap', $auth_settings ) || '1' !== $auth_settings['ldap'] ) &&
2174 ( ! array_key_exists( 'google', $auth_settings ) || '1' !== $auth_settings['google'] ) &&
2175 array_key_exists( 'advanced_hide_wp_login', $auth_settings ) && '1' === $auth_settings['advanced_hide_wp_login']
2176 ) {
2177 wp_redirect( $this->modify_current_url_for_cas_login() );
2178 exit;
2179 }
2180
2181 return $errors;
2182 }
2183
2184
2185 /**
2186 * Set a unique cookie to add to Google auth nonce to avoid CSRF detection.
2187 * Note: hook into login_init so this fires at the start of the visit to
2188 * wp-login.php, but before any html output is started (so setting the
2189 * cookie header doesn't complain about data already being sent).
2190 *
2191 * Action: login_init
2192 *
2193 * @return void
2194 */
2195 public function login_init__maybe_set_google_nonce_cookie() {
2196 // Grab plugin settings.
2197 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
2198
2199 // If Google logins are enabled, make sure the cookie is set.
2200 if ( array_key_exists( 'google', $auth_settings ) && '1' === $auth_settings['google'] ) {
2201 if ( ! isset( $_COOKIE['login_unique'] ) ) {
2202 $this->cookie_value = md5( rand() );
2203 setcookie( 'login_unique', $this->cookie_value, time() + 1800, '/', defined( 'COOKIE_DOMAIN' ) ? COOKIE_DOMAIN : '' );
2204 $_COOKIE['login_unique'] = $this->cookie_value;
2205 }
2206 }
2207 }
2208
2209
2210 /**
2211 * Implements hook: do_action( 'wp_login_failed', $username );
2212 * Update the user meta for the user that just failed logging in.
2213 * Keep track of time of last failed attempt and number of failed attempts.
2214 *
2215 * Action: wp_login_failed
2216 *
2217 * @param string $username Username to update login count for.
2218 * @return void
2219 */
2220 public function update_login_failed_count( $username ) {
2221 // Grab plugin settings.
2222 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
2223
2224 // Get user trying to log in.
2225 // If this isn't a real user, update the global failed attempt
2226 // variables. We'll use these global variables to institute the
2227 // lockouts on nonexistent accounts. We do this so an attacker
2228 // won't be able to determine which accounts are real by which
2229 // accounts get locked out on multiple invalid attempts.
2230 $user = get_user_by( 'login', $username );
2231
2232 if ( false !== $user ) {
2233 $last_attempt = get_user_meta( $user->ID, 'auth_settings_advanced_lockouts_time_last_failed', true );
2234 $num_attempts = get_user_meta( $user->ID, 'auth_settings_advanced_lockouts_failed_attempts', true );
2235 } else {
2236 $last_attempt = get_option( 'auth_settings_advanced_lockouts_time_last_failed' );
2237 $num_attempts = get_option( 'auth_settings_advanced_lockouts_failed_attempts' );
2238 }
2239
2240 // Make sure $last_attempt (time) and $num_attempts are positive integers.
2241 // Note: this addresses resetting them if either is unset from above.
2242 $last_attempt = abs( intval( $last_attempt ) );
2243 $num_attempts = abs( intval( $num_attempts ) );
2244
2245 // Reset the failed attempt count if the time since the last
2246 // failed attempt is greater than the reset duration.
2247 $time_since_last_fail = time() - $last_attempt;
2248 $reset_duration = $auth_settings['advanced_lockouts']['reset_duration'] * 60; // minutes to seconds.
2249 if ( $time_since_last_fail > $reset_duration ) {
2250 $num_attempts = 0;
2251 }
2252
2253 // Set last failed time to now and increment last failed count.
2254 if ( false !== $user ) {
2255 update_user_meta( $user->ID, 'auth_settings_advanced_lockouts_time_last_failed', time() );
2256 update_user_meta( $user->ID, 'auth_settings_advanced_lockouts_failed_attempts', $num_attempts + 1 );
2257 } else {
2258 update_option( 'auth_settings_advanced_lockouts_time_last_failed', time() );
2259 update_option( 'auth_settings_advanced_lockouts_failed_attempts', $num_attempts + 1 );
2260 }
2261 }
2262
2263
2264 /**
2265 * When they successfully log in, make sure WordPress users are in the approved list.
2266 *
2267 * Action: wp_login
2268 *
2269 * @param string $user_login Username of the user logging in.
2270 * @param object $user WP_User object of the user logging in.
2271 * @return void
2272 */
2273 public function ensure_wordpress_user_in_approved_list_on_login( $user_login, $user ) {
2274 $this->add_user_to_authorizer_when_created( $user->user_email, $user->user_registered, $user->roles );
2275 }
2276
2277
2278 /**
2279 * Overwrite the URL for the lost password link on the login form.
2280 * If we're authenticating against an external service, standard
2281 * WordPress password resets won't work.
2282 *
2283 * Filter: lostpassword_url
2284 *
2285 * @param string $lostpassword_url URL to reset password.
2286 * @return string URL to reset password.
2287 */
2288 public function custom_lostpassword_url( $lostpassword_url ) {
2289 // Grab plugin settings.
2290 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
2291
2292 if (
2293 array_key_exists( 'ldap_lostpassword_url', $auth_settings ) &&
2294 filter_var( $auth_settings['ldap_lostpassword_url'], FILTER_VALIDATE_URL )
2295 ) {
2296 $lostpassword_url = $auth_settings['ldap_lostpassword_url'];
2297 }
2298 return $lostpassword_url;
2299 }
2300
2301
2302
2303 /**
2304 * ***************************
2305 * Options page
2306 * ***************************
2307 */
2308
2309
2310
2311 /**
2312 * Add a link to this plugin's settings page from the WordPress Plugins page.
2313 * Called from "plugin_action_links" filter in __construct() above.
2314 *
2315 * Filter: plugin_action_links_authorizer.php
2316 *
2317 * @param array $links Admin sidebar links.
2318 * @return array Admin sidebar links with Authorizer added.
2319 */
2320 public function plugin_settings_link( $links ) {
2321 $admin_menu = $this->get_plugin_option( 'advanced_admin_menu' );
2322 $settings_url = 'settings' === $admin_menu ? admin_url( 'options-general.php?page=authorizer' ) : admin_url( 'admin.php?page=authorizer' );
2323 array_unshift( $links, '<a href="' . $settings_url . '">' . __( 'Settings', 'authorizer' ) . '</a>' );
2324 return $links;
2325 }
2326
2327
2328 /**
2329 * Add a link to this plugin's network settings page from the WordPress Plugins page.
2330 * Called from "network_admin_plugin_action_links" filter in __construct() above.
2331 *
2332 * Filter: network_admin_plugin_action_links_authorizer.php
2333 *
2334 * @param array $links Network admin sidebar links.
2335 * @return array Network admin sidebar links with Authorizer added.
2336 */
2337 public function network_admin_plugin_settings_link( $links ) {
2338 $settings_link = '<a href="admin.php?page=authorizer">' . __( 'Network Settings', 'authorizer' ) . '</a>';
2339 array_unshift( $links, $settings_link );
2340 return $links;
2341 }
2342
2343
2344 /**
2345 * Create the options page under Dashboard > Settings.
2346 *
2347 * Action: admin_menu
2348 */
2349 public function add_plugin_page() {
2350 $admin_menu = $this->get_plugin_option( 'advanced_admin_menu' );
2351 if ( 'settings' === $admin_menu ) {
2352 // @see http://codex.wordpress.org/Function_Reference/add_options_page
2353 add_options_page(
2354 'Authorizer',
2355 'Authorizer',
2356 'create_users',
2357 'authorizer',
2358 array( $this, 'create_admin_page' )
2359 );
2360 } else {
2361 // @see http://codex.wordpress.org/Function_Reference/add_menu_page
2362 add_menu_page(
2363 'Authorizer',
2364 'Authorizer',
2365 'create_users',
2366 'authorizer',
2367 array( $this, 'create_admin_page' ),
2368 'dashicons-groups',
2369 '99.0018465' // position (decimal is to make overlap with other plugins less likely).
2370 );
2371 }
2372 }
2373
2374
2375 /**
2376 * Output the HTML for the options page.
2377 */
2378 public function create_admin_page() {
2379 ?>
2380 <div class="wrap">
2381 <h2><?php esc_html_e( 'Authorizer Settings', 'authorizer' ); ?></h2>
2382 <form method="post" action="options.php" autocomplete="off">
2383 <?php
2384 // This prints out all hidden settings fields.
2385 settings_fields( 'auth_settings_group' );
2386 // This prints out all the sections.
2387 do_settings_sections( 'authorizer' );
2388 submit_button();
2389 ?>
2390 </form>
2391 </div>
2392 <?php
2393 }
2394
2395
2396 /**
2397 * Load external resources on this plugin's options page.
2398 *
2399 * Action: load-settings_page_authorizer
2400 * Action: load-toplevel_page_authorizer
2401 * Action: admin_head-index.php
2402 */
2403 public function load_options_page() {
2404 wp_enqueue_script(
2405 'authorizer',
2406 plugins_url( 'js/authorizer.js', __FILE__ ),
2407 array( 'jquery-effects-shake' ), '2.7.2', true
2408 );
2409 wp_localize_script(
2410 'authorizer', 'authL10n', array(
2411 'baseurl' => get_bloginfo( 'url' ),
2412 'saved' => esc_html__( 'Saved', 'authorizer' ),
2413 'duplicate' => esc_html__( 'Duplicate', 'authorizer' ),
2414 'failed' => esc_html__( 'Failed', 'authorizer' ),
2415 'local_wordpress_user' => esc_html__( 'Local WordPress user', 'authorizer' ),
2416 'block_ban_user' => esc_html__( 'Block/Ban user', 'authorizer' ),
2417 'remove_user' => esc_html__( 'Remove user', 'authorizer' ),
2418 'no_users_in' => esc_html__( 'No users in', 'authorizer' ),
2419 'save_changes' => esc_html__( 'Save Changes', 'authorizer' ),
2420 'private_pages' => esc_html__( 'Private Pages', 'authorizer' ),
2421 'public_pages' => esc_html__( 'Public Pages', 'authorizer' ),
2422 'first_page' => esc_html__( 'First page' ),
2423 'previous_page' => esc_html__( 'Previous page' ),
2424 'next_page' => esc_html__( 'Next page' ),
2425 'last_page' => esc_html__( 'Last page' ),
2426 'is_network_admin' => is_network_admin() ? '1' : '0',
2427 )
2428 );
2429
2430 wp_enqueue_script(
2431 'jquery-autogrow-textarea',
2432 plugins_url( 'vendor/jquery.autogrow-textarea/jquery.autogrow-textarea.js', __FILE__ ),
2433 array( 'jquery' ), '2.7.0', true
2434 );
2435
2436 wp_enqueue_script(
2437 'jquery.multi-select',
2438 plugins_url( 'vendor/jquery.multi-select/js/jquery.multi-select.js', __FILE__ ),
2439 array( 'jquery' ), '1.8', true
2440 );
2441
2442 wp_register_style( 'authorizer-css', plugins_url( 'css/authorizer.css', __FILE__ ), array(), '2.7.3' );
2443 wp_enqueue_style( 'authorizer-css' );
2444
2445 wp_register_style( 'jquery-multi-select-css', plugins_url( 'vendor/jquery.multi-select/css/multi-select.css', __FILE__ ), array(), '1.8' );
2446 wp_enqueue_style( 'jquery-multi-select-css' );
2447
2448 add_action( 'admin_notices', array( $this, 'admin_notices' ) ); // Add any notices to the top of the options page.
2449 add_action( 'admin_head', array( $this, 'admin_head' ) ); // Add help documentation to the options page.
2450 }
2451
2452
2453 /**
2454 * Show custom admin notice.
2455 *
2456 * Note: currently unused, but if anywhere we:
2457 * add_option( 'auth_settings_advanced_admin_notice, 'Your message.' );
2458 * It will display and then delete that message on the admin dashboard.
2459 *
2460 * Filter: admin_notices
2461 * filter: network_admin_notices
2462 */
2463 public function show_advanced_admin_notice() {
2464 $notice = get_option( 'auth_settings_advanced_admin_notice' );
2465 delete_option( 'auth_settings_advanced_admin_notice' );
2466
2467 if ( $notice && strlen( $notice ) > 0 ) {
2468 ?>
2469 <div class="error">
2470 <p><?php echo wp_kses( $notice, $this->allowed_html ); ?></p>
2471 </div>
2472 <?php
2473 }
2474 }
2475
2476
2477 /**
2478 * Add notices to the top of the options page.
2479 *
2480 * Action: load-settings_page_authorizer > admin_notices
2481 *
2482 * Description: Check for invalid settings combinations and show a warning message, e.g.:
2483 * if ( cas url inaccessible ) : ?>
2484 * <div class='updated settings-error'><p>Can't reach CAS server.</p></div>
2485 * <?php endif;
2486 */
2487 public function admin_notices() {
2488 // Grab plugin settings.
2489 $auth_settings = $this->get_plugin_options( WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
2490
2491 if ( '1' === $auth_settings['cas'] ) :
2492 // Check if provided CAS URL is accessible.
2493 $protocol = in_array( strval( $auth_settings['cas_port'] ), array( '80', '8080' ), true ) ? 'http' : 'https';
2494 $cas_url = $protocol . '://' . $auth_settings['cas_host'] . ':' . $auth_settings['cas_port'] . $auth_settings['cas_path'];
2495 $legacy_cas_url = trailingslashit( $cas_url ) . 'login'; // Check the specific CAS login endpoint (old; some servers don't register a ./login endpoint, use serviceValidate instead).
2496 $cas_url = trailingslashit( $cas_url ) . 'serviceValidate'; // Check the specific CAS login endpoint.
2497 if ( ! $this->url_is_accessible( $cas_url ) && ! $this->url_is_accessible( $legacy_cas_url ) ) :
2498 $authorizer_options_url = 'settings' === $auth_settings['advanced_admin_menu'] ? admin_url( 'options-general.php?page=authorizer' ) : admin_url( '?page=authorizer' );
2499 ?>
2500 <div class='notice notice-warning is-dismissible'>
2501 <p><?php esc_html_e( "Can't reach CAS server. Please provide", 'authorizer' ); ?> <a href='<?php echo esc_attr( $authorizer_options_url ); ?>&tab=external'><?php esc_html_e( 'accurate CAS settings', 'authorizer' ); ?></a> <?php esc_html_e( 'if you intend to use it.', 'authorizer' ); ?></p>
2502 </div>
2503 <?php
2504 endif;
2505 endif;
2506 }
2507
2508
2509 /**
2510 * Create sections and options.
2511 *
2512 * Action: admin_init
2513 */
2514 public function page_init() {
2515 /**
2516 * Create one setting that holds all the options (array).
2517 *
2518 * @see http://codex.wordpress.org/Function_Reference/register_setting
2519 * @see http://codex.wordpress.org/Function_Reference/add_settings_section
2520 * @see http://codex.wordpress.org/Function_Reference/add_settings_field
2521 */
2522 register_setting(
2523 'auth_settings_group',
2524 'auth_settings',
2525 array( $this, 'sanitize_options' )
2526 );
2527
2528 add_settings_section(
2529 'auth_settings_tabs',
2530 '',
2531 array( $this, 'print_section_info_tabs' ),
2532 'authorizer'
2533 );
2534
2535 // Create Access Lists section.
2536 add_settings_section(
2537 'auth_settings_lists',
2538 '',
2539 array( $this, 'print_section_info_access_lists' ),
2540 'authorizer'
2541 );
2542
2543 // Create Login Access section.
2544 add_settings_section(
2545 'auth_settings_access_login',
2546 '',
2547 array( $this, 'print_section_info_access_login' ),
2548 'authorizer'
2549 );
2550 add_settings_field(
2551 'auth_settings_access_who_can_login',
2552 __( 'Who can log into the site?', 'authorizer' ),
2553 array( $this, 'print_radio_auth_access_who_can_login' ),
2554 'authorizer',
2555 'auth_settings_access_login'
2556 );
2557 add_settings_field(
2558 'auth_settings_access_role_receive_pending_emails',
2559 __( 'Which role should receive email notifications about pending users?', 'authorizer' ),
2560 array( $this, 'print_select_auth_access_role_receive_pending_emails' ),
2561 'authorizer',
2562 'auth_settings_access_login'
2563 );
2564 add_settings_field(
2565 'auth_settings_access_pending_redirect_to_message',
2566 __( 'What message should pending users see after attempting to log in?', 'authorizer' ),
2567 array( $this, 'print_wysiwyg_auth_access_pending_redirect_to_message' ),
2568 'authorizer',
2569 'auth_settings_access_login'
2570 );
2571 add_settings_field(
2572 'auth_settings_access_blocked_redirect_to_message',
2573 __( 'What message should blocked users see after attempting to log in?', 'authorizer' ),
2574 array( $this, 'print_wysiwyg_auth_access_blocked_redirect_to_message' ),
2575 'authorizer',
2576 'auth_settings_access_login'
2577 );
2578 add_settings_field(
2579 'auth_settings_access_should_email_approved_users',
2580 __( 'Send welcome email to new approved users?', 'authorizer' ),
2581 array( $this, 'print_checkbox_auth_access_should_email_approved_users' ),
2582 'authorizer',
2583 'auth_settings_access_login'
2584 );
2585 add_settings_field(
2586 'auth_settings_access_email_approved_users_subject',
2587 __( 'Welcome email subject', 'authorizer' ),
2588 array( $this, 'print_text_auth_access_email_approved_users_subject' ),
2589 'authorizer',
2590 'auth_settings_access_login'
2591 );
2592 add_settings_field(
2593 'auth_settings_access_email_approved_users_body',
2594 __( 'Welcome email body', 'authorizer' ),
2595 array( $this, 'print_wysiwyg_auth_access_email_approved_users_body' ),
2596 'authorizer',
2597 'auth_settings_access_login'
2598 );
2599
2600 // Create Public Access section.
2601 add_settings_section(
2602 'auth_settings_access_public',
2603 '',
2604 array( $this, 'print_section_info_access_public' ),
2605 'authorizer'
2606 );
2607 add_settings_field(
2608 'auth_settings_access_who_can_view',
2609 __( 'Who can view the site?', 'authorizer' ),
2610 array( $this, 'print_radio_auth_access_who_can_view' ),
2611 'authorizer',
2612 'auth_settings_access_public'
2613 );
2614 add_settings_field(
2615 'auth_settings_access_public_pages',
2616 __( 'What pages (if any) should be available to everyone?', 'authorizer' ),
2617 array( $this, 'print_multiselect_auth_access_public_pages' ),
2618 'authorizer',
2619 'auth_settings_access_public'
2620 );
2621 add_settings_field(
2622 'auth_settings_access_redirect',
2623 __( 'What happens to people without access when they visit a private page?', 'authorizer' ),
2624 array( $this, 'print_radio_auth_access_redirect' ),
2625 'authorizer',
2626 'auth_settings_access_public'
2627 );
2628 add_settings_field(
2629 'auth_settings_access_public_warning',
2630 __( 'What happens to people without access when they visit a public page?', 'authorizer' ),
2631 array( $this, 'print_radio_auth_access_public_warning' ),
2632 'authorizer',
2633 'auth_settings_access_public'
2634 );
2635 add_settings_field(
2636 'auth_settings_access_redirect_to_message',
2637 __( 'What message should people without access see?', 'authorizer' ),
2638 array( $this, 'print_wysiwyg_auth_access_redirect_to_message' ),
2639 'authorizer',
2640 'auth_settings_access_public'
2641 );
2642
2643 // Create External Service Settings section.
2644 add_settings_section(
2645 'auth_settings_external',
2646 '',
2647 array( $this, 'print_section_info_external' ),
2648 'authorizer'
2649 );
2650 add_settings_field(
2651 'auth_settings_access_default_role',
2652 __( 'Default role for new users', 'authorizer' ),
2653 array( $this, 'print_select_auth_access_default_role' ),
2654 'authorizer',
2655 'auth_settings_external'
2656 );
2657 add_settings_field(
2658 'auth_settings_external_google',
2659 __( 'Google Logins', 'authorizer' ),
2660 array( $this, 'print_checkbox_auth_external_google' ),
2661 'authorizer',
2662 'auth_settings_external'
2663 );
2664 add_settings_field(
2665 'auth_settings_google_clientid',
2666 __( 'Google Client ID', 'authorizer' ),
2667 array( $this, 'print_text_google_clientid' ),
2668 'authorizer',
2669 'auth_settings_external'
2670 );
2671 add_settings_field(
2672 'auth_settings_google_clientsecret',
2673 __( 'Google Client Secret', 'authorizer' ),
2674 array( $this, 'print_text_google_clientsecret' ),
2675 'authorizer',
2676 'auth_settings_external'
2677 );
2678 add_settings_field(
2679 'auth_settings_google_hosteddomain',
2680 __( 'Google Hosted Domain', 'authorizer' ),
2681 array( $this, 'print_text_google_hosteddomain' ),
2682 'authorizer',
2683 'auth_settings_external'
2684 );
2685 add_settings_field(
2686 'auth_settings_external_cas',
2687 __( 'CAS Logins', 'authorizer' ),
2688 array( $this, 'print_checkbox_auth_external_cas' ),
2689 'authorizer',
2690 'auth_settings_external'
2691 );
2692 add_settings_field(
2693 'auth_settings_cas_custom_label',
2694 __( 'CAS custom label', 'authorizer' ),
2695 array( $this, 'print_text_cas_custom_label' ),
2696 'authorizer',
2697 'auth_settings_external'
2698 );
2699 add_settings_field(
2700 'auth_settings_cas_host',
2701 __( 'CAS server hostname', 'authorizer' ),
2702 array( $this, 'print_text_cas_host' ),
2703 'authorizer',
2704 'auth_settings_external'
2705 );
2706 add_settings_field(
2707 'auth_settings_cas_port',
2708 __( 'CAS server port', 'authorizer' ),
2709 array( $this, 'print_text_cas_port' ),
2710 'authorizer',
2711 'auth_settings_external'
2712 );
2713 add_settings_field(
2714 'auth_settings_cas_path',
2715 __( 'CAS server path/context', 'authorizer' ),
2716 array( $this, 'print_text_cas_path' ),
2717 'authorizer',
2718 'auth_settings_external'
2719 );
2720 add_settings_field(
2721 'auth_settings_cas_version',
2722 'CAS server version',
2723 array( $this, 'print_select_cas_version' ),
2724 'authorizer',
2725 'auth_settings_external'
2726 );
2727 add_settings_field(
2728 'auth_settings_cas_attr_email',
2729 __( 'CAS attribute containing email address', 'authorizer' ),
2730 array( $this, 'print_text_cas_attr_email' ),
2731 'authorizer',
2732 'auth_settings_external'
2733 );
2734 add_settings_field(
2735 'auth_settings_cas_attr_first_name',
2736 __( 'CAS attribute containing first name', 'authorizer' ),
2737 array( $this, 'print_text_cas_attr_first_name' ),
2738 'authorizer',
2739 'auth_settings_external'
2740 );
2741 add_settings_field(
2742 'auth_settings_cas_attr_last_name',
2743 __( 'CAS attribute containing last name', 'authorizer' ),
2744 array( $this, 'print_text_cas_attr_last_name' ),
2745 'authorizer',
2746 'auth_settings_external'
2747 );
2748 add_settings_field(
2749 'auth_settings_cas_attr_update_on_login',
2750 __( 'CAS attribute update', 'authorizer' ),
2751 array( $this, 'print_checkbox_cas_attr_update_on_login' ),
2752 'authorizer',
2753 'auth_settings_external'
2754 );
2755 add_settings_field(
2756 'auth_settings_cas_auto_login',
2757 __( 'CAS automatic login', 'authorizer' ),
2758 array( $this, 'print_checkbox_cas_auto_login' ),
2759 'authorizer',
2760 'auth_settings_external'
2761 );
2762 add_settings_field(
2763 'auth_settings_external_ldap',
2764 __( 'LDAP Logins', 'authorizer' ),
2765 array( $this, 'print_checkbox_auth_external_ldap' ),
2766 'authorizer',
2767 'auth_settings_external'
2768 );
2769 add_settings_field(
2770 'auth_settings_ldap_host',
2771 __( 'LDAP Host', 'authorizer' ),
2772 array( $this, 'print_text_ldap_host' ),
2773 'authorizer',
2774 'auth_settings_external'
2775 );
2776 add_settings_field(
2777 'auth_settings_ldap_port',
2778 __( 'LDAP Port', 'authorizer' ),
2779 array( $this, 'print_text_ldap_port' ),
2780 'authorizer',
2781 'auth_settings_external'
2782 );
2783 add_settings_field(
2784 'auth_settings_ldap_tls',
2785 __( 'Use TLS', 'authorizer' ),
2786 array( $this, 'print_checkbox_ldap_tls' ),
2787 'authorizer',
2788 'auth_settings_external'
2789 );
2790 add_settings_field(
2791 'auth_settings_ldap_search_base',
2792 __( 'LDAP Search Base', 'authorizer' ),
2793 array( $this, 'print_text_ldap_search_base' ),
2794 'authorizer',
2795 'auth_settings_external'
2796 );
2797 add_settings_field(
2798 'auth_settings_ldap_uid',
2799 __( 'LDAP attribute containing username', 'authorizer' ),
2800 array( $this, 'print_text_ldap_uid' ),
2801 'authorizer',
2802 'auth_settings_external'
2803 );
2804 add_settings_field(
2805 'auth_settings_ldap_attr_email',
2806 __( 'LDAP attribute containing email address', 'authorizer' ),
2807 array( $this, 'print_text_ldap_attr_email' ),
2808 'authorizer',
2809 'auth_settings_external'
2810 );
2811 add_settings_field(
2812 'auth_settings_ldap_user',
2813 __( 'LDAP Directory User', 'authorizer' ),
2814 array( $this, 'print_text_ldap_user' ),
2815 'authorizer',
2816 'auth_settings_external'
2817 );
2818 add_settings_field(
2819 'auth_settings_ldap_password',
2820 __( 'LDAP Directory User Password', 'authorizer' ),
2821 array( $this, 'print_password_ldap_password' ),
2822 'authorizer',
2823 'auth_settings_external'
2824 );
2825 add_settings_field(
2826 'auth_settings_ldap_lostpassword_url',
2827 __( 'Custom lost password URL', 'authorizer' ),
2828 array( $this, 'print_text_ldap_lostpassword_url' ),
2829 'authorizer',
2830 'auth_settings_external'
2831 );
2832 add_settings_field(
2833 'auth_settings_ldap_attr_first_name',
2834 __( 'LDAP attribute containing first name', 'authorizer' ),
2835 array( $this, 'print_text_ldap_attr_first_name' ),
2836 'authorizer',
2837 'auth_settings_external'
2838 );
2839 add_settings_field(
2840 'auth_settings_ldap_attr_last_name',
2841 __( 'LDAP attribute containing last name', 'authorizer' ),
2842 array( $this, 'print_text_ldap_attr_last_name' ),
2843 'authorizer',
2844 'auth_settings_external'
2845 );
2846 add_settings_field(
2847 'auth_settings_ldap_attr_update_on_login',
2848 __( 'LDAP attribute update', 'authorizer' ),
2849 array( $this, 'print_checkbox_ldap_attr_update_on_login' ),
2850 'authorizer',
2851 'auth_settings_external'
2852 );
2853
2854 // Create Advanced Settings section.
2855 add_settings_section(
2856 'auth_settings_advanced',
2857 '',
2858 array( $this, 'print_section_info_advanced' ),
2859 'authorizer'
2860 );
2861 add_settings_field(
2862 'auth_settings_advanced_lockouts',
2863 __( 'Limit invalid login attempts', 'authorizer' ),
2864 array( $this, 'print_text_auth_advanced_lockouts' ),
2865 'authorizer',
2866 'auth_settings_advanced'
2867 );
2868 add_settings_field(
2869 'auth_settings_advanced_hide_wp_login',
2870 __( 'Hide WordPress Login', 'authorizer' ),
2871 array( $this, 'print_checkbox_auth_advanced_hide_wp_login' ),
2872 'authorizer',
2873 'auth_settings_advanced'
2874 );
2875 add_settings_field(
2876 'auth_settings_advanced_branding',
2877 __( 'Custom WordPress login branding', 'authorizer' ),
2878 array( $this, 'print_radio_auth_advanced_branding' ),
2879 'authorizer',
2880 'auth_settings_advanced'
2881 );
2882 add_settings_field(
2883 'auth_settings_advanced_admin_menu',
2884 __( 'Authorizer admin menu item location', 'authorizer' ),
2885 array( $this, 'print_radio_auth_advanced_admin_menu' ),
2886 'authorizer',
2887 'auth_settings_advanced'
2888 );
2889 add_settings_field(
2890 'auth_settings_advanced_usermeta',
2891 __( 'Show custom usermeta in user list', 'authorizer' ),
2892 array( $this, 'print_select_auth_advanced_usermeta' ),
2893 'authorizer',
2894 'auth_settings_advanced'
2895 );
2896 add_settings_field(
2897 'auth_settings_advanced_users_per_page',
2898 __( 'Number of users per page', 'authorizer' ),
2899 array( $this, 'print_text_auth_advanced_users_per_page' ),
2900 'authorizer',
2901 'auth_settings_advanced'
2902 );
2903 add_settings_field(
2904 'auth_settings_advanced_users_sort_by',
2905 __( 'Approved users sort method', 'authorizer' ),
2906 array( $this, 'print_select_auth_advanced_users_sort_by' ),
2907 'authorizer',
2908 'auth_settings_advanced'
2909 );
2910 add_settings_field(
2911 'auth_settings_advanced_users_sort_order',
2912 __( 'Approved users sort order', 'authorizer' ),
2913 array( $this, 'print_select_auth_advanced_users_sort_order' ),
2914 'authorizer',
2915 'auth_settings_advanced'
2916 );
2917 add_settings_field(
2918 'auth_settings_advanced_widget_enabled',
2919 __( 'Show dashboard widget to admin users', 'authorizer' ),
2920 array( $this, 'print_checkbox_auth_advanced_widget_enabled' ),
2921 'authorizer',
2922 'auth_settings_advanced'
2923 );
2924 // On multisite installs, add an option to override all multisite settings on individual sites.
2925 if ( is_multisite() ) {
2926 add_settings_field(
2927 'auth_settings_advanced_override_multisite',
2928 __( 'Override multisite options', 'authorizer' ),
2929 array( $this, 'print_checkbox_auth_advanced_override_multisite' ),
2930 'authorizer',
2931 'auth_settings_advanced'
2932 );
2933 }
2934 }
2935
2936
2937 /**
2938 * Set meaningful defaults for the plugin options.
2939 *
2940 * Note: This function is called on plugin activation.
2941 */
2942 private function set_default_options() {
2943 global $wp_roles;
2944
2945 $auth_settings = get_option( 'auth_settings' );
2946 if ( false === $auth_settings ) {
2947 $auth_settings = array();
2948 }
2949
2950 // Access Lists Defaults.
2951 $auth_settings_access_users_pending = get_option( 'auth_settings_access_users_pending' );
2952 if ( false === $auth_settings_access_users_pending ) {
2953 $auth_settings_access_users_pending = array();
2954 }
2955 $auth_settings_access_users_approved = get_option( 'auth_settings_access_users_approved' );
2956 if ( false === $auth_settings_access_users_approved ) {
2957 $auth_settings_access_users_approved = array();
2958 }
2959 $auth_settings_access_users_blocked = get_option( 'auth_settings_access_users_blocked' );
2960 if ( false === $auth_settings_access_users_blocked ) {
2961 $auth_settings_access_users_blocked = array();
2962 }
2963
2964 // Login Access Defaults.
2965 if ( ! array_key_exists( 'access_who_can_login', $auth_settings ) ) {
2966 $auth_settings['access_who_can_login'] = 'approved_users';
2967 }
2968 if ( ! array_key_exists( 'access_role_receive_pending_emails', $auth_settings ) ) {
2969 $auth_settings['access_role_receive_pending_emails'] = '---';
2970 }
2971 if ( ! array_key_exists( 'access_pending_redirect_to_message', $auth_settings ) ) {
2972 $auth_settings['access_pending_redirect_to_message'] = '<p>' . __( "You're not currently allowed to view this site. Your administrator has been notified, and once he/she has approved your request, you will be able to log in. If you need any other help, please contact your administrator.", 'authorizer' ) . '</p>';
2973 }
2974 if ( ! array_key_exists( 'access_blocked_redirect_to_message', $auth_settings ) ) {
2975 $auth_settings['access_blocked_redirect_to_message'] = '<p>' . __( "You're not currently allowed to log into this site. If you think this is a mistake, please contact your administrator.", 'authorizer' ) . '</p>';
2976 }
2977 if ( ! array_key_exists( 'access_should_email_approved_users', $auth_settings ) ) {
2978 $auth_settings['access_should_email_approved_users'] = '';
2979 }
2980 if ( ! array_key_exists( 'access_email_approved_users_subject', $auth_settings ) ) {
2981 $auth_settings['access_email_approved_users_subject'] = sprintf(
2982 /* TRANSLATORS: %s: Shortcode for name of site */
2983 __( 'Welcome to %s!', 'authorizer' ),
2984 '[site_name]'
2985 );
2986 }
2987 if ( ! array_key_exists( 'access_email_approved_users_body', $auth_settings ) ) {
2988 $auth_settings['access_email_approved_users_body'] = sprintf(
2989 /* TRANSLATORS: 1: Shortcode for user email 2: Shortcode for site name 3: Shortcode for site URL */
2990 __( "Hello %1\$s,\nWelcome to %2\$s! You now have access to all content on the site. Please visit us here:\n%3\$s\n", 'authorizer' ),
2991 '[user_email]',
2992 '[site_name]',
2993 '[site_url]'
2994 );
2995 }
2996
2997 // Public Access to Private Page Defaults.
2998 if ( ! array_key_exists( 'access_who_can_view', $auth_settings ) ) {
2999 $auth_settings['access_who_can_view'] = 'everyone';
3000 }
3001 if ( ! array_key_exists( 'access_public_pages', $auth_settings ) ) {
3002 $auth_settings['access_public_pages'] = array();
3003 }
3004 if ( ! array_key_exists( 'access_redirect', $auth_settings ) ) {
3005 $auth_settings['access_redirect'] = 'login';
3006 }
3007 if ( ! array_key_exists( 'access_public_warning', $auth_settings ) ) {
3008 $auth_settings['access_public_warning'] = 'no_warning';
3009 }
3010 if ( ! array_key_exists( 'access_redirect_to_message', $auth_settings ) ) {
3011 $auth_settings['access_redirect_to_message'] = '<p>' . __( 'Notice: You are browsing this site anonymously, and only have access to a portion of its content.', 'authorizer' ) . '</p>';
3012 }
3013
3014 // External Service Defaults.
3015 if ( ! array_key_exists( 'access_default_role', $auth_settings ) ) {
3016 // Set default role to 'student' if that role exists, 'subscriber' otherwise.
3017 $all_roles = $wp_roles->roles;
3018 $editable_roles = apply_filters( 'editable_roles', $all_roles );
3019 if ( array_key_exists( 'student', $editable_roles ) ) {
3020 $auth_settings['access_default_role'] = 'student';
3021 } else {
3022 $auth_settings['access_default_role'] = 'subscriber';
3023 }
3024 }
3025
3026 if ( ! array_key_exists( 'google', $auth_settings ) ) {
3027 $auth_settings['google'] = '';
3028 }
3029 if ( ! array_key_exists( 'cas', $auth_settings ) ) {
3030 $auth_settings['cas'] = '';
3031 }
3032 if ( ! array_key_exists( 'ldap', $auth_settings ) ) {
3033 $auth_settings['ldap'] = '';
3034 }
3035
3036 if ( ! array_key_exists( 'google_clientid', $auth_settings ) ) {
3037 $auth_settings['google_clientid'] = '';
3038 }
3039 if ( ! array_key_exists( 'google_clientsecret', $auth_settings ) ) {
3040 $auth_settings['google_clientsecret'] = '';
3041 }
3042 if ( ! array_key_exists( 'google_hosteddomain', $auth_settings ) ) {
3043 $auth_settings['google_hosteddomain'] = '';
3044 }
3045
3046 if ( ! array_key_exists( 'cas_custom_label', $auth_settings ) ) {
3047 $auth_settings['cas_custom_label'] = 'CAS';
3048 }
3049 if ( ! array_key_exists( 'cas_host', $auth_settings ) ) {
3050 $auth_settings['cas_host'] = '';
3051 }
3052 if ( ! array_key_exists( 'cas_port', $auth_settings ) ) {
3053 $auth_settings['cas_port'] = '';
3054 }
3055 if ( ! array_key_exists( 'cas_path', $auth_settings ) ) {
3056 $auth_settings['cas_path'] = '';
3057 }
3058 if ( ! array_key_exists( 'cas_version', $auth_settings ) ) {
3059 $auth_settings['cas_version'] = 'SAML_VERSION_1_1';
3060 }
3061 if ( ! array_key_exists( 'cas_attr_email', $auth_settings ) ) {
3062 $auth_settings['cas_attr_email'] = '';
3063 }
3064 if ( ! array_key_exists( 'cas_attr_first_name', $auth_settings ) ) {
3065 $auth_settings['cas_attr_first_name'] = '';
3066 }
3067 if ( ! array_key_exists( 'cas_attr_last_name', $auth_settings ) ) {
3068 $auth_settings['cas_attr_last_name'] = '';
3069 }
3070 if ( ! array_key_exists( 'cas_attr_update_on_login', $auth_settings ) ) {
3071 $auth_settings['cas_attr_update_on_login'] = '';
3072 }
3073 if ( ! array_key_exists( 'cas_auto_login', $auth_settings ) ) {
3074 $auth_settings['cas_auto_login'] = '';
3075 }
3076
3077 if ( ! array_key_exists( 'ldap_host', $auth_settings ) ) {
3078 $auth_settings['ldap_host'] = '';
3079 }
3080 if ( ! array_key_exists( 'ldap_port', $auth_settings ) ) {
3081 $auth_settings['ldap_port'] = '389';
3082 }
3083 if ( ! array_key_exists( 'ldap_tls', $auth_settings ) ) {
3084 $auth_settings['ldap_tls'] = '1';
3085 }
3086 if ( ! array_key_exists( 'ldap_search_base', $auth_settings ) ) {
3087 $auth_settings['ldap_search_base'] = '';
3088 }
3089 if ( ! array_key_exists( 'ldap_uid', $auth_settings ) ) {
3090 $auth_settings['ldap_uid'] = 'uid';
3091 }
3092 if ( ! array_key_exists( 'ldap_attr_email', $auth_settings ) ) {
3093 $auth_settings['ldap_attr_email'] = '';
3094 }
3095 if ( ! array_key_exists( 'ldap_user', $auth_settings ) ) {
3096 $auth_settings['ldap_user'] = '';
3097 }
3098 if ( ! array_key_exists( 'ldap_password', $auth_settings ) ) {
3099 $auth_settings['ldap_password'] = '';
3100 }
3101 if ( ! array_key_exists( 'ldap_lostpassword_url', $auth_settings ) ) {
3102 $auth_settings['ldap_lostpassword_url'] = '';
3103 }
3104 if ( ! array_key_exists( 'ldap_attr_first_name', $auth_settings ) ) {
3105 $auth_settings['ldap_attr_first_name'] = '';
3106 }
3107 if ( ! array_key_exists( 'ldap_attr_last_name', $auth_settings ) ) {
3108 $auth_settings['ldap_attr_last_name'] = '';
3109 }
3110 if ( ! array_key_exists( 'ldap_attr_update_on_login', $auth_settings ) ) {
3111 $auth_settings['ldap_attr_update_on_login'] = '';
3112 }
3113
3114 // Advanced defaults.
3115 if ( ! array_key_exists( 'advanced_lockouts', $auth_settings ) ) {
3116 $auth_settings['advanced_lockouts'] = array(
3117 'attempts_1' => 10,
3118 'duration_1' => 1,
3119 'attempts_2' => 10,
3120 'duration_2' => 10,
3121 'reset_duration' => 120,
3122 );
3123 }
3124 if ( ! array_key_exists( 'advanced_hide_wp_login', $auth_settings ) ) {
3125 $auth_settings['advanced_hide_wp_login'] = '';
3126 }
3127 if ( ! array_key_exists( 'advanced_branding', $auth_settings ) ) {
3128 $auth_settings['advanced_branding'] = 'default';
3129 }
3130 if ( ! array_key_exists( 'advanced_admin_menu', $auth_settings ) ) {
3131 $auth_settings['advanced_admin_menu'] = 'top';
3132 }
3133 if ( ! array_key_exists( 'advanced_usermeta', $auth_settings ) ) {
3134 $auth_settings['advanced_usermeta'] = '';
3135 }
3136 if ( ! array_key_exists( 'advanced_users_per_page', $auth_settings ) ) {
3137 $auth_settings['advanced_users_per_page'] = 20;
3138 }
3139 if ( ! array_key_exists( 'advanced_users_sort_by', $auth_settings ) ) {
3140 $auth_settings['advanced_users_sort_by'] = 'created';
3141 }
3142 if ( ! array_key_exists( 'advanced_users_sort_order', $auth_settings ) ) {
3143 $auth_settings['advanced_users_sort_order'] = 'asc';
3144 }
3145 if ( ! array_key_exists( 'advanced_widget_enabled', $auth_settings ) ) {
3146 $auth_settings['advanced_widget_enabled'] = '1';
3147 }
3148 if ( ! array_key_exists( 'advanced_override_multisite', $auth_settings ) ) {
3149 $auth_settings['advanced_override_multisite'] = '';
3150 }
3151
3152 // Save default options to database.
3153 update_option( 'auth_settings', $auth_settings );
3154 update_option( 'auth_settings_access_users_pending', $auth_settings_access_users_pending );
3155 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
3156 update_option( 'auth_settings_access_users_blocked', $auth_settings_access_users_blocked );
3157
3158 // Multisite defaults.
3159 if ( is_multisite() ) {
3160 $auth_multisite_settings = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', array() );
3161
3162 if ( false === $auth_multisite_settings ) {
3163 $auth_multisite_settings = array();
3164 }
3165 // Global switch for enabling multisite options.
3166 if ( ! array_key_exists( 'multisite_override', $auth_multisite_settings ) ) {
3167 $auth_multisite_settings['multisite_override'] = '';
3168 }
3169 // Access Lists Defaults.
3170 $auth_multisite_settings_access_users_approved = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved' );
3171 if ( false === $auth_multisite_settings_access_users_approved ) {
3172 $auth_multisite_settings_access_users_approved = array();
3173 }
3174 // Login Access Defaults.
3175 if ( ! array_key_exists( 'access_who_can_login', $auth_multisite_settings ) ) {
3176 $auth_multisite_settings['access_who_can_login'] = 'approved_users';
3177 }
3178 // View Access Defaults.
3179 if ( ! array_key_exists( 'access_who_can_view', $auth_multisite_settings ) ) {
3180 $auth_multisite_settings['access_who_can_view'] = 'everyone';
3181 }
3182 // External Service Defaults.
3183 if ( ! array_key_exists( 'access_default_role', $auth_multisite_settings ) ) {
3184 // Set default role to 'student' if that role exists, 'subscriber' otherwise.
3185 $all_roles = $wp_roles->roles;
3186 $editable_roles = apply_filters( 'editable_roles', $all_roles );
3187 if ( array_key_exists( 'student', $editable_roles ) ) {
3188 $auth_multisite_settings['access_default_role'] = 'student';
3189 } else {
3190 $auth_multisite_settings['access_default_role'] = 'subscriber';
3191 }
3192 }
3193 if ( ! array_key_exists( 'google', $auth_multisite_settings ) ) {
3194 $auth_multisite_settings['google'] = '';
3195 }
3196 if ( ! array_key_exists( 'cas', $auth_multisite_settings ) ) {
3197 $auth_multisite_settings['cas'] = '';
3198 }
3199 if ( ! array_key_exists( 'ldap', $auth_multisite_settings ) ) {
3200 $auth_multisite_settings['ldap'] = '';
3201 }
3202 if ( ! array_key_exists( 'google_clientid', $auth_multisite_settings ) ) {
3203 $auth_multisite_settings['google_clientid'] = '';
3204 }
3205 if ( ! array_key_exists( 'google_clientsecret', $auth_multisite_settings ) ) {
3206 $auth_multisite_settings['google_clientsecret'] = '';
3207 }
3208 if ( ! array_key_exists( 'google_hosteddomain', $auth_multisite_settings ) ) {
3209 $auth_multisite_settings['google_hosteddomain'] = '';
3210 }
3211 if ( ! array_key_exists( 'cas_custom_label', $auth_multisite_settings ) ) {
3212 $auth_multisite_settings['cas_custom_label'] = 'CAS';
3213 }
3214 if ( ! array_key_exists( 'cas_host', $auth_multisite_settings ) ) {
3215 $auth_multisite_settings['cas_host'] = '';
3216 }
3217 if ( ! array_key_exists( 'cas_port', $auth_multisite_settings ) ) {
3218 $auth_multisite_settings['cas_port'] = '';
3219 }
3220 if ( ! array_key_exists( 'cas_path', $auth_multisite_settings ) ) {
3221 $auth_multisite_settings['cas_path'] = '';
3222 }
3223 if ( ! array_key_exists( 'cas_version', $auth_multisite_settings ) ) {
3224 $auth_multisite_settings['cas_version'] = 'SAML_VERSION_1_1';
3225 }
3226 if ( ! array_key_exists( 'cas_attr_email', $auth_multisite_settings ) ) {
3227 $auth_multisite_settings['cas_attr_email'] = '';
3228 }
3229 if ( ! array_key_exists( 'cas_attr_first_name', $auth_multisite_settings ) ) {
3230 $auth_multisite_settings['cas_attr_first_name'] = '';
3231 }
3232 if ( ! array_key_exists( 'cas_attr_last_name', $auth_multisite_settings ) ) {
3233 $auth_multisite_settings['cas_attr_last_name'] = '';
3234 }
3235 if ( ! array_key_exists( 'cas_attr_update_on_login', $auth_multisite_settings ) ) {
3236 $auth_multisite_settings['cas_attr_update_on_login'] = '';
3237 }
3238 if ( ! array_key_exists( 'cas_auto_login', $auth_multisite_settings ) ) {
3239 $auth_multisite_settings['cas_auto_login'] = '';
3240 }
3241 if ( ! array_key_exists( 'ldap_host', $auth_multisite_settings ) ) {
3242 $auth_multisite_settings['ldap_host'] = '';
3243 }
3244 if ( ! array_key_exists( 'ldap_port', $auth_multisite_settings ) ) {
3245 $auth_multisite_settings['ldap_port'] = '389';
3246 }
3247 if ( ! array_key_exists( 'ldap_tls', $auth_multisite_settings ) ) {
3248 $auth_multisite_settings['ldap_tls'] = '1';
3249 }
3250 if ( ! array_key_exists( 'ldap_search_base', $auth_multisite_settings ) ) {
3251 $auth_multisite_settings['ldap_search_base'] = '';
3252 }
3253 if ( ! array_key_exists( 'ldap_uid', $auth_multisite_settings ) ) {
3254 $auth_multisite_settings['ldap_uid'] = 'uid';
3255 }
3256 if ( ! array_key_exists( 'ldap_attr_email', $auth_multisite_settings ) ) {
3257 $auth_multisite_settings['ldap_attr_email'] = '';
3258 }
3259 if ( ! array_key_exists( 'ldap_user', $auth_multisite_settings ) ) {
3260 $auth_multisite_settings['ldap_user'] = '';
3261 }
3262 if ( ! array_key_exists( 'ldap_password', $auth_multisite_settings ) ) {
3263 $auth_multisite_settings['ldap_password'] = '';
3264 }
3265 if ( ! array_key_exists( 'ldap_lostpassword_url', $auth_multisite_settings ) ) {
3266 $auth_multisite_settings['ldap_lostpassword_url'] = '';
3267 }
3268 if ( ! array_key_exists( 'ldap_attr_first_name', $auth_multisite_settings ) ) {
3269 $auth_multisite_settings['ldap_attr_first_name'] = '';
3270 }
3271 if ( ! array_key_exists( 'ldap_attr_last_name', $auth_multisite_settings ) ) {
3272 $auth_multisite_settings['ldap_attr_last_name'] = '';
3273 }
3274 if ( ! array_key_exists( 'ldap_attr_update_on_login', $auth_multisite_settings ) ) {
3275 $auth_multisite_settings['ldap_attr_update_on_login'] = '';
3276 }
3277 // Advanced defaults.
3278 if ( ! array_key_exists( 'advanced_lockouts', $auth_multisite_settings ) ) {
3279 $auth_multisite_settings['advanced_lockouts'] = array(
3280 'attempts_1' => 10,
3281 'duration_1' => 1,
3282 'attempts_2' => 10,
3283 'duration_2' => 10,
3284 'reset_duration' => 120,
3285 );
3286 }
3287 if ( ! array_key_exists( 'advanced_hide_wp_login', $auth_multisite_settings ) ) {
3288 $auth_multisite_settings['advanced_hide_wp_login'] = '';
3289 }
3290 if ( ! array_key_exists( 'advanced_users_per_page', $auth_multisite_settings ) ) {
3291 $auth_multisite_settings['advanced_users_per_page'] = 20;
3292 }
3293 if ( ! array_key_exists( 'advanced_users_sort_by', $auth_multisite_settings ) ) {
3294 $auth_multisite_settings['advanced_users_sort_by'] = 'created';
3295 }
3296 if ( ! array_key_exists( 'advanced_users_sort_order', $auth_multisite_settings ) ) {
3297 $auth_multisite_settings['advanced_users_sort_order'] = 'asc';
3298 }
3299 if ( ! array_key_exists( 'advanced_widget_enabled', $auth_multisite_settings ) ) {
3300 $auth_multisite_settings['advanced_widget_enabled'] = '1';
3301 }
3302 // Save default network options to database.
3303 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', $auth_multisite_settings );
3304 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
3305 }
3306
3307 return $auth_settings;
3308 }
3309
3310
3311 /**
3312 * List sanitizer.
3313 *
3314 * @param array $list Array of users to sanitize.
3315 * @param string $side_effect Set to 'update roles' if role syncing should be performed.
3316 * @param string $multisite_mode Set to 'multisite' to sync roles on all sites the user belongs to.
3317 * @return array Array of sanitized users.
3318 */
3319 private function sanitize_user_list( $list, $side_effect = 'none', $multisite_mode = 'single' ) {
3320 // If it's not a list, make it so.
3321 if ( ! is_array( $list ) ) {
3322 $list = array();
3323 }
3324 foreach ( $list as $key => $user_info ) {
3325 if ( strlen( $user_info['email'] ) < 1 ) {
3326 // Make sure there are no empty entries in the list.
3327 unset( $list[ $key ] );
3328 } elseif ( 'update roles' === $side_effect ) {
3329 // Make sure the WordPress user accounts have the same role
3330 // as that indicated in the list.
3331 $wp_user = get_user_by( 'email', $user_info['email'] );
3332 if ( $wp_user ) {
3333 if ( is_multisite() && 'multisite' === $multisite_mode ) {
3334 foreach ( get_blogs_of_user( $wp_user->ID ) as $blog ) {
3335 add_user_to_blog( $blog->userblog_id, $wp_user->ID, $user_info['role'] );
3336 }
3337 } else {
3338 $wp_user->set_role( $user_info['role'] );
3339 }
3340 }
3341 }
3342 }
3343 return $list;
3344 }
3345
3346
3347 /**
3348 * Settings sanitizer callback.
3349 *
3350 * @param array $auth_settings Authorizer settings array.
3351 * @return array Sanitized Authorizer settings array.
3352 */
3353 public function sanitize_options( $auth_settings ) {
3354 // Default to "Approved Users" login access restriction.
3355 if ( ! in_array( $auth_settings['access_who_can_login'], array( 'external_users', 'approved_users' ), true ) ) {
3356 $auth_settings['access_who_can_login'] = 'approved_users';
3357 }
3358
3359 // Default to "Everyone" view access restriction.
3360 if ( ! in_array( $auth_settings['access_who_can_view'], array( 'everyone', 'logged_in_users' ), true ) ) {
3361 $auth_settings['access_who_can_view'] = 'everyone';
3362 }
3363
3364 // Default to WordPress login access redirect.
3365 // Note: this option doesn't exist in multisite options, so we first
3366 // check to see if it exists.
3367 if ( array_key_exists( 'access_redirect', $auth_settings ) && ! in_array( $auth_settings['access_redirect'], array( 'login', 'page', 'message' ), true ) ) {
3368 $auth_settings['access_redirect'] = 'login';
3369 }
3370
3371 // Default to warning message for anonymous users on public pages.
3372 // Note: this option doesn't exist in multisite options, so we first
3373 // check to see if it exists.
3374 if ( array_key_exists( 'access_public_warning', $auth_settings ) && ! in_array( $auth_settings['access_public_warning'], array( 'no_warning', 'warning' ), true ) ) {
3375 $auth_settings['access_public_warning'] = 'no_warning';
3376 }
3377
3378 // Sanitize Send welcome email (checkbox: value can only be '1' or empty string).
3379 $auth_settings['access_should_email_approved_users'] = array_key_exists( 'access_should_email_approved_users', $auth_settings ) && strlen( $auth_settings['access_should_email_approved_users'] ) > 0 ? '1' : '';
3380
3381 // Sanitize Enable Google Logins (checkbox: value can only be '1' or empty string).
3382 $auth_settings['google'] = array_key_exists( 'google', $auth_settings ) && strlen( $auth_settings['google'] ) > 0 ? '1' : '';
3383
3384 // Sanitize Enable CAS Logins (checkbox: value can only be '1' or empty string).
3385 $auth_settings['cas'] = array_key_exists( 'cas', $auth_settings ) && strlen( $auth_settings['cas'] ) > 0 ? '1' : '';
3386
3387 // Sanitize CAS Host setting.
3388 $auth_settings['cas_host'] = filter_var( $auth_settings['cas_host'], FILTER_SANITIZE_URL );
3389
3390 // Sanitize CAS Port (int).
3391 $auth_settings['cas_port'] = filter_var( $auth_settings['cas_port'], FILTER_SANITIZE_NUMBER_INT );
3392
3393 // Sanitize CAS attribute update (checkbox: value can only be '1' or empty string).
3394 $auth_settings['cas_attr_update_on_login'] = array_key_exists( 'cas_attr_update_on_login', $auth_settings ) && strlen( $auth_settings['cas_attr_update_on_login'] ) > 0 ? '1' : '';
3395
3396 // Sanitize CAS auto-login (checkbox: value can only be '1' or empty string).
3397 $auth_settings['cas_auto_login'] = array_key_exists( 'cas_auto_login', $auth_settings ) && strlen( $auth_settings['cas_auto_login'] ) > 0 ? '1' : '';
3398
3399 // Sanitize Enable LDAP Logins (checkbox: value can only be '1' or empty string).
3400 $auth_settings['ldap'] = array_key_exists( 'ldap', $auth_settings ) && strlen( $auth_settings['ldap'] ) > 0 ? '1' : '';
3401
3402 // Sanitize LDAP Host setting.
3403 $auth_settings['ldap_host'] = filter_var( $auth_settings['ldap_host'], FILTER_SANITIZE_URL );
3404
3405 // Sanitize LDAP Port (int).
3406 $auth_settings['ldap_port'] = filter_var( $auth_settings['ldap_port'], FILTER_SANITIZE_NUMBER_INT );
3407
3408 // Sanitize LDAP TLS (checkbox: value can only be '1' or empty string).
3409 $auth_settings['ldap_tls'] = array_key_exists( 'ldap_tls', $auth_settings ) && strlen( $auth_settings['ldap_tls'] ) > 0 ? '1' : '';
3410
3411 // Sanitize LDAP attributes (basically make sure they don't have any parentheses).
3412 $auth_settings['ldap_uid'] = filter_var( $auth_settings['ldap_uid'], FILTER_SANITIZE_EMAIL );
3413
3414 // Sanitize LDAP Lost Password URL.
3415 $auth_settings['ldap_lostpassword_url'] = filter_var( $auth_settings['ldap_lostpassword_url'], FILTER_SANITIZE_URL );
3416
3417 // Obfuscate LDAP directory user password.
3418 if ( strlen( $auth_settings['ldap_password'] ) > 0 ) {
3419 // encrypt the directory user password for some minor obfuscation in the database.
3420 $auth_settings['ldap_password'] = $this->encrypt( $auth_settings['ldap_password'] );
3421 }
3422
3423 // Sanitize LDAP attribute update (checkbox: value can only be '1' or empty string).
3424 $auth_settings['ldap_attr_update_on_login'] = array_key_exists( 'ldap_attr_update_on_login', $auth_settings ) && strlen( $auth_settings['ldap_attr_update_on_login'] ) > 0 ? '1' : '';
3425
3426 // Make sure public pages is an empty array if it's empty.
3427 // Note: this option doesn't exist in multisite options, so we first
3428 // check to see if it exists.
3429 if ( array_key_exists( 'access_public_pages', $auth_settings ) && ! is_array( $auth_settings['access_public_pages'] ) ) {
3430 $auth_settings['access_public_pages'] = array();
3431 }
3432
3433 // Make sure all lockout options are integers (attempts_1,
3434 // duration_1, attempts_2, duration_2, reset_duration).
3435 foreach ( $auth_settings['advanced_lockouts'] as $key => $value ) {
3436 $auth_settings['advanced_lockouts'][ $key ] = filter_var( $value, FILTER_SANITIZE_NUMBER_INT );
3437 }
3438
3439 // Sanitize Hide WordPress logins (checkbox: value can only be '1' or empty string).
3440 $auth_settings['advanced_hide_wp_login'] = array_key_exists( 'advanced_hide_wp_login', $auth_settings ) && strlen( $auth_settings['advanced_hide_wp_login'] ) > 0 ? '1' : '';
3441
3442 // Sanitize Users per page (text: value can only int from 1 to MAX_INT).
3443 $auth_settings['advanced_users_per_page'] = array_key_exists( 'advanced_users_per_page', $auth_settings ) && intval( $auth_settings['advanced_users_per_page'] ) > 0 ? intval( $auth_settings['advanced_users_per_page'] ) : 1;
3444
3445 // Sanitize Sort users by (select: value can be 'email', 'role', 'date_added', 'created').
3446 if ( ! isset( $auth_settings['advanced_users_sort_by'] ) || ! in_array( $auth_settings['advanced_users_sort_by'], array( 'email', 'role', 'date_added', 'created' ), true ) ) {
3447 $auth_settings['advanced_users_sort_by'] = 'created';
3448 }
3449
3450 // Sanitize Sort users order (select: value can be 'asc', 'desc').
3451 if ( ! isset( $auth_settings['advanced_users_sort_order'] ) || ! in_array( $auth_settings['advanced_users_sort_order'], array( 'asc', 'desc' ), true ) ) {
3452 $auth_settings['advanced_users_sort_order'] = 'asc';
3453 }
3454
3455 // Sanitize Show Dashboard Widget (checkbox: value can only be '1' or empty string).
3456 $auth_settings['advanced_widget_enabled'] = array_key_exists( 'advanced_widget_enabled', $auth_settings ) && strlen( $auth_settings['advanced_widget_enabled'] ) > 0 ? '1' : '';
3457
3458 // Sanitize Override multisite options (checkbox: value can only be '1' or empty string).
3459 $auth_settings['advanced_override_multisite'] = array_key_exists( 'advanced_override_multisite', $auth_settings ) && strlen( $auth_settings['advanced_override_multisite'] ) > 0 ? '1' : '';
3460
3461 return $auth_settings;
3462 }
3463
3464
3465 /**
3466 * Keep authorizer approved users' roles in sync with WordPress roles
3467 * if someone changes the role via the WordPress Edit User page
3468 * (wp-admin/user-edit.php or wp-admin/profile.php).
3469 *
3470 * Action: user_profile_update_errors
3471 *
3472 * @param WP_Error $errors Errors object to add any custom errors to (passed by reference).
3473 * @param bool $update True if updating existing user, false if saving a new one.
3474 * @param stdClass $user Updated WP_User object for user being edited (passed by reference).
3475 */
3476 public function edit_user_profile_update_role( &$errors, $update, &$user ) {
3477 // Do nothing if we're not updating role.
3478 if ( ! property_exists( $user, 'role' ) ) {
3479 return;
3480 }
3481
3482 // Safety check; will likely not fire if we reach this function.
3483 if ( ! current_user_can( 'edit_user', $user->ID ) ) {
3484 return;
3485 }
3486
3487 // Don't perform Authorizer updates if we have a WordPress error.
3488 $errors_on_user_update = $errors->get_error_codes();
3489 if ( ! empty( $errors_on_user_update ) ) {
3490 return;
3491 }
3492
3493 // Get original user object (fail if not a real WordPress user).
3494 $userdata = get_userdata( $user->ID );
3495 if ( ! $userdata ) {
3496 return;
3497 }
3498
3499 // If user is in approved list, update his/her associated role.
3500 if ( $this->is_email_in_list( $userdata->user_email, 'approved' ) ) {
3501 $auth_settings_access_users_approved = $this->sanitize_user_list( $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT ) );
3502 foreach ( $auth_settings_access_users_approved as $key => $check_user ) {
3503 if ( 0 === strcasecmp( $check_user['email'], $userdata->user_email ) ) {
3504 $auth_settings_access_users_approved[ $key ]['role'] = $user->role;
3505 }
3506 }
3507 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
3508 }
3509 }
3510
3511
3512 /**
3513 * Sync any email address changes to WordPress accounts to the corresponding
3514 * entry in the Authorizer approved list.
3515 *
3516 * Note: This filter fires in wp_update_user() if the update includes an
3517 * email address change, and fires after all security and integrity checks
3518 * have been performed, so we can simply update the Authorizer approved
3519 * list, changing the email address on the approved entry, and removing any
3520 * existing entries that also have the new email address (duplicates).
3521 *
3522 * Filter: send_email_change_email
3523 *
3524 * @param bool $send Whether to send the email.
3525 * @param array $user The original user array.
3526 * @param array $userdata The updated user array.
3527 */
3528 public function edit_user_profile_update_email( $send, $user, $userdata ) {
3529 // If we're in multisite, update the email on all sites in the network
3530 // (and remove from any subsites if it's a network-approved user).
3531 if ( is_multisite() ) {
3532 // If it's a multisite approved user, sync the email there.
3533 $changed_user_is_multisite_user = false;
3534 if ( $this->is_email_in_list( $user['user_email'], 'approved', 'multisite' ) ) {
3535 $changed_user_is_multisite_user = true;
3536 $auth_multisite_settings_access_users_approved = $this->sanitize_user_list(
3537 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
3538 );
3539 foreach ( $auth_multisite_settings_access_users_approved as $key => $check_user ) {
3540 // Update old user email in approved list to the new email.
3541 if ( 0 === strcasecmp( $check_user['email'], $user['user_email'] ) ) {
3542 $auth_multisite_settings_access_users_approved[ $key ]['email'] = $this->lowercase( $userdata['user_email'] );
3543 }
3544 // If new user email is already in approved list, remove that entry.
3545 if ( 0 === strcasecmp( $check_user['email'], $userdata['user_email'] ) ) {
3546 unset( $auth_multisite_settings_access_users_approved[ $key ] );
3547 }
3548 }
3549 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
3550 }
3551
3552 // Go through all approved lists on individual sites and sync this user there.
3553 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
3554 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
3555 foreach ( $sites as $site ) {
3556 $updated = false;
3557 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
3558 $auth_settings_access_users_approved = get_blog_option( $blog_id, 'auth_settings_access_users_approved', array() );
3559 foreach ( $auth_settings_access_users_approved as $key => $check_user ) {
3560 // Update old user email in approved list to the new email.
3561 if ( 0 === strcasecmp( $check_user['email'], $user['user_email'] ) ) {
3562 // But if the user is already a multisite user, just remove the entry in the subsite.
3563 if ( $changed_user_is_multisite_user ) {
3564 unset( $auth_settings_access_users_approved[ $key ] );
3565 } else {
3566 $auth_settings_access_users_approved[ $key ]['email'] = $this->lowercase( $userdata['user_email'] );
3567 }
3568 $updated = true;
3569 }
3570 // If new user email is already in approved list, remove that entry.
3571 if ( 0 === strcasecmp( $check_user['email'], $userdata['user_email'] ) ) {
3572 unset( $auth_settings_access_users_approved[ $key ] );
3573 $updated = true;
3574 }
3575 }
3576 if ( $updated ) {
3577 update_blog_option( $blog_id, 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
3578 }
3579 }
3580 } else {
3581 // In a single site environment, just find the old user in the approved list and update the email.
3582 if ( $this->is_email_in_list( $user['user_email'], 'approved' ) ) {
3583 $auth_settings_access_users_approved = $this->sanitize_user_list( $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT ) );
3584 foreach ( $auth_settings_access_users_approved as $key => $check_user ) {
3585 // Update old user email in approved list to the new email.
3586 if ( 0 === strcasecmp( $check_user['email'], $user['user_email'] ) ) {
3587 $auth_settings_access_users_approved[ $key ]['email'] = $this->lowercase( $userdata['user_email'] );
3588 }
3589 // If new user email is already in approved list, remove that entry.
3590 if ( 0 === strcasecmp( $check_user['email'], $userdata['user_email'] ) ) {
3591 unset( $auth_settings_access_users_approved[ $key ] );
3592 }
3593 }
3594 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
3595 }
3596 }
3597
3598 // We're hooking into this filter merely for its location in the codebase,
3599 // so make sure to return the filter value unmodified.
3600 return $send;
3601 }
3602
3603
3604 /**
3605 * Settings print callback.
3606 *
3607 * @param string $args Args (e.g., multisite admin mode).
3608 * @return void
3609 */
3610 public function print_section_info_tabs( $args = '' ) {
3611 if ( WP_Plugin_Authorizer::NETWORK_CONTEXT === $this->get_admin_mode( $args ) ) :
3612 ?>
3613 <h2 class="nav-tab-wrapper">
3614 <a class="nav-tab nav-tab-access_lists nav-tab-active" href="javascript:chooseTab('access_lists' );"><?php esc_html_e( 'Access Lists', 'authorizer' ); ?></a>
3615 <a class="nav-tab nav-tab-external" href="javascript:chooseTab('external' );"><?php esc_html_e( 'External Service', 'authorizer' ); ?></a>
3616 <a class="nav-tab nav-tab-advanced" href="javascript:chooseTab('advanced' );"><?php esc_html_e( 'Advanced', 'authorizer' ); ?></a>
3617 </h2>
3618 <?php else : ?>
3619 <h2 class="nav-tab-wrapper">
3620 <a class="nav-tab nav-tab-access_lists nav-tab-active" href="javascript:chooseTab('access_lists' );"><?php esc_html_e( 'Access Lists', 'authorizer' ); ?></a>
3621 <a class="nav-tab nav-tab-access_login" href="javascript:chooseTab('access_login' );"><?php esc_html_e( 'Login Access', 'authorizer' ); ?></a>
3622 <a class="nav-tab nav-tab-access_public" href="javascript:chooseTab('access_public' );"><?php esc_html_e( 'Public Access', 'authorizer' ); ?></a>
3623 <a class="nav-tab nav-tab-external" href="javascript:chooseTab('external' );"><?php esc_html_e( 'External Service', 'authorizer' ); ?></a>
3624 <a class="nav-tab nav-tab-advanced" href="javascript:chooseTab('advanced' );"><?php esc_html_e( 'Advanced', 'authorizer' ); ?></a>
3625 </h2>
3626 <?php
3627 endif;
3628 }
3629
3630
3631 /**
3632 * Settings print callback.
3633 *
3634 * @param string $args Args (e.g., multisite admin mode).
3635 * @return void
3636 */
3637 public function print_section_info_access_lists( $args = '' ) {
3638 $admin_mode = $this->get_admin_mode( $args );
3639 ?>
3640 <div id="section_info_access_lists" class="section_info">
3641 <p><?php esc_html_e( 'Manage who has access to this site using these lists.', 'authorizer' ); ?></p>
3642 <ol>
3643 <li><?php echo wp_kses( __( "<strong>Pending</strong> users are users who have successfully logged in to the site, but who haven't yet been approved (or blocked) by you.", 'authorizer' ), $this->allowed_html ); ?></li>
3644 <li><?php echo wp_kses( __( '<strong>Approved</strong> users have access to the site once they successfully log in.', 'authorizer' ), $this->allowed_html ); ?></li>
3645 <li><?php echo wp_kses( __( '<strong>Blocked</strong> users will receive an error message when they try to visit the site after authenticating.', 'authorizer' ), $this->allowed_html ); ?></li>
3646 </ol>
3647 </div>
3648 <table class="form-table">
3649 <tbody>
3650 <tr>
3651 <th scope="row"><?php esc_html_e( 'Pending Users', 'authorizer' ); ?> <em>(<?php echo esc_html( $this->get_user_count_from_list( 'pending', $admin_mode ) ); ?>)</em></th>
3652 <td><?php $this->print_combo_auth_access_users_pending(); ?></td>
3653 </tr>
3654 <tr>
3655 <th scope="row"><?php esc_html_e( 'Approved Users', 'authorizer' ); ?> <em>(<?php echo esc_html( $this->get_user_count_from_list( 'approved', $admin_mode ) ); ?>)</em></th>
3656 <td><?php $this->print_combo_auth_access_users_approved(); ?></td>
3657 </tr>
3658 <tr>
3659 <th scope="row"><?php esc_html_e( 'Blocked Users', 'authorizer' ); ?> <em>(<?php echo esc_html( $this->get_user_count_from_list( 'blocked', $admin_mode ) ); ?>)</em></th>
3660 <td><?php $this->print_combo_auth_access_users_blocked(); ?></td>
3661 </tr>
3662 </tbody>
3663 </table>
3664 <?php
3665 }
3666
3667
3668 /**
3669 * Settings print callback.
3670 *
3671 * @param string $args Args (e.g., multisite admin mode).
3672 * @return void
3673 */
3674 public function print_combo_auth_access_users_pending( $args = '' ) {
3675 // Get plugin option.
3676 $option = 'access_users_pending';
3677 $auth_settings_option = $this->get_plugin_option( $option );
3678 $auth_settings_option = is_array( $auth_settings_option ) ? $auth_settings_option : array();
3679
3680 // Render wrapper div (for aligning pager to width of content).
3681 ?>
3682 <div class="wrapper_<?php echo esc_attr( $option ); ?>">
3683 <ul id="list_auth_settings_access_users_pending" style="margin:0;">
3684 <?php
3685 if ( count( $auth_settings_option ) > 0 ) :
3686 foreach ( $auth_settings_option as $key => $pending_user ) :
3687 if ( empty( $pending_user ) || count( $pending_user ) < 1 ) :
3688 continue;
3689 endif;
3690 $pending_user['is_wp_user'] = false;
3691 ?>
3692 <li>
3693 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $pending_user['email'] ); ?>" readonly="true" class="auth-email" />
3694 <select id="auth_settings_<?php echo esc_attr( $option ); ?>_<?php echo esc_attr( $key ); ?>_role" class="auth-role">
3695 <?php $this->wp_dropdown_permitted_roles( $pending_user['role'] ); ?>
3696 </select>
3697 <a href="javascript:void(0);" class="button-primary" id="approve_user_<?php echo esc_attr( $key ); ?>" onclick="authAddUser( this, 'approved', false ); authIgnoreUser( this, 'pending' );"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Approve', 'authorizer' ); ?></a>
3698 <a href="javascript:void(0);" class="button-primary" id="block_user_<?php echo esc_attr( $key ); ?>" onclick="authAddUser( this, 'blocked', false ); authIgnoreUser( this, 'pending' );"><span class="glyphicon glyphicon-ban-circle"></span> <?php esc_html_e( 'Block', 'authorizer' ); ?></a>
3699 <a href="javascript:void(0);" class="button button-secondary" id="ignore_user_<?php echo esc_attr( $key ); ?>" onclick="authIgnoreUser( this, 'pending' );" title="<?php esc_html_e( 'Remove user', 'authorizer' ); ?>"><span class="glyphicon glyphicon-remove"></span> <?php esc_html_e( 'Ignore', 'authorizer' ); ?></a>
3700 </li>
3701 <?php endforeach; ?>
3702 <?php else : ?>
3703 <li class="auth-empty"><em><?php esc_html_e( 'No pending users', 'authorizer' ); ?></em></li>
3704 <?php endif; ?>
3705 </ul>
3706 </div>
3707 <?php
3708 }
3709
3710
3711 /**
3712 * Settings print callback.
3713 *
3714 * @param string $args Args (e.g., multisite admin mode).
3715 * @return void
3716 */
3717 public function print_combo_auth_access_users_approved( $args = '' ) {
3718 // Get plugin option.
3719 $option = 'access_users_approved';
3720 $admin_mode = $this->get_admin_mode( $args );
3721 $auth_settings_option = $this->get_plugin_option( $option, $admin_mode, 'no override' );
3722 $auth_settings_option = is_array( $auth_settings_option ) ? $auth_settings_option : array();
3723
3724 // Get multisite approved users (will be added to top of list, greyed out).
3725 $auth_override_multisite = $this->get_plugin_option( 'advanced_override_multisite' );
3726 $auth_multisite_settings = $this->get_plugin_options( WP_Plugin_Authorizer::NETWORK_CONTEXT );
3727 $auth_settings_option_multisite = array();
3728 if (
3729 is_multisite() &&
3730 ! is_network_admin() &&
3731 '1' !== intval( $auth_override_multisite ) &&
3732 array_key_exists( 'multisite_override', $auth_multisite_settings ) &&
3733 '1' === $auth_multisite_settings['multisite_override']
3734 ) {
3735 $auth_settings_option_multisite = $this->get_plugin_option( $option, WP_Plugin_Authorizer::NETWORK_CONTEXT, 'allow override' );
3736 $auth_settings_option_multisite = is_array( $auth_settings_option_multisite ) ? $auth_settings_option_multisite : array();
3737 // Add multisite users to the beginning of the main user array.
3738 foreach ( array_reverse( $auth_settings_option_multisite ) as $approved_user ) {
3739 $approved_user['multisite_user'] = true;
3740 array_unshift( $auth_settings_option, $approved_user );
3741 }
3742 }
3743
3744 // Get default role for new user dropdown.
3745 $access_default_role = $this->get_plugin_option( 'access_default_role', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
3746
3747 // Get custom usermeta field to show.
3748 $advanced_usermeta = $this->get_plugin_option( 'advanced_usermeta' );
3749
3750 // Adjust javascript function prefixes if multisite.
3751 $js_function_prefix = WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode ? 'authMultisite' : 'auth';
3752 $is_multisite_admin_page = WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode;
3753
3754 // Filter user list to search terms.
3755 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
3756 if ( isset( $_REQUEST['search'] ) && strlen( sanitize_text_field( wp_unslash( $_REQUEST['search'] ) ) ) > 0 ) {
3757 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
3758 $search_term = sanitize_text_field( wp_unslash( $_REQUEST['search'] ) );
3759 $auth_settings_option = array_filter(
3760 $auth_settings_option, function ( $user ) use ( $search_term ) {
3761 return stripos( $user['email'], $search_term ) !== false ||
3762 stripos( $user['role'], $search_term ) !== false ||
3763 stripos( $user['date_added'], $search_term ) !== false;
3764 }
3765 );
3766 }
3767
3768 // Sort user list.
3769 $sort_by = $this->get_plugin_option( 'advanced_users_sort_by', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' ); // email, role, date_added (registered), created (date approved).
3770 $sort_order = $this->get_plugin_option( 'advanced_users_sort_order', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' ); // asc or desc.
3771 $sort_dimension = array();
3772 if ( in_array( $sort_by, array( 'email', 'role', 'date_added' ), true ) ) {
3773 foreach ( $auth_settings_option as $key => $user ) {
3774 if ( 'date_added' === $sort_by ) {
3775 $sort_dimension[ $key ] = date( 'Ymd', strtotime( $user[ $sort_by ] ) );
3776 } else {
3777 $sort_dimension[ $key ] = strtolower( $user[ $sort_by ] );
3778 }
3779 }
3780 $sort_order = 'asc' === $sort_order ? SORT_ASC : SORT_DESC;
3781 array_multisort( $sort_dimension, $sort_order, $auth_settings_option );
3782 } elseif ( 'created' === $sort_by && 'asc' !== $sort_order ) {
3783 // If default sort method and reverse order, just reverse the array.
3784 $auth_settings_option = array_reverse( $auth_settings_option );
3785 }
3786
3787 // Ensure array keys run from 0..max (keys in database will be the original,
3788 // index, and removing users will not reorder the array keys of other users).
3789 $auth_settings_option = array_values( $auth_settings_option );
3790
3791 // Get pager params.
3792 $total_users = count( $auth_settings_option );
3793 $users_per_page = intval( $this->get_plugin_option( 'advanced_users_per_page', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' ) );
3794 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
3795 $current_page = isset( $_REQUEST['paged'] ) ? intval( $_REQUEST['paged'] ) : 1;
3796 $total_pages = ceil( $total_users / $users_per_page );
3797 if ( $total_pages < 1 ) {
3798 $total_pages = 1;
3799 }
3800
3801 // Make sure current_page is between 1 and max pages.
3802 if ( $current_page < 1 ) {
3803 $current_page = 1;
3804 } elseif ( $current_page > $total_pages ) {
3805 $current_page = $total_pages;
3806 }
3807
3808 // Render wrapper div (for aligning pager to width of content).
3809 ?>
3810 <div class="wrapper_<?php echo esc_attr( $option ); ?>">
3811 <?php $this->render_user_pager( $current_page, $users_per_page, $total_users, 'top' ); ?>
3812 <ul id="list_auth_settings_access_users_approved" class="<?php echo strlen( $advanced_usermeta ) > 0 ? 'has-usermeta' : ''; ?>">
3813 <?php
3814 $offset = ( $current_page - 1 ) * $users_per_page;
3815 $max = min( $offset + $users_per_page, count( $auth_settings_option ) );
3816 for ( $key = $offset; $key < $max; $key++ ) :
3817 $approved_user = $auth_settings_option[ $key ];
3818 if ( empty( $approved_user ) || count( $approved_user ) < 1 ) :
3819 continue;
3820 endif;
3821 $this->render_user_element( $approved_user, $key, $option, $admin_mode, $advanced_usermeta );
3822 endfor;
3823 ?>
3824 </ul>
3825
3826 <div id="new_auth_settings_<?php echo esc_attr( $option ); ?>">
3827 <textarea id="new_approved_user_email" placeholder="<?php esc_attr_e( 'email address', 'authorizer' ); ?>" class="auth-email new autogrow-short" rows="1"></textarea>
3828 <select id="new_approved_user_role" class="auth-role">
3829 <?php $this->wp_dropdown_permitted_roles( $access_default_role, 'not disabled', $admin_mode ); ?>
3830 </select>
3831 <div class="btn-group">
3832 <a href="javascript:void(0);" class="btn button-primary dropdown-toggle button-add-user" id="approve_user_new" onclick="<?php echo esc_attr( $js_function_prefix ); ?>AddUser(this, 'approved' );"><span class="glyphicon glyphicon-ok"></span> <?php esc_html_e( 'Approve', 'authorizer' ); ?></a>
3833 <button type="button" class="btn button-primary dropdown-toggle" data-toggle="dropdown">
3834 <span class="caret"></span>
3835 <span class="sr-only"><?php esc_html_e( 'Toggle Dropdown', 'authorizer' ); ?></span>
3836 </button>
3837 <ul class="dropdown-menu" role="menu">
3838 <li><a href="javascript:void(0);" onclick="<?php echo esc_attr( $js_function_prefix ); ?>AddUser( document.getElementById( 'approve_user_new' ), 'approved', true);"><?php esc_html_e( 'Create a local WordPress account instead, and email the user their password.', 'authorizer' ); ?></a></li>
3839 </ul>
3840 </div>
3841 </div>
3842 <?php $this->render_user_pager( $current_page, $users_per_page, $total_users, 'bottom' ); ?>
3843 </div>
3844 <?php
3845 }
3846
3847
3848 /**
3849 * Renders the html elements for the pager above and below the Approved User list.
3850 *
3851 * @param integer $current_page Which page we are currently viewing.
3852 * @param integer $users_per_page How many users to show per page.
3853 * @param integer $total_users Total count of users in list.
3854 * @param string $which Where to render the pager ('top' or 'bottom').
3855 * @return void
3856 */
3857 private function render_user_pager( $current_page = 1, $users_per_page = 20, $total_users = 0, $which = 'top' ) {
3858 $total_pages = ceil( $total_users / $users_per_page );
3859 if ( $total_pages < 1 ) {
3860 $total_pages = 1;
3861 }
3862
3863 /* TRANSLATORS: %s: number of users */
3864 $output = ' <span class="displaying-num">' . sprintf( _n( '%s user', '%s users', $total_users, 'authorizer' ), number_format_i18n( $total_users ) ) . '</span>';
3865
3866 $disable_first = $current_page <= 1;
3867 $disable_prev = $current_page <= 1;
3868 $disable_next = $current_page >= $total_pages;
3869 $disable_last = $current_page >= $total_pages;
3870
3871 $current_url = '';
3872 if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
3873 $current_url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] ) ) . esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
3874 $current_url = remove_query_arg( wp_removable_query_args(), $current_url );
3875 }
3876
3877 $page_links = array();
3878
3879 $total_pages_before = '<span class="paging-input">';
3880 $total_pages_after = '</span></span>';
3881
3882 if ( $disable_first ) {
3883 $page_links[] = '<span class="first-page tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
3884 } else {
3885 $page_links[] = sprintf(
3886 "<a class='first-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
3887 esc_url( remove_query_arg( 'paged', $current_url ) ),
3888 __( 'First page' ),
3889 '&laquo;'
3890 );
3891 }
3892
3893 if ( $disable_prev ) {
3894 $page_links[] = '<span class="prev-page tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>';
3895 } else {
3896 $page_links[] = sprintf(
3897 "<a class='prev-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
3898 esc_url( add_query_arg( 'paged', max( 1, $current_page - 1 ), $current_url ) ),
3899 __( 'Previous page' ),
3900 '&lsaquo;'
3901 );
3902 }
3903
3904 if ( 'bottom' === $which ) {
3905 $html_current_page = '<span class="current-page-text">' . $current_page . '</span>';
3906 $total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
3907 } else {
3908 $html_current_page = sprintf(
3909 "%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
3910 '<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
3911 $current_page,
3912 strlen( $total_pages )
3913 );
3914 }
3915 /* TRANSLATORS: %s: number of pages */
3916 $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
3917 /* TRANSLATORS: 1: number of current page 2: number of total pages */
3918 $page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
3919
3920 if ( $disable_next ) {
3921 $page_links[] = '<span class="next-page tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>';
3922 } else {
3923 $page_links[] = sprintf(
3924 "<a class='next-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
3925 esc_url( add_query_arg( 'paged', min( $total_pages, $current_page + 1 ), $current_url ) ),
3926 __( 'Next page' ),
3927 '&rsaquo;'
3928 );
3929 }
3930
3931 if ( $disable_last ) {
3932 $page_links[] = '<span class="last-page tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
3933 } else {
3934 $page_links[] = sprintf(
3935 "<a class='last-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
3936 esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
3937 __( 'Last page' ),
3938 '&raquo;'
3939 );
3940 }
3941
3942 $pagination_links_class = 'pagination-links';
3943 $output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
3944
3945 $search_form = array();
3946 if ( 'top' === $which ) {
3947 // phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification
3948 $search_term = isset( $_REQUEST['search'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search'] ) ) : '';
3949 $search_form[] = '<div class="search-box">';
3950 $search_form[] = '<label class="screen-reader-text" for="user-search-input">' . __( 'Search Users', 'authorizer' ) . '</label>';
3951 $search_form[] = '<input type="search" size="14" id="user-search-input" name="search" value="' . $search_term . '">';
3952 $search_form[] = '<input type="button" id="search-submit" class="button" value="' . __( 'Search', 'authorizer' ) . '">';
3953 $search_form[] = '</div>';
3954 }
3955 $search_form = join( "\n", $search_form );
3956
3957 $output = "<div class='tablenav-pages'>$output</div>";
3958 ?>
3959 <div class="tablenav top">
3960 <?php echo wp_kses( $output, $this->allowed_html ); ?>
3961 <?php echo wp_kses( $search_form, $this->allowed_html ); ?>
3962 </div>
3963 <?php
3964 }
3965
3966
3967 /**
3968 * Renders the html <li> element for a given user in a list.
3969 *
3970 * @param array $approved_user User array to render.
3971 * @param int $key Index of user in list of users.
3972 * @param string $option List user is in (e.g., 'access_users_approved').
3973 * @param string $admin_mode Current admin context.
3974 * @param string $advanced_usermeta Usermeta field to display.
3975 * @return void
3976 */
3977 private function render_user_element( $approved_user, $key, $option, $admin_mode, $advanced_usermeta ) {
3978 $is_local_user = array_key_exists( 'local_user', $approved_user ) && 'true' === $approved_user['local_user'];
3979 $is_multisite_user = array_key_exists( 'multisite_user', $approved_user ) && true === $approved_user['multisite_user'];
3980 $option_prefix = $is_multisite_user ? 'auth_multisite_settings_' : 'auth_settings_';
3981 $option_id = $option_prefix . $option . '_' . $key;
3982 $approved_wp_user = get_user_by( 'email', $approved_user['email'] );
3983 $is_current_user = $approved_wp_user && get_current_user_id() === $approved_wp_user->ID;
3984
3985 // Adjust javascript function prefixes if multisite.
3986 $js_function_prefix = WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode ? 'authMultisite' : 'auth';
3987 $is_multisite_admin_page = WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode;
3988
3989 if ( ! $approved_wp_user ) :
3990 $approved_user['is_wp_user'] = false;
3991 else :
3992 $approved_user['is_wp_user'] = true;
3993 $approved_user['email'] = $approved_wp_user->user_email;
3994 $approved_user['role'] = $is_multisite_admin_page || count( $approved_wp_user->roles ) === 0 ? $approved_user['role'] : array_shift( $approved_wp_user->roles );
3995 $approved_user['date_added'] = $approved_wp_user->user_registered;
3996
3997 // Get usermeta field from the WordPress user's real usermeta.
3998 if ( strlen( $advanced_usermeta ) > 0 ) :
3999 if ( strpos( $advanced_usermeta, 'acf___' ) === 0 && class_exists( 'acf' ) ) :
4000 // Get ACF Field value for the user.
4001 $approved_user['usermeta'] = get_field( str_replace( 'acf___', '', $advanced_usermeta ), 'user_' . $approved_wp_user->ID );
4002 else :
4003 // Get regular usermeta value for the user.
4004 $approved_user['usermeta'] = get_user_meta( $approved_wp_user->ID, $advanced_usermeta, true );
4005 endif;
4006 if ( is_array( $approved_user['usermeta'] ) || is_object( $approved_user['usermeta'] ) ) :
4007 $approved_user['usermeta'] = serialize( $approved_user['usermeta'] );
4008 endif;
4009 endif;
4010 endif;
4011 if ( ! array_key_exists( 'usermeta', $approved_user ) ) :
4012 $approved_user['usermeta'] = '';
4013 endif;
4014 ?>
4015 <li>
4016 <input
4017 type="text"
4018 id="<?php echo esc_attr( $option_id ); ?>"
4019 value="<?php echo esc_attr( $approved_user['email'] ); ?>"
4020 readonly="true"
4021 class="<?php echo esc_attr( $this->create_class_name( 'email', $is_multisite_user ) ); ?>"
4022 />
4023 <select
4024 id="<?php echo esc_attr( $option_id ); ?>_role"
4025 class="<?php echo esc_attr( $this->create_class_name( 'role', $is_multisite_user ) ); ?>"
4026 onchange="<?php echo esc_attr( $js_function_prefix ); ?>ChangeRole( this );"
4027 <?php if ( $is_multisite_user ) : ?>
4028 disabled="disabled"
4029 <?php endif; ?>
4030 >
4031 <?php $disable_input = $is_current_user ? 'disabled' : null; ?>
4032 <?php $this->wp_dropdown_permitted_roles( $approved_user['role'], $disable_input, $admin_mode ); ?>
4033 </select>
4034 <input
4035 type="text"
4036 id="<?php echo esc_attr( $option_id ); ?>_date_added"
4037 value="<?php echo esc_attr( date( 'M Y', strtotime( $approved_user['date_added'] ) ) ); ?>"
4038 readonly="true"
4039 class="<?php echo esc_attr( $this->create_class_name( 'date-added', $is_multisite_user ) ); ?>"
4040 />
4041 <?php
4042 if ( strlen( $advanced_usermeta ) > 0 ) :
4043 $should_show_usermeta_in_text_field = true; // Fallback renderer for usermeta; try to use a select first.
4044 if ( strpos( $advanced_usermeta, 'acf___' ) === 0 && class_exists( 'acf' ) ) :
4045 $field_object = get_field_object( str_replace( 'acf___', '', $advanced_usermeta ) );
4046 if ( is_array( $field_object ) && array_key_exists( 'type', $field_object ) && 'select' === $field_object['type'] ) :
4047 $should_show_usermeta_in_text_field = false;
4048 ?>
4049 <select
4050 id="<?php echo esc_attr( $option_id ); ?>_usermeta"
4051 class="<?php echo esc_attr( $this->create_class_name( 'usermeta', $is_multisite_user ) ); ?>"
4052 onchange="<?php echo esc_attr( $js_function_prefix ); ?>UpdateUsermeta( this );"
4053 >
4054 <option value=""<?php selected( empty( $approved_user['usermeta'] ) ); ?>><?php esc_html_e( '-- None --', 'authorizer' ); ?></option>
4055 <?php foreach ( $field_object['choices'] as $key => $label ) : ?>
4056 <option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key === $approved_user['usermeta'] || ( isset( $approved_user['usermeta']['meta_value'] ) && $key === $approved_user['usermeta']['meta_value'] ) ); ?>><?php echo esc_html( $label ); ?></option>
4057 <?php endforeach; ?>
4058 </select>
4059 <?php endif; ?>
4060 <?php endif; ?>
4061 <?php if ( $should_show_usermeta_in_text_field ) : ?>
4062 <input
4063 type="text"
4064 id="<?php echo esc_attr( $option_id ); ?>_usermeta"
4065 value="<?php echo esc_attr( $approved_user['usermeta'], ENT_COMPAT ); ?>"
4066 class="<?php echo esc_attr( $this->create_class_name( 'usermeta', $is_multisite_user ) ); ?>"
4067 />
4068 <a class="button button-small button-primary update-usermeta" id="update_usermeta_<?php echo esc_attr( $key ); ?>" onclick="<?php echo esc_attr( $js_function_prefix ); ?>UpdateUsermeta( this );" title="Update usermeta"><span class="glyphicon glyphicon-floppy-saved"></span></a>
4069 <?php endif; ?>
4070 <?php endif; ?>
4071 <?php if ( ! $is_current_user && ! $is_multisite_user ) : ?>
4072 <?php if ( ! $is_multisite_admin_page ) : ?>
4073 <a class="button" id="block_user_<?php echo esc_attr( $key ); ?>" onclick="<?php echo esc_attr( $js_function_prefix ); ?>AddUser( this, 'blocked', false ); <?php echo esc_attr( $js_function_prefix ); ?>IgnoreUser( this, 'approved' );" title="<?php esc_attr_e( 'Block/Ban user', 'authorizer' ); ?>"><span class="glyphicon glyphicon-ban-circle"></span></a>
4074 <?php endif; ?>
4075 <a class="button" id="ignore_user_<?php echo esc_attr( $key ); ?>" onclick="<?php echo esc_attr( $js_function_prefix ); ?>IgnoreUser(this, 'approved' );" title="<?php esc_attr_e( 'Remove user', 'authorizer' ); ?>"><span class="glyphicon glyphicon-remove"></span></a>
4076 <?php endif; ?>
4077 <?php if ( $is_local_user ) : ?>
4078 &nbsp;<a title="Local WordPress user" class="auth-local-user"><span class="glyphicon glyphicon-user"></span></a>
4079 <?php endif; ?>
4080 <?php if ( $is_multisite_user ) : ?>
4081 &nbsp;<a title="WordPress Multisite user" class="auth-multisite-user"><span class="glyphicon glyphicon-globe"></span></a>
4082 <?php endif; ?>
4083 </li>
4084 <?php
4085 }
4086
4087
4088 /**
4089 * Settings print callback.
4090 *
4091 * @param string $args Args (e.g., multisite admin mode).
4092 * @return void
4093 */
4094 public function print_combo_auth_access_users_blocked( $args = '' ) {
4095 // Get plugin option.
4096 $option = 'access_users_blocked';
4097 $auth_settings_option = $this->get_plugin_option( $option );
4098 $auth_settings_option = is_array( $auth_settings_option ) ? $auth_settings_option : array();
4099
4100 // Get default role for new blocked user dropdown.
4101 $access_default_role = $this->get_plugin_option( 'access_default_role', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
4102
4103 // Render wrapper div (for aligning pager to width of content).
4104 ?>
4105 <div class="wrapper_<?php echo esc_attr( $option ); ?>">
4106 <ul id="list_auth_settings_<?php echo esc_attr( $option ); ?>" style="margin:0;">
4107 <?php
4108 foreach ( $auth_settings_option as $key => $blocked_user ) :
4109 if ( empty( $blocked_user ) || count( $blocked_user ) < 1 ) :
4110 continue;
4111 endif;
4112 $blocked_wp_user = get_user_by( 'email', $blocked_user['email'] );
4113 if ( $blocked_wp_user ) :
4114 $blocked_user['email'] = $blocked_wp_user->user_email;
4115 $blocked_user['role'] = array_shift( $blocked_wp_user->roles );
4116 $blocked_user['date_added'] = $blocked_wp_user->user_registered;
4117 $blocked_user['is_wp_user'] = true;
4118 else :
4119 $blocked_user['is_wp_user'] = false;
4120 endif;
4121 ?>
4122 <li>
4123 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $blocked_user['email'] ); ?>" readonly="true" class="auth-email" />
4124 <select id="auth_settings_<?php echo esc_attr( $option ); ?>_<?php echo esc_attr( $key ); ?>_role" class="auth-role">
4125 <?php $this->wp_dropdown_permitted_roles( $blocked_user['role'] ); ?>
4126 </select>
4127 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_<?php echo esc_attr( $key ); ?>_date_added" value="<?php echo esc_attr( date( 'M Y', strtotime( $blocked_user['date_added'] ) ) ); ?>" readonly="true" class="auth-date-added" />
4128 <a class="button" id="ignore_user_<?php echo esc_attr( $key ); ?>" onclick="authIgnoreUser( this, 'blocked' );" title="<?php esc_attr_e( 'Remove user', 'authorizer' ); ?>"><span class="glyphicon glyphicon-remove"></span></a>
4129 </li>
4130 <?php endforeach; ?>
4131 </ul>
4132 <div id="new_auth_settings_<?php echo esc_attr( $option ); ?>">
4133 <input type="text" id="new_blocked_user_email" placeholder="<?php esc_attr_e( 'email address', 'authorizer' ); ?>" class="auth-email new" />
4134 <select id="new_blocked_user_role" class="auth-role">
4135 <option value="<?php echo esc_attr( $access_default_role ); ?>"><?php echo esc_html( ucfirst( $access_default_role ) ); ?></option>
4136 </select>
4137 <a href="javascript:void(0);" class="button-primary button-add-user" id="block_user_new" onclick="authAddUser( this, 'blocked' );"><span class="glyphicon glyphicon-ban-circle"></span> <?php esc_html_e( 'Block', 'authorizer' ); ?></a>
4138 </div>
4139 </div>
4140 <?php
4141 }
4142
4143
4144 /**
4145 * Settings print callback.
4146 *
4147 * @param string $args Args (e.g., multisite admin mode).
4148 * @return void
4149 */
4150 public function print_section_info_access_login( $args = '' ) {
4151 ?>
4152 <div id="section_info_access_login" class="section_info">
4153 <?php wp_nonce_field( 'save_auth_settings', 'nonce_save_auth_settings' ); ?>
4154 <p><?php esc_html_e( 'Choose who is able to log into this site below.', 'authorizer' ); ?></p>
4155 </div>
4156 <?php
4157 }
4158
4159
4160 /**
4161 * Settings print callback.
4162 *
4163 * @param string $args Args (e.g., multisite admin mode).
4164 * @return void
4165 */
4166 public function print_radio_auth_access_who_can_login( $args = '' ) {
4167 // Get plugin option.
4168 $option = 'access_who_can_login';
4169 $admin_mode = $this->get_admin_mode( $args );
4170 $auth_settings_option = $this->get_plugin_option( $option, $admin_mode, 'allow override', 'print overlay' );
4171
4172 // If this site is configured independently of any multisite overrides, make sure we are not grabbing the multisite value; otherwise, grab the multisite value to show behind the disabled overlay.
4173 if ( is_multisite() && 1 === intval( $this->get_plugin_option( 'advanced_override_multisite' ) ) ) {
4174 $auth_settings_option = $this->get_plugin_option( $option );
4175 } elseif ( is_multisite() && WP_Plugin_Authorizer::SINGLE_CONTEXT === $admin_mode && $this->get_plugin_option( 'multisite_override', WP_Plugin_Authorizer::NETWORK_CONTEXT ) === '1' ) {
4176 // Workaround: javascript code hides/shows other settings based
4177 // on the selection in this option. If this option is overridden
4178 // by a multisite option, it should show that value in order to
4179 // correctly display the other appropriate options.
4180 // Side effect: this site option will be overwritten by the
4181 // multisite option on save. Since this is a 2-item radio, we
4182 // determined this was acceptable.
4183 $auth_settings_option = $this->get_plugin_option( $option, WP_Plugin_Authorizer::NETWORK_CONTEXT );
4184 }
4185
4186 // Print option elements.
4187 ?>
4188 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_external_users" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="external_users"<?php checked( 'external_users' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_external_users"><?php esc_html_e( 'All authenticated users (All external service users and all WordPress users)', 'authorizer' ); ?></label><br />
4189 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_approved_users" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="approved_users"<?php checked( 'approved_users' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_approved_users"><?php esc_html_e( 'Only', 'authorizer' ); ?> <a href="javascript:chooseTab('access_lists' );" id="dashboard_link_approved_users"><?php esc_html_e( 'approved users', 'authorizer' ); ?></a> <?php esc_html_e( '(Approved external users and all WordPress users)', 'authorizer' ); ?></label><br />
4190 <?php
4191 }
4192
4193
4194 /**
4195 * Settings print callback.
4196 *
4197 * @param string $args Args (e.g., multisite admin mode).
4198 * @return void
4199 */
4200 public function print_select_auth_access_role_receive_pending_emails( $args = '' ) {
4201 // Get plugin option.
4202 $option = 'access_role_receive_pending_emails';
4203 $auth_settings_option = $this->get_plugin_option( $option );
4204
4205 // Print option elements.
4206 ?>
4207 <select id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]">
4208 <option value="---" <?php selected( $auth_settings_option, '---' ); ?>><?php esc_html_e( "None (Don't send notification emails)", 'authorizer' ); ?></option>
4209 <?php wp_dropdown_roles( $auth_settings_option ); ?>
4210 </select>
4211 <?php
4212 }
4213
4214
4215 /**
4216 * Settings print callback.
4217 *
4218 * @param string $args Args (e.g., multisite admin mode).
4219 * @return void
4220 */
4221 public function print_wysiwyg_auth_access_pending_redirect_to_message( $args = '' ) {
4222 // Get plugin option.
4223 $option = 'access_pending_redirect_to_message';
4224 $auth_settings_option = $this->get_plugin_option( $option );
4225
4226 // Print option elements.
4227 wp_editor(
4228 wpautop( $auth_settings_option ),
4229 "auth_settings_$option",
4230 array(
4231 'media_buttons' => false,
4232 'textarea_name' => "auth_settings[$option]",
4233 'textarea_rows' => 5,
4234 'tinymce' => true,
4235 'teeny' => true,
4236 'quicktags' => false,
4237 )
4238 );
4239 }
4240
4241
4242 /**
4243 * Settings print callback.
4244 *
4245 * @param string $args Args (e.g., multisite admin mode).
4246 * @return void
4247 */
4248 public function print_wysiwyg_auth_access_blocked_redirect_to_message( $args = '' ) {
4249 // Get plugin option.
4250 $option = 'access_blocked_redirect_to_message';
4251 $auth_settings_option = $this->get_plugin_option( $option );
4252
4253 // Print option elements.
4254 wp_editor(
4255 wpautop( $auth_settings_option ),
4256 "auth_settings_$option",
4257 array(
4258 'media_buttons' => false,
4259 'textarea_name' => "auth_settings[$option]",
4260 'textarea_rows' => 5,
4261 'tinymce' => true,
4262 'teeny' => true,
4263 'quicktags' => false,
4264 )
4265 );
4266 }
4267
4268
4269 /**
4270 * Settings print callback.
4271 *
4272 * @param string $args Args (e.g., multisite admin mode).
4273 * @return void
4274 */
4275 public function print_checkbox_auth_access_should_email_approved_users( $args = '' ) {
4276 // Get plugin option.
4277 $option = 'access_should_email_approved_users';
4278 $auth_settings_option = $this->get_plugin_option( $option );
4279
4280 // Print option elements.
4281 ?>
4282 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Send a welcome email when approving a new user', 'authorizer' ); ?></label>
4283 <?php
4284 }
4285
4286
4287 /**
4288 * Settings print callback.
4289 *
4290 * @param string $args Args (e.g., multisite admin mode).
4291 * @return void
4292 */
4293 public function print_text_auth_access_email_approved_users_subject( $args = '' ) {
4294 // Get plugin option.
4295 $option = 'access_email_approved_users_subject';
4296 $auth_settings_option = $this->get_plugin_option( $option );
4297
4298 // Print option elements.
4299 ?>
4300 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="Welcome to [site_name]!" style="width:320px;" /><br /><small><?php echo wp_kses( __( 'You can use the <b>[site_name]</b> shortcode.', 'authorizer' ), $this->allowed_html ); ?></small>
4301 <?php
4302 }
4303
4304
4305 /**
4306 * Settings print callback.
4307 *
4308 * @param string $args Args (e.g., multisite admin mode).
4309 * @return void
4310 */
4311 public function print_wysiwyg_auth_access_email_approved_users_body( $args = '' ) {
4312 // Get plugin option.
4313 $option = 'access_email_approved_users_body';
4314 $auth_settings_option = $this->get_plugin_option( $option );
4315
4316 // Print option elements.
4317 wp_editor(
4318 wpautop( $auth_settings_option ),
4319 "auth_settings_$option",
4320 array(
4321 'media_buttons' => false,
4322 'textarea_name' => "auth_settings[$option]",
4323 'textarea_rows' => 9,
4324 'tinymce' => true,
4325 'teeny' => true,
4326 'quicktags' => false,
4327 )
4328 );
4329 ?>
4330 <small>
4331 <?php
4332 printf(
4333 /* TRANSLATORS: 1: Shortcode for site name 2: Shortcode for site URL 3: Shortcode for user email */
4334 wp_kses( __( 'You can use %1$s, %2$s, and %3$s shortcodes.', 'authorizer' ), $this->allowed_html ),
4335 '<b>[site_name]</b>',
4336 '<b>[site_url]</b>',
4337 '<b>[user_email]</b>'
4338 );
4339 ?>
4340 </small>
4341 <?php
4342 }
4343
4344
4345 /**
4346 * Settings print callback.
4347 *
4348 * @param string $args Args (e.g., multisite admin mode).
4349 * @return void
4350 */
4351 public function print_section_info_access_public( $args = '' ) {
4352 ?>
4353 <div id="section_info_access_public" class="section_info">
4354 <p><?php esc_html_e( 'Choose your public access options here.', 'authorizer' ); ?></p>
4355 </div>
4356 <?php
4357 }
4358
4359
4360 /**
4361 * Settings print callback.
4362 *
4363 * @param string $args Args (e.g., multisite admin mode).
4364 * @return void
4365 */
4366 public function print_radio_auth_access_who_can_view( $args = '' ) {
4367 // Get plugin option.
4368 $option = 'access_who_can_view';
4369 $admin_mode = $this->get_admin_mode( $args );
4370 $auth_settings_option = $this->get_plugin_option( $option, $admin_mode, 'allow override', 'print overlay' );
4371
4372 // If this site is configured independently of any multisite overrides, make sure we are not grabbing the multisite value; otherwise, grab the multisite value to show behind the disabled overlay.
4373 if ( is_multisite() && 1 === intval( $this->get_plugin_option( 'advanced_override_multisite' ) ) ) {
4374 $auth_settings_option = $this->get_plugin_option( $option );
4375 } elseif ( is_multisite() && WP_Plugin_Authorizer::SINGLE_CONTEXT === $admin_mode && '1' === $this->get_plugin_option( 'multisite_override', WP_Plugin_Authorizer::NETWORK_CONTEXT ) ) {
4376 // Workaround: javascript code hides/shows other settings based
4377 // on the selection in this option. If this option is overridden
4378 // by a multisite option, it should show that value in order to
4379 // correctly display the other appropriate options.
4380 // Side effect: this site option will be overwritten by the
4381 // multisite option on save. Since this is a 2-item radio, we
4382 // determined this was acceptable.
4383 $auth_settings_option = $this->get_plugin_option( $option, WP_Plugin_Authorizer::NETWORK_CONTEXT );
4384 }
4385
4386 // Print option elements.
4387 ?>
4388 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_everyone" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="everyone"<?php checked( 'everyone' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_everyone"><?php esc_html_e( 'Everyone can see the site', 'authorizer' ); ?></label><br />
4389 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_logged_in_users" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="logged_in_users"<?php checked( 'logged_in_users' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_logged_in_users"><?php esc_html_e( 'Only logged in users can see the site', 'authorizer' ); ?></label><br />
4390 <?php
4391 }
4392
4393
4394 /**
4395 * Settings print callback.
4396 *
4397 * @param string $args Args (e.g., multisite admin mode).
4398 * @return void
4399 */
4400 public function print_radio_auth_access_redirect( $args = '' ) {
4401 // Get plugin option.
4402 $option = 'access_redirect';
4403 $auth_settings_option = $this->get_plugin_option( $option );
4404
4405 // Print option elements.
4406 ?>
4407 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_to_login" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="login"<?php checked( 'login' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_to_login"><?php esc_html_e( 'Send them to the login screen', 'authorizer' ); ?></label><br />
4408 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_to_message" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="message"<?php checked( 'message' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_to_message"><?php esc_html_e( 'Show them the anonymous access message (below)', 'authorizer' ); ?></label>
4409 <?php
4410 }
4411
4412
4413 /**
4414 * Settings print callback.
4415 *
4416 * @param string $args Args (e.g., multisite admin mode).
4417 * @return void
4418 */
4419 public function print_radio_auth_access_public_warning( $args = '' ) {
4420 // Get plugin option.
4421 $option = 'access_public_warning';
4422 $auth_settings_option = $this->get_plugin_option( $option );
4423
4424 // Print option elements.
4425 ?>
4426 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_no" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="no_warning"<?php checked( 'no_warning' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_no"><?php echo wp_kses( __( 'Show them the page <strong>without</strong> the anonymous access message', 'authorizer' ), $this->allowed_html ); ?></label><br />
4427 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="warning"<?php checked( 'warning' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>"><?php echo wp_kses( __( 'Show them the page <strong>with</strong> the anonymous access message (marked up as a <a href="http://getbootstrap.com/components/#alerts-dismissible" target="_blank">Bootstrap Dismissible Alert</a>)', 'authorizer' ), $this->allowed_html ); ?></label>
4428 <?php
4429 }
4430
4431
4432 /**
4433 * Settings print callback.
4434 *
4435 * @param string $args Args (e.g., multisite admin mode).
4436 * @return void
4437 */
4438 public function print_wysiwyg_auth_access_redirect_to_message( $args = '' ) {
4439 // Get plugin option.
4440 $option = 'access_redirect_to_message';
4441 $auth_settings_option = $this->get_plugin_option( $option );
4442
4443 // Print option elements.
4444 wp_editor(
4445 wpautop( $auth_settings_option ),
4446 "auth_settings_$option",
4447 array(
4448 'media_buttons' => false,
4449 'textarea_name' => "auth_settings[$option]",
4450 'textarea_rows' => 5,
4451 'tinymce' => true,
4452 'teeny' => true,
4453 'quicktags' => false,
4454 )
4455 );
4456 }
4457
4458
4459 /**
4460 * Settings print callback.
4461 *
4462 * @param string $args Args (e.g., multisite admin mode).
4463 * @return void
4464 */
4465 public function print_multiselect_auth_access_public_pages( $args = '' ) {
4466 // Get plugin option.
4467 $option = 'access_public_pages';
4468 $auth_settings_option = $this->get_plugin_option( $option );
4469 $auth_settings_option = is_array( $auth_settings_option ) ? $auth_settings_option : array();
4470
4471 $post_types = array_merge( array( 'page', 'post' ), get_post_types( array( '_builtin' => false ), 'names' ) );
4472 $post_types = is_array( $post_types ) ? $post_types : array();
4473
4474 // Print option elements.
4475 ?>
4476 <select id="auth_settings_<?php echo esc_attr( $option ); ?>" multiple="multiple" name="auth_settings[<?php echo esc_attr( $option ); ?>][]">
4477 <optgroup label="<?php esc_attr_e( 'Home', 'authorizer' ); ?>">
4478 <option value="home" <?php selected( in_array( 'home', $auth_settings_option, true ) ); ?>><?php esc_html_e( 'Home Page', 'authorizer' ); ?></option>
4479 <option value="auth_public_404" <?php selected( in_array( 'auth_public_404', $auth_settings_option, true ) ); ?>><?php esc_html_e( 'Nonexistent (404) Pages', 'authorizer' ); ?></option>
4480 </optgroup>
4481 <?php foreach ( $post_types as $post_type ) : ?>
4482 <optgroup label="<?php echo esc_attr( ucfirst( $post_type ) ); ?>">
4483 <?php
4484 $pages = get_posts(
4485 array(
4486 'post_type' => $post_type,
4487 'posts_per_page' => 1000, // phpcs:ignore WordPress.VIP.PostsPerPage.posts_per_page_posts_per_page
4488 )
4489 );
4490 $pages = is_array( $pages ) ? $pages : array();
4491 foreach ( $pages as $page ) :
4492 ?>
4493 <option value="<?php echo esc_attr( $page->ID ); ?>" <?php selected( in_array( strval( $page->ID ), $auth_settings_option, true ) ); ?>><?php echo esc_html( $page->post_title ); ?></option>
4494 <?php endforeach; ?>
4495 </optgroup>
4496 <?php endforeach; ?>
4497 <optgroup label="<?php esc_attr_e( 'Categories', 'authorizer' ); ?>">
4498 <?php
4499 // If sitepress-multilingual-cms plugin is enabled, temporarily disable
4500 // its terms_clauses filter since it conflicts with the category handling.
4501 if ( array_key_exists( 'sitepress', $GLOBALS ) && is_object( $GLOBALS['sitepress'] ) ) {
4502 remove_filter( 'terms_clauses', array( $GLOBALS['sitepress'], 'terms_clauses' ) );
4503 $categories = get_categories( array( 'hide_empty' => false ) );
4504 add_filter( 'terms_clauses', array( $GLOBALS['sitepress'], 'terms_clauses' ) );
4505 } else {
4506 $categories = get_categories( array( 'hide_empty' => false ) );
4507 }
4508 foreach ( $categories as $category ) :
4509 ?>
4510 <option value="<?php echo esc_attr( 'cat_' . $category->slug ); ?>" <?php selected( in_array( 'cat_' . $category->slug, $auth_settings_option, true ) ); ?>><?php echo esc_html( $category->name ); ?></option>
4511 <?php endforeach; ?>
4512 </optgroup>
4513 </select>
4514 <?php
4515 }
4516
4517
4518 /**
4519 * Settings print callback.
4520 *
4521 * @param string $args Args (e.g., multisite admin mode).
4522 * @return void
4523 */
4524 public function print_section_info_external( $args = '' ) {
4525 ?>
4526 <div id="section_info_external" class="section_info">
4527 <p><?php esc_html_e( 'Enter your external server settings below.', 'authorizer' ); ?></p>
4528 </div>
4529 <?php
4530 }
4531
4532
4533 /**
4534 * Settings print callback.
4535 *
4536 * @param string $args Args (e.g., multisite admin mode).
4537 * @return void
4538 */
4539 public function print_select_auth_access_default_role( $args = '' ) {
4540 // Get plugin option.
4541 $option = 'access_default_role';
4542 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4543
4544 // Print option elements.
4545 ?>
4546 <select id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]">
4547 <?php wp_dropdown_roles( $auth_settings_option ); ?>
4548 <option value=""<?php selected( '' === $auth_settings_option ); ?>><?php esc_html_e( '-- None --', 'authorizer' ); ?></option>
4549 </select>
4550 <?php
4551 }
4552
4553
4554 /**
4555 * Settings print callback.
4556 *
4557 * @param string $args Args (e.g., multisite admin mode).
4558 * @return void
4559 */
4560 public function print_checkbox_auth_external_google( $args = '' ) {
4561 // Get plugin option.
4562 $option = 'google';
4563 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4564
4565 // Print option elements.
4566 ?>
4567 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Enable Google Logins', 'authorizer' ); ?></label>
4568 <?php
4569 }
4570
4571
4572 /**
4573 * Settings print callback.
4574 *
4575 * @param string $args Args (e.g., multisite admin mode).
4576 * @return void
4577 */
4578 public function print_text_google_clientid( $args = '' ) {
4579 // Get plugin option.
4580 $option = 'google_clientid';
4581 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4582
4583 // Print option elements.
4584 $site_url_parts = wp_parse_url( get_site_url() );
4585 $site_url_host = $site_url_parts['scheme'] . '://' . $site_url_parts['host'] . '/';
4586
4587 esc_html_e( "If you don't have a Google Client ID and Secret, generate them by following these instructions:", 'authorizer' );
4588 ?>
4589 <ol>
4590 <li><?php echo wp_kses( __( 'Click <strong>Create a Project</strong> on the <a href="https://cloud.google.com/console" target="_blank">Google Developers Console</a>. You can name it whatever you want.', 'authorizer' ), $this->allowed_html ); ?></li>
4591 <li><?php echo wp_kses( __( 'Within the project, navigate to <em>APIs and Auth</em> &gt; <em>Credentials</em>, then click <strong>Create New Client ID</strong> under OAuth. Use these settings:', 'authorizer' ), $this->allowed_html ); ?>
4592 <ul>
4593 <li><?php echo wp_kses( __( 'Application Type: <strong>Web application</strong>', 'authorizer' ), $this->allowed_html ); ?></li>
4594 <li><?php esc_html_e( 'Authorized Javascript Origins:', 'authorizer' ); ?> <strong><?php echo esc_html( rtrim( $site_url_host, '/' ) ); ?></strong></li>
4595 <li><?php echo wp_kses( __( 'Authorized Redirect URI: <em>none</em>', 'authorizer' ), $this->allowed_html ); ?></li>
4596 </ul>
4597 </li>
4598 <li><?php esc_html_e( 'Copy/paste your new Client ID/Secret pair into the fields below.', 'authorizer' ); ?></li>
4599 <li><?php echo wp_kses( __( '<strong>Note</strong>: Navigate to <em>APIs and Auth</em> &gt; <em>Consent screen</em> to change the way the Google consent screen appears after a user has successfully entered their password, but before they are redirected back to WordPress.', 'authorizer' ), $this->allowed_html ); ?></li>
4600 <li><?php echo wp_kses( __( 'Note: Google may have a more recent version of these instructions in their <a href="https://developers.google.com/identity/sign-in/web/devconsole-project" target="_blank">developer documentation</a>.', 'authorizer' ), $this->allowed_html ); ?></li>
4601 </ol>
4602 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width:560px;" />
4603 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: 1234567890123-kdjr85yt6vjr6d8g7dhr8g7d6durjf7g.apps.googleusercontent.com', 'authorizer' ); ?></label>
4604 <?php
4605 }
4606
4607
4608 /**
4609 * Settings print callback.
4610 *
4611 * @param string $args Args (e.g., multisite admin mode).
4612 * @return void
4613 */
4614 public function print_text_google_clientsecret( $args = '' ) {
4615 // Get plugin option.
4616 $option = 'google_clientsecret';
4617 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4618
4619 // Print option elements.
4620 ?>
4621 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width:220px;" />
4622 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: sDNgX5_pr_5bly-frKmvp8jT', 'authorizer' ); ?></label>
4623 <?php
4624 }
4625
4626
4627 /**
4628 * Settings print callback.
4629 *
4630 * @param string $args Args (e.g., multisite admin mode).
4631 * @return void
4632 */
4633 public function print_text_google_hosteddomain( $args = '' ) {
4634 // Get plugin option.
4635 $option = 'google_hosteddomain';
4636 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4637
4638 // Print option elements.
4639 ?>
4640 <textarea id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" placeholder="" style="width:220px;"><?php echo esc_html( $auth_settings_option ); ?></textarea>
4641 <br /><small><?php esc_html_e( 'Restrict Google logins to a specific Google Apps hosted domain (for example, mycollege.edu). Leave blank to allow all Google sign-ins.', 'authorizer' ); ?><br /><?php esc_html_e( 'If restricting to multiple domains, add one domain per line.', 'authorizer' ); ?></small>
4642 <?php
4643 }
4644
4645
4646 /**
4647 * Settings print callback.
4648 *
4649 * @param string $args Args (e.g., multisite admin mode).
4650 * @return void
4651 */
4652 public function print_checkbox_auth_external_cas( $args = '' ) {
4653 // Get plugin option.
4654 $option = 'cas';
4655 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4656
4657 // Make sure php5-curl extension is installed on server.
4658 $curl_installed_message = ! function_exists( 'curl_init' ) ? __( '<a href="http://www.php.net//manual/en/curl.installation.php" target="_blank" style="color: red;">PHP CURL extension</a> is not installed', 'authorizer' ) : '';
4659
4660 // Make sure php_openssl extension is installed on server.
4661 $openssl_installed_message = ! extension_loaded( 'openssl' ) ? __( '<a href="http://stackoverflow.com/questions/23424459/enable-php-openssl-not-working" target="_blank" style="color: red;">PHP openssl extension</a> is not installed', 'authorizer' ) : '';
4662
4663 // Build error message string.
4664 $error_message = '';
4665 if ( strlen( $curl_installed_message ) > 0 || strlen( $openssl_installed_message ) > 0 ) {
4666 $error_message = '<span style="color: red;">(' .
4667 __( 'Warning', 'authorizer' ) . ': ' .
4668 $curl_installed_message .
4669 ( strlen( $curl_installed_message ) > 0 && strlen( $openssl_installed_message ) > 0 ? '; ' : '' ) .
4670 $openssl_installed_message .
4671 ')</span>';
4672 }
4673
4674 // Print option elements.
4675 ?>
4676 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Enable CAS Logins', 'authorizer' ); ?></label> <?php echo wp_kses( $error_message, $this->allowed_html ); ?>
4677 <?php
4678 }
4679
4680
4681 /**
4682 * Settings print callback.
4683 *
4684 * @param string $args Args (e.g., multisite admin mode).
4685 * @return void
4686 */
4687 public function print_text_cas_custom_label( $args = '' ) {
4688 // Get plugin option.
4689 $option = 'cas_custom_label';
4690 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4691
4692 // Print option elements.
4693 esc_html_e( 'The button on the login page will read:', 'authorizer' );
4694 ?>
4695 <p><a class="button-primary button-large" style="padding: 3px 16px; height: 36px;"><span class="dashicons dashicons-lock" style="margin: 4px 4px 0 0;"></span> <strong><?php esc_html_e( 'Sign in with', 'authorizer' ); ?> </strong><input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="CAS" style="width: 100px;" /></a></p>
4696 <?php
4697 }
4698
4699
4700 /**
4701 * Settings print callback.
4702 *
4703 * @param string $args Args (e.g., multisite admin mode).
4704 * @return void
4705 */
4706 public function print_text_cas_host( $args = '' ) {
4707 // Get plugin option.
4708 $option = 'cas_host';
4709 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4710
4711 // Print option elements.
4712 ?>
4713 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
4714 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: authn.example.edu', 'authorizer' ); ?></label>
4715 <?php
4716 }
4717
4718
4719 /**
4720 * Settings print callback.
4721 *
4722 * @param string $args Args (e.g., multisite admin mode).
4723 * @return void
4724 */
4725 public function print_text_cas_port( $args = '' ) {
4726 // Get plugin option.
4727 $option = 'cas_port';
4728 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4729
4730 // Print option elements.
4731 ?>
4732 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width:50px;" />
4733 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: 443', 'authorizer' ); ?></label>
4734 <?php
4735 }
4736
4737
4738 /**
4739 * Settings print callback.
4740 *
4741 * @param string $args Args (e.g., multisite admin mode).
4742 * @return void
4743 */
4744 public function print_text_cas_path( $args = '' ) {
4745 // Get plugin option.
4746 $option = 'cas_path';
4747 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4748
4749 // Print option elements.
4750 ?>
4751 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
4752 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: /cas', 'authorizer' ); ?></label>
4753 <?php
4754 }
4755
4756
4757 /**
4758 * Settings print callback.
4759 *
4760 * @param string $args Args (e.g., multisite admin mode).
4761 * @return void
4762 */
4763 public function print_select_cas_version( $args = '' ) {
4764 // Get plugin option.
4765 $option = 'cas_version';
4766 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4767
4768 // Print option elements.
4769 ?>
4770 <select id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]">
4771 <option value="SAML_VERSION_1_1" <?php selected( $auth_settings_option, 'SAML_VERSION_1_1' ); ?>>SAML_VERSION_1_1</option>
4772 <option value="CAS_VERSION_3_0" <?php selected( $auth_settings_option, 'CAS_VERSION_3_0' ); ?>>CAS_VERSION_3_0</option>
4773 <option value="CAS_VERSION_2_0" <?php selected( $auth_settings_option, 'CAS_VERSION_2_0' ); ?>>CAS_VERSION_2_0</option>
4774 <option value="CAS_VERSION_1_0" <?php selected( $auth_settings_option, 'CAS_VERSION_1_0' ); ?>>CAS_VERSION_1_0</option>
4775 </select>
4776 <?php
4777 }
4778
4779
4780 /**
4781 * Settings print callback.
4782 *
4783 * @param string $args Args (e.g., multisite admin mode).
4784 * @return void
4785 */
4786 public function print_text_cas_attr_email( $args = '' ) {
4787 // Get plugin option.
4788 $option = 'cas_attr_email';
4789 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4790
4791 // Print option elements.
4792 ?>
4793 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
4794 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: mail', 'authorizer' ); ?></label>
4795 <br /><small><?php echo wp_kses( __( "Note: If your CAS server doesn't return an attribute containing an email, you can specify the @domain portion of the email address here, and the email address will be constructed from it and the username. For example, if user 'bob' logs in and his email address should be bob@example.edu, then enter <strong>@example.edu</strong> in this field.", 'authorizer' ), $this->allowed_html ); ?></small>
4796 <?php
4797 }
4798
4799
4800 /**
4801 * Settings print callback.
4802 *
4803 * @param string $args Args (e.g., multisite admin mode).
4804 * @return void
4805 */
4806 public function print_text_cas_attr_first_name( $args = '' ) {
4807 // Get plugin option.
4808 $option = 'cas_attr_first_name';
4809 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4810
4811 // Print option elements.
4812 ?>
4813 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
4814 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: givenName', 'authorizer' ); ?></label>
4815 <?php
4816 }
4817
4818
4819 /**
4820 * Settings print callback.
4821 *
4822 * @param string $args Args (e.g., multisite admin mode).
4823 * @return void
4824 */
4825 public function print_text_cas_attr_last_name( $args = '' ) {
4826 // Get plugin option.
4827 $option = 'cas_attr_last_name';
4828 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4829
4830 // Print option elements.
4831 ?>
4832 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
4833 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: sn', 'authorizer' ); ?></label>
4834 <?php
4835 }
4836
4837
4838 /**
4839 * Settings print callback.
4840 *
4841 * @param string $args Args (e.g., multisite admin mode).
4842 * @return void
4843 */
4844 public function print_checkbox_cas_attr_update_on_login( $args = '' ) {
4845 // Get plugin option.
4846 $option = 'cas_attr_update_on_login';
4847 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4848
4849 // Print option elements.
4850 ?>
4851 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Update first and last name fields on login (will overwrite any name the user has supplied in their profile)', 'authorizer' ); ?></label>
4852 <?php
4853 }
4854
4855
4856 /**
4857 * Settings print callback.
4858 *
4859 * @param string $args Args (e.g., multisite admin mode).
4860 * @return void
4861 */
4862 public function print_checkbox_cas_auto_login( $args = '' ) {
4863 // Get plugin option.
4864 $option = 'cas_auto_login';
4865 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4866
4867 // Print option elements.
4868 ?>
4869 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( "Immediately redirect to CAS login form if it's the only enabled external service and WordPress logins are hidden", 'authorizer' ); ?></label>
4870 <p><small><?php esc_html_e( 'Note: This feature will only work if you have checked "Hide WordPress Logins" in Advanced settings, and if CAS is the only enabled service (i.e., no Google or LDAP). If you have enabled CAS Single Sign-On (SSO), and a user has already logged into CAS elsewhere, enabling this feature will allow automatic logins without any user interaction.', 'authorizer' ); ?></small></p>
4871 <?php
4872 }
4873
4874
4875 /**
4876 * Settings print callback.
4877 *
4878 * @param string $args Args (e.g., multisite admin mode).
4879 * @return void
4880 */
4881 public function print_checkbox_auth_external_ldap( $args = '' ) {
4882 // Get plugin option.
4883 $option = 'ldap';
4884 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4885
4886 // Make sure php5-ldap extension is installed on server.
4887 $ldap_installed_message = ! function_exists( 'ldap_connect' ) ? '<span style="color: red;">(' . __( 'Warning: <a href="http://www.php.net/manual/en/ldap.installation.php" target="_blank" style="color: red;">PHP LDAP extension</a> is <strong>not</strong> installed', 'authorizer' ) . ')</span>' : '';
4888
4889 // Print option elements.
4890 ?>
4891 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Enable LDAP Logins', 'authorizer' ); ?></label> <?php echo wp_kses( $ldap_installed_message, $this->allowed_html ); ?>
4892 <?php
4893 }
4894
4895
4896 /**
4897 * Settings print callback.
4898 *
4899 * @param string $args Args (e.g., multisite admin mode).
4900 * @return void
4901 */
4902 public function print_text_ldap_host( $args = '' ) {
4903 // Get plugin option.
4904 $option = 'ldap_host';
4905 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4906
4907 // Print option elements.
4908 ?>
4909 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width:330px;" />
4910 <br /><small><?php esc_html_e( 'Specify either a hostname (for example, ldap.example.edu) or a full LDAP URI (for example, ldaps://ldap.example.edu:636).', 'authorizer' ); ?></small>
4911 <?php
4912 }
4913
4914
4915 /**
4916 * Settings print callback.
4917 *
4918 * @param string $args Args (e.g., multisite admin mode).
4919 * @return void
4920 */
4921 public function print_text_ldap_port( $args = '' ) {
4922 // Get plugin option.
4923 $option = 'ldap_port';
4924 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4925
4926 // Print option elements.
4927 ?>
4928 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width:50px;" />
4929 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: 389', 'authorizer' ); ?></label>
4930 <br /><small><?php esc_html_e( 'If a full LDAP URI (ldaps://hostname:port) is specified above, this field is ignored.', 'authorizer' ); ?></small>
4931 <?php
4932 }
4933
4934
4935 /**
4936 * Settings print callback.
4937 *
4938 * @param string $args Args (e.g., multisite admin mode).
4939 * @return void
4940 */
4941 public function print_checkbox_ldap_tls( $args = '' ) {
4942 // Get plugin option.
4943 $option = 'ldap_tls';
4944 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4945
4946 // Print option elements.
4947 ?>
4948 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Use TLS', 'authorizer' ); ?></label>
4949 <br /><small><?php esc_html_e( 'If ldaps is used, this should be unchecked', 'authorizer' ); ?></small>
4950 <?php
4951 }
4952
4953
4954 /**
4955 * Settings print callback.
4956 *
4957 * @param string $args Args (e.g., multisite admin mode).
4958 * @return void
4959 */
4960 public function print_text_ldap_search_base( $args = '' ) {
4961 // Get plugin option.
4962 $option = 'ldap_search_base';
4963 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4964
4965 // Print option elements.
4966 ?>
4967 <textarea id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" placeholder="" style="width:330px;"><?php echo esc_attr( $auth_settings_option ); ?></textarea>
4968 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: ou=people,dc=example,dc=edu', 'authorizer' ); ?></label>
4969 <br /><small><?php esc_html_e( 'If you have multiple search bases, separate them by newlines (one per line).', 'authorizer' ); ?></small>
4970 <?php
4971 }
4972
4973
4974 /**
4975 * Settings print callback.
4976 *
4977 * @param string $args Args (e.g., multisite admin mode).
4978 * @return void
4979 */
4980 public function print_text_ldap_uid( $args = '' ) {
4981 // Get plugin option.
4982 $option = 'ldap_uid';
4983 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
4984
4985 // Print option elements.
4986 ?>
4987 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width:80px;" />
4988 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: uid', 'authorizer' ); ?></label>
4989 <?php
4990 }
4991
4992
4993 /**
4994 * Settings print callback.
4995 *
4996 * @param string $args Args (e.g., multisite admin mode).
4997 * @return void
4998 */
4999 public function print_text_ldap_attr_email( $args = '' ) {
5000 // Get plugin option.
5001 $option = 'ldap_attr_email';
5002 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5003
5004 // Print option elements.
5005 ?>
5006 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
5007 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: mail', 'authorizer' ); ?></label>
5008 <br /><small><?php echo wp_kses( __( "Note: If your LDAP server doesn't return an attribute containing an email, you can specify the @domain portion of the email address here, and the email address will be constructed from it and the username. For example, if user 'bob' logs in and his email address should be bob@example.edu, then enter <strong>@example.edu</strong> in this field.", 'authorizer' ), $this->allowed_html ); ?></small>
5009 <?php
5010 }
5011
5012
5013 /**
5014 * Settings print callback.
5015 *
5016 * @param string $args Args (e.g., multisite admin mode).
5017 * @return void
5018 */
5019 public function print_text_ldap_user( $args = '' ) {
5020 // Get plugin option.
5021 $option = 'ldap_user';
5022 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5023
5024 // Print option elements.
5025 ?>
5026 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width:330px;" />
5027 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: cn=directory-user,ou=specials,dc=example,dc=edu', 'authorizer' ); ?></label>
5028 <?php
5029 }
5030
5031
5032 /**
5033 * Settings print callback.
5034 *
5035 * @param string $args Args (e.g., multisite admin mode).
5036 * @return void
5037 */
5038 public function print_password_ldap_password( $args = '' ) {
5039 // Get plugin option.
5040 $option = 'ldap_password';
5041 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5042
5043 // Print option elements.
5044 ?>
5045 <input type="password" id="garbage_to_stop_autofill" name="garbage" value="" autocomplete="off" style="display:none;" />
5046 <input type="password" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $this->decrypt( $auth_settings_option ) ); ?>" autocomplete="off" />
5047 <?php
5048 }
5049
5050
5051 /**
5052 * Settings print callback.
5053 *
5054 * @param string $args Args (e.g., multisite admin mode).
5055 * @return void
5056 */
5057 public function print_text_ldap_lostpassword_url( $args = '' ) {
5058 // Get plugin option.
5059 $option = 'ldap_lostpassword_url';
5060 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5061
5062 // Print option elements.
5063 ?>
5064 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" style="width: 400px;" />
5065 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: https://myschool.example.edu:8888/am-forgot-password', 'authorizer' ); ?></label>
5066 <?php
5067 }
5068
5069
5070 /**
5071 * Settings print callback.
5072 *
5073 * @param string $args Args (e.g., multisite admin mode).
5074 * @return void
5075 */
5076 public function print_text_ldap_attr_first_name( $args = '' ) {
5077 // Get plugin option.
5078 $option = 'ldap_attr_first_name';
5079 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5080
5081 // Print option elements.
5082 ?>
5083 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
5084 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: givenname', 'authorizer' ); ?></label>
5085 <?php
5086 }
5087
5088
5089 /**
5090 * Settings print callback.
5091 *
5092 * @param string $args Args (e.g., multisite admin mode).
5093 * @return void
5094 */
5095 public function print_text_ldap_attr_last_name( $args = '' ) {
5096 // Get plugin option.
5097 $option = 'ldap_attr_last_name';
5098 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5099
5100 // Print option elements.
5101 ?>
5102 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" />
5103 <br /><label for="auth_settings_<?php echo esc_attr( $option ); ?>" class="helper"><?php esc_html_e( 'Example: sn', 'authorizer' ); ?></label>
5104 <?php
5105 }
5106
5107
5108 /**
5109 * Settings print callback.
5110 *
5111 * @param string $args Args (e.g., multisite admin mode).
5112 * @return void
5113 */
5114 public function print_checkbox_ldap_attr_update_on_login( $args = '' ) {
5115 // Get plugin option.
5116 $option = 'ldap_attr_update_on_login';
5117 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5118
5119 // Print option elements.
5120 ?>
5121 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Update first and last name fields on login (will overwrite any name the user has supplied in their profile)', 'authorizer' ); ?></label>
5122 <?php
5123 }
5124
5125
5126 /**
5127 * Settings print callback.
5128 *
5129 * @param string $args Args (e.g., multisite admin mode).
5130 * @return void
5131 */
5132 public function print_section_info_advanced( $args = '' ) {
5133 ?>
5134 <div id="section_info_advanced" class="section_info">
5135 <p><?php esc_html_e( 'You may optionally specify some advanced settings below.', 'authorizer' ); ?></p>
5136 </div>
5137 <?php
5138 }
5139
5140
5141 /**
5142 * Settings print callback.
5143 *
5144 * @param string $args Args (e.g., multisite admin mode).
5145 * @return void
5146 */
5147 public function print_text_auth_advanced_lockouts( $args = '' ) {
5148 // Get plugin option.
5149 $option = 'advanced_lockouts';
5150 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5151
5152 // Print option elements.
5153 esc_html_e( 'After', 'authorizer' );
5154 ?>
5155 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_attempts_1" name="auth_settings[<?php echo esc_attr( $option ); ?>][attempts_1]" value="<?php echo esc_attr( $auth_settings_option['attempts_1'] ); ?>" placeholder="10" style="width:30px;" />
5156 <?php esc_html_e( 'invalid password attempts, delay further attempts on that user for', 'authorizer' ); ?>
5157 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_duration_1" name="auth_settings[<?php echo esc_attr( $option ); ?>][duration_1]" value="<?php echo esc_attr( $auth_settings_option['duration_1'] ); ?>" placeholder="1" style="width:30px;" />
5158 <?php esc_html_e( 'minute(s).', 'authorizer' ); ?>
5159 <br />
5160 <?php esc_html_e( 'After', 'authorizer' ); ?>
5161 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_attempts_2" name="auth_settings[<?php echo esc_attr( $option ); ?>][attempts_2]" value="<?php echo esc_attr( $auth_settings_option['attempts_2'] ); ?>" placeholder="10" style="width:30px;" />
5162 <?php esc_html_e( 'more invalid attempts, increase the delay to', 'authorizer' ); ?>
5163 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_duration_2" name="auth_settings[<?php echo esc_attr( $option ); ?>][duration_2]" value="<?php echo esc_attr( $auth_settings_option['duration_2'] ); ?>" placeholder="10" style="width:30px;" />
5164 <?php esc_html_e( 'minutes.', 'authorizer' ); ?>
5165 <br />
5166 <?php esc_html_e( 'Reset the delays after', 'authorizer' ); ?>
5167 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>_reset_duration" name="auth_settings[<?php echo esc_attr( $option ); ?>][reset_duration]" value="<?php echo esc_attr( $auth_settings_option['reset_duration'] ); ?>" placeholder="240" style="width:40px;" />
5168 <?php esc_html_e( 'minutes with no invalid attempts.', 'authorizer' ); ?>
5169 <?php
5170 }
5171
5172
5173 /**
5174 * Settings print callback.
5175 *
5176 * @param string $args Args (e.g., multisite admin mode).
5177 * @return void
5178 */
5179 public function print_checkbox_auth_advanced_hide_wp_login( $args = '' ) {
5180 // Get plugin option.
5181 $option = 'advanced_hide_wp_login';
5182 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5183
5184 // Print option elements.
5185 ?>
5186 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Hide WordPress Logins', 'authorizer' ); ?></label>
5187 <p><small><?php esc_html_e( 'Note: You can always access the WordPress logins by adding external=wordpress to the wp-login URL, like so:', 'authorizer' ); ?><br /><a href="<?php echo esc_attr( wp_login_url() ); ?>?external=wordpress" target="_blank"><?php echo esc_html( wp_login_url() ); ?>?external=wordpress</a>.</p>
5188 <?php
5189 }
5190
5191
5192 /**
5193 * Settings print callback.
5194 *
5195 * @param string $args Args (e.g., multisite admin mode).
5196 * @return void
5197 */
5198 public function print_radio_auth_advanced_branding( $args = '' ) {
5199 // Get plugin option.
5200 $option = 'advanced_branding';
5201 $auth_settings_option = $this->get_plugin_option( $option );
5202
5203 // Print option elements.
5204 ?>
5205 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_default" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="default"<?php checked( 'default' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_default"><?php esc_html_e( 'Default WordPress login screen', 'authorizer' ); ?></label><br />
5206 <?php
5207
5208 /**
5209 * Developers can use the `authorizer_add_branding_option` filter
5210 * to add a radio button for "Custom WordPress login branding"
5211 * under the "Advanced" tab in Authorizer options. Example:
5212 * function my_authorizer_add_branding_option( $branding_options ) {
5213 * $new_branding_option = array(
5214 * 'value' => 'your_brand'
5215 * 'description' => 'Custom Your Brand Login Screen',
5216 * 'css_url' => 'http://url/to/your_brand.css',
5217 * 'js_url' => 'http://url/to/your_brand.js',
5218 * );
5219 * array_push( $branding_options, $new_branding_option );
5220 * return $branding_options;
5221 * }
5222 * add_filter( 'authorizer_add_branding_option', 'my_authorizer_add_branding_option' );
5223 */
5224 $branding_options = array();
5225 $branding_options = apply_filters( 'authorizer_add_branding_option', $branding_options );
5226 foreach ( $branding_options as $branding_option ) {
5227 // Make sure the custom brands have the required values.
5228 if ( ! ( is_array( $branding_option ) && array_key_exists( 'value', $branding_option ) && array_key_exists( 'description', $branding_option ) ) ) {
5229 continue;
5230 }
5231 ?>
5232 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_<?php echo esc_attr( sanitize_title( $branding_option['value'] ) ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $branding_option['value'] ); ?>"<?php checked( $branding_option['value'] === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_<?php echo esc_attr( sanitize_title( $branding_option['value'] ) ); ?>"><?php echo esc_html( $branding_option['description'] ); ?></label><br />
5233 <?php
5234 }
5235
5236 // Print message about adding custom brands if there are none.
5237 if ( count( $branding_options ) === 0 ) {
5238 ?>
5239 <p><em><?php echo wp_kses( __( '<strong>Note for theme developers</strong>: Add more options here by using the `authorizer_add_branding_option` filter in your theme. You can see an example theme that implements this filter in the plugin directory under sample-theme-add-branding.', 'authorizer' ), $this->allowed_html ); ?></em></p>
5240 <?php
5241 }
5242 }
5243
5244
5245 /**
5246 * Settings print callback.
5247 *
5248 * @param string $args Args (e.g., multisite admin mode).
5249 * @return void
5250 */
5251 public function print_radio_auth_advanced_admin_menu( $args = '' ) {
5252 // Get plugin option.
5253 $option = 'advanced_admin_menu';
5254 $auth_settings_option = $this->get_plugin_option( $option );
5255
5256 // Print option elements.
5257 ?>
5258 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_settings" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="settings"<?php checked( 'settings' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_settings"><?php esc_html_e( 'Show in Settings menu', 'authorizer' ); ?></label><br />
5259 <input type="radio" id="radio_auth_settings_<?php echo esc_attr( $option ); ?>_top" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="top"<?php checked( 'top' === $auth_settings_option ); ?> /><label for="radio_auth_settings_<?php echo esc_attr( $option ); ?>_top"><?php esc_html_e( 'Show in sidebar (top level)', 'authorizer' ); ?></label><br />
5260 <?php
5261
5262 }
5263
5264
5265 /**
5266 * Settings print callback.
5267 *
5268 * @param string $args Args (e.g., multisite admin mode).
5269 * @return void
5270 */
5271 public function print_select_auth_advanced_usermeta( $args = '' ) {
5272 // Get plugin option.
5273 $option = 'advanced_usermeta';
5274 $auth_settings_option = $this->get_plugin_option( $option );
5275
5276 // Print option elements.
5277 ?>
5278 <select id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]">
5279 <option value=""><?php esc_html_e( '-- None --', 'authorizer' ); ?></option>
5280 <?php
5281 if ( class_exists( 'acf' ) ) :
5282 // Get ACF 5 fields. Note: it would be much easier to use `get_field_objects()`
5283 // or `get_field_objects( 'user_' . get_current_user_id() )`, but neither will
5284 // list fields that have never been given values for users (i.e., new ACF
5285 // fields). Therefore we fall back on finding any ACF fields applied to users
5286 // (user_role or user_form location rules in the field group definition).
5287 $fields = array();
5288 $acf_field_group_ids = array();
5289 $acf_field_groups = new WP_Query(
5290 array(
5291 'post_type' => 'acf-field-group',
5292 )
5293 );
5294 while ( $acf_field_groups->have_posts() ) : $acf_field_groups->the_post();
5295 if ( strpos( get_the_content(), 's:5:"param";s:9:"user_role"' ) !== false || strpos( get_the_content(), 's:5:"param";s:9:"user_form"' ) !== false ) :
5296 array_push( $acf_field_group_ids, get_the_ID() );
5297 endif;
5298 endwhile;
5299 wp_reset_postdata();
5300 foreach ( $acf_field_group_ids as $acf_field_group_id ) :
5301 $acf_fields = new WP_Query(
5302 array(
5303 'post_type' => 'acf-field',
5304 'post_parent' => $acf_field_group_id,
5305 )
5306 );
5307 while ( $acf_fields->have_posts() ) : $acf_fields->the_post();
5308 global $post;
5309 $fields[ $post->post_name ] = get_field_object( $post->post_name );
5310 endwhile;
5311 wp_reset_postdata();
5312 endforeach;
5313 // Get ACF 4 fields.
5314 $acf4_field_groups = new WP_Query(
5315 array(
5316 'post_type' => 'acf',
5317 )
5318 );
5319 while ( $acf4_field_groups->have_posts() ) : $acf4_field_groups->the_post();
5320 $field_group_rules = get_post_meta( get_the_ID(), 'rule', true );
5321 if ( is_array( $field_group_rules ) && array_key_exists( 'param', $field_group_rules ) && 'ef_user' === $field_group_rules['param'] ) :
5322 $acf4_fields = get_post_custom( get_the_ID() );
5323 foreach ( $acf4_fields as $meta_key => $meta_value ) :
5324 if ( strpos( $meta_key, 'field_' ) === 0 ) :
5325 $meta_value = unserialize( $meta_value[0] );
5326 $fields[ $meta_key ] = $meta_value;
5327 endif;
5328 endforeach;
5329 endif;
5330 endwhile;
5331 wp_reset_postdata();
5332 ?>
5333 <optgroup label="ACF User Fields:">
5334 <?php foreach ( (array) $fields as $field => $field_object ) : ?>
5335 <option value="acf___<?php echo esc_attr( $field_object['key'] ); ?>"<?php selected( "acf___{$field_object['key']}" === $auth_settings_option ); ?>><?php echo esc_html( $field_object['label'] ); ?></option>
5336 <?php endforeach; ?>
5337 </optgroup>
5338 <?php endif; ?>
5339 <optgroup label="<?php esc_attr_e( 'All Usermeta:', 'authorizer' ); ?>">
5340 <?php
5341 foreach ( $this->get_all_usermeta_keys() as $meta_key ) :
5342 if ( substr( $meta_key, 0, 3 ) === 'wp_' ) :
5343 continue;
5344 endif;
5345 ?>
5346 <option value="<?php echo esc_attr( $meta_key ); ?>"<?php selected( $auth_settings_option === $meta_key ); ?>><?php echo esc_html( $meta_key ); ?></option>
5347 <?php endforeach; ?>
5348 </optgroup>
5349 </select>
5350 <?php
5351 }
5352
5353
5354 /**
5355 * Settings print callback.
5356 *
5357 * @param string $args Args (e.g., multisite admin mode).
5358 * @return void
5359 */
5360 public function print_text_auth_advanced_users_per_page( $args = '' ) {
5361 // Get plugin option.
5362 $option = 'advanced_users_per_page';
5363 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5364
5365 // Print option elements.
5366 ?>
5367 <input type="text" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="<?php echo esc_attr( $auth_settings_option ); ?>" placeholder="" size="4" />
5368 <?php
5369 }
5370
5371
5372 /**
5373 * Settings print callback.
5374 *
5375 * @param string $args Args (e.g., multisite admin mode).
5376 * @return void
5377 */
5378 public function print_select_auth_advanced_users_sort_by( $args = '' ) {
5379 // Get plugin option.
5380 $option = 'advanced_users_sort_by';
5381 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5382
5383 // Print option elements.
5384 ?>
5385 <select id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]">
5386 <option value="created" <?php selected( $auth_settings_option, 'created' ); ?>><?php esc_html_e( 'Date approved', 'authorizer' ); ?></option>
5387 <option value="email" <?php selected( $auth_settings_option, 'email' ); ?>><?php esc_html_e( 'Email', 'authorizer' ); ?></option>
5388 <option value="role" <?php selected( $auth_settings_option, 'role' ); ?>><?php esc_html_e( 'Role', 'authorizer' ); ?></option>
5389 <option value="date_added" <?php selected( $auth_settings_option, 'date_added' ); ?>><?php esc_html_e( 'Date registered', 'authorizer' ); ?></option>
5390 </select>
5391 <?php
5392 }
5393
5394
5395 /**
5396 * Settings print callback.
5397 *
5398 * @param string $args Args (e.g., multisite admin mode).
5399 * @return void
5400 */
5401 public function print_select_auth_advanced_users_sort_order( $args = '' ) {
5402 // Get plugin option.
5403 $option = 'advanced_users_sort_order';
5404 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5405
5406 // Print option elements.
5407 ?>
5408 <select id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]">
5409 <option value="asc" <?php selected( $auth_settings_option, 'asc' ); ?>><?php esc_html_e( 'Ascending', 'authorizer' ); ?></option>
5410 <option value="desc" <?php selected( $auth_settings_option, 'desc' ); ?>><?php esc_html_e( 'Descending', 'authorizer' ); ?></option>
5411 </select>
5412 <?php
5413 }
5414
5415
5416 /**
5417 * Settings print callback.
5418 *
5419 * @param string $args Args (e.g., multisite admin mode).
5420 * @return void
5421 */
5422 public function print_checkbox_auth_advanced_widget_enabled( $args = '' ) {
5423 // Get plugin option.
5424 $option = 'advanced_widget_enabled';
5425 $auth_settings_option = $this->get_plugin_option( $option, $this->get_admin_mode( $args ), 'allow override', 'print overlay' );
5426
5427 // Print option elements.
5428 ?>
5429 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( 'Show Dashboard Widget', 'authorizer' ); ?></label>
5430 <p><small><?php esc_html_e( 'Note: Only users with the create_users capability will be able to see the dashboard widget.', 'authorizer' ); ?></small></p>
5431 <?php
5432 }
5433
5434
5435 /**
5436 * Settings print callback.
5437 *
5438 * @param string $args Args (e.g., multisite admin mode).
5439 * @return void
5440 */
5441 public function print_checkbox_auth_advanced_override_multisite( $args = '' ) {
5442 // Get plugin option.
5443 $option = 'advanced_override_multisite';
5444 $auth_settings_option = $this->get_plugin_option( $option );
5445
5446 // Print option elements.
5447 ?>
5448 <input type="checkbox" id="auth_settings_<?php echo esc_attr( $option ); ?>" name="auth_settings[<?php echo esc_attr( $option ); ?>]" value="1"<?php checked( 1 === intval( $auth_settings_option ) ); ?> /><label for="auth_settings_<?php echo esc_attr( $option ); ?>"><?php esc_html_e( "Configure this site independently (don't inherit any multisite settings)", 'authorizer' ); ?></label>
5449 <?php
5450 }
5451
5452
5453
5454 /**
5455 * Determines whether we are in single site or multisite admin context.
5456 *
5457 * @param string $args Args (e.g., multisite admin mode).
5458 * @return int Current mode.
5459 */
5460 private function get_admin_mode( $args ) {
5461 if ( is_array( $args ) && array_key_exists( WP_Plugin_Authorizer::NETWORK_CONTEXT, $args ) && true === $args[ WP_Plugin_Authorizer::NETWORK_CONTEXT ] ) {
5462 return WP_Plugin_Authorizer::NETWORK_CONTEXT;
5463 } else {
5464 return WP_Plugin_Authorizer::SINGLE_CONTEXT;
5465 }
5466 }
5467
5468
5469 /**
5470 * Add help documentation to the options page.
5471 *
5472 * Action: load-settings_page_authorizer > admin_head
5473 */
5474 public function admin_head() {
5475 $screen = get_current_screen();
5476
5477 // Add help tab for Access Lists Settings.
5478 $help_auth_settings_access_lists_content = '
5479 <p>' . __( "<strong>Pending Users</strong>: Pending users are users who have successfully logged in to the site, but who haven't yet been approved (or blocked) by you.", 'authorizer' ) . '</p>
5480 <p>' . __( '<strong>Approved Users</strong>: Approved users have access to the site once they successfully log in.', 'authorizer' ) . '</p>
5481 <p>' . __( '<strong>Blocked Users</strong>: Blocked users will receive an error message when they try to visit the site after authenticating.', 'authorizer' ) . '</p>
5482 <p>' . __( 'Users in the <strong>Pending</strong> list appear automatically after a new user tries to log in from the configured external authentication service. You can add users to the <strong>Approved</strong> or <strong>Blocked</strong> lists by typing them in manually, or by clicking the <em>Approve</em> or <em>Block</em> buttons next to a user in the <strong>Pending</strong> list.', 'authorizer' ) . '</p>
5483 ';
5484 $screen->add_help_tab(
5485 array(
5486 'id' => 'help_auth_settings_access_lists_content',
5487 'title' => __( 'Access Lists', 'authorizer' ),
5488 'content' => $help_auth_settings_access_lists_content,
5489 )
5490 );
5491
5492 // Add help tab for Login Access Settings.
5493 $help_auth_settings_access_login_content = '
5494 <p>' . __( "<strong>Who can log in to the site?</strong>: Choose the level of access restriction you'd like to use on your site here. You can leave the site open to anyone with a WordPress account or an account on an external service like Google, CAS, or LDAP, or restrict it to WordPress users and only the external users that you specify via the <em>Access Lists</em>.", 'authorizer' ) . '</p>
5495 <p>' . __( "<strong>Which role should receive email notifications about pending users?</strong>: If you've restricted access to <strong>approved users</strong>, you can determine which WordPress users will receive a notification email everytime a new external user successfully logs in and is added to the pending list. All users of the specified role will receive an email, and the external user will get a message (specified below) telling them their access is pending approval.", 'authorizer' ) . '</p>
5496 <p>' . __( '<strong>What message should pending users see after attempting to log in?</strong>: Here you can specify the exact message a new external user will see once they try to log in to the site for the first time.', 'authorizer' ) . '</p>
5497 ';
5498 $screen->add_help_tab(
5499 array(
5500 'id' => 'help_auth_settings_access_login_content',
5501 'title' => __( 'Login Access', 'authorizer' ),
5502 'content' => $help_auth_settings_access_login_content,
5503 )
5504 );
5505
5506 // Add help tab for Public Access Settings.
5507 $help_auth_settings_access_public_content = '
5508 <p>' . __( "<strong>Who can view the site?</strong>: You can restrict the site's visibility by only allowing logged in users to see pages. If you do so, you can customize the specifics about the site's privacy using the settings below.", 'authorizer' ) . '</p>
5509 <p>' . __( "<strong>What pages (if any) should be available to everyone?</strong>: If you'd like to declare certain pages on your site as always public (such as the course syllabus, introduction, or calendar), specify those pages here. These pages will always be available no matter what access restrictions exist.", 'authorizer' ) . '</p>
5510 <p>' . __( '<strong>What happens to people without access when they visit a <em>private</em> page?</strong>: Choose the response anonymous users receive when visiting the site. You can choose between immediately taking them to the <strong>login screen</strong>, or simply showing them a <strong>message</strong>.', 'authorizer' ) . '</p>
5511 <p>' . __( '<strong>What happens to people without access when they visit a <em>public</em> page?</strong>: Choose the response anonymous users receive when visiting a page on the site marked as public. You can choose between showing them the page without any message, or showing them a the page with a message above the content.', 'authorizer' ) . '</p>
5512 <p>' . __( '<strong>What message should people without access see?</strong>: If you chose to show new users a <strong>message</strong> above, type that message here.', 'authorizer' ) . '</p>
5513 ';
5514 $screen->add_help_tab(
5515 array(
5516 'id' => 'help_auth_settings_access_public_content',
5517 'title' => __( 'Public Access', 'authorizer' ),
5518 'content' => $help_auth_settings_access_public_content,
5519 )
5520 );
5521
5522 // Add help tab for External Service (CAS, LDAP) Settings.
5523 $help_auth_settings_external_content = '
5524 <p>' . __( "<strong>Type of external service to authenticate against</strong>: Choose which authentication service type you will be using. You'll have to fill out different fields below depending on which service you choose.", 'authorizer' ) . '</p>
5525 <p>' . __( '<strong>Enable Google Logins</strong>: Choose if you want to allow users to log in with their Google Account credentials. You will need to enter your API Client ID and Secret to enable Google Logins.', 'authorizer' ) . '</p>
5526 <p>' . __( '<strong>Enable CAS Logins</strong>: Choose if you want to allow users to log in with via CAS (Central Authentication Service). You will need to enter details about your CAS server (host, port, and path) to enable CAS Logins.', 'authorizer' ) . '</p>
5527 <p>' . __( '<strong>Enable LDAP Logins</strong>: Choose if you want to allow users to log in with their LDAP (Lightweight Directory Access Protocol) credentials. You will need to enter details about your LDAP server (host, port, search base, uid attribute, directory user, directory user password, and whether to use TLS) to enable Google Logins.', 'authorizer' ) . '</p>
5528 <p>' . __( '<strong>Default role for new CAS users</strong>: Specify which role new external users will get by default. Be sure to choose a role with limited permissions!', 'authorizer' ) . '</p>
5529 <p><strong><em>' . __( 'If you enable Google logins:', 'authorizer' ) . '</em></strong></p>
5530 <ul>
5531 <li>' . __( "<strong>Google Client ID</strong>: You can generate this ID by creating a new Project in the <a href='https://cloud.google.com/console'>Google Developers Console</a>. A Client ID typically looks something like this: 1234567890123-kdjr85yt6vjr6d8g7dhr8g7d6durjf7g.apps.googleusercontent.com", 'authorizer' ) . '</li>
5532 <li>' . __( "<strong>Google Client Secret</strong>: You can generate this secret by creating a new Project in the <a href='https://cloud.google.com/console'>Google Developers Console</a>. A Client Secret typically looks something like this: sDNgX5_pr_5bly-frKmvp8jT", 'authorizer' ) . '</li>
5533 </ul>
5534 <p><strong><em>' . __( 'If you enable CAS logins:', 'authorizer' ) . '</em></strong></p>
5535 <ul>
5536 <li>' . __( '<strong>CAS server hostname</strong>: Enter the hostname of the CAS server you authenticate against (e.g., authn.example.edu).', 'authorizer' ) . '</li>
5537 <li>' . __( '<strong>CAS server port</strong>: Enter the port on the CAS server to connect to (e.g., 443).', 'authorizer' ) . '</li>
5538 <li>' . __( '<strong>CAS server path/context</strong>: Enter the path to the login endpoint on the CAS server (e.g., /cas).', 'authorizer' ) . '</li>
5539 <li>' . __( "<strong>CAS attribute containing first name</strong>: Enter the CAS attribute that has the user's first name. When this user first logs in, their WordPress account will have their first name retrieved from CAS and added to their WordPress profile.", 'authorizer' ) . '</li>
5540 <li>' . __( "<strong>CAS attribute containing last name</strong>: Enter the CAS attribute that has the user's last name. When this user first logs in, their WordPress account will have their last name retrieved from CAS and added to their WordPress profile.", 'authorizer' ) . '</li>
5541 <li>' . __( '<strong>CAS attribute update</strong>: Select whether the first and last names retrieved from CAS should overwrite any value the user has entered in the first and last name fields in their WordPress profile. If this is not set, this only happens the first time they log in.', 'authorizer' ) . '</li>
5542 </ul>
5543 <p><strong><em>' . __( 'If you enable LDAP logins:', 'authorizer' ) . '</em></strong></p>
5544 <ul>
5545 <li>' . __( '<strong>LDAP Host</strong>: Enter the URL of the LDAP server you authenticate against.', 'authorizer' ) . '</li>
5546 <li>' . __( '<strong>LDAP Port</strong>: Enter the port number that the LDAP server listens on.', 'authorizer' ) . '</li>
5547 <li>' . __( '<strong>LDAP Search Base</strong>: Enter the LDAP string that represents the search base, e.g., ou=people,dc=example,dc=edu', 'authorizer' ) . '</li>
5548 <li>' . __( '<strong>LDAP attribute containing username</strong>: Enter the name of the LDAP attribute that contains the usernames used by those attempting to log in. The plugin will search on this attribute to find the cn to bind against for login attempts.', 'authorizer' ) . '</li>
5549 <li>' . __( '<strong>LDAP Directory User</strong>: Enter the name of the LDAP user that has permissions to browse the directory.', 'authorizer' ) . '</li>
5550 <li>' . __( '<strong>LDAP Directory User Password</strong>: Enter the password for the LDAP user that has permission to browse the directory.', 'authorizer' ) . '</li>
5551 <li>' . __( '<strong>Use TLS</strong>: Select whether all communication with the LDAP server should be performed over a TLS-secured connection.', 'authorizer' ) . '</li>
5552 <li>' . __( "<strong>Custom lost password URL</strong>: The WordPress login page contains a link to recover a lost password. If you have external users who shouldn't change the password on their WordPress account, point them to the appropriate location to change the password on their external authentication service here.", 'authorizer' ) . '</li>
5553 <li>' . __( "<strong>LDAP attribute containing first name</strong>: Enter the LDAP attribute that has the user's first name. When this user first logs in, their WordPress account will have their first name retrieved from LDAP and added to their WordPress profile.", 'authorizer' ) . '</li>
5554 <li>' . __( "<strong>LDAP attribute containing last name</strong>: Enter the LDAP attribute that has the user's last name. When this user first logs in, their WordPress account will have their last name retrieved from LDAP and added to their WordPress profile.", 'authorizer' ) . '</li>
5555 <li>' . __( '<strong>LDAP attribute update</strong>: Select whether the first and last names retrieved from LDAP should overwrite any value the user has entered in the first and last name fields in their WordPress profile. If this is not set, this only happens the first time they log in.', 'authorizer' ) . '</li>
5556 </ul>
5557 ';
5558 $screen->add_help_tab(
5559 array(
5560 'id' => 'help_auth_settings_external_content',
5561 'title' => __( 'External Service', 'authorizer' ),
5562 'content' => $help_auth_settings_external_content,
5563 )
5564 );
5565
5566 // Add help tab for Advanced Settings.
5567 $help_auth_settings_advanced_content = '
5568 <p>' . __( '<strong>Limit invalid login attempts</strong>: Choose how soon (and for how long) to restrict access to individuals (or bots) making repeated invalid login attempts. You may set a shorter delay first, and then a longer delay after repeated invalid attempts; you may also set how much time must pass before the delays will be reset to normal.', 'authorizer' ) . '</p>
5569 <p>' . __( '<strong>Hide WordPress Logins</strong>: If you want to hide the WordPress username and password fields and the Log In button on the wp-login screen, enable this option. Note: You can always access the WordPress logins by adding external=wordpress to the wp-login URL, like so:', 'authorizer' ) . ' <a href="' . wp_login_url() . '?external=wordpress" target="_blank">' . wp_login_url() . '?external=wordpress</a>.</p>
5570 <p>' . __( "<strong>Custom WordPress login branding</strong>: If you'd like to use custom branding on the WordPress login page, select that here. You will need to use the `authorizer_add_branding_option` filter in your theme to add it. You can see an example theme that implements this filter in the plugin directory under sample-theme-add-branding.", 'authorizer' ) . '</p>
5571 ';
5572 $screen->add_help_tab(
5573 array(
5574 'id' => 'help_auth_settings_advanced_content',
5575 'title' => __( 'Advanced', 'authorizer' ),
5576 'content' => $help_auth_settings_advanced_content,
5577 )
5578 );
5579 }
5580
5581
5582
5583 /**
5584 * ***************************
5585 * Multisite: Network Admin Options page
5586 * ***************************
5587 */
5588
5589
5590 /**
5591 * Network Admin menu item
5592 *
5593 * Action: network_admin_menu
5594 *
5595 * @return void
5596 */
5597 public function network_admin_menu() {
5598 // @see http://codex.wordpress.org/Function_Reference/add_menu_page
5599 add_menu_page(
5600 'Authorizer',
5601 'Authorizer',
5602 'manage_network_options',
5603 'authorizer',
5604 array( $this, 'create_network_admin_page' ),
5605 'dashicons-groups',
5606 89 // Position.
5607 );
5608 }
5609
5610
5611 /**
5612 * Output the HTML for the options page.
5613 */
5614 public function create_network_admin_page() {
5615 if ( ! current_user_can( 'manage_network_options' ) ) {
5616 wp_die( wp_kses( __( 'You do not have sufficient permissions to access this page.', 'authorizer' ), $this->allowed_html ) );
5617 }
5618 $auth_settings = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', array() );
5619 ?>
5620 <div class="wrap">
5621 <form method="post" action="" autocomplete="off">
5622 <h2><?php esc_html_e( 'Authorizer Settings', 'authorizer' ); ?></h2>
5623 <p><?php echo wp_kses( __( 'Most <strong>Authorizer</strong> settings are set in the individual sites, but you can specify a few options here that apply to <strong>all sites in the network</strong>. These settings will override settings in the individual sites.', 'authorizer' ), $this->allowed_html ); ?></p>
5624
5625 <input type="checkbox" id="auth_settings_multisite_override" name="auth_settings[multisite_override]" value="1"<?php checked( 1 === intval( $auth_settings['multisite_override'] ) ); ?> /><label for="auth_settings_multisite_override"><?php esc_html_e( 'Override individual site settings with the settings below', 'authorizer' ); ?></label>
5626
5627 <div id="auth_multisite_settings_disabled_overlay" style="display: none;"></div>
5628
5629 <div class="wrap" id="auth_multisite_settings">
5630 <?php $this->print_section_info_tabs( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?>
5631
5632 <?php wp_nonce_field( 'save_auth_settings', 'nonce_save_auth_settings' ); ?>
5633
5634 <?php // Custom access lists (for network, we only really want approved list, not pending or blocked). ?>
5635 <div id="section_info_access_lists" class="section_info">
5636 <p><?php esc_html_e( 'Manage who has access to all sites in the network.', 'authorizer' ); ?></p>
5637 </div>
5638 <table class="form-table"><tbody>
5639 <tr>
5640 <th scope="row"><?php esc_html_e( 'Who can log in to sites in this network?', 'authorizer' ); ?></th>
5641 <td><?php $this->print_radio_auth_access_who_can_login( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5642 </tr>
5643 <tr>
5644 <th scope="row"><?php esc_html_e( 'Who can view sites in this network?', 'authorizer' ); ?></th>
5645 <td><?php $this->print_radio_auth_access_who_can_view( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5646 </tr>
5647 <tr>
5648 <th scope="row"><?php esc_html_e( 'Approved Users (All Sites)', 'authorizer' ); ?><br /><small><em><?php echo wp_kses( __( 'Note: these users will <strong>not</strong> receive welcome emails when approved. Only users approved from individual sites can receive these messages.', 'authorizer' ), $this->allowed_html ); ?></em></small></th>
5649 <td><?php $this->print_combo_auth_access_users_approved( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5650 </tr>
5651 </tbody></table>
5652
5653 <?php $this->print_section_info_external(); ?>
5654 <table class="form-table"><tbody>
5655 <tr>
5656 <th scope="row"><?php esc_html_e( 'Default role for new users', 'authorizer' ); ?></th>
5657 <td><?php $this->print_select_auth_access_default_role( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5658 </tr>
5659 <tr>
5660 <th scope="row"><?php esc_html_e( 'Google Logins', 'authorizer' ); ?></th>
5661 <td><?php $this->print_checkbox_auth_external_google( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5662 </tr>
5663 <tr>
5664 <th scope="row"><?php esc_html_e( 'Google Client ID', 'authorizer' ); ?></th>
5665 <td><?php $this->print_text_google_clientid( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5666 </tr>
5667 <tr>
5668 <th scope="row"><?php esc_html_e( 'Google Client Secret', 'authorizer' ); ?></th>
5669 <td><?php $this->print_text_google_clientsecret( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5670 </tr>
5671 <tr>
5672 <th scope="row"><?php esc_html_e( 'Google Hosted Domain', 'authorizer' ); ?></th>
5673 <td><?php $this->print_text_google_hosteddomain( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5674 </tr>
5675 <tr>
5676 <th scope="row"><?php esc_html_e( 'CAS Logins', 'authorizer' ); ?></th>
5677 <td><?php $this->print_checkbox_auth_external_cas( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5678 </tr>
5679 <tr>
5680 <th scope="row"><?php esc_html_e( 'CAS Custom Label', 'authorizer' ); ?></th>
5681 <td><?php $this->print_text_cas_custom_label( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5682 </tr>
5683 <tr>
5684 <th scope="row"><?php esc_html_e( 'CAS server hostname', 'authorizer' ); ?></th>
5685 <td><?php $this->print_text_cas_host( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5686 </tr>
5687 <tr>
5688 <th scope="row"><?php esc_html_e( 'CAS server port', 'authorizer' ); ?></th>
5689 <td><?php $this->print_text_cas_port( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5690 </tr>
5691 <tr>
5692 <th scope="row"><?php esc_html_e( 'CAS server path/context', 'authorizer' ); ?></th>
5693 <td><?php $this->print_text_cas_path( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5694 </tr>
5695 <tr>
5696 <th scope="row"><?php esc_html_e( 'CAS server version', 'authorizer' ); ?></th>
5697 <td><?php $this->print_select_cas_version( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5698 </tr>
5699 <tr>
5700 <th scope="row"><?php esc_html_e( 'CAS attribute containing email', 'authorizer' ); ?></th>
5701 <td><?php $this->print_text_cas_attr_email( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5702 </tr>
5703 <tr>
5704 <th scope="row"><?php esc_html_e( 'CAS attribute containing first name', 'authorizer' ); ?></th>
5705 <td><?php $this->print_text_cas_attr_first_name( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5706 </tr>
5707 <tr>
5708 <th scope="row"><?php esc_html_e( 'CAS attribute containing last name', 'authorizer' ); ?></th>
5709 <td><?php $this->print_text_cas_attr_last_name( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5710 </tr>
5711 <tr>
5712 <th scope="row"><?php esc_html_e( 'CAS attribute update', 'authorizer' ); ?></th>
5713 <td><?php $this->print_checkbox_cas_attr_update_on_login( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5714 </tr>
5715 <tr>
5716 <th scope="row"><?php esc_html_e( 'CAS automatic login', 'authorizer' ); ?></th>
5717 <td><?php $this->print_checkbox_cas_auto_login( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5718 </tr>
5719 <tr>
5720 <th scope="row"><?php esc_html_e( 'LDAP Logins', 'authorizer' ); ?></th>
5721 <td><?php $this->print_checkbox_auth_external_ldap( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5722 </tr>
5723 <tr>
5724 <th scope="row"><?php esc_html_e( 'LDAP Host', 'authorizer' ); ?></th>
5725 <td><?php $this->print_text_ldap_host( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5726 </tr>
5727 <tr>
5728 <th scope="row"><?php esc_html_e( 'LDAP Port', 'authorizer' ); ?></th>
5729 <td><?php $this->print_text_ldap_port( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5730 </tr>
5731 <tr>
5732 <th scope="row"><?php esc_html_e( 'Use TLS', 'authorizer' ); ?></th>
5733 <td><?php $this->print_checkbox_ldap_tls( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5734 </tr>
5735 <tr>
5736 <th scope="row"><?php esc_html_e( 'LDAP Search Base', 'authorizer' ); ?></th>
5737 <td><?php $this->print_text_ldap_search_base( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5738 </tr>
5739 <tr>
5740 <th scope="row"><?php esc_html_e( 'LDAP attribute containing username', 'authorizer' ); ?></th>
5741 <td><?php $this->print_text_ldap_uid( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5742 </tr>
5743 <tr>
5744 <th scope="row"><?php esc_html_e( 'LDAP attribute containing email', 'authorizer' ); ?></th>
5745 <td><?php $this->print_text_ldap_attr_email( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5746 </tr>
5747 <tr>
5748 <th scope="row"><?php esc_html_e( 'LDAP Directory User', 'authorizer' ); ?></th>
5749 <td><?php $this->print_text_ldap_user( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5750 </tr>
5751 <tr>
5752 <th scope="row"><?php esc_html_e( 'LDAP Directory User Password', 'authorizer' ); ?></th>
5753 <td><?php $this->print_password_ldap_password( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5754 </tr>
5755 <tr>
5756 <th scope="row"><?php esc_html_e( 'Custom lost password URL', 'authorizer' ); ?></th>
5757 <td><?php $this->print_text_ldap_lostpassword_url( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5758 </tr>
5759 <tr>
5760 <th scope="row"><?php esc_html_e( 'LDAP attribute containing first name', 'authorizer' ); ?></th>
5761 <td><?php $this->print_text_ldap_attr_first_name( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5762 </tr>
5763 <tr>
5764 <th scope="row"><?php esc_html_e( 'LDAP attribute containing last name', 'authorizer' ); ?></th>
5765 <td><?php $this->print_text_ldap_attr_last_name( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5766 </tr>
5767 <tr>
5768 <th scope="row"><?php esc_html_e( 'LDAP attribute update', 'authorizer' ); ?></th>
5769 <td><?php $this->print_checkbox_ldap_attr_update_on_login( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5770 </tr>
5771 </tbody></table>
5772
5773 <?php $this->print_section_info_advanced(); ?>
5774 <table class="form-table"><tbody>
5775 <tr>
5776 <th scope="row"><?php esc_html_e( 'Limit invalid login attempts', 'authorizer' ); ?></th>
5777 <td><?php $this->print_text_auth_advanced_lockouts( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5778 </tr>
5779 <tr>
5780 <th scope="row"><?php esc_html_e( 'Hide WordPress Logins', 'authorizer' ); ?></th>
5781 <td><?php $this->print_checkbox_auth_advanced_hide_wp_login( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5782 </tr>
5783 <tr>
5784 <th scope="row"><?php esc_html_e( 'Number of users per page', 'authorizer' ); ?></th>
5785 <td><?php $this->print_text_auth_advanced_users_per_page( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5786 </tr>
5787 <tr>
5788 <th scope="row"><?php esc_html_e( 'Approved users sort method', 'authorizer' ); ?></th>
5789 <td><?php $this->print_select_auth_advanced_users_sort_by( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5790 </tr>
5791 <tr>
5792 <th scope="row"><?php esc_html_e( 'Approved users sort order', 'authorizer' ); ?></th>
5793 <td><?php $this->print_select_auth_advanced_users_sort_order( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5794 </tr>
5795 <tr>
5796 <th scope="row"><?php esc_html_e( 'Show Dashboard Widget', 'authorizer' ); ?></th>
5797 <td><?php $this->print_checkbox_auth_advanced_widget_enabled( array( WP_Plugin_Authorizer::NETWORK_CONTEXT => true ) ); ?></td>
5798 </tr>
5799 </tbody></table>
5800
5801 <br class="clear" />
5802 </div>
5803 <input type="button" name="submit" id="submit" class="button button-primary" value="<?php esc_attr_e( 'Save Changes', 'authorizer' ); ?>" onclick="saveAuthMultisiteSettings(this);" />
5804 </form>
5805 </div>
5806 <?php
5807 }
5808
5809
5810 /**
5811 * Save multisite settings (ajax call).
5812 *
5813 * Action: wp_ajax_save_auth_multisite_settings
5814 */
5815 public function ajax_save_auth_multisite_settings() {
5816 // Fail silently if current user doesn't have permissions.
5817 if ( ! current_user_can( 'manage_network_options' ) ) {
5818 die( '' );
5819 }
5820
5821 // Make sure nonce exists.
5822 if ( empty( $_POST['nonce'] ) ) {
5823 die( '' );
5824 }
5825
5826 // Nonce check.
5827 if ( ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'save_auth_settings' ) ) {
5828 die( '' );
5829 }
5830
5831 // Assert multisite.
5832 if ( ! is_multisite() ) {
5833 die( '' );
5834 }
5835
5836 // Get multisite settings.
5837 $auth_multisite_settings = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', array() );
5838
5839 // Sanitize settings.
5840 $auth_multisite_settings = $this->sanitize_options( $_POST );
5841
5842 // Filter options to only the allowed values (multisite options are a subset of all options).
5843 $allowed = array(
5844 'multisite_override',
5845 'access_who_can_login',
5846 'access_who_can_view',
5847 'access_default_role',
5848 'google',
5849 'google_clientid',
5850 'google_clientsecret',
5851 'google_hosteddomain',
5852 'cas',
5853 'cas_custom_label',
5854 'cas_host',
5855 'cas_port',
5856 'cas_path',
5857 'cas_version',
5858 'cas_attr_email',
5859 'cas_attr_first_name',
5860 'cas_attr_last_name',
5861 'cas_attr_update_on_login',
5862 'cas_auto_login',
5863 'ldap',
5864 'ldap_host',
5865 'ldap_port',
5866 'ldap_tls',
5867 'ldap_search_base',
5868 'ldap_uid',
5869 'ldap_attr_email',
5870 'ldap_user',
5871 'ldap_password',
5872 'ldap_lostpassword_url',
5873 'ldap_attr_first_name',
5874 'ldap_attr_last_name',
5875 'ldap_attr_update_on_login',
5876 'advanced_lockouts',
5877 'advanced_hide_wp_login',
5878 'advanced_users_per_page',
5879 'advanced_users_sort_by',
5880 'advanced_users_sort_order',
5881 'advanced_widget_enabled',
5882 );
5883 $auth_multisite_settings = array_intersect_key( $auth_multisite_settings, array_flip( $allowed ) );
5884
5885 // Update multisite settings in database.
5886 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', $auth_multisite_settings );
5887
5888 // Return 'success' value to AJAX call.
5889 die( 'success' );
5890 }
5891
5892
5893
5894 /**
5895 * ***************************
5896 * Dashboard widget
5897 * ***************************
5898 */
5899
5900
5901
5902 /**
5903 * Load Authorizer dashboard widget if it's enabled.
5904 *
5905 * Action: wp_dashboard_setup
5906 */
5907 public function add_dashboard_widgets() {
5908 $widget_enabled = $this->get_plugin_option( 'advanced_widget_enabled', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' ) === '1';
5909
5910 // Load authorizer dashboard widget if it's enabled and user has permission.
5911 if ( current_user_can( 'create_users' ) && $widget_enabled ) {
5912 // Add dashboard widget for adding/editing users with access.
5913 wp_add_dashboard_widget( 'auth_dashboard_widget', __( 'Authorizer Settings', 'authorizer' ), array( $this, 'add_auth_dashboard_widget' ) );
5914 }
5915 }
5916
5917
5918 /**
5919 * Render Authorizer dashboard widget (callback).
5920 */
5921 public function add_auth_dashboard_widget() {
5922 ?>
5923 <form method="post" id="auth_settings_access_form" action="">
5924 <?php $this->print_section_info_access_login(); ?>
5925 <div>
5926 <h2><?php esc_html_e( 'Pending Users', 'authorizer' ); ?></h2>
5927 <?php $this->print_combo_auth_access_users_pending(); ?>
5928 </div>
5929 <div>
5930 <h2><?php esc_html_e( 'Approved Users', 'authorizer' ); ?></h2>
5931 <?php $this->print_combo_auth_access_users_approved(); ?>
5932 </div>
5933 <div>
5934 <h2><?php esc_html_e( 'Blocked Users', 'authorizer' ); ?></h2>
5935 <?php $this->print_combo_auth_access_users_blocked(); ?>
5936 </div>
5937 <br class="clear" />
5938 </form>
5939 <?php
5940 }
5941
5942
5943
5944 /**
5945 * ***************************
5946 * AJAX Actions
5947 * ***************************
5948 */
5949
5950
5951
5952 /**
5953 * Re-render the Approved User list (usually triggered if pager params have
5954 * changed, e.g., current page, search term, sort order).
5955 *
5956 * Action: wp_ajax_refresh_approved_user_list
5957 *
5958 * @return void
5959 */
5960 public function ajax_refresh_approved_user_list() {
5961 // Fail silently if current user doesn't have permissions.
5962 if ( ! current_user_can( 'create_users' ) ) {
5963 die( '' );
5964 }
5965
5966 // Nonce check.
5967 if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'save_auth_settings' ) ) {
5968 die( '' );
5969 }
5970
5971 // Fail if required post data doesn't exist.
5972 if ( ! array_key_exists( 'paged', $_REQUEST ) ) {
5973 die( '' );
5974 }
5975
5976 // Get defaults.
5977 $success = true;
5978 $message = '';
5979 $is_network_admin = isset( $_REQUEST['is_network_admin'] ) && '1' === $_REQUEST['is_network_admin'];
5980
5981 // Get user list.
5982 $option = 'access_users_approved';
5983 $admin_mode = is_multisite() && $is_network_admin ? WP_Plugin_Authorizer::NETWORK_CONTEXT : WP_Plugin_Authorizer::SINGLE_CONTEXT;
5984 $auth_settings_option = $this->get_plugin_option( $option, $admin_mode, 'no override' );
5985 $auth_settings_option = is_array( $auth_settings_option ) ? $auth_settings_option : array();
5986
5987 // Get multisite approved users (will be added to top of list, greyed out).
5988 $auth_override_multisite = $this->get_plugin_option( 'advanced_override_multisite' );
5989 $auth_multisite_settings = $this->get_plugin_options( WP_Plugin_Authorizer::NETWORK_CONTEXT );
5990 $auth_settings_option_multisite = array();
5991 if (
5992 is_multisite() &&
5993 ! $is_network_admin &&
5994 1 !== intval( $auth_override_multisite ) &&
5995 array_key_exists( 'multisite_override', $auth_multisite_settings ) &&
5996 '1' === $auth_multisite_settings['multisite_override']
5997 ) {
5998 $auth_settings_option_multisite = $this->get_plugin_option( $option, WP_Plugin_Authorizer::NETWORK_CONTEXT, 'allow override' );
5999 $auth_settings_option_multisite = is_array( $auth_settings_option_multisite ) ? $auth_settings_option_multisite : array();
6000 // Add multisite users to the beginning of the main user array.
6001 foreach ( array_reverse( $auth_settings_option_multisite ) as $approved_user ) {
6002 $approved_user['multisite_user'] = true;
6003 array_unshift( $auth_settings_option, $approved_user );
6004 }
6005 }
6006
6007 // Get custom usermeta field to show.
6008 $advanced_usermeta = $this->get_plugin_option( 'advanced_usermeta' );
6009
6010 // Filter user list to search terms.
6011 if ( ! empty( $_REQUEST['search'] ) ) {
6012 $search_term = sanitize_text_field( wp_unslash( $_REQUEST['search'] ) );
6013 $auth_settings_option = array_filter(
6014 $auth_settings_option, function ( $user ) use ( $search_term ) {
6015 return stripos( $user['email'], $search_term ) !== false ||
6016 stripos( $user['role'], $search_term ) !== false ||
6017 stripos( $user['date_added'], $search_term ) !== false;
6018 }
6019 );
6020 }
6021
6022 // Sort user list.
6023 $sort_by = $this->get_plugin_option( 'advanced_users_sort_by', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' ); // email, role, date_added (registered), created (date approved).
6024 $sort_order = $this->get_plugin_option( 'advanced_users_sort_order', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' ); // asc or desc.
6025 $sort_dimension = array();
6026 if ( in_array( $sort_by, array( 'email', 'role', 'date_added' ), true ) ) {
6027 foreach ( $auth_settings_option as $key => $user ) {
6028 if ( 'date_added' === $sort_by ) {
6029 $sort_dimension[ $key ] = date( 'Ymd', strtotime( $user[ $sort_by ] ) );
6030 } else {
6031 $sort_dimension[ $key ] = strtolower( $user[ $sort_by ] );
6032 }
6033 }
6034 $sort_order = 'asc' === $sort_order ? SORT_ASC : SORT_DESC;
6035 array_multisort( $sort_dimension, $sort_order, $auth_settings_option );
6036 } elseif ( 'created' === $sort_by && 'asc' !== $sort_order ) {
6037 // If default sort method and reverse order, just reverse the array.
6038 $auth_settings_option = array_reverse( $auth_settings_option );
6039 }
6040
6041 // Ensure array keys run from 0..max (keys in database will be the original,
6042 // index, and removing users will not reorder the array keys of other users).
6043 $auth_settings_option = array_values( $auth_settings_option );
6044
6045 // Get pager params.
6046 $total_users = count( $auth_settings_option );
6047 $users_per_page = intval( $this->get_plugin_option( 'advanced_users_per_page', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' ) );
6048 $current_page = isset( $_REQUEST['paged'] ) ? intval( $_REQUEST['paged'] ) : 1;
6049 $total_pages = ceil( $total_users / $users_per_page );
6050 if ( $total_pages < 1 ) {
6051 $total_pages = 1;
6052 }
6053
6054 // Make sure current_page is between 1 and max pages.
6055 if ( $current_page < 1 ) {
6056 $current_page = 1;
6057 } elseif ( $current_page > $total_pages ) {
6058 $current_page = $total_pages;
6059 }
6060
6061 // Render user list.
6062 ob_start();
6063 $offset = ( $current_page - 1 ) * $users_per_page;
6064 $max = min( $offset + $users_per_page, count( $auth_settings_option ) );
6065 for ( $key = $offset; $key < $max; $key++ ) :
6066 $approved_user = $auth_settings_option[ $key ];
6067 if ( empty( $approved_user ) || count( $approved_user ) < 1 ) :
6068 continue;
6069 endif;
6070 $this->render_user_element( $approved_user, $key, $option, $admin_mode, $advanced_usermeta );
6071 endfor;
6072
6073 // Send response to client.
6074 $response = array(
6075 'success' => $success,
6076 'message' => $message,
6077 'html' => ob_get_clean(),
6078 /* TRANSLATORS: %s: number of users */
6079 'total_users_html' => sprintf( _n( '%s user', '%s users', $total_users, 'authorizer' ), number_format_i18n( $total_users ) ),
6080 'total_pages_html' => number_format_i18n( $total_pages ),
6081 'total_pages' => $total_pages,
6082 );
6083 header( 'content-type: application/json' );
6084 echo wp_json_encode( $response );
6085 exit;
6086 }
6087
6088
6089 /**
6090 * Fired on a change event from the optional usermeta field in the approved
6091 * user list. Updates the selected usermeta value, or saves it in the user's
6092 * approved list entry if the user hasn't logged in yet and created a
6093 * WordPress account.
6094 *
6095 * Action: wp_ajax_update_auth_usermeta
6096 *
6097 * @return void
6098 */
6099 public function ajax_update_auth_usermeta() {
6100 // Fail silently if current user doesn't have permissions.
6101 if ( ! current_user_can( 'create_users' ) ) {
6102 die( '' );
6103 }
6104
6105 // Nonce check.
6106 if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'save_auth_settings' ) ) {
6107 die( '' );
6108 }
6109
6110 // Fail if required post data doesn't exist.
6111 if ( ! isset( $_REQUEST['email'], $_REQUEST['usermeta'] ) ) {
6112 die( '' );
6113 }
6114
6115 // Get values to update from post data.
6116 $email = sanitize_email( wp_unslash( $_REQUEST['email'] ) );
6117 $meta_value = sanitize_meta( 'authorizer-usermeta', wp_unslash( $_REQUEST['usermeta'] ), 'user' );
6118 $meta_key = $this->get_plugin_option( 'advanced_usermeta' );
6119
6120 // If user doesn't exist, save usermeta selection to authorizer
6121 // list. This value will get saved to usermeta when the user first
6122 // logs in (i.e., when their WordPress account is created).
6123 $wp_user = get_user_by( 'email', $email );
6124 if ( ! $wp_user ) {
6125 // Look through multisite approved users and add a usermeta
6126 // reference for the current blog if the user is found.
6127 $auth_multisite_settings_access_users_approved = is_multisite() ? get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', array() ) : array();
6128 $should_update_auth_multisite_settings_access_users_approved = false;
6129 foreach ( $auth_multisite_settings_access_users_approved as $index => $approved_user ) {
6130 if ( 0 === strcasecmp( $email, $approved_user['email'] ) ) {
6131 if ( ! is_array( $auth_multisite_settings_access_users_approved[ $index ]['usermeta'] ) ) {
6132 // Initialize the array of usermeta for each blog this user belongs to.
6133 $auth_multisite_settings_access_users_approved[ $index ]['usermeta'] = array();
6134 } else {
6135 // There is already usermeta associated with this
6136 // preapproved user; iterate through it and make
6137 // sure it's not for old meta_keys (delete it if
6138 // so). This can happen if someone changes the
6139 // usermeta key in authorizer options, and we don't
6140 // want to hang on to old data.
6141 foreach ( $auth_multisite_settings_access_users_approved[ $index ]['usermeta'] as $blog_id => $usermeta ) {
6142 if ( array_key_exists( 'meta_key', $usermeta ) && $usermeta['meta_key'] === $meta_key ) {
6143 continue;
6144 } else {
6145 unset( $auth_multisite_settings_access_users_approved[ $index ]['usermeta'][ $blog_id ] );
6146 }
6147 }
6148 }
6149 $auth_multisite_settings_access_users_approved[ $index ]['usermeta'][ get_current_blog_id() ] = array(
6150 'meta_key' => $meta_key,
6151 'meta_value' => $meta_value,
6152 );
6153 $should_update_auth_multisite_settings_access_users_approved = true;
6154 }
6155 }
6156 if ( $should_update_auth_multisite_settings_access_users_approved ) {
6157 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
6158 }
6159
6160 // Look through the approved users (of the current blog in a
6161 // multisite install, or just of the single site) and add a
6162 // usermeta reference if the user is found.
6163 $auth_settings_access_users_approved = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
6164 $should_update_auth_settings_access_users_approved = false;
6165 foreach ( $auth_settings_access_users_approved as $index => $approved_user ) {
6166 if ( 0 === strcasecmp( $email, $approved_user['email'] ) ) {
6167 $auth_settings_access_users_approved[ $index ]['usermeta'] = array(
6168 'meta_key' => $meta_key,
6169 'meta_value' => $meta_value,
6170 );
6171 $should_update_auth_settings_access_users_approved = true;
6172 }
6173 }
6174 if ( $should_update_auth_settings_access_users_approved ) {
6175 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
6176 }
6177 } else {
6178 // Update user's usermeta value for usermeta key stored in authorizer options.
6179 if ( strpos( $meta_key, 'acf___' ) === 0 && class_exists( 'acf' ) ) {
6180 // We have an ACF field value, so use the ACF function to update it.
6181 update_field( str_replace( 'acf___', '', $meta_key ), $meta_value, 'user_' . $wp_user->ID );
6182 } else {
6183 // We have a normal usermeta value, so just update it via the WordPress function.
6184 update_user_meta( $wp_user->ID, $meta_key, $meta_value );
6185 }
6186 }
6187
6188 // Return 'success' value to AJAX call.
6189 die( 'success' );
6190 }
6191
6192
6193 /**
6194 * Fired on a change event from the user fields in the user lists. Updates
6195 * the selected user value.
6196 *
6197 * Action: wp_ajax_update_auth_user
6198 *
6199 * @return void
6200 */
6201 public function ajax_update_auth_user() {
6202 // Fail silently if current user doesn't have permissions.
6203 if ( ! current_user_can( 'create_users' ) ) {
6204 die( '' );
6205 }
6206
6207 // Nonce check.
6208 if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), 'save_auth_settings' ) ) {
6209 die( '' );
6210 }
6211
6212 // Fail if requesting a change to an invalid setting.
6213 if ( ! isset( $_POST['setting'] ) || ! in_array( wp_unslash( $_POST['setting'] ), array( 'access_users_pending', 'access_users_approved', 'access_users_blocked' ), true ) ) {
6214 die( '' );
6215 }
6216
6217 // Track any emails that couldn't be added (used when adding users).
6218 $invalid_emails = array();
6219
6220 // Editing a pending list entry.
6221 if ( 'access_users_pending' === $_POST['setting'] ) {
6222 // Sanitize posted data.
6223 $access_users_pending = array();
6224 if ( isset( $_POST['access_users_pending'] ) && is_array( $_POST['access_users_pending'] ) ) {
6225 $access_users_pending = $this->sanitize_update_auth_users( wp_unslash( $_POST['access_users_pending'] ) );
6226 }
6227
6228 // Deal with each modified user (add or remove).
6229 foreach ( $access_users_pending as $pending_user ) {
6230
6231 if ( 'add' === $pending_user['edit_action'] ) {
6232
6233 // Add new user to pending list and save (skip if it's
6234 // already there--someone else might have just done it).
6235 if ( ! $this->is_email_in_list( $pending_user['email'], 'pending' ) ) {
6236 $auth_settings_access_users_pending = $this->sanitize_user_list(
6237 $this->get_plugin_option( 'access_users_pending', WP_Plugin_Authorizer::SINGLE_CONTEXT )
6238 );
6239 array_push( $auth_settings_access_users_pending, $pending_user );
6240 update_option( 'auth_settings_access_users_pending', $auth_settings_access_users_pending );
6241 }
6242 } elseif ( 'remove' === $pending_user['edit_action'] ) {
6243
6244 // Remove user from pending list and save.
6245 if ( $this->is_email_in_list( $pending_user['email'], 'pending' ) ) {
6246 $auth_settings_access_users_pending = $this->sanitize_user_list(
6247 $this->get_plugin_option( 'access_users_pending', WP_Plugin_Authorizer::SINGLE_CONTEXT )
6248 );
6249 foreach ( $auth_settings_access_users_pending as $key => $existing_user ) {
6250 if ( 0 === strcasecmp( $pending_user['email'], $existing_user['email'] ) ) {
6251 unset( $auth_settings_access_users_pending[ $key ] );
6252 break;
6253 }
6254 }
6255 update_option( 'auth_settings_access_users_pending', $auth_settings_access_users_pending );
6256 }
6257 }
6258 }
6259 }
6260
6261 // Editing an approved list entry.
6262 if ( 'access_users_approved' === $_POST['setting'] ) {
6263 // Sanitize posted data.
6264 $access_users_approved = array();
6265 if ( isset( $_POST['access_users_approved'] ) && is_array( $_POST['access_users_approved'] ) ) {
6266 $access_users_approved = $this->sanitize_update_auth_users( wp_unslash( $_POST['access_users_approved'] ) );
6267 }
6268
6269 // Deal with each modified user (add, remove, or change_role).
6270 foreach ( $access_users_approved as $approved_user ) {
6271 // Skip blank entries.
6272 if ( strlen( $approved_user['email'] ) < 1 ) {
6273 continue;
6274 }
6275
6276 // New user (create user, or add existing user to current site in multisite).
6277 if ( 'add' === $approved_user['edit_action'] ) {
6278 $new_user = get_user_by( 'email', $approved_user['email'] );
6279 if ( false !== $new_user ) {
6280 // If we're adding an existing multisite user, make sure their
6281 // newly-assigned role is updated on all sites they are already in.
6282 if ( is_multisite() && 'false' !== $approved_user['multisite_user'] ) {
6283 foreach ( get_blogs_of_user( $new_user->ID ) as $blog ) {
6284 add_user_to_blog( $blog->userblog_id, $new_user->ID, $approved_user['role'] );
6285 }
6286 }
6287 // If this user already has an account on another site in the network, add them to this site.
6288 if ( is_multisite() ) {
6289 add_user_to_blog( get_current_blog_id(), $new_user->ID, $approved_user['role'] );
6290 }
6291 } elseif ( $approved_user['local_user'] && 'false' !== $approved_user['local_user'] ) {
6292 // Create a WP account for this new *local* user and email the password.
6293 $plaintext_password = wp_generate_password(); // random password
6294 // If there's already a user with this username (e.g.,
6295 // johndoe/johndoe@gmail.com exists, and we're trying to add
6296 // johndoe/johndoe@example.com), use the full email address
6297 // as the username.
6298 $username = explode( '@', $approved_user['email'] );
6299 $username = $username[0];
6300 if ( get_user_by( 'login', $username ) !== false ) {
6301 $username = $this->lowercase( $approved_user['email'] );
6302 }
6303 if ( 'false' !== $approved_user['multisite_user'] ) {
6304 $result = wpmu_create_user(
6305 strtolower( $username ),
6306 $plaintext_password,
6307 $this->lowercase( $approved_user['email'] )
6308 );
6309 } else {
6310 $result = wp_insert_user(
6311 array(
6312 'user_login' => strtolower( $username ),
6313 'user_pass' => $plaintext_password,
6314 'first_name' => '',
6315 'last_name' => '',
6316 'user_email' => $this->lowercase( $approved_user['email'] ),
6317 'user_registered' => date( 'Y-m-d H:i:s' ),
6318 'role' => $approved_user['role'],
6319 )
6320 );
6321 }
6322 if ( ! is_wp_error( $result ) ) {
6323 // Email login credentials to new user.
6324 wp_new_user_notification( $result, null, 'both' );
6325 }
6326 }
6327
6328 // Email new user welcome message if plugin option is set.
6329 $this->maybe_email_welcome_message( $approved_user['email'] );
6330
6331 // Add new user to approved list and save (skip if it's
6332 // already there--someone else might have just done it).
6333 if ( 'false' !== $approved_user['multisite_user'] ) {
6334 if ( ! $this->is_email_in_list( $approved_user['email'], 'approved', 'multisite' ) ) {
6335 $auth_multisite_settings_access_users_approved = $this->sanitize_user_list(
6336 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
6337 );
6338 $approved_user['date_added'] = date( 'M Y' );
6339 array_push( $auth_multisite_settings_access_users_approved, $approved_user );
6340 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
6341 } else {
6342 $invalid_emails[] = $approved_user['email'];
6343 }
6344 } else {
6345 if ( ! $this->is_email_in_list( $approved_user['email'], 'approved' ) ) {
6346 $auth_settings_access_users_approved = $this->sanitize_user_list(
6347 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT )
6348 );
6349 $approved_user['date_added'] = date( 'M Y' );
6350 array_push( $auth_settings_access_users_approved, $approved_user );
6351 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
6352 } else {
6353 $invalid_emails[] = $approved_user['email'];
6354 }
6355 }
6356
6357 // If we've added a new multisite user, go through all pending/approved/blocked lists
6358 // on individual sites and remove this user from them (to prevent duplicate entries).
6359 if ( 'false' !== $approved_user['multisite_user'] && is_multisite() ) {
6360 $list_names = array( 'access_users_pending', 'access_users_approved', 'access_users_blocked' );
6361 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
6362 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
6363 foreach ( $sites as $site ) {
6364 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
6365 foreach ( $list_names as $list_name ) {
6366 $user_list = get_blog_option( $blog_id, 'auth_settings_' . $list_name, array() );
6367 $list_changed = false;
6368 foreach ( $user_list as $key => $user ) {
6369 if ( 0 === strcasecmp( $user['email'], $approved_user['email'] ) ) {
6370 unset( $user_list[ $key ] );
6371 $list_changed = true;
6372 }
6373 }
6374 if ( $list_changed ) {
6375 update_blog_option( $blog_id, 'auth_settings_' . $list_name, $user_list );
6376 }
6377 }
6378 }
6379 }
6380 } elseif ( 'remove' === $approved_user['edit_action'] ) { // Remove user from approved list and save (also remove their role if they have a WordPress account).
6381 if ( 'false' !== $approved_user['multisite_user'] ) {
6382 if ( $this->is_email_in_list( $approved_user['email'], 'approved', 'multisite' ) ) {
6383 $auth_multisite_settings_access_users_approved = $this->sanitize_user_list(
6384 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
6385 );
6386 foreach ( $auth_multisite_settings_access_users_approved as $key => $existing_user ) {
6387 if ( 0 === strcasecmp( $approved_user['email'], $existing_user['email'] ) ) {
6388 // Remove role of the associated WordPress user from all blogs (but don't delete the user).
6389 $user = get_user_by( 'email', $approved_user['email'] );
6390 if ( false !== $user ) {
6391 // Loop through all of the blogs this user is a member of and remove their capabilities.
6392 foreach ( get_blogs_of_user( $user->ID ) as $blog ) {
6393 remove_user_from_blog( $user->ID, $blog->userblog_id, '' );
6394 }
6395 }
6396 // Remove entry from Approved Users list.
6397 unset( $auth_multisite_settings_access_users_approved[ $key ] );
6398 break;
6399 }
6400 }
6401 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
6402 }
6403 } else {
6404 if ( $this->is_email_in_list( $approved_user['email'], 'approved' ) ) {
6405 $auth_settings_access_users_approved = $this->sanitize_user_list(
6406 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT )
6407 );
6408 foreach ( $auth_settings_access_users_approved as $key => $existing_user ) {
6409 if ( 0 === strcasecmp( $approved_user['email'], $existing_user['email'] ) ) {
6410 // Remove role of the associated WordPress user (but don't delete the user).
6411 $user = get_user_by( 'email', $approved_user['email'] );
6412 if ( false !== $user ) {
6413 $user->set_role( '' );
6414 }
6415 // Remove entry from Approved Users list.
6416 unset( $auth_settings_access_users_approved[ $key ] );
6417 break;
6418 }
6419 }
6420 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
6421 }
6422 }
6423 } elseif ( 'change_role' === $approved_user['edit_action'] ) { // Update user's role in WordPress.
6424 $changed_user = get_user_by( 'email', $approved_user['email'] );
6425 if ( $changed_user ) {
6426 if ( is_multisite() && 'false' !== $approved_user['multisite_user'] ) {
6427 foreach ( get_blogs_of_user( $changed_user->ID ) as $blog ) {
6428 add_user_to_blog( $blog->userblog_id, $changed_user->ID, $approved_user['role'] );
6429 }
6430 } else {
6431 $changed_user->set_role( $approved_user['role'] );
6432 }
6433 }
6434
6435 if ( 'false' !== $approved_user['multisite_user'] ) {
6436 if ( $this->is_email_in_list( $approved_user['email'], 'approved', 'multisite' ) ) {
6437 $auth_multisite_settings_access_users_approved = $this->sanitize_user_list(
6438 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
6439 );
6440 foreach ( $auth_multisite_settings_access_users_approved as $key => $existing_user ) {
6441 if ( 0 === strcasecmp( $approved_user['email'], $existing_user['email'] ) ) {
6442 $auth_multisite_settings_access_users_approved[ $key ]['role'] = $approved_user['role'];
6443 break;
6444 }
6445 }
6446 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
6447 }
6448 } else {
6449 // Update user's role in approved list and save.
6450 if ( $this->is_email_in_list( $approved_user['email'], 'approved' ) ) {
6451 $auth_settings_access_users_approved = $this->sanitize_user_list(
6452 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT )
6453 );
6454 foreach ( $auth_settings_access_users_approved as $key => $existing_user ) {
6455 if ( 0 === strcasecmp( $approved_user['email'], $existing_user['email'] ) ) {
6456 $auth_settings_access_users_approved[ $key ]['role'] = $approved_user['role'];
6457 break;
6458 }
6459 }
6460 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
6461 }
6462 }
6463 }
6464 }
6465 }
6466
6467 // Editing a blocked list entry.
6468 if ( 'access_users_blocked' === $_POST['setting'] ) {
6469 // Sanitize post data.
6470 $access_users_blocked = array();
6471 if ( isset( $_POST['access_users_blocked'] ) && is_array( $_POST['access_users_blocked'] ) ) {
6472 $access_users_blocked = $this->sanitize_update_auth_users( wp_unslash( $_POST['access_users_blocked'] ) );
6473 }
6474
6475 // Deal with each modified user (add or remove).
6476 foreach ( $access_users_blocked as $blocked_user ) {
6477
6478 if ( 'add' === $blocked_user['edit_action'] ) {
6479
6480 // Add auth_blocked usermeta for the user.
6481 $blocked_wp_user = get_user_by( 'email', $blocked_user['email'] );
6482 if ( false !== $blocked_wp_user ) {
6483 update_user_meta( $blocked_wp_user->ID, 'auth_blocked', 'yes' );
6484 }
6485
6486 // Add new user to blocked list and save (skip if it's
6487 // already there--someone else might have just done it).
6488 if ( ! $this->is_email_in_list( $blocked_user['email'], 'blocked' ) ) {
6489 $auth_settings_access_users_blocked = $this->sanitize_user_list(
6490 $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT )
6491 );
6492 $blocked_user['date_added'] = date( 'M Y' );
6493 array_push( $auth_settings_access_users_blocked, $blocked_user );
6494 update_option( 'auth_settings_access_users_blocked', $auth_settings_access_users_blocked );
6495 } else {
6496 $invalid_emails[] = $blocked_user['email'];
6497 }
6498 } elseif ( 'remove' === $blocked_user['edit_action'] ) {
6499
6500 // Remove auth_blocked usermeta for the user.
6501 $unblocked_user = get_user_by( 'email', $blocked_user['email'] );
6502 if ( false !== $unblocked_user ) {
6503 delete_user_meta( $unblocked_user->ID, 'auth_blocked', 'yes' );
6504 }
6505
6506 // Remove user from blocked list and save.
6507 if ( $this->is_email_in_list( $blocked_user['email'], 'blocked' ) ) {
6508 $auth_settings_access_users_blocked = $this->sanitize_user_list(
6509 $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT )
6510 );
6511 foreach ( $auth_settings_access_users_blocked as $key => $existing_user ) {
6512 if ( 0 === strcasecmp( $blocked_user['email'], $existing_user['email'] ) ) {
6513 unset( $auth_settings_access_users_blocked[ $key ] );
6514 break;
6515 }
6516 }
6517 update_option( 'auth_settings_access_users_blocked', $auth_settings_access_users_blocked );
6518 }
6519 }
6520 }
6521 }
6522
6523 // Send response to client.
6524 $response = array(
6525 'success' => true,
6526 'invalid_emails' => $invalid_emails,
6527 );
6528 header( 'content-type: application/json' );
6529 echo wp_json_encode( $response );
6530 exit;
6531 }
6532
6533
6534 /**
6535 * Sanitizes an array of user update commands coming from the AJAX handler in Authorizer Settings.
6536 *
6537 * Example $users array:
6538 * array(
6539 * array(
6540 * edit_action: 'add' or 'remove' or 'change_role',
6541 * email: 'johndoe@example.com',
6542 * role: 'subscriber',
6543 * date_added: 'Jun 2014',
6544 * local_user: 'true' or 'false',
6545 * multisite_user: 'true' or 'false',
6546 * ),
6547 * ...
6548 * )
6549 *
6550 * @param array $users Users to edit.
6551 * @return array Sanitized users to edit.
6552 */
6553 private function sanitize_update_auth_users( $users = array() ) {
6554 if ( ! is_array( $users ) ) {
6555 $users = array();
6556 }
6557 $users = array_map( array( $this, 'sanitize_update_auth_user' ), $users );
6558
6559 return $users;
6560 }
6561
6562
6563 /**
6564 * Callback for array_map in sanitize_update_auth_users().
6565 *
6566 * @param array $user User data to sanitize.
6567 * @return array Sanitized user data.
6568 */
6569 private function sanitize_update_auth_user( $user ) {
6570 if ( array_key_exists( 'edit_action', $user ) ) {
6571 $user['edit_action'] = sanitize_text_field( $user['edit_action'] );
6572 }
6573 if ( isset( $user['email'] ) ) {
6574 $user['email'] = sanitize_email( $user['email'] );
6575 }
6576 if ( isset( $user['role'] ) ) {
6577 $user['role'] = sanitize_text_field( $user['role'] );
6578 }
6579 if ( isset( $user['date_added'] ) ) {
6580 $user['date_added'] = sanitize_text_field( $user['date_added'] );
6581 }
6582 if ( isset( $user['local_user'] ) ) {
6583 $user['local_user'] = 'true' === $user['local_user'] ? 'true' : 'false';
6584 }
6585 if ( isset( $user['multisite_user'] ) ) {
6586 $user['multisite_user'] = 'true' === $user['multisite_user'] ? 'true' : 'false';
6587 }
6588
6589 return $user;
6590 }
6591
6592
6593
6594 /**
6595 * ***************************
6596 * Helper functions
6597 * ***************************
6598 */
6599
6600
6601 /**
6602 * Retrieves a specific plugin option from db. Multisite enabled.
6603 *
6604 * @param string $option Option name.
6605 * @param string $admin_mode WP_Plugin_Authorizer::NETWORK_CONTEXT will retrieve the multisite value.
6606 * @param string $override_mode 'allow override' will retrieve the multisite value if it exists.
6607 * @param string $print_mode 'print overlay' will output overlay that hides this option on the settings page.
6608 * @return mixed Option value, or null on failure.
6609 */
6610 private function get_plugin_option( $option, $admin_mode = WP_Plugin_Authorizer::SINGLE_CONTEXT, $override_mode = 'no override', $print_mode = 'no overlay' ) {
6611 // Special case for user lists (they are saved seperately to prevent concurrency issues).
6612 if ( in_array( $option, array( 'access_users_pending', 'access_users_approved', 'access_users_blocked' ), true ) ) {
6613 $list = WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode ? array() : get_option( 'auth_settings_' . $option );
6614 if ( is_multisite() && WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode ) {
6615 $list = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_' . $option, array() );
6616 }
6617 return $list;
6618 }
6619
6620 // Get all plugin options.
6621 $auth_settings = $this->get_plugin_options( $admin_mode, $override_mode );
6622
6623 // Set option to null if it wasn't found.
6624 if ( ! array_key_exists( $option, $auth_settings ) ) {
6625 return null;
6626 }
6627
6628 // If requested and appropriate, print the overlay hiding the
6629 // single site option that is overridden by a multisite option.
6630 if (
6631 WP_Plugin_Authorizer::NETWORK_CONTEXT !== $admin_mode &&
6632 'allow override' === $override_mode &&
6633 'print overlay' === $print_mode &&
6634 array_key_exists( 'multisite_override', $auth_settings ) &&
6635 '1' === $auth_settings['multisite_override'] &&
6636 ( ! array_key_exists( 'advanced_override_multisite', $auth_settings ) || 1 !== intval( $auth_settings['advanced_override_multisite'] ) )
6637 ) {
6638 // Get original plugin options (not overridden value). We'll
6639 // show this old value behind the disabled overlay.
6640 // $auth_settings = $this->get_plugin_options( $admin_mode, 'no override' );
6641 // (This feature is disabled).
6642 //
6643 $name = "auth_settings[$option]";
6644 $id = "auth_settings_$option";
6645 ?>
6646 <div id="overlay-hide-auth_settings_<?php echo esc_attr( $option ); ?>" class="auth_multisite_override_overlay">
6647 <span class="overlay-note">
6648 <?php esc_html_e( 'This setting is overridden by a', 'authorizer' ); ?> <a href="<?php echo esc_attr( network_admin_url( 'admin.php?page=authorizer' ) ); ?>"><?php esc_html_e( 'multisite option', 'authorizer' ); ?></a>.
6649 </span>
6650 </div>
6651 <?php
6652 }
6653
6654 // If we're getting an option in a site that has overridden the multisite override, make
6655 // sure we are returning the option value from that site (not the multisite value).
6656 if ( array_key_exists( 'advanced_override_multisite', $auth_settings ) && 1 === intval( $auth_settings['advanced_override_multisite'] ) ) {
6657 $auth_settings = $this->get_plugin_options( $admin_mode, 'no override' );
6658 }
6659
6660 // Set option to null if it wasn't found.
6661 if ( ! array_key_exists( $option, $auth_settings ) ) {
6662 return null;
6663 }
6664
6665 return $auth_settings[ $option ];
6666 }
6667
6668 /**
6669 * Retrieves all plugin options from db. Multisite enabled.
6670 *
6671 * @param string $admin_mode WP_Plugin_Authorizer::NETWORK_CONTEXT will retrieve the multisite value.
6672 * @param string $override_mode 'allow override' will retrieve the multisite value if it exists.
6673 * @return mixed Option value, or null on failure.
6674 */
6675 private function get_plugin_options( $admin_mode = WP_Plugin_Authorizer::SINGLE_CONTEXT, $override_mode = 'no override' ) {
6676 // Grab plugin settings (skip if in WP_Plugin_Authorizer::NETWORK_CONTEXT mode).
6677 $auth_settings = WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode ? array() : get_option( 'auth_settings' );
6678
6679 // Initialize to default values if the plugin option doesn't exist.
6680 if ( false === $auth_settings ) {
6681 $auth_settings = $this->set_default_options();
6682 }
6683
6684 // Merge multisite options if we're in a network and the current site hasn't overridden multisite settings.
6685 if ( is_multisite() && ( ! array_key_exists( 'advanced_override_multisite', $auth_settings ) || 1 !== intval( $auth_settings['advanced_override_multisite'] ) ) ) {
6686 // Get multisite options.
6687 $auth_multisite_settings = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', array() );
6688
6689 // Return the multisite options if we're viewing the network admin options page.
6690 // Otherwise override options with their multisite equivalents.
6691 if ( WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode ) {
6692 $auth_settings = $auth_multisite_settings;
6693 } elseif (
6694 'allow override' === $override_mode &&
6695 array_key_exists( 'multisite_override', $auth_multisite_settings ) &&
6696 '1' === $auth_multisite_settings['multisite_override']
6697 ) {
6698 // Keep track of the multisite override selection.
6699 $auth_settings['multisite_override'] = $auth_multisite_settings['multisite_override'];
6700
6701 /**
6702 * Note: the options below should be the complete list of overridden
6703 * options. It is *not* the complete list of all options (some options
6704 * don't have a multisite equivalent).
6705 */
6706
6707 /**
6708 * Note: access_users_approved, access_users_pending, and
6709 * access_users_blocked do not get overridden. However, since
6710 * access_users_approved has a multisite equivalent, you must retrieve
6711 * them both seperately. This is done because the two lists should be
6712 * treated differently.
6713 *
6714 * $approved_users = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
6715 * $ms_approved_users = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT );
6716 */
6717
6718 // Override external services (google, cas, or ldap) and associated options.
6719 $auth_settings['google'] = $auth_multisite_settings['google'];
6720 $auth_settings['google_clientid'] = $auth_multisite_settings['google_clientid'];
6721 $auth_settings['google_clientsecret'] = $auth_multisite_settings['google_clientsecret'];
6722 $auth_settings['google_hosteddomain'] = $auth_multisite_settings['google_hosteddomain'];
6723 $auth_settings['cas'] = $auth_multisite_settings['cas'];
6724 $auth_settings['cas_custom_label'] = $auth_multisite_settings['cas_custom_label'];
6725 $auth_settings['cas_host'] = $auth_multisite_settings['cas_host'];
6726 $auth_settings['cas_port'] = $auth_multisite_settings['cas_port'];
6727 $auth_settings['cas_path'] = $auth_multisite_settings['cas_path'];
6728 $auth_settings['cas_version'] = $auth_multisite_settings['cas_version'];
6729 $auth_settings['cas_attr_email'] = $auth_multisite_settings['cas_attr_email'];
6730 $auth_settings['cas_attr_first_name'] = $auth_multisite_settings['cas_attr_first_name'];
6731 $auth_settings['cas_attr_last_name'] = $auth_multisite_settings['cas_attr_last_name'];
6732 $auth_settings['cas_attr_update_on_login'] = $auth_multisite_settings['cas_attr_update_on_login'];
6733 $auth_settings['cas_auto_login'] = $auth_multisite_settings['cas_auto_login'];
6734 $auth_settings['ldap'] = $auth_multisite_settings['ldap'];
6735 $auth_settings['ldap_host'] = $auth_multisite_settings['ldap_host'];
6736 $auth_settings['ldap_port'] = $auth_multisite_settings['ldap_port'];
6737 $auth_settings['ldap_tls'] = $auth_multisite_settings['ldap_tls'];
6738 $auth_settings['ldap_search_base'] = $auth_multisite_settings['ldap_search_base'];
6739 $auth_settings['ldap_uid'] = $auth_multisite_settings['ldap_uid'];
6740 $auth_settings['ldap_attr_email'] = $auth_multisite_settings['ldap_attr_email'];
6741 $auth_settings['ldap_user'] = $auth_multisite_settings['ldap_user'];
6742 $auth_settings['ldap_password'] = $auth_multisite_settings['ldap_password'];
6743 $auth_settings['ldap_lostpassword_url'] = $auth_multisite_settings['ldap_lostpassword_url'];
6744 $auth_settings['ldap_attr_first_name'] = $auth_multisite_settings['ldap_attr_first_name'];
6745 $auth_settings['ldap_attr_last_name'] = $auth_multisite_settings['ldap_attr_last_name'];
6746 $auth_settings['ldap_attr_update_on_login'] = $auth_multisite_settings['ldap_attr_update_on_login'];
6747
6748 // Override access_who_can_login and access_who_can_view.
6749 $auth_settings['access_who_can_login'] = $auth_multisite_settings['access_who_can_login'];
6750 $auth_settings['access_who_can_view'] = $auth_multisite_settings['access_who_can_view'];
6751
6752 // Override access_default_role.
6753 $auth_settings['access_default_role'] = $auth_multisite_settings['access_default_role'];
6754
6755 // Override lockouts.
6756 $auth_settings['advanced_lockouts'] = $auth_multisite_settings['advanced_lockouts'];
6757
6758 // Override Hide WordPress login.
6759 $auth_settings['advanced_hide_wp_login'] = $auth_multisite_settings['advanced_hide_wp_login'];
6760
6761 // Override Users per page.
6762 $auth_settings['advanced_users_per_page'] = $auth_multisite_settings['advanced_users_per_page'];
6763
6764 // Override Sort users by.
6765 $auth_settings['advanced_users_sort_by'] = $auth_multisite_settings['advanced_users_sort_by'];
6766
6767 // Override Sort users order.
6768 $auth_settings['advanced_users_sort_order'] = $auth_multisite_settings['advanced_users_sort_order'];
6769
6770 // Override Show Dashboard Widget.
6771 $auth_settings['advanced_widget_enabled'] = $auth_multisite_settings['advanced_widget_enabled'];
6772 }
6773 }
6774 return $auth_settings;
6775 }
6776
6777
6778 /**
6779 * Remove user from authorizer lists when that user is deleted in WordPress.
6780 *
6781 * Action: delete_user
6782 *
6783 * @param int $user_id User ID to remove.
6784 * @return void
6785 */
6786 public function remove_user_from_authorizer_when_deleted( $user_id ) {
6787 $user = get_user_by( 'id', $user_id );
6788 $deleted_email = $user->user_email;
6789
6790 // Remove user from pending/approved lists and save.
6791 $list_names = array( 'access_users_pending', 'access_users_approved' );
6792 foreach ( $list_names as $list_name ) {
6793 $user_list = $this->sanitize_user_list( $this->get_plugin_option( $list_name, WP_Plugin_Authorizer::SINGLE_CONTEXT ) );
6794 $list_changed = false;
6795 foreach ( $user_list as $key => $existing_user ) {
6796 if ( 0 === strcasecmp( $deleted_email, $existing_user['email'] ) ) {
6797 $list_changed = true;
6798 unset( $user_list[ $key ] );
6799 }
6800 }
6801 if ( $list_changed ) {
6802 update_option( 'auth_settings_' . $list_name, $user_list );
6803 }
6804 }
6805 }
6806
6807
6808 /**
6809 * Remove multisite user from authorizer lists when that user is deleted from Network Users.
6810 *
6811 * Action: wpmu_delete_user
6812 *
6813 * @param int $user_id User ID to remove.
6814 * @return void
6815 */
6816 public function remove_network_user_from_authorizer_when_deleted( $user_id ) {
6817 $user = get_user_by( 'id', $user_id );
6818 $deleted_email = $user->user_email;
6819
6820 // Go through multisite approved user list and remove this user.
6821 $auth_multisite_settings_access_users_approved = $this->sanitize_user_list(
6822 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
6823 );
6824 $list_changed = false;
6825 foreach ( $auth_multisite_settings_access_users_approved as $key => $existing_user ) {
6826 if ( 0 === strcasecmp( $deleted_email, $existing_user['email'] ) ) {
6827 $list_changed = true;
6828 unset( $auth_multisite_settings_access_users_approved[ $key ] );
6829 }
6830 }
6831 if ( $list_changed ) {
6832 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
6833 }
6834
6835 // Go through all pending/approved lists on individual sites and remove this user from them.
6836 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
6837 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
6838 foreach ( $sites as $site ) {
6839 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
6840 $this->remove_network_user_from_site_when_removed( $user_id, $blog_id );
6841 }
6842
6843 }
6844
6845
6846 /**
6847 * Remove multisite user from a specific site's lists when that user is removed from the site.
6848 *
6849 * Action: remove_user_from_blog
6850 *
6851 * @param int $user_id User ID to remove.
6852 * @param int $blog_id Blog ID to remove from.
6853 * @return void
6854 */
6855 public function remove_network_user_from_site_when_removed( $user_id, $blog_id ) {
6856 $user = get_user_by( 'id', $user_id );
6857 $deleted_email = $user->user_email;
6858
6859 $list_names = array( 'access_users_pending', 'access_users_approved' );
6860 foreach ( $list_names as $list_name ) {
6861 $user_list = get_blog_option( $blog_id, 'auth_settings_' . $list_name, array() );
6862 $list_changed = false;
6863 foreach ( $user_list as $key => $existing_user ) {
6864 if ( 0 === strcasecmp( $deleted_email, $existing_user['email'] ) ) {
6865 $list_changed = true;
6866 unset( $user_list[ $key ] );
6867 }
6868 }
6869 if ( $list_changed ) {
6870 update_blog_option( $blog_id, 'auth_settings_' . $list_name, $user_list );
6871 }
6872 }
6873 }
6874
6875
6876 /**
6877 * Helper: Add multisite user to a specific site's approved list.
6878 *
6879 * @param int $user_id User ID to add.
6880 * @param int $blog_id Blog ID to add to.
6881 * @return void
6882 */
6883 private function add_network_user_to_site( $user_id, $blog_id ) {
6884 // Switch to blog.
6885 switch_to_blog( $blog_id );
6886
6887 // Get user details and role.
6888 $access_default_role = $this->get_plugin_option( 'access_default_role', WP_Plugin_Authorizer::SINGLE_CONTEXT, 'allow override' );
6889 $user = get_user_by( 'id', $user_id );
6890 $user_email = $user->user_email;
6891 $user_role = $user && is_array( $user->roles ) && count( $user->roles ) > 0 ? $user->roles[0] : $access_default_role;
6892
6893 // Add user to approved list if not already there and not in blocked list.
6894 $auth_settings_access_users_approved = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
6895 $auth_settings_access_users_blocked = $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT );
6896 if ( ! $this->in_multi_array( $user_email, $auth_settings_access_users_approved ) && ! $this->in_multi_array( $user_email, $auth_settings_access_users_blocked ) ) {
6897 $approved_user = array(
6898 'email' => $this->lowercase( $user_email ),
6899 'role' => $user_role,
6900 'date_added' => date( 'M Y', strtotime( $user->user_registered ) ),
6901 'local_user' => true,
6902 );
6903 array_push( $auth_settings_access_users_approved, $approved_user );
6904 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
6905 }
6906
6907 // Restore original blog.
6908 restore_current_blog();
6909 }
6910
6911
6912 /**
6913 * Multisite:
6914 * When an existing user is invited to the current site (or a new user is created),
6915 * add them to the authorizer approved list. This action fires when the admin
6916 * doesn't select the "Skip Confirmation Email" option.
6917 *
6918 * Action: invite_user
6919 *
6920 * @param int $user_id The invited user's ID.
6921 * @param array $role The role of the invited user (or none if a new user creation).
6922 * @param string $newuser_key The key of the invitation.
6923 */
6924 public function add_existing_user_to_authorizer_when_created( $user_id, $role = array(), $newuser_key = '' ) {
6925 $user = get_user_by( 'id', $user_id );
6926 $this->add_user_to_authorizer_when_created( $user->user_email, $user->user_registered, $user->roles, $role );
6927 }
6928
6929
6930 /**
6931 * Multisite:
6932 * When an existing user is invited to the current site (or a new user is created),
6933 * add them to the authorizer approved list. This action fires when the admin
6934 * selects the "Skip Confirmation Email" option.
6935 *
6936 * Action: added_existing_user
6937 *
6938 * @param int $user_id The invited user's ID.
6939 * @param mixed $result True on success or a WP_Error object if the user doesn't exist.
6940 */
6941 public function add_existing_user_to_authorizer_when_created_noconfirmation( $user_id, $result ) {
6942 $user = get_user_by( 'id', $user_id );
6943 $this->add_user_to_authorizer_when_created( $user->user_email, $user->user_registered, $user->roles );
6944 }
6945
6946
6947 /**
6948 * Multisite:
6949 * When a new user is invited to the current site (or a new user is created),
6950 * add them to the authorizer approved list.
6951 *
6952 * Action: after_signup_user
6953 *
6954 * @param string $user User's requested login name.
6955 * @param string $user_email User's email address.
6956 * @param string $key User's activation key.
6957 * @param array $meta Additional signup meta, including initially set roles.
6958 */
6959 public function add_new_user_to_authorizer_when_created( $user, $user_email, $key, $meta ) {
6960 $user_roles = isset( $meta['new_role'] ) ? array( $meta['new_role'] ) : array();
6961 $this->add_user_to_authorizer_when_created( $user_email, time(), $user_roles );
6962 }
6963
6964
6965 /**
6966 * Single site:
6967 * When a new user is added in single site mode, add them to the authorizer
6968 * approved list.
6969 *
6970 * Action: edit_user_created_user
6971 *
6972 * @param int $user_id ID of the newly created user.
6973 * @param string $notify Type of notification that should happen. See
6974 * wp_send_new_user_notifications() for more
6975 * information on possible values.
6976 */
6977 public function add_new_user_to_authorizer_when_created_single_site( $user_id, $notify ) {
6978 $user = get_user_by( 'id', $user_id );
6979 $this->add_user_to_authorizer_when_created( $user->user_email, $user->user_registered, $user->roles );
6980 }
6981
6982
6983 /**
6984 * Helper: When a new user is added/invited to the current site (or a new
6985 * user is created), add them to the authorizer approved list.
6986 *
6987 * @param string $user_email Email address of user to add.
6988 * @param string $date_registered Date user registered.
6989 * @param array $user_roles Role to add for user.
6990 * @param array $default_role Default role, if no role specified.
6991 */
6992 private function add_user_to_authorizer_when_created( $user_email, $date_registered, $user_roles = array(), $default_role = array() ) {
6993 $auth_multisite_settings_access_users_approved = is_multisite() ? get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', array() ) : array();
6994 $auth_settings_access_users_pending = $this->get_plugin_option( 'access_users_pending', WP_Plugin_Authorizer::SINGLE_CONTEXT );
6995 $auth_settings_access_users_approved = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
6996 $auth_settings_access_users_blocked = $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT );
6997
6998 // Get default role if one isn't specified.
6999 if ( count( $default_role ) < 1 ) {
7000 $default_role = '';
7001 } else {
7002 $default_role = strtolower( $default_role['name'] );
7003 }
7004
7005 $updated = false;
7006
7007 // Skip if user is in blocked list.
7008 if ( $this->in_multi_array( $user_email, $auth_settings_access_users_blocked ) ) {
7009 return;
7010 }
7011 // Remove from pending list if there.
7012 foreach ( $auth_settings_access_users_pending as $key => $pending_user ) {
7013 if ( 0 === strcasecmp( $pending_user['email'], $user_email ) ) {
7014 unset( $auth_settings_access_users_pending[ $key ] );
7015 $updated = true;
7016 }
7017 }
7018 // Skip if user is in multisite approved list.
7019 if ( $this->in_multi_array( $user_email, $auth_multisite_settings_access_users_approved ) ) {
7020 return;
7021 }
7022 // Add to approved list if not there.
7023 if ( ! $this->in_multi_array( $user_email, $auth_settings_access_users_approved ) ) {
7024 $approved_user = array(
7025 'email' => $this->lowercase( $user_email ),
7026 'role' => is_array( $user_roles ) && count( $user_roles ) > 0 ? $user_roles[0] : $default_role,
7027 'date_added' => date( 'M Y', strtotime( $date_registered ) ),
7028 'local_user' => true,
7029 );
7030 array_push( $auth_settings_access_users_approved, $approved_user );
7031 $updated = true;
7032 }
7033
7034 if ( $updated ) {
7035 update_option( 'auth_settings_access_users_pending', $auth_settings_access_users_pending );
7036 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
7037 }
7038 }
7039
7040
7041 /**
7042 * Multisite:
7043 * When a user is granted super admin status (checkbox on network user edit
7044 * screen), add them to the authorizer network approved list. Also remove
7045 * them from pending/approved list on any individual sites.
7046 *
7047 * Action: grant_super_admin
7048 *
7049 * @param int $user_id The user's ID.
7050 */
7051 public function grant_super_admin__add_to_network_approved( $user_id ) {
7052 $user = get_user_by( 'id', $user_id );
7053 $user_email = $user->user_email;
7054
7055 // Add user to multisite approved user list (if not already there).
7056 $auth_multisite_settings_access_users_approved = $this->sanitize_user_list(
7057 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
7058 );
7059 if ( ! $this->in_multi_array( $user_email, $auth_multisite_settings_access_users_approved ) ) {
7060 $multisite_approved_user = array(
7061 'email' => $this->lowercase( $user_email ),
7062 'role' => count( $user->roles ) > 0 ? $user->roles[0] : 'administrator',
7063 'date_added' => date( 'M Y', strtotime( $user->user_registered ) ),
7064 'local_user' => true,
7065 );
7066 array_push( $auth_multisite_settings_access_users_approved, $multisite_approved_user );
7067 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
7068 }
7069
7070 // Go through all pending/approved lists on individual sites and remove this user from them.
7071 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7072 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7073 foreach ( $sites as $site ) {
7074 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7075 $this->remove_network_user_from_site_when_removed( $user_id, $blog_id );
7076 }
7077
7078 }
7079
7080 /**
7081 * Multisite:
7082 * When a user's super admin status is revoked (checkbox on network user edit
7083 * screen), remove them from the authorizer network approved list. Also add
7084 * them to approved list on any individual sites they are already a part of.
7085 *
7086 * Action: revoke_super_admin
7087 *
7088 * @param int $user_id The user's ID.
7089 */
7090 public function revoke_super_admin__remove_from_network_approved( $user_id ) {
7091 $user = get_user_by( 'id', $user_id );
7092 $revoked_email = $user->user_email;
7093
7094 // Go through multisite approved user list and remove this user.
7095 $auth_multisite_settings_access_users_approved = $this->sanitize_user_list(
7096 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
7097 );
7098 $list_changed = false;
7099 foreach ( $auth_multisite_settings_access_users_approved as $key => $existing_user ) {
7100 if ( 0 === strcasecmp( $revoked_email, $existing_user['email'] ) ) {
7101 $list_changed = true;
7102 unset( $auth_multisite_settings_access_users_approved[ $key ] );
7103 }
7104 }
7105 if ( $list_changed ) {
7106 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
7107 }
7108
7109 // Go through this user's current sites and add them to the approved list
7110 // (since they are no longer on the network approved list).
7111 $sites_of_user = get_blogs_of_user( $user_id );
7112 foreach ( $sites_of_user as $site ) {
7113 $blog_id = $site->userblog_id;
7114 $this->add_network_user_to_site( $user_id, $blog_id );
7115 }
7116
7117 }
7118
7119 /**
7120 * Send a welcome email message to a newly approved user (if the "Should
7121 * email approved users" setting is enabled).
7122 *
7123 * @param string $email Email address to send welcome email to.
7124 * @return bool Whether the email was sent.
7125 */
7126 private function maybe_email_welcome_message( $email ) {
7127 // Get option for whether to email welcome messages.
7128 $should_email_new_approved_users = $this->get_plugin_option( 'access_should_email_approved_users' );
7129
7130 // Do not send welcome email if option not enabled.
7131 if ( '1' !== $should_email_new_approved_users ) {
7132 return false;
7133 }
7134
7135 // Make sure we didn't just email this user (can happen with
7136 // multiple admins saving at the same time, or by clicking
7137 // Approve button too rapidly).
7138 $recently_sent_emails = get_option( 'auth_settings_recently_sent_emails' );
7139 if ( false === $recently_sent_emails ) {
7140 $recently_sent_emails = array();
7141 }
7142 foreach ( $recently_sent_emails as $key => $recently_sent_email ) {
7143 if ( $recently_sent_email['time'] < strtotime( 'now -1 minutes' ) ) {
7144 // Remove emails sent more than 1 minute ago.
7145 unset( $recently_sent_emails[ $key ] );
7146 } elseif ( $recently_sent_email['email'] === $email ) {
7147 // Sent an email to this user within the last 1 minute, so
7148 // quit without sending.
7149 return false;
7150 }
7151 }
7152 // Add the email we're about to send to the list.
7153 $recently_sent_emails[] = array(
7154 'email' => $email,
7155 'time' => time(),
7156 );
7157 update_option( 'auth_settings_recently_sent_emails', $recently_sent_emails );
7158
7159 // Get welcome email subject and body text.
7160 $subject = $this->get_plugin_option( 'access_email_approved_users_subject' );
7161 $body = apply_filters( 'the_content', $this->get_plugin_option( 'access_email_approved_users_body' ) );
7162
7163 // Fail if the subject/body options don't exist or are empty.
7164 if ( is_null( $subject ) || is_null( $body ) || strlen( $subject ) === 0 || strlen( $body ) === 0 ) {
7165 return false;
7166 }
7167
7168 // Replace approved shortcode patterns in subject and body.
7169 $site_name = get_bloginfo( 'name' );
7170 $site_url = get_site_url();
7171 $subject = str_replace( '[site_name]', $site_name, $subject );
7172 $body = str_replace( '[site_name]', $site_name, $body );
7173 $body = str_replace( '[site_url]', $site_url, $body );
7174 $body = str_replace( '[user_email]', $email, $body );
7175 $headers = 'Content-type: text/html' . "\r\n";
7176
7177 // Send email.
7178 wp_mail( $email, $subject, $body, $headers );
7179
7180 // Indicate mail was sent.
7181 return true;
7182 }
7183
7184
7185 /**
7186 * Generate a unique cookie to add to nonces to prevent CSRF.
7187 *
7188 * @var string
7189 */
7190 private $cookie_value = null;
7191
7192 /**
7193 * Retrieve the unique login cookie.
7194 *
7195 * @return string Login cookie value.
7196 */
7197 private function get_cookie_value() {
7198 if ( ! $this->cookie_value ) {
7199 if ( isset( $_COOKIE['login_unique'] ) ) {
7200 $this->cookie_value = sanitize_key( wp_unslash( $_COOKIE['login_unique'] ) );
7201 } else {
7202 $this->cookie_value = md5( rand() );
7203 }
7204 }
7205 return $this->cookie_value;
7206 }
7207
7208
7209 /**
7210 * Encryption key (not secret!).
7211 *
7212 * @var string
7213 */
7214 private static $key = "8QxnrvjdtweisvCBKEY!+0\0\0";
7215
7216 /**
7217 * Encryption salt (not secret!).
7218 *
7219 * @var string
7220 */
7221 private static $iv = 'R_O2D]jPn]1[fhJl!-P1.oe';
7222
7223 /**
7224 * Basic encryption using a public (not secret!) key. Used for general
7225 * database obfuscation of passwords.
7226 *
7227 * @param string $text String to encrypt.
7228 * @param string $library Encryption library to use (openssl).
7229 * @return string Encrypted string.
7230 */
7231 private function encrypt( $text, $library = 'openssl' ) {
7232 $result = '';
7233
7234 // Use openssl library (better) if it is enabled.
7235 if ( function_exists( 'openssl_encrypt' ) && 'openssl' === $library ) {
7236 $result = base64_encode(
7237 openssl_encrypt(
7238 $text,
7239 'AES-256-CBC',
7240 hash( 'sha256', self::$key ),
7241 0,
7242 substr( hash( 'sha256', self::$iv ), 0, 16 )
7243 )
7244 );
7245 } elseif ( function_exists( 'mcrypt_encrypt' ) ) { // Use mcrypt library (deprecated in PHP 7.1) if php5-mcrypt extension is enabled.
7246 $result = base64_encode( mcrypt_encrypt( MCRYPT_RIJNDAEL_256, self::$key, $text, MCRYPT_MODE_ECB, 'abcdefghijklmnopqrstuvwxyz012345' ) );
7247 } else { // Fall back to basic obfuscation.
7248 $length = strlen( $text );
7249 for ( $i = 0; $i < $length; $i++ ) {
7250 $char = substr( $text, $i, 1 );
7251 $keychar = substr( self::$key, ( $i % strlen( self::$key ) ) - 1, 1 );
7252 $char = chr( ord( $char ) + ord( $keychar ) );
7253 $result .= $char;
7254 }
7255 $result = base64_encode( $result );
7256 }
7257
7258 return $result;
7259 }
7260
7261
7262 /**
7263 * Basic decryption using a public (not secret!) key. Used for general
7264 * database obfuscation of passwords.
7265 *
7266 * @param string $secret String to encrypt.
7267 * @param string $library Encryption lib to use (openssl).
7268 * @return string Decrypted string
7269 */
7270 private function decrypt( $secret, $library = 'openssl' ) {
7271 $result = '';
7272
7273 // Use openssl library (better) if it is enabled.
7274 if ( function_exists( 'openssl_decrypt' ) && 'openssl' === $library ) {
7275 $result = openssl_decrypt(
7276 base64_decode( $secret ),
7277 'AES-256-CBC',
7278 hash( 'sha256', self::$key ),
7279 0,
7280 substr( hash( 'sha256', self::$iv ), 0, 16 )
7281 );
7282 } elseif ( function_exists( 'mcrypt_decrypt' ) ) { // Use mcrypt library (deprecated in PHP 7.1) if php5-mcrypt extension is enabled.
7283 $secret = base64_decode( $secret );
7284 $result = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, self::$key, $secret, MCRYPT_MODE_ECB, 'abcdefghijklmnopqrstuvwxyz012345' ), "\0$result" );
7285 } else { // Fall back to basic obfuscation.
7286 $secret = base64_decode( $secret );
7287 $length = strlen( $secret );
7288 for ( $i = 0; $i < $length; $i++ ) {
7289 $char = substr( $secret, $i, 1 );
7290 $keychar = substr( self::$key, ( $i % strlen( self::$key ) ) - 1, 1 );
7291 $char = chr( ord( $char ) - ord( $keychar ) );
7292 $result .= $char;
7293 }
7294 }
7295
7296 return $result;
7297 }
7298
7299
7300 /**
7301 * In a multisite environment, returns true if the current user is logged
7302 * in and a user of the current blog. In single site mode, simply returns
7303 * true if the current user is logged in.
7304 *
7305 * @return bool Whether current user is logged in and a user of the current blog.
7306 */
7307 protected function is_user_logged_in_and_blog_user() {
7308 $is_user_logged_in_and_blog_user = false;
7309 if ( is_multisite() ) {
7310 $is_user_logged_in_and_blog_user = is_user_logged_in() && is_user_member_of_blog( get_current_user_id() );
7311 } else {
7312 $is_user_logged_in_and_blog_user = is_user_logged_in();
7313 }
7314 return $is_user_logged_in_and_blog_user;
7315 }
7316
7317
7318 /**
7319 * Helper function to determine whether a given email is in one of
7320 * the lists (pending, approved, blocked). Defaults to the list of
7321 * approved users.
7322 *
7323 * @param string $email Email to check existent of.
7324 * @param string $list List to look for email in.
7325 * @param string $multisite_mode Admin context.
7326 * @return boolean Whether email was found.
7327 */
7328 protected function is_email_in_list( $email = '', $list = 'approved', $multisite_mode = 'single' ) {
7329 if ( empty( $email ) ) {
7330 return false;
7331 }
7332
7333 switch ( $list ) {
7334 case 'pending':
7335 $auth_settings_access_users_pending = $this->get_plugin_option( 'access_users_pending', WP_Plugin_Authorizer::SINGLE_CONTEXT );
7336 return $this->in_multi_array( $email, $auth_settings_access_users_pending );
7337 case 'blocked':
7338 $auth_settings_access_users_blocked = $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT );
7339 return $this->in_multi_array( $email, $auth_settings_access_users_blocked );
7340 case 'approved':
7341 default:
7342 if ( 'single' !== $multisite_mode ) {
7343 // Get multisite users only.
7344 $auth_settings_access_users_approved = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT );
7345 } elseif ( is_multisite() && 1 === intval( $this->get_plugin_option( 'advanced_override_multisite' ) ) ) {
7346 // This site has overridden any multisite settings, so only get its users.
7347 $auth_settings_access_users_approved = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
7348 } else {
7349 // Get all site users and all multisite users.
7350 $auth_settings_access_users_approved = array_merge(
7351 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT ),
7352 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
7353 );
7354 }
7355 return $this->in_multi_array( $email, $auth_settings_access_users_approved );
7356 }
7357 }
7358
7359
7360 /**
7361 * Helper function to get number of users (including multisite users)
7362 * in a given list (pending, approved, or blocked).
7363 *
7364 * @param string $list List to get count of.
7365 * @param string $admin_mode WP_Plugin_Authorizer::SINGLE_CONTEXT or WP_Plugin_Authorizer::NETWORK_CONTEXT determines whether to include multisite users.
7366 * @return int Number of users in list.
7367 */
7368 protected function get_user_count_from_list( $list, $admin_mode = WP_Plugin_Authorizer::SINGLE_CONTEXT ) {
7369 $auth_settings_access_users = array();
7370
7371 switch ( $list ) {
7372 case 'pending':
7373 $auth_settings_access_users = $this->get_plugin_option( 'access_users_pending', WP_Plugin_Authorizer::SINGLE_CONTEXT );
7374 break;
7375 case 'blocked':
7376 $auth_settings_access_users = $this->get_plugin_option( 'access_users_blocked', WP_Plugin_Authorizer::SINGLE_CONTEXT );
7377 break;
7378 case 'approved':
7379 if ( WP_Plugin_Authorizer::SINGLE_CONTEXT !== $admin_mode ) {
7380 // Get multisite users only.
7381 $auth_settings_access_users = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT );
7382 } elseif ( is_multisite() && 1 === intval( $this->get_plugin_option( 'advanced_override_multisite' ) ) ) {
7383 // This site has overridden any multisite settings, so only get its users.
7384 $auth_settings_access_users = $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT );
7385 } else {
7386 // Get all site users and all multisite users.
7387 $auth_settings_access_users = array_merge(
7388 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::SINGLE_CONTEXT ),
7389 $this->get_plugin_option( 'access_users_approved', WP_Plugin_Authorizer::NETWORK_CONTEXT )
7390 );
7391 }
7392 }
7393
7394 return count( $auth_settings_access_users );
7395 }
7396
7397
7398 /**
7399 * Helper function to search a multidimensional array for a value.
7400 *
7401 * @param string $needle Value to search for.
7402 * @param array $haystack Multidimensional array to search.
7403 * @param string $strict_mode 'strict' if strict comparisons should be used.
7404 * @param string $case_sensitivity 'case sensitive' if comparisons should respect case.
7405 * @return bool Whether needle was found.
7406 */
7407 protected function in_multi_array( $needle = '', $haystack = array(), $strict_mode = 'not strict', $case_sensitivity = 'case insensitive' ) {
7408 if ( ! is_array( $haystack ) ) {
7409 return false;
7410 }
7411 if ( 'case insensitive' === $case_sensitivity ) {
7412 $needle = strtolower( $needle );
7413 }
7414 foreach ( $haystack as $item ) {
7415 if ( 'case insensitive' === $case_sensitivity && ! is_array( $item ) ) {
7416 $item = strtolower( $item );
7417 }
7418 if ( ( 'strict' === $strict_mode ? $item === $needle : $item == $needle ) || ( is_array( $item ) && $this->in_multi_array( $needle, $item, $strict_mode, $case_sensitivity ) ) ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
7419 return true;
7420 }
7421 }
7422 return false;
7423 }
7424
7425
7426 /**
7427 * Helper function to determine if an URL is accessible.
7428 *
7429 * @param string $url URL that should be publicly reachable.
7430 * @return boolean Whether the URL is publicly reachable.
7431 */
7432 protected function url_is_accessible( $url ) {
7433 // Use wp_remote_retrieve_response_code() to retrieve the URL.
7434 $response = wp_remote_get( $url );
7435 $response_code = wp_remote_retrieve_response_code( $response );
7436
7437 // Return true if the document has loaded successfully without any redirection or error.
7438 return $response_code >= 200 && $response_code < 400;
7439 }
7440
7441
7442 /**
7443 * Helper function to reconstruct a URL split using parse_url().
7444 *
7445 * @param array $parts Array returned from parse_url().
7446 * @return string URL.
7447 */
7448 protected function build_url( $parts = array() ) {
7449 return (
7450 ( isset( $parts['scheme'] ) ? "{$parts['scheme']}:" : '' ) .
7451 ( ( isset( $parts['user'] ) || isset( $parts['host'] ) ) ? '//' : '' ) .
7452 ( isset( $parts['user'] ) ? "{$parts['user']}" : '' ) .
7453 ( isset( $parts['pass'] ) ? ":{$parts['pass']}" : '' ) .
7454 ( isset( $parts['user'] ) ? '@' : '' ) .
7455 ( isset( $parts['host'] ) ? "{$parts['host']}" : '' ) .
7456 ( isset( $parts['port'] ) ? ":{$parts['port']}" : '' ) .
7457 ( isset( $parts['path'] ) ? "{$parts['path']}" : '' ) .
7458 ( isset( $parts['query'] ) ? "?{$parts['query']}" : '' ) .
7459 ( isset( $parts['fragment'] ) ? "#{$parts['fragment']}" : '' )
7460 );
7461 }
7462
7463
7464 /**
7465 * Helper function that prints option tags for a select element for all
7466 * roles the current user has permission to assign.
7467 *
7468 * @param string $selected_role Which role should be selected in the dropdown.
7469 * @param string $disable_input 'disabled' if select element should be disabled.
7470 * @param int $admin_mode WP_Plugin_Authorizer::NETWORK_CONTEXT if we are in that context.
7471 * @return void
7472 */
7473 protected function wp_dropdown_permitted_roles( $selected_role = 'subscriber', $disable_input = 'not disabled', $admin_mode = WP_Plugin_Authorizer::SINGLE_CONTEXT ) {
7474 $roles = get_editable_roles();
7475 $current_user = wp_get_current_user();
7476
7477 // If we're in network admin, also show any roles that might exist only on
7478 // specific sites in the network (themes can add their own roles).
7479 if ( WP_Plugin_Authorizer::NETWORK_CONTEXT === $admin_mode ) {
7480 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7481 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7482 foreach ( $sites as $site ) {
7483 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7484 switch_to_blog( $blog_id );
7485 $roles = array_merge( $roles, get_editable_roles() );
7486 restore_current_blog();
7487 }
7488 $unique_role_names = array();
7489 foreach ( $roles as $role_name => $role_info ) {
7490 if ( array_key_exists( $role_name, $unique_role_names ) ) {
7491 unset( $roles[ $role_name ] );
7492 } else {
7493 $unique_role_names[ $role_name ] = true;
7494 }
7495 }
7496 }
7497
7498 // If the currently selected role exists, but is not in the list of roles,
7499 // the current user is not permitted to assign it. Assume they can't edit
7500 // that user's role at all. Return only the one role for the dropdown list.
7501 if ( strlen( $selected_role ) > 0 && ! array_key_exists( $selected_role, $roles ) && ! is_null( get_role( $selected_role ) ) ) {
7502 return;
7503 }
7504
7505 // Print an option element for each permitted role.
7506 foreach ( $roles as $name => $role ) {
7507 $is_selected = $selected_role === $name;
7508
7509 // Don't let a user change their own role (but network admins always can).
7510 $is_disabled = $selected_role !== $name && 'disabled' === $disable_input && ! ( is_multisite() && current_user_can( 'manage_network' ) );
7511 ?>
7512 <option value="<?php echo esc_attr( $name ); ?>"<?php selected( $is_selected ); ?><?php disabled( $is_disabled ); ?>><?php echo esc_html( $role['name'] ); ?></option>
7513 <?php
7514 }
7515
7516 // Print default role (no role).
7517 $is_selected = strlen( $selected_role ) === 0 || ! array_key_exists( $selected_role, $roles );
7518 $is_disabled = strlen( $selected_role ) > 0 && 'disabled' === $disable_input && ! ( is_multisite() && current_user_can( 'manage_network' ) );
7519 ?>
7520 <option value=""<?php selected( $is_selected ); ?><?php disabled( $is_disabled ); ?>><?php esc_html_e( '&mdash; No role for this site &mdash;', 'authorizer' ); ?></option>
7521 <?php
7522
7523 }
7524
7525
7526 /**
7527 * Helper function to get a single user info array from one of the access
7528 * control lists (pending, approved, or blocked).
7529 *
7530 * @param string $email Email address to retrieve info for.
7531 * @param string $list List to get info from.
7532 * @return mixed false if not found, otherwise: array(
7533 * 'email' => '',
7534 * 'role' => '',
7535 * 'date_added' => '',
7536 * ['usermeta' => [''|array()]]
7537 * );
7538 */
7539 protected function get_user_info_from_list( $email, $list ) {
7540 foreach ( $list as $user_info ) {
7541 if ( 0 === strcasecmp( $user_info['email'], $email ) ) {
7542 return $user_info;
7543 }
7544 }
7545 return false;
7546 }
7547
7548 /**
7549 * Helper function to convert a string to lowercase. Prefers to use mb_strtolower,
7550 * but will fall back to strtolower if the former is not available.
7551 *
7552 * @param string $string String to convert to lowercase.
7553 * @return string Input in lowercase.
7554 */
7555 protected function lowercase( $string ) {
7556 return function_exists( 'mb_strtolower' ) ? mb_strtolower( $string ) : strtolower( $string );
7557 }
7558
7559
7560 /**
7561 * Helper function to convert seconds to human readable text.
7562 *
7563 * @see: http://csl.name/php-secs-to-human-text/
7564 *
7565 * @param int $secs Seconds to display as readable text.
7566 * @return string Readable version of number of seconds.
7567 */
7568 protected function seconds_as_sentence( $secs ) {
7569 $units = array(
7570 'week' => 3600 * 24 * 7,
7571 'day' => 3600 * 24,
7572 'hour' => 3600,
7573 'minute' => 60,
7574 'second' => 1,
7575 );
7576
7577 // Specifically handle zero.
7578 if ( 0 === intval( $secs ) ) {
7579 return '0 seconds';
7580 }
7581
7582 $s = '';
7583
7584 foreach ( $units as $name => $divisor ) {
7585 $quot = intval( $secs / $divisor );
7586 if ( $quot ) {
7587 $s .= "$quot $name";
7588 $s .= ( abs( $quot ) > 1 ? 's' : '' ) . ', ';
7589 $secs -= $quot * $divisor;
7590 }
7591 }
7592
7593 return substr( $s, 0, -2 );
7594 }
7595
7596 /**
7597 * Helper function to get all available usermeta keys as an array.
7598 *
7599 * @return array All usermeta keys for user.
7600 */
7601 protected function get_all_usermeta_keys() {
7602 global $wpdb;
7603 $usermeta_keys = $wpdb->get_col( "SELECT DISTINCT $wpdb->usermeta.meta_key FROM $wpdb->usermeta" );
7604 return $usermeta_keys;
7605 }
7606
7607
7608 /**
7609 * Load translated strings from *.mo files in /languages.
7610 *
7611 * Action: plugins_loaded
7612 */
7613 public function load_textdomain() {
7614 load_plugin_textdomain(
7615 'authorizer',
7616 false,
7617 plugin_basename( dirname( __FILE__ ) ) . '/languages'
7618 );
7619 }
7620
7621
7622 /**
7623 * Generate CAS authentication URL (wp-login.php URL with reauth=1 removed
7624 * and external=cas added).
7625 */
7626 private function modify_current_url_for_cas_login() {
7627 // Construct the URL of the current page (wp-login.php).
7628 $url = '';
7629 if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
7630 $url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] ) ) . esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
7631 }
7632
7633 // Parse the URL into its components.
7634 $parsed_url = wp_parse_url( $url );
7635
7636 // Fix up the querystring values (remove reauth, make sure external=cas).
7637 $querystring = array();
7638 if ( array_key_exists( 'query', $parsed_url ) ) {
7639 parse_str( $parsed_url['query'], $querystring );
7640 }
7641 unset( $querystring['reauth'] );
7642 $querystring['external'] = 'cas';
7643 $parsed_url['query'] = http_build_query( $querystring );
7644
7645 // Return the URL as a string.
7646 return $this->unparse_url( $parsed_url );
7647 }
7648
7649
7650 /**
7651 * Reconstruct a URL after it has been deconstructed with parse_url().
7652 *
7653 * @param array $parsed_url Keys from parse_url().
7654 * @return string URL constructed from the components in $parsed_url.
7655 */
7656 protected function unparse_url( $parsed_url = array() ) {
7657 $scheme = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : '';
7658 $host = isset( $parsed_url['host'] ) ? $parsed_url['host'] : '';
7659 $port = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : '';
7660 $user = isset( $parsed_url['user'] ) ? $parsed_url['user'] : '';
7661 $pass = isset( $parsed_url['pass'] ) ? ':' . $parsed_url['pass'] : '';
7662 $pass = $user || $pass ? "$pass@" : '';
7663 $path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
7664 $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : '';
7665 $fragment = isset( $parsed_url['fragment'] ) ? '#' . $parsed_url['fragment'] : '';
7666 return "$scheme$user$pass$host$port$path$query$fragment";
7667 }
7668
7669
7670 /**
7671 * Helper function to generate an HTML class name for an option (used in
7672 * Authorizer Settings in the Approved User list).
7673 *
7674 * @param string $suffix Unique part of class name.
7675 * @param boolean $is_multisite_user Whether the class name should indicate it's a multisite user.
7676 * @return string Class name, e.g., "auth-email auth-multisite-email".
7677 */
7678 private function create_class_name( $suffix = '', $is_multisite_user = false ) {
7679 return $is_multisite_user ? "auth-$suffix auth-multisite-$suffix" : "auth-$suffix";
7680 }
7681
7682
7683 /**
7684 * Plugin Update Routines.
7685 *
7686 * Action: plugins_loaded
7687 */
7688 public function auth_update_check() {
7689 // Get current version.
7690 $needs_updating = false;
7691 if ( is_multisite() ) {
7692 $auth_version = get_blog_option( $this->current_site_blog_id, 'auth_version' );
7693 } else {
7694 $auth_version = get_option( 'auth_version' );
7695 }
7696
7697 // Update: migrate user lists to own options (addresses concurrency
7698 // when saving plugin options, since user lists are changed often
7699 // and we don't want to overwrite changes to the lists when an
7700 // admin saves all of the plugin options.)
7701 // Note: Pending user list is changed whenever a new user tries to
7702 // log in; approved and blocked lists are changed whenever an admin
7703 // changes them from the multisite panel, the dashboard widget, or
7704 // the plugin options page.
7705 $update_if_older_than = 20140709;
7706 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7707 // Copy single site user lists to new options (if they exist).
7708 $auth_settings = get_option( 'auth_settings' );
7709 if ( is_array( $auth_settings ) && array_key_exists( 'access_users_pending', $auth_settings ) ) {
7710 update_option( 'auth_settings_access_users_pending', $auth_settings['access_users_pending'] );
7711 unset( $auth_settings['access_users_pending'] );
7712 update_option( 'auth_settings', $auth_settings );
7713 }
7714 if ( is_array( $auth_settings ) && array_key_exists( 'access_users_approved', $auth_settings ) ) {
7715 update_option( 'auth_settings_access_users_approved', $auth_settings['access_users_approved'] );
7716 unset( $auth_settings['access_users_approved'] );
7717 update_option( 'auth_settings', $auth_settings );
7718 }
7719 if ( is_array( $auth_settings ) && array_key_exists( 'access_users_blocked', $auth_settings ) ) {
7720 update_option( 'auth_settings_access_users_blocked', $auth_settings['access_users_blocked'] );
7721 unset( $auth_settings['access_users_blocked'] );
7722 update_option( 'auth_settings', $auth_settings );
7723 }
7724 // Copy multisite user lists to new options (if they exist).
7725 if ( is_multisite() ) {
7726 $auth_multisite_settings = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', array() );
7727 if ( is_array( $auth_multisite_settings ) && array_key_exists( 'access_users_pending', $auth_multisite_settings ) ) {
7728 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_pending', $auth_multisite_settings['access_users_pending'] );
7729 unset( $auth_multisite_settings['access_users_pending'] );
7730 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', $auth_multisite_settings );
7731 }
7732 if ( is_array( $auth_multisite_settings ) && array_key_exists( 'access_users_approved', $auth_multisite_settings ) ) {
7733 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings['access_users_approved'] );
7734 unset( $auth_multisite_settings['access_users_approved'] );
7735 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', $auth_multisite_settings );
7736 }
7737 if ( is_array( $auth_multisite_settings ) && array_key_exists( 'access_users_blocked', $auth_multisite_settings ) ) {
7738 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_blocked', $auth_multisite_settings['access_users_blocked'] );
7739 unset( $auth_multisite_settings['access_users_blocked'] );
7740 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', $auth_multisite_settings );
7741 }
7742 }
7743 // Update version to reflect this change has been made.
7744 $auth_version = $update_if_older_than;
7745 $needs_updating = true;
7746 }
7747
7748 // Update: Set default values for newly added options (forgot to do
7749 // this, so some users are getting debug log notices about undefined
7750 // indexes in $auth_settings).
7751 $update_if_older_than = 20160831;
7752 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7753 // Provide default values for any $auth_settings options that don't exist.
7754 if ( is_multisite() ) {
7755 // Get all blog ids.
7756 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7757 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7758 foreach ( $sites as $site ) {
7759 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7760 switch_to_blog( $blog_id );
7761 // Set meaningful defaults for other sites in the network.
7762 $this->set_default_options();
7763 // Switch back to original blog.
7764 restore_current_blog();
7765 }
7766 } else {
7767 // Set meaningful defaults for this site.
7768 $this->set_default_options();
7769 }
7770 // Update version to reflect this change has been made.
7771 $auth_version = $update_if_older_than;
7772 $needs_updating = true;
7773 }
7774
7775 // Update: Migrate LDAP passwords encrypted with mcrypt since mcrypt is
7776 // deprecated as of PHP 7.1. Use openssl library instead.
7777 $update_if_older_than = 20170510;
7778 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7779 if ( is_multisite() ) {
7780 // Reencrypt LDAP passwords in each site in the network.
7781 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7782 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7783 foreach ( $sites as $site ) {
7784 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7785 $auth_settings = get_blog_option( $blog_id, 'auth_settings', array() );
7786 if ( array_key_exists( 'ldap_password', $auth_settings ) && strlen( $auth_settings['ldap_password'] ) > 0 ) {
7787 $plaintext_ldap_password = $this->decrypt( $auth_settings['ldap_password'], 'mcrypt' );
7788 $auth_settings['ldap_password'] = $this->encrypt( $plaintext_ldap_password );
7789 update_blog_option( $blog_id, 'auth_settings', $auth_settings );
7790 }
7791 }
7792 } else {
7793 // Reencrypt LDAP password on this single-site install.
7794 $auth_settings = get_option( 'auth_settings', array() );
7795 if ( array_key_exists( 'ldap_password', $auth_settings ) && strlen( $auth_settings['ldap_password'] ) > 0 ) {
7796 $plaintext_ldap_password = $this->decrypt( $auth_settings['ldap_password'], 'mcrypt' );
7797 $auth_settings['ldap_password'] = $this->encrypt( $plaintext_ldap_password );
7798 update_option( 'auth_settings', $auth_settings );
7799 }
7800 }
7801 // Update version to reflect this change has been made.
7802 $auth_version = $update_if_older_than;
7803 $needs_updating = true;
7804 }
7805
7806 // Update: Migrate LDAP passwords encrypted with mcrypt since mcrypt is
7807 // deprecated as of PHP 7.1. Use openssl library instead.
7808 // Note: Forgot to update the auth_multisite_settings ldap password! Do it here.
7809 $update_if_older_than = 20170511;
7810 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7811 if ( is_multisite() ) {
7812 // Reencrypt LDAP password in network (multisite) options.
7813 $auth_multisite_settings = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', array() );
7814 if ( array_key_exists( 'ldap_password', $auth_multisite_settings ) && strlen( $auth_multisite_settings['ldap_password'] ) > 0 ) {
7815 $plaintext_ldap_password = $this->decrypt( $auth_multisite_settings['ldap_password'], 'mcrypt' );
7816 $auth_multisite_settings['ldap_password'] = $this->encrypt( $plaintext_ldap_password );
7817 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings', $auth_multisite_settings );
7818 }
7819 }
7820 // Update version to reflect this change has been made.
7821 $auth_version = $update_if_older_than;
7822 $needs_updating = true;
7823 }
7824
7825 // Update: Remove duplicates from approved list caused by authorizer_automatically_approve_login
7826 // filter not respecting users who are already in the approved list
7827 // (causing them to get re-added each time they logged in).
7828 $update_if_older_than = 20170711;
7829 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7830 // Remove duplicates from approved user lists.
7831 if ( is_multisite() ) {
7832 // Remove duplicates from each site in the multisite.
7833 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7834 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7835 foreach ( $sites as $site ) {
7836 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7837 $auth_settings_access_users_approved = get_blog_option( $blog_id, 'auth_settings_access_users_approved', array() );
7838 if ( is_array( $auth_settings_access_users_approved ) ) {
7839 $should_update = false;
7840 $distinct_emails = array();
7841 foreach ( $auth_settings_access_users_approved as $key => $user ) {
7842 if ( in_array( $user['email'], $distinct_emails, true ) ) {
7843 $should_update = true;
7844 unset( $auth_settings_access_users_approved[ $key ] );
7845 } else {
7846 $distinct_emails[] = $user['email'];
7847 }
7848 }
7849 if ( $should_update ) {
7850 update_blog_option( $blog_id, 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
7851 }
7852 }
7853 }
7854 // Remove duplicates from multisite approved user list.
7855 $auth_multisite_settings_access_users_approved = get_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', array() );
7856 if ( is_array( $auth_multisite_settings_access_users_approved ) ) {
7857 $should_update = false;
7858 $distinct_emails = array();
7859 foreach ( $auth_multisite_settings_access_users_approved as $key => $user ) {
7860 if ( in_array( $user['email'], $distinct_emails, true ) ) {
7861 $should_update = true;
7862 unset( $auth_multisite_settings_access_users_approved[ $key ] );
7863 } else {
7864 $distinct_emails[] = $user['email'];
7865 }
7866 }
7867 if ( $should_update ) {
7868 update_blog_option( $this->current_site_blog_id, 'auth_multisite_settings_access_users_approved', $auth_multisite_settings_access_users_approved );
7869 }
7870 }
7871 } else {
7872 // Remove duplicates from single site approved user list.
7873 $auth_settings_access_users_approved = get_option( 'auth_settings_access_users_approved' );
7874 if ( is_array( $auth_settings_access_users_approved ) ) {
7875 $should_update = false;
7876 $distinct_emails = array();
7877 foreach ( $auth_settings_access_users_approved as $key => $user ) {
7878 if ( in_array( $user['email'], $distinct_emails, true ) ) {
7879 $should_update = true;
7880 unset( $auth_settings_access_users_approved[ $key ] );
7881 } else {
7882 $distinct_emails[] = $user['email'];
7883 }
7884 }
7885 if ( $should_update ) {
7886 update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved );
7887 }
7888 }
7889 }
7890 // Update version to reflect this change has been made.
7891 $auth_version = $update_if_older_than;
7892 $needs_updating = true;
7893 }
7894
7895 // Update: Set default value for newly added option advanced_widget_enabled.
7896 $update_if_older_than = 20171023;
7897 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7898 // Provide default values for any $auth_settings options that don't exist.
7899 if ( is_multisite() ) {
7900 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7901 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7902 foreach ( $sites as $site ) {
7903 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7904 switch_to_blog( $blog_id );
7905 $this->set_default_options();
7906 restore_current_blog();
7907 }
7908 } else {
7909 $this->set_default_options();
7910 }
7911 // Update version to reflect this change has been made.
7912 $auth_version = $update_if_older_than;
7913 $needs_updating = true;
7914 }
7915
7916 // Update: Set default value for newly added option advanced_users_per_page.
7917 $update_if_older_than = 20171215;
7918 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7919 // Provide default values for any $auth_settings options that don't exist.
7920 if ( is_multisite() ) {
7921 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7922 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7923 foreach ( $sites as $site ) {
7924 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7925 switch_to_blog( $blog_id );
7926 $this->set_default_options();
7927 restore_current_blog();
7928 }
7929 } else {
7930 $this->set_default_options();
7931 }
7932 // Update version to reflect this change has been made.
7933 $auth_version = $update_if_older_than;
7934 $needs_updating = true;
7935 }
7936
7937 // Update: Set default value for newly added options advanced_users_sort_by and advanced_users_sort_order.
7938 $update_if_older_than = 20171219;
7939 if ( false === $auth_version || intval( $auth_version ) < $update_if_older_than ) {
7940 // Provide default values for any $auth_settings options that don't exist.
7941 if ( is_multisite() ) {
7942 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7943 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7944 foreach ( $sites as $site ) {
7945 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7946 switch_to_blog( $blog_id );
7947 $this->set_default_options();
7948 restore_current_blog();
7949 }
7950 } else {
7951 $this->set_default_options();
7952 }
7953 // Update version to reflect this change has been made.
7954 $auth_version = $update_if_older_than;
7955 $needs_updating = true;
7956 }
7957
7958 /*
7959 // Update: TEMPLATE
7960 $update_if_older_than = YYYYMMDD;
7961 if ( $auth_version === false || intval( $auth_version ) < $update_if_older_than ) {
7962 UPDATE CODE HERE
7963 // Update version to reflect this change has been made.
7964 $auth_version = $update_if_older_than;
7965 $needs_updating = true;
7966 }
7967 */
7968
7969 // Save new version number if we performed any updates.
7970 if ( $needs_updating ) {
7971 if ( is_multisite() ) {
7972 // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound
7973 $sites = function_exists( 'get_sites' ) ? get_sites() : wp_get_sites( array( 'limit' => PHP_INT_MAX ) );
7974 foreach ( $sites as $site ) {
7975 $blog_id = function_exists( 'get_sites' ) ? $site->blog_id : $site['blog_id'];
7976 update_blog_option( $blog_id, 'auth_version', $auth_version );
7977 }
7978 } else {
7979 update_option( 'auth_version', $auth_version );
7980 }
7981 }
7982 }
7983
7984 }
7985 }
7986
7987 // Instantiate the plugin class.
7988 $wp_plugin_authorizer = new WP_Plugin_Authorizer();
7989