From cc66cbe8f79c9639ce46796b6bc4a3e1cdd09918 Mon Sep 17 00:00:00 2001 From: Andrei Mondoc <andreimondoc@gmail.com> Date: Fri, 20 Mar 2020 12:15:22 +0000 Subject: [PATCH] log in and sync wp user before dispatching rest response Signed-off-by: Kevin Cristiano <kcristiano@kcristiano.com> --- wp-rest/Controller/Rest.php | 74 ++------------- wp-rest/Plugin.php | 175 ++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 69 deletions(-) diff --git a/wp-rest/Controller/Rest.php b/wp-rest/Controller/Rest.php index 1fe15caae9..68b669895b 100644 --- a/wp-rest/Controller/Rest.php +++ b/wp-rest/Controller/Rest.php @@ -451,7 +451,7 @@ class Rest extends Base { * @param string $param * @return bool */ - protected function is_valid_json( $param ) { + public function is_valid_json( $param ) { $param = json_decode( $param, true ); @@ -467,7 +467,7 @@ class Rest extends Base { * @since 0.1 * @return bool $is_valid_site_key */ - private function is_valid_site_key() { + public function is_valid_site_key() { return \CRM_Utils_System::authenticateKey( false ); @@ -480,7 +480,7 @@ class Rest extends Base { * @param WP_REST_Resquest $request * @return bool $is_valid_api_key */ - private function is_valid_api_key( $request ) { + public function is_valid_api_key( $request ) { $api_key = $request->get_param( 'api_key' ); @@ -488,73 +488,9 @@ class Rest extends Base { $contact_id = \CRM_Core_DAO::getFieldValue( 'CRM_Contact_DAO_Contact', $api_key, 'id', 'api_key' ); - // validate contact and login - if ( $contact_id ) { + if ( ! $contact_id ) return false; - $wp_user = $this->get_wp_user( $contact_id ); - - $this->do_user_login( $wp_user ); - - return true; - - } - - return false; - - } - - /** - * Get WordPress user data. - * - * @since 0.1 - * @param int $contact_id The contact id - * @return bool|WP_User $user The WordPress user data - */ - protected function get_wp_user( int $contact_id ) { - - try { - - // Get CiviCRM domain group ID from constant, if set. - $domain_id = defined( 'CIVICRM_DOMAIN_ID' ) ? CIVICRM_DOMAIN_ID : 0; - - // If this fails, get it from config. - if ( $domain_id === 0 ) { - $domain_id = \CRM_Core_Config::domainID(); - } - - // Call API. - $uf_match = civicrm_api3( 'UFMatch', 'getsingle', [ - 'contact_id' => $contact_id, - 'domain_id' => $domain_id, - ] ); - - } catch ( \CiviCRM_API3_Exception $e ) { - - return $this->civi_rest_error( $e->getMessage() ); - - } - - $wp_user = get_userdata( $uf_match['uf_id'] ); - - return $wp_user; - - } - - /** - * Logs in the WordPress user, needed to respect CiviCRM ACL and permissions. - * - * @since 0.1 - * @param WP_User $user - */ - protected function do_user_login( \WP_User $user ) { - - if ( is_user_logged_in() ) return; - - wp_set_current_user( $user->ID, $user->user_login ); - - wp_set_auth_cookie( $user->ID ); - - do_action( 'wp_login', $user->user_login, $user ); + return true; } diff --git a/wp-rest/Plugin.php b/wp-rest/Plugin.php index 8c94296c71..3531e597e4 100644 --- a/wp-rest/Plugin.php +++ b/wp-rest/Plugin.php @@ -56,6 +56,17 @@ class Plugin { civi_wp()->initialize(); + // rest calls need a wp user, do login + if ( false !== strpos( $request->get_route(), 'rest' ) ) { + + $logged_in_wp_user = $this->do_user_login( $request ); + + // return error + if ( is_wp_error( $logged_in_wp_user ) ) { + return $logged_in_wp_user; + } + } + } return $result; @@ -201,4 +212,168 @@ class Plugin { } + /** + * Performs the necessary checks and + * data retrieval to login a WordPress user. + * + * @since 0.1 + * @param \WP_REST_Request $request The request + * @return \WP_User|\WP_Error|void $logged_in_wp_user The logged in WordPress user object, \Wp_Error, or nothing + */ + public function do_user_login( $request ) { + + /** + * Filter and opportunity to bypass + * the default user login. + * + * @since 0.1 + * @param bool $login + */ + $logged_in = apply_filters( 'civi_wp_rest/plugin/do_user_login', false, $request ); + + if ( $logged_in ) return; + + // default login based on contact's api_key + if ( ! ( new Controller\Rest )->is_valid_api_key( $request ) ) { + return new \WP_Error( + 'civicrm_rest_api_error', + __( 'Missing or invalid param "api_key".', 'civicrm' ) + ); + } + + $contact_id = \CRM_Core_DAO::getFieldValue( + 'CRM_Contact_DAO_Contact', + $request->get_param( 'api_key' ), + 'id', + 'api_key' + ); + + $wp_user = $this->get_wp_user( $contact_id ); + + if ( is_wp_error( $wp_user ) ) { + return $wp_user; + } + + return $this->login_wp_user( $wp_user, $request ); + + } + + /** + * Get WordPress user data. + * + * @since 0.1 + * @param int $contact_id The contact id + * @return WP_User|WP_Error $user The WordPress user data or WP_Error object + */ + public function get_wp_user( int $contact_id ) { + + try { + + // Call API. + $uf_match = civicrm_api3( 'UFMatch', 'getsingle', [ + 'contact_id' => $contact_id, + 'domain_id' => $this->get_civi_domain_id(), + ] ); + + } catch ( \CiviCRM_API3_Exception $e ) { + + return new \WP_Error( + 'civicrm_rest_api_error', + __( 'A WordPress user must be associated with the contact for the provided API key.', 'civicrm' ) + ); + + } + + // filter uf_match + add_filter( 'civi_wp_rest/plugin/uf_match', function() use ( $uf_match ) { + + return ! empty( $uf_match ) ? $uf_match : null; + + } ); + + return get_userdata( $uf_match['uf_id'] ); + + } + + /** + * Logs in the WordPress user, and + * syncs it with it's CiviCRM contact. + * + * @since 0.1 + * @param \WP_User $user The WordPress user object + * @param \WP_REST_Request|null $request The request object or null + * @return \WP_User|void $wp_user The logged in WordPress user object or nothing + */ + public function login_wp_user( \WP_User $wp_user, $request = null ) { + + /** + * Filter the user about to be logged in. + * + * @since 0.1 + * @param \WP_User $user The WordPress user object + * @param \WP_REST_Request|null $request The request object or null + */ + $wp_user = apply_filters( 'civi_wp_rest/plugin/wp_user_login', $wp_user, $request ); + + wp_set_current_user( $wp_user->ID, $wp_user->user_login ); + + wp_set_auth_cookie( $wp_user->ID ); + + do_action( 'wp_login', $wp_user->user_login, $wp_user ); + + $this->set_civi_user_session( $wp_user ); + + return $wp_user; + + } + + /** + * Sets the necessary user + * session variables for CiviCRM. + * + * @since 0.1 + * @param \WP_User $wp_user The WordPress user + * @return void + */ + public function set_civi_user_session( $wp_user ): void { + + $uf_match = apply_filters( 'civi_wp_rest/plugin/uf_match', null ); + + if ( ! $uf_match ) { + + // Call API. + $uf_match = civicrm_api3( 'UFMatch', 'getsingle', [ + 'uf_id' => $wp_user->ID, + 'domain_id' => $this->get_civi_domain_id(), + ] ); + } + + // Set necessary session variables. + $session = \CRM_Core_Session::singleton(); + $session->set( 'ufID', $wp_user->ID ); + $session->set( 'userID', $uf_match['contact_id'] ); + $session->set( 'ufUniqID', $uf_match['uf_name'] ); + + } + + /** + * Retrieves the CiviCRM domain_id. + * + * @since 0.1 + * @return int $domain_id The domain id + */ + public function get_civi_domain_id(): int { + + // Get CiviCRM domain group ID from constant, if set. + $domain_id = defined( 'CIVICRM_DOMAIN_ID' ) ? CIVICRM_DOMAIN_ID : 0; + + // If this fails, get it from config. + if ( $domain_id === 0 ) { + $domain_id = \CRM_Core_Config::domainID(); + } + + return $domain_id; + + } + } -- GitLab