PluginProbe
Authorizer / 2.8.3
Authorizer v2.8.3
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.3, at authorizer.php

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