From 3a9c7103bf5358fb18bd686bc66dee8a4f1b2e8d Mon Sep 17 00:00:00 2001 From: Micah Wood Date: Mon, 20 Jun 2022 17:43:01 -0400 Subject: [PATCH] Authenticate Hiive REST API calls --- composer.json | 8 ++++++ composer.lock | 55 ++++++++++++++++++++++++++++++++++------ src/Data.php | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 41794a4..4150692 100644 --- a/composer.json +++ b/composer.json @@ -42,5 +42,13 @@ "scripts-descriptions": { "fix": "Automatically fix coding standards issues where possible.", "lint": "Check files against coding standards." + }, + "require": { + "wpscholar/url": "^1.2" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/composer.lock b/composer.lock index c4cb9b6..6488019 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,47 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a9a7aee9514c3018235d58ae6f161031", - "packages": [], + "content-hash": "4558cf0cf6fca0f0384504f5da828f1f", + "packages": [ + { + "name": "wpscholar/url", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/wpscholar/url.git", + "reference": "c339972ed8e6876f1cfacbc512c6205db63645d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wpscholar/url/zipball/c339972ed8e6876f1cfacbc512c6205db63645d0", + "reference": "c339972ed8e6876f1cfacbc512c6205db63645d0", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "wpscholar\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "Micah Wood", + "email": "micah@wpscholar.com", + "homepage": "http://wpscholar.com" + } + ], + "description": "A PHP class for parsing and manipulating URLs.", + "support": { + "issues": "https://github.com/wpscholar/url/issues", + "source": "https://github.com/wpscholar/url/tree/1.2.2" + }, + "time": "2020-10-27T20:10:04+00:00" + } + ], "packages-dev": [ { "name": "bluehost/wp-php-standards", @@ -293,16 +332,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.2", + "version": "3.7.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", - "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", + "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", "shasum": "" }, "require": { @@ -345,7 +384,7 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-12-12T21:44:58+00:00" + "time": "2022-06-18T07:21:10+00:00" }, { "name": "wp-coding-standards/wpcs", @@ -406,5 +445,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Data.php b/src/Data.php index 9605ae7..c4c1a86 100644 --- a/src/Data.php +++ b/src/Data.php @@ -2,6 +2,8 @@ namespace NewfoldLabs\WP\Module\Data; +use wpscholar\Url; + /** * Main class for the data plugin module */ @@ -39,6 +41,7 @@ public function start() { // Delays our primary module setup until init add_action( 'init', array( $this, 'init' ) ); + add_action( 'rest_authentication_errors', array( $this, 'authenticate' ) ); } @@ -80,4 +83,70 @@ public function init() { } + /** + * Authenticate incoming REST API requests. + * + * @param bool|null|\WP_Error $status + * + * @return bool|null|\WP_Error + */ + public function authenticate( $status ) { + + // Make sure there wasn't a different authentication method used before this + if ( ! is_null( $status ) ) { + return $status; + } + + // Make sure this is a REST API request + if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) { + return $status; + } + + // If no auth header included, bail to allow a different auth method + if ( empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) { + return null; + } + + $token = str_replace( 'Bearer ', '', $_SERVER['HTTP_AUTHORIZATION'] ); + + $data = [ + 'method' => $_SERVER['REQUEST_METHOD'], + 'url' => Url::getCurrentUrl(), + 'body' => file_get_contents( 'php://input' ), + 'timestamp' => data_get( getallheaders(), 'X-Timestamp' ), + ]; + + $hash = hash( 'sha256', wp_json_encode( $data ) ); + $salt = hash( 'sha256', strrev( HiiveConnection::get_auth_token() ) ); + + $is_valid = hash( 'sha256', $hash . $salt ) === $token; + + // Allow access if token is valid + if ( $is_valid ) { + + if ( isset( $_GET['user_id'] ) ) { + + // If a user ID is provided, use it to find the desired user. + $user = get_user_by( 'id', filter_input( INPUT_GET, 'user_id', FILTER_SANITIZE_NUMBER_INT ) ); + + } else { + + // If no user ID is provided, find the first admin user. + $admins = get_users( array( 'role' => 'administrator' ) ); + $user = array_shift( $admins ); + + } + + if ( ! empty( $user ) && is_a( $user, \WP_User::class ) ) { + wp_set_current_user( $user->id ); + + return true; + } + } + + // Don't return false, since we could be interfering with a basic auth implementation. + return null; + + } + }