PluginProbe
Authorizer / 2.8.6
Authorizer v2.8.6
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.6, at authorizer.php

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