From 94f02ef8b109739ecb39a576848c94eb0e9374bb Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 20 Apr 2015 07:26:05 +0000 Subject: [PATCH] In Multisite, prevent plugins from unintentionally switching sites. Props mdawaffe. git-svn-id: https://develop.svn.wordpress.org/trunk@32173 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/capabilities.php | 12 ++++++--- tests/phpunit/tests/user/capabilities.php | 33 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php index bf9e8e3a41..588432dcfc 100644 --- a/src/wp-includes/capabilities.php +++ b/src/wp-includes/capabilities.php @@ -1403,21 +1403,25 @@ function current_user_can( $capability ) { * @return bool */ function current_user_can_for_blog( $blog_id, $capability ) { - if ( is_multisite() ) - switch_to_blog( $blog_id ); + $switched = is_multisite() ? switch_to_blog( $blog_id ) : false; $current_user = wp_get_current_user(); - if ( empty( $current_user ) ) + if ( empty( $current_user ) ) { + if ( $switched ) { + restore_current_blog(); + } return false; + } $args = array_slice( func_get_args(), 2 ); $args = array_merge( array( $capability ), $args ); $can = call_user_func_array( array( $current_user, 'has_cap' ), $args ); - if ( is_multisite() ) + if ( $switched ) { restore_current_blog(); + } return $can; } diff --git a/tests/phpunit/tests/user/capabilities.php b/tests/phpunit/tests/user/capabilities.php index 6903441752..8458697d11 100644 --- a/tests/phpunit/tests/user/capabilities.php +++ b/tests/phpunit/tests/user/capabilities.php @@ -695,6 +695,39 @@ class Tests_User_Capabilities extends WP_UnitTestCase { wp_set_current_user( $old_uid ); } + function test_borked_current_user_can_for_blog() { + if ( ! is_multisite() ) { + $this->markTestSkipped( 'Test only runs in multisite' ); + return; + } + + $orig_blog_id = get_current_blog_id(); + $blog_id = $this->factory->blog->create(); + + $nullify_current_user = function() { + // Prevents fatal errors in ::tearDown()'s and other uses of restore_current_blog() + $function_stack = wp_debug_backtrace_summary( null, 0, false ); + if ( in_array( 'restore_current_blog', $function_stack ) ) { + return; + } + $GLOBALS['current_user'] = null; + }; + + $nullify_current_user_and_keep_nullifying_user = function() use ( $nullify_current_user ) { + $nullify_current_user(); + + add_action( 'set_current_user', $nullify_current_user ); + }; + + $nullify_current_user(); + + add_action( 'switch_blog', $nullify_current_user_and_keep_nullifying_user ); + + current_user_can_for_blog( $blog_id, 'edit_posts' ); + + $this->assertEquals( $orig_blog_id, get_current_blog_id() ); + } + /** * @ticket 28374 */