Skip to content

Commit

Permalink
Add function to fetch user info with blog token (#12478)
Browse files Browse the repository at this point in the history
* Add function to fetch user info with blog token

* Add caps and allcaps to response

* Improve inline docs

* jetpack.getUser: Simpler signature, more error reporting, return Token Key.

* Recomplicate signature :)


Co-authored-by: Michael D Adams <michael.d.adams@gmail.com>
  • Loading branch information
2 people authored and jeherve committed Jun 18, 2019
1 parent e9c84c4 commit e6e34ae
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 3 deletions.
78 changes: 75 additions & 3 deletions class.jetpack-xmlrpc-server.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function xmlrpc_methods( $core_methods ) {
$jetpack_methods = array(
'jetpack.jsonAPI' => array( $this, 'json_api' ),
'jetpack.verifyAction' => array( $this, 'verify_action' ),
'jetpack.getUser' => array( $this, 'get_user' ),
'jetpack.remoteRegister' => array( $this, 'remote_register' ),
'jetpack.remoteProvision' => array( $this, 'remote_provision' ),
);
Expand Down Expand Up @@ -97,6 +98,73 @@ function provision_xmlrpc_methods() {
'jetpack.remoteRegister' => array( $this, 'remote_register' ),
'jetpack.remoteProvision' => array( $this, 'remote_provision' ),
'jetpack.remoteConnect' => array( $this, 'remote_connect' ),
'jetpack.getUser' => array( $this, 'get_user' ),
);
}

/**
* Used to verify whether a local user exists and what role they have.
*
* @param int|string|array $request One of:
* int|string The local User's ID, username, or email address.
* array A request array containing:
* 0: int|string The local User's ID, username, or email address.
*
* @return array|IXR_Error Information about the user, or error if no such user found:
* roles: string[] The user's rols.
* login: string The user's username.
* email_hash string[] The MD5 hash of the user's normalized email address.
* caps string[] The user's capabilities.
* allcaps string[] The user's granular capabilities, merged from role capabilities.
* token_key string The Token Key of the user's Jetpack token. Empty string if none.
*/
function get_user( $request ) {
$user_id = is_array( $request ) ? $request[0] : $request;

if ( ! $user_id ) {
return $this->error(
new Jetpack_Error(
'invalid_user',
__( 'Invalid user identifier.', 'jetpack' ),
400
),
'jpc_get_user_fail'
);
}

$user = $this->get_user_by_anything( $user_id );

if ( ! $user ) {
return $this->error(
new Jetpack_Error(
'user_unknown',
__( 'User not found.', 'jetpack' ),
404
),
'jpc_get_user_fail'
);
}

$connection = Jetpack::connection();
$user_token = $connection->get_access_token( $user->ID );

if ( $user_token ) {
list( $user_token_key, $user_token_private ) = explode( '.', $user_token->secret );
if ( $user_token_key === $user_token->secret ) {
$user_token_key = '';
}
} else {
$user_token_key = '';
}

return array(
'id' => $user->ID,
'login' => $user->user_login,
'email_hash' => md5( strtolower( trim( $user->user_email ) ) ),
'roles' => $user->roles,
'caps' => $user->caps,
'allcaps' => $user->allcaps,
'token_key' => $user_token_key,
);
}

Expand Down Expand Up @@ -373,14 +441,18 @@ private function fetch_and_verify_local_user( $request ) {
// local user is used to look up by login, email or ID
$local_user_info = $request['local_user'];

$user = get_user_by( 'login', $local_user_info );
return $this->get_user_by_anything( $local_user_info );
}

private function get_user_by_anything( $user_id ) {
$user = get_user_by( 'login', $user_id );

if ( ! $user ) {
$user = get_user_by( 'email', $local_user_info );
$user = get_user_by( 'email', $user_id );
}

if ( ! $user ) {
$user = get_user_by( 'ID', $local_user_info );
$user = get_user_by( 'ID', $user_id );
}

return $user;
Expand Down
67 changes: 67 additions & 0 deletions tests/php/general/test_class.jetpack-xmlrpc-server.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
require_once dirname( __FILE__ ) . '/../../../class.jetpack-xmlrpc-server.php';

class WP_Test_Jetpack_XMLRPC_Server extends WP_UnitTestCase {
static $xmlrpc_admin = 0;

public static function wpSetupBeforeClass( $factory ) {
$user_id = $factory->user->create();
$user = get_user_by( 'ID', $user_id );
$user->set_role( 'administrator' );
Jetpack::update_user_token( $user_id, sprintf( '%s.%s.%d', 'key', 'private', $user_id ), false );

self::$xmlrpc_admin = $user_id;
}

function test_xmlrpc_features_available() {
$server = new Jetpack_XMLRPC_Server();
$response = $server->features_available();
Expand Down Expand Up @@ -47,6 +58,62 @@ function test_xmlrpc_get_sync_object_for_user() {
$this->assertEquals( $user_id, $decoded_object->ID );
}

function test_xmlrpc_get_user_by_id() {
$user = get_user_by( 'id', self::$xmlrpc_admin );
$server = new Jetpack_XMLRPC_Server();

$response = $server->get_user( $user->ID );
$this->assertGetUserEqual( $user, $response );
$this->assertEquals( 'key', $response['token_key'] );
}

function test_xmlrpc_get_user_by_user_login() {
$user = get_user_by( 'id', self::$xmlrpc_admin );
$server = new Jetpack_XMLRPC_Server();

$response = $server->get_user( $user->user_login );
$this->assertGetUserEqual( $user, $response );
$this->assertEquals( 'key', $response['token_key'] );
}

function test_xmlrpc_get_user_by_user_email() {
$user = get_user_by( 'id', self::$xmlrpc_admin );
$server = new Jetpack_XMLRPC_Server();

$response = $server->get_user( $user->user_email );
$this->assertGetUserEqual( $user, $response );
$this->assertEquals( 'key', $response['token_key'] );
}

function test_xmlrpc_get_user_invalid_input() {
$server = new Jetpack_XMLRPC_Server();

$missing_response = $server->get_user( '' );

$this->assertEquals( 'IXR_Error', get_class( $missing_response ) );
$this->assertEquals( 400, $missing_response->code );
$this->assertEquals( 'Jetpack: [invalid_user] Invalid user identifier.', $missing_response->message );
}

function test_xmlrpc_get_user_no_matching_user() {
$server = new Jetpack_XMLRPC_Server();

$missing_response = $server->get_user( 'nope@nope.nope' );

$this->assertEquals( 'IXR_Error', get_class( $missing_response ) );
$this->assertEquals( 404, $missing_response->code );
$this->assertEquals( 'Jetpack: [user_unknown] User not found.', $missing_response->message );
}

protected function assertGetUserEqual( $user, $response ) {
$this->assertEquals( $user->ID, $response['id'] );
$this->assertEquals( md5( strtolower( trim( $user->user_email ) ) ), $response['email_hash'] );
$this->assertEquals( $user->user_login, $response['login'] );
$this->assertEquals( sort( $user->roles ), sort( $response['roles'] ) );
$this->assertEquals( sort( $user->caps ), sort( $response['caps'] ) );
$this->assertEquals( sort( $user->allcaps ), sort( $response['allcaps'] ) );
}

function test_xmlrpc_remote_register_fails_no_nonce() {
$server = new Jetpack_XMLRPC_Server();

Expand Down

0 comments on commit e6e34ae

Please sign in to comment.