PluginProbe
Authorizer / 2.8.7
Authorizer v2.8.7
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.7, at authorizer.php

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