| @@ -14,9 +14,9 @@ | ||
| 14 | 14 | |
| 15 | 15 | /** |
| 16 | 16 | * Implements the authorization (roles and permissions) features of the plugin. |
| 17 | 17 | */ |
| 18 | -class Authorization extends Static_Instance { | |
| 18 | +class Authorization extends Singleton { | |
| 19 | 19 | |
| 20 | 20 | /** |
| 21 | 21 | * This function will fail with a wp_die() message to the user if they |
| 22 | 22 | * don't have access. |
| @@ -23,9 +23,10 @@ | ||
| 23 | 23 | * |
| 24 | 24 | * @param WP_User $user User to check. |
| 25 | 25 | * @param array $user_emails Array of user's plaintext emails (in case current user doesn't have a WP account). |
| 26 | 26 | * @param array $user_data Array of keys for email, username, first_name, last_name, |
| 27 | - * authenticated_by, google_attributes, cas_attributes, ldap_attributes. | |
| 27 | + * authenticated_by, google_attributes, cas_attributes, ldap_attributes, | |
| 28 | + * oauth2_attributes. | |
| 28 | 29 | * @return WP_Error|WP_User |
| 29 | 30 | * WP_Error if there was an error on user creation / adding user to blog. |
| 30 | 31 | * WP_Error / wp_die() if user does not have access. |
| 31 | 32 | * WP_User if user has access. |
| @@ -45,8 +46,40 @@ | ||
| 45 | 46 | $auth_settings_access_users_approved_multi |
| 46 | 47 | ) |
| 47 | 48 | ); |
| 48 | 49 | |
| 50 | + // Detect whether this user's first and last name should be updated below | |
| 51 | + // (if the external CAS/LDAP service provides a different value, the option | |
| 52 | + // is set to update it, and it's empty if the option to only set it if empty | |
| 53 | + // is enabled). | |
| 54 | + $should_update_first_name = | |
| 55 | + $user && ! empty( $user_data['first_name'] ) && $user_data['first_name'] !== $user->first_name && | |
| 56 | + ( | |
| 57 | + ( | |
| 58 | + ! empty( $user_data['authenticated_by'] ) && 'cas' === $user_data['authenticated_by'] && | |
| 59 | + ! empty( $auth_settings['cas_attr_update_on_login'] ) && | |
| 60 | + ( '1' === $auth_settings['cas_attr_update_on_login'] || ( 'update-if-empty' === $auth_settings['cas_attr_update_on_login'] && empty( $user->first_name ) ) ) | |
| 61 | + ) || ( | |
| 62 | + ! empty( $user_data['authenticated_by'] ) && 'ldap' === $user_data['authenticated_by'] && | |
| 63 | + ! empty( $auth_settings['ldap_attr_update_on_login'] ) && | |
| 64 | + ( '1' === $auth_settings['ldap_attr_update_on_login'] || ( 'update-if-empty' === $auth_settings['ldap_attr_update_on_login'] && empty( $user->first_name ) ) ) | |
| 65 | + ) | |
| 66 | + ); | |
| 67 | + | |
| 68 | + $should_update_last_name = | |
| 69 | + $user && ! empty( $user_data['last_name'] ) && $user_data['last_name'] !== $user->last_name && | |
| 70 | + ( | |
| 71 | + ( | |
| 72 | + ! empty( $user_data['authenticated_by'] ) && 'cas' === $user_data['authenticated_by'] && | |
| 73 | + ! empty( $auth_settings['cas_attr_update_on_login'] ) && | |
| 74 | + ( '1' === $auth_settings['cas_attr_update_on_login'] || ( 'update-if-empty' === $auth_settings['cas_attr_update_on_login'] && empty( $user->last_name ) ) ) | |
| 75 | + ) || ( | |
| 76 | + ! empty( $user_data['authenticated_by'] ) && 'ldap' === $user_data['authenticated_by'] && | |
| 77 | + ! empty( $auth_settings['ldap_attr_update_on_login'] ) && | |
| 78 | + ( '1' === $auth_settings['ldap_attr_update_on_login'] || ( 'update-if-empty' === $auth_settings['ldap_attr_update_on_login'] && empty( $user->last_name ) ) ) | |
| 79 | + ) | |
| 80 | + ); | |
| 81 | + | |
| 49 | 82 | /** |
| 50 | 83 | * Filter whether to block the currently logging in user based on any of |
| 51 | 84 | * their user attributes. |
| 52 | 85 | * |
| @@ -70,9 +103,9 @@ | ||
| 70 | 103 | array_push( |
| 71 | 104 | $auth_settings_access_users_blocked, |
| 72 | 105 | array( |
| 73 | 106 | 'email' => Helper::lowercase( $user_email ), |
| 74 | - 'date_added' => date( 'M Y' ), | |
| 107 | + 'date_added' => wp_date( 'M Y' ), | |
| 75 | 108 | ) |
| 76 | 109 | ); |
| 77 | 110 | update_option( 'auth_settings_access_users_blocked', $auth_settings_access_users_blocked ); |
| 78 | 111 | } |
| @@ -127,8 +160,22 @@ | ||
| 127 | 160 | * @param array $user_data User data returned from external service. |
| 128 | 161 | */ |
| 129 | 162 | $automatically_approve_login = apply_filters( 'authorizer_automatically_approve_login', false, $user_data ); |
| 130 | 163 | |
| 164 | + // If this externally-authenticated user is an existing administrator (admin | |
| 165 | + // in single site mode, or super admin in network mode), and isn't blocked, | |
| 166 | + // let them in. Update their first/last name if needed (CAS/LDAP). | |
| 167 | + if ( $user && is_super_admin( $user->ID ) ) { | |
| 168 | + if ( $should_update_first_name ) { | |
| 169 | + update_user_meta( $user->ID, 'first_name', $user_data['first_name'] ); | |
| 170 | + } | |
| 171 | + if ( $should_update_last_name ) { | |
| 172 | + update_user_meta( $user->ID, 'last_name', $user_data['last_name'] ); | |
| 173 | + } | |
| 174 | + | |
| 175 | + return $user; | |
| 176 | + } | |
| 177 | + | |
| 131 | 178 | // Iterate through each of the email addresses provided by the external |
| 132 | 179 | // service and determine if any of them have access. |
| 133 | 180 | $last_email = end( $user_emails ); |
| 134 | 181 | reset( $user_emails ); |
| @@ -134,15 +181,8 @@ | ||
| 134 | 181 | reset( $user_emails ); |
| 135 | 182 | foreach ( $user_emails as $user_email ) { |
| 136 | 183 | $is_newly_approved_user = false; |
| 137 | 184 | |
| 138 | - // If this externally authenticated user is an existing administrator | |
| 139 | - // (administrator in single site mode, or super admin in network mode), | |
| 140 | - // and is not in the blocked list, let them in. | |
| 141 | - if ( $user && is_super_admin( $user->ID ) ) { | |
| 142 | - return $user; | |
| 143 | - } | |
| 144 | - | |
| 145 | 185 | // If this externally authenticated user isn't in the approved list |
| 146 | 186 | // and login access is set to "All authenticated users," or if they were |
| 147 | 187 | // automatically approved in the "authorizer_approve_login" filter |
| 148 | 188 | // above, then add them to the approved list (they'll get an account |
| @@ -168,9 +208,9 @@ | ||
| 168 | 208 | // Add this user to the approved list. |
| 169 | 209 | $approved_user = array( |
| 170 | 210 | 'email' => Helper::lowercase( $user_email ), |
| 171 | 211 | 'role' => $approved_role, |
| 172 | - 'date_added' => date( 'Y-m-d H:i:s' ), | |
| 212 | + 'date_added' => wp_date( 'Y-m-d H:i:s' ), | |
| 173 | 213 | ); |
| 174 | 214 | array_push( $auth_settings_access_users_approved, $approved_user ); |
| 175 | 215 | array_push( $auth_settings_access_users_approved_single, $approved_user ); |
| 176 | 216 | update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved_single ); |
| @@ -181,13 +221,37 @@ | ||
| 181 | 221 | // if necessary). |
| 182 | 222 | if ( $is_newly_approved_user || $this->is_email_in_list( $user_email, 'approved' ) ) { |
| 183 | 223 | $user_info = $is_newly_approved_user ? $approved_user : Helper::get_user_info_from_list( $user_email, $auth_settings_access_users_approved ); |
| 184 | 224 | |
| 185 | - // If this user's role was modified above (in the | |
| 186 | - // authorizer_custom_role filter), use that value instead of | |
| 187 | - // whatever is specified in the approved list. | |
| 188 | - if ( $default_role !== $approved_role ) { | |
| 225 | + // If this user's role was modified above (in the authorizer_custom_role | |
| 226 | + // filter), update the role in the approved list and use that role | |
| 227 | + // (i.e., if the roles are out of sync, use the authorizer_custom_role | |
| 228 | + // value instead of the role in the approved list). | |
| 229 | + if ( has_filter( 'authorizer_custom_role' ) ) { | |
| 189 | 230 | $user_info['role'] = $approved_role; |
| 231 | + | |
| 232 | + // Find the user in either the single site or multisite approved list | |
| 233 | + // and update their role there if different. | |
| 234 | + foreach ( $auth_settings_access_users_approved_single as $index => $auth_settings_access_user_approved_single ) { | |
| 235 | + if ( $user_info['email'] === $auth_settings_access_user_approved_single['email'] ) { | |
| 236 | + if ( $auth_settings_access_users_approved_single[ $index ]['role'] !== $approved_role ) { | |
| 237 | + $auth_settings_access_users_approved_single[ $index ]['role'] = $approved_role; | |
| 238 | + update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved_single ); | |
| 239 | + } | |
| 240 | + break; | |
| 241 | + } | |
| 242 | + } | |
| 243 | + if ( is_multisite() ) { | |
| 244 | + foreach ( $auth_settings_access_users_approved_multi as $index => $auth_settings_access_user_approved_multi ) { | |
| 245 | + if ( $user_info['email'] === $auth_settings_access_user_approved_multi['email'] ) { | |
| 246 | + if ( $auth_settings_access_users_approved_multi[ $index ]['role'] !== $approved_role ) { | |
| 247 | + $auth_settings_access_users_approved_multi[ $index ]['role'] = $approved_role; | |
| 248 | + update_blog_option( get_main_site_id( get_main_network_id() ), 'auth_multisite_settings_access_users_approved', $auth_settings_access_users_approved_multi ); | |
| 249 | + } | |
| 250 | + break; | |
| 251 | + } | |
| 252 | + } | |
| 253 | + } | |
| 190 | 254 | } |
| 191 | 255 | |
| 192 | 256 | // If the approved external user does not have a WordPress account, create it. |
| 193 | 257 | if ( ! $user ) { |
| @@ -210,9 +274,9 @@ | ||
| 210 | 274 | 'user_pass' => wp_generate_password(), // random password. |
| 211 | 275 | 'first_name' => array_key_exists( 'first_name', $user_data ) ? $user_data['first_name'] : '', |
| 212 | 276 | 'last_name' => array_key_exists( 'last_name', $user_data ) ? $user_data['last_name'] : '', |
| 213 | 277 | 'user_email' => Helper::lowercase( $user_info['email'] ), |
| 214 | - 'user_registered' => date( 'Y-m-d H:i:s' ), | |
| 278 | + 'user_registered' => wp_date( 'Y-m-d H:i:s' ), | |
| 215 | 279 | 'role' => $user_info['role'], |
| 216 | 280 | ) |
| 217 | 281 | ); |
| 218 | 282 | |
| @@ -320,43 +384,14 @@ | ||
| 320 | 384 | } |
| 321 | 385 | } |
| 322 | 386 | } |
| 323 | 387 | } else { |
| 324 | - // Update first/last names of WordPress user from external | |
| 325 | - // service if that option is set. | |
| 326 | - 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'] ) ) ) { | |
| 327 | - if ( array_key_exists( 'first_name', $user_data ) && 0 < strlen( $user_data['first_name'] ) ) { | |
| 328 | - wp_update_user( | |
| 329 | - array( | |
| 330 | - 'ID' => $user->ID, | |
| 331 | - 'first_name' => $user_data['first_name'], | |
| 332 | - ) | |
| 333 | - ); | |
| 334 | - } | |
| 335 | - if ( array_key_exists( 'last_name', $user_data ) && strlen( $user_data['last_name'] ) > 0 ) { | |
| 336 | - wp_update_user( | |
| 337 | - array( | |
| 338 | - 'ID' => $user->ID, | |
| 339 | - 'last_name' => $user_data['last_name'], | |
| 340 | - ) | |
| 341 | - ); | |
| 342 | - } | |
| 388 | + // Update first/last name from CAS/LDAP if needed. | |
| 389 | + if ( $should_update_first_name ) { | |
| 390 | + update_user_meta( $user->ID, 'first_name', $user_data['first_name'] ); | |
| 343 | 391 | } |
| 344 | - | |
| 345 | - // Update this user's role if it was modified in the | |
| 346 | - // authorizer_custom_role filter. | |
| 347 | - if ( $default_role !== $approved_role ) { | |
| 348 | - // Update user's role in WordPress. | |
| 349 | - $user->set_role( $approved_role ); | |
| 350 | - | |
| 351 | - // Update user's role in this site's approved list and save. | |
| 352 | - foreach ( $auth_settings_access_users_approved_single as $key => $existing_user ) { | |
| 353 | - if ( 0 === strcasecmp( $user->user_email, $existing_user['email'] ) ) { | |
| 354 | - $auth_settings_access_users_approved_single[ $key ]['role'] = $approved_role; | |
| 355 | - break; | |
| 356 | - } | |
| 357 | - } | |
| 358 | - update_option( 'auth_settings_access_users_approved', $auth_settings_access_users_approved_single ); | |
| 392 | + if ( $should_update_last_name ) { | |
| 393 | + update_user_meta( $user->ID, 'last_name', $user_data['last_name'] ); | |
| 359 | 394 | } |
| 360 | 395 | } |
| 361 | 396 | |
| 362 | 397 | // If this is multisite, add new user to current blog. |
| @@ -420,8 +455,15 @@ | ||
| 420 | 455 | } |
| 421 | 456 | } |
| 422 | 457 | } |
| 423 | 458 | |
| 459 | + // Fetch the external service this user authenticated with, and append | |
| 460 | + // it to the logout URL below (so we can fire custom logout routines in | |
| 461 | + // custom_logout() based on their external service. This is necessary | |
| 462 | + // because a pending user does not have a WP_User, and thus no | |
| 463 | + // "authenticated_by" usermeta that is normally used to do this. | |
| 464 | + $external_param = isset( $user_data['authenticated_by'] ) ? '&external=' . $user_data['authenticated_by'] : ''; | |
| 465 | + | |
| 424 | 466 | // Notify user about pending status and return without authenticating them. |
| 425 | 467 | // phpcs:ignore WordPress.Security.NonceVerification |
| 426 | 468 | $redirect_to = ! empty( $_REQUEST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_REQUEST['redirect_to'] ) ) : home_url(); |
| 427 | 469 | $page_title = get_bloginfo( 'name' ) . ' - Access Pending'; |
| @@ -428,9 +470,9 @@ | ||
| 428 | 470 | $error_message = |
| 429 | 471 | apply_filters( 'the_content', $auth_settings['access_pending_redirect_to_message'] ) . |
| 430 | 472 | '<hr />' . |
| 431 | 473 | '<p style="text-align: center;">' . |
| 432 | - '<a class="button" href="' . wp_logout_url( $redirect_to ) . '">' . | |
| 474 | + '<a class="button" href="' . wp_logout_url( $redirect_to ) . $external_param . '">' . | |
| 433 | 475 | __( 'Back', 'authorizer' ) . |
| 434 | 476 | '</a></p>'; |
| 435 | 477 | update_option( 'auth_settings_advanced_login_error', $error_message ); |
| 436 | 478 | wp_die( wp_kses( $error_message, Helper::$allowed_html ), esc_html( $page_title ) ); |
| @@ -438,9 +480,8 @@ | ||
| 438 | 480 | } |
| 439 | 481 | |
| 440 | 482 | // Sanity check: if we made it here without returning, something has gone wrong. |
| 441 | 483 | return new \WP_Error( 'invalid_login', __( 'Invalid login attempted.', 'authorizer' ) ); |
| 442 | - | |
| 443 | 484 | } |
| 444 | 485 | |
| 445 | 486 | |
| 446 | 487 | /** |
| @@ -447,9 +488,9 @@ | ||
| 447 | 488 | * Restrict access to WordPress site based on settings (everyone, logged_in_users). |
| 448 | 489 | * |
| 449 | 490 | * Action: parse_request |
| 450 | 491 | * |
| 451 | - * @param array $wp WordPress object. | |
| 492 | + * @param WP $wp WordPress object. | |
| 452 | 493 | * @return WP|void WP object when passing through to WordPress authentication, or void. |
| 453 | 494 | */ |
| 454 | 495 | public function restrict_access( $wp ) { |
| 455 | 496 | // Grab plugin settings. |
| @@ -468,15 +509,11 @@ | ||
| 468 | 509 | // Allow access if option is set to 'everyone'. |
| 469 | 510 | ( 'everyone' === $auth_settings['access_who_can_view'] ) || |
| 470 | 511 | // Allow access to approved external users and logged in users if option is set to 'logged_in_users'. |
| 471 | 512 | ( 'logged_in_users' === $auth_settings['access_who_can_view'] && Helper::is_user_logged_in_and_blog_user() && $this->is_email_in_list( $current_user->user_email, 'approved' ) ) || |
| 472 | - // Allow access for requests to /wp-json/oauth1 so oauth clients can authenticate to use the REST API. | |
| 473 | - ( property_exists( $wp, 'matched_query' ) && stripos( $wp->matched_query, 'rest_oauth1=' ) === 0 ) || | |
| 474 | - // Allow access for non-GET requests to /wp-json/*, since REST API authentication already covers them. | |
| 475 | - ( property_exists( $wp, 'matched_query' ) && 0 === stripos( $wp->matched_query, 'rest_route=' ) && isset( $_SERVER['REQUEST_METHOD'] ) && 'GET' !== $_SERVER['REQUEST_METHOD'] ) || | |
| 476 | - // Allow access for GET requests to /wp-json/ (root), since REST API discovery calls rely on this. | |
| 477 | - ( property_exists( $wp, 'matched_query' ) && 'rest_route=/' === $wp->matched_query ) | |
| 478 | - // Note that GET requests to a rest endpoint will be restricted by authorizer. In that case, error messages will be returned as JSON. | |
| 513 | + // Allow REST API requests (access is determined later in the rest_authentication_errors hook). | |
| 514 | + // See: https://github.com/WordPress/WordPress/blob/8e41746cb11271d063608a63e3f6091a8685e677/wp-includes/rest-api.php#L131-L133. | |
| 515 | + ( ! empty( $GLOBALS['wp']->query_vars['rest_route'] ) ) | |
| 479 | 516 | ); |
| 480 | 517 | |
| 481 | 518 | /** |
| 482 | 519 | * Developers can use the `authorizer_has_access` filter to override |
| @@ -505,9 +542,9 @@ | ||
| 505 | 542 | return $wp; |
| 506 | 543 | } |
| 507 | 544 | |
| 508 | 545 | // Allow HEAD requests to the root (usually discovery from a REST client). |
| 509 | - if ( 'HEAD' === $_SERVER['REQUEST_METHOD'] && empty( $wp->request ) && empty( $wp->matched_query ) ) { | |
| 546 | + if ( ! empty( $_SERVER['REQUEST_METHOD'] ) && 'HEAD' === $_SERVER['REQUEST_METHOD'] && empty( $wp->request ) && empty( $wp->matched_query ) ) { | |
| 510 | 547 | return $wp; |
| 511 | 548 | } |
| 512 | 549 | |
| 513 | 550 | /* We've determined that the current user doesn't have access, so we deal with them now. */ |
| @@ -568,9 +605,10 @@ | ||
| 568 | 605 | |
| 569 | 606 | // Check to see if the requested category is public. If so, show it. |
| 570 | 607 | $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'] : ''; |
| 571 | 608 | if ( $current_category_name ) { |
| 572 | - $current_category_name = end( explode( '/', $current_category_name ) ); | |
| 609 | + $current_category_name_pieces = explode( '/', $current_category_name ); | |
| 610 | + $current_category_name = end( $current_category_name_pieces ); | |
| 573 | 611 | if ( in_array( 'cat_' . $current_category_name, $auth_settings['access_public_pages'], true ) ) { |
| 574 | 612 | if ( 'no_warning' === $auth_settings['access_public_warning'] ) { |
| 575 | 613 | update_option( 'auth_settings_advanced_public_notice', false ); |
| 576 | 614 | } else { |
| @@ -616,20 +654,123 @@ | ||
| 616 | 654 | // Sanity check: we should never get here. |
| 617 | 655 | wp_die( '<p>Access denied.</p>', 'Site Access Restricted' ); |
| 618 | 656 | } |
| 619 | 657 | |
| 658 | + /** | |
| 659 | + * If we're showing search results or a post listing (home or archive page) to | |
| 660 | + * an anonymous user, and Authorizer is configured to only allow logged in | |
| 661 | + * users to see the site, filter the query to only posts marked public. | |
| 662 | + * | |
| 663 | + * Action: pre_get_posts | |
| 664 | + * | |
| 665 | + * @param WP_Query $query The WP_Query instance (passed by reference). | |
| 666 | + * @return void | |
| 667 | + */ | |
| 668 | + public function remove_private_pages_from_search_and_archives( $query ) { | |
| 669 | + // It's possible for pre_get_posts to fire before wp-includes/pluggable.php | |
| 670 | + // is loaded, so verify before using the is_user_logged_in() function. | |
| 671 | + if ( ! function_exists( 'is_user_logged_in' ) ) { | |
| 672 | + require ABSPATH . WPINC . '/pluggable.php'; | |
| 673 | + } | |
| 620 | 674 | |
| 675 | + // Fix for edge case when viewing admin pages in Pressbooks (Undefined | |
| 676 | + // constant "SECURE_AUTH_COOKIE"). | |
| 677 | + if ( ! defined( 'SECURE_AUTH_COOKIE' ) ) { | |
| 678 | + wp_cookie_constants(); | |
| 679 | + } | |
| 680 | + | |
| 681 | + // Do nothing if user is logged in, this isn't the main query, or we're not | |
| 682 | + // showing search results, home page, or an archive page. | |
| 683 | + if ( | |
| 684 | + is_user_logged_in() || ! $query->is_main_query() || | |
| 685 | + ! ( $query->is_search() || $query->is_home() || $query->is_archive() ) | |
| 686 | + ) { | |
| 687 | + return; | |
| 688 | + } | |
| 689 | + | |
| 690 | + $options = Options::get_instance(); | |
| 691 | + $who_can_view = $options->get( 'access_who_can_view' ); | |
| 692 | + $public_pages = $options->get( 'access_public_pages' ); | |
| 693 | + $public_pages = is_array( $public_pages ) ? $public_pages : array(); | |
| 694 | + | |
| 695 | + // Do nothing if this site isn't restricted to logged in users only. | |
| 696 | + if ( 'logged_in_users' !== $who_can_view ) { | |
| 697 | + return; | |
| 698 | + } | |
| 699 | + | |
| 700 | + // Check for special public types (home, 404, categories). | |
| 701 | + $public_category_ids = array(); | |
| 702 | + foreach ( $public_pages as $index => $public_page ) { | |
| 703 | + if ( 'home' === $public_page || 'auth_public_404' === $public_page ) { | |
| 704 | + unset( $public_pages[ $index ] ); | |
| 705 | + } elseif ( 'cat_' === substr( $public_page, 0, 4 ) ) { | |
| 706 | + $public_category_name = substr( $public_page, 4 ); | |
| 707 | + unset( $public_pages[ $index ] ); | |
| 708 | + $public_category_ids[] = get_cat_ID( $public_category_name ); | |
| 709 | + } | |
| 710 | + } | |
| 711 | + if ( ! empty( $public_category_ids ) ) { | |
| 712 | + $pages_in_public_categories = get_posts( array( | |
| 713 | + 'posts_per_page' => -1, | |
| 714 | + 'fields' => 'ids', | |
| 715 | + 'category__in' => $public_category_ids, | |
| 716 | + ) ); | |
| 717 | + $public_pages = array_merge( $public_pages, $pages_in_public_categories ); | |
| 718 | + } | |
| 719 | + | |
| 720 | + $query->set( 'post__in', $public_pages ); | |
| 721 | + } | |
| 722 | + | |
| 621 | 723 | /** |
| 724 | + * Prevent REST API access if user isn't authenticated and "only logged in | |
| 725 | + * users can see the site" is enabled. | |
| 726 | + * | |
| 727 | + * Filter: rest_authentication_errors | |
| 728 | + * | |
| 729 | + * @param WP_Error|null|true $errors WP_Error if authentication error, null if authentication method wasn't used, true if authentication succeeded. | |
| 730 | + * @return WP_Error|null|true WP_Error if not logged in and "only logged in users can see the site" is enabled. | |
| 731 | + */ | |
| 732 | + public function restrict_rest_api( $errors ) { | |
| 733 | + // If there is already an error, just return that. | |
| 734 | + if ( ! empty( $errors ) ) { | |
| 735 | + return $errors; | |
| 736 | + } | |
| 737 | + | |
| 738 | + // If user isn't logged in, check for "only logged in users can see the site". | |
| 739 | + if ( ! is_user_logged_in() ) { | |
| 740 | + // Grab plugin settings. | |
| 741 | + $options = Options::get_instance(); | |
| 742 | + $auth_settings = $options->get_all( Helper::SINGLE_CONTEXT, 'allow override' ); | |
| 743 | + | |
| 744 | + if ( | |
| 745 | + 'logged_in_users' === $auth_settings['access_who_can_view'] && | |
| 746 | + false === apply_filters( 'authorizer_has_access', false, $GLOBALS['wp'] ) | |
| 747 | + ) { | |
| 748 | + return new \WP_Error( | |
| 749 | + 'rest_cannot_view', | |
| 750 | + wp_strip_all_tags( $auth_settings['access_redirect_to_message'] ), | |
| 751 | + array( | |
| 752 | + 'status' => 401, | |
| 753 | + ) | |
| 754 | + ); | |
| 755 | + } | |
| 756 | + } | |
| 757 | + | |
| 758 | + return $errors; | |
| 759 | + } | |
| 760 | + | |
| 761 | + | |
| 762 | + /** | |
| 622 | 763 | * Helper function to determine whether a given email is in one of |
| 623 | 764 | * the lists (pending, approved, blocked). Defaults to the list of |
| 624 | 765 | * approved users. |
| 625 | 766 | * |
| 626 | 767 | * @param string $email Email to check existent of. |
| 627 | - * @param string $list List to look for email in. | |
| 768 | + * @param string $user_list List to look for email in. | |
| 628 | 769 | * @param string $multisite_mode Admin context. |
| 629 | 770 | * @return boolean Whether email was found. |
| 630 | 771 | */ |
| 631 | - public function is_email_in_list( $email = '', $list = 'approved', $multisite_mode = 'single' ) { | |
| 772 | + public function is_email_in_list( $email = '', $user_list = 'approved', $multisite_mode = 'single' ) { | |
| 632 | 773 | if ( empty( $email ) ) { |
| 633 | 774 | return false; |
| 634 | 775 | } |
| 635 | 776 | |
| @@ -634,9 +775,9 @@ | ||
| 634 | 775 | } |
| 635 | 776 | |
| 636 | 777 | $options = Options::get_instance(); |
| 637 | 778 | |
| 638 | - switch ( $list ) { | |
| 779 | + switch ( $user_list ) { | |
| 639 | 780 | case 'pending': |
| 640 | 781 | $auth_settings_access_users_pending = $options->get( 'access_users_pending', Helper::SINGLE_CONTEXT ); |
| 641 | 782 | return Helper::in_multi_array( $email, $auth_settings_access_users_pending ); |
| 642 | 783 | case 'blocked': |
| @@ -665,10 +806,10 @@ | ||
| 665 | 806 | default: |
| 666 | 807 | if ( 'single' !== $multisite_mode ) { |
| 667 | 808 | // Get multisite users only. |
| 668 | 809 | $auth_settings_access_users_approved = $options->get( 'access_users_approved', Helper::NETWORK_CONTEXT ); |
| 669 | - } elseif ( is_multisite() && 1 === intval( $options->get( 'advanced_override_multisite' ) ) ) { | |
| 670 | - // This site has overridden any multisite settings, so only get its users. | |
| 810 | + } elseif ( is_multisite() && 1 === intval( $options->get( 'advanced_override_multisite' ) ) && empty( $options->get( 'prevent_override_multisite', Helper::NETWORK_CONTEXT ) ) ) { | |
| 811 | + // This site has overridden any multisite settings (and is not prevented from doing so), so only get its users. | |
| 671 | 812 | $auth_settings_access_users_approved = $options->get( 'access_users_approved', Helper::SINGLE_CONTEXT ); |
| 672 | 813 | } else { |
| 673 | 814 | // Get all site users and all multisite users. |
| 674 | 815 | $auth_settings_access_users_approved = array_merge( |
| @@ -678,6 +819,5 @@ | ||
| 678 | 819 | } |
| 679 | 820 | return Helper::in_multi_array( $email, $auth_settings_access_users_approved ); |
| 680 | 821 | } |
| 681 | 822 | } |
| 682 | - | |
| 683 | 823 | } |