Create New Item
×
Item Type
File
Folder
Item Name
×
Search file in folder and subfolders...
File Manager
/
wp-content
/
plugins
/
woocommerce
/
includes
/
legacy
/
api
/
v3
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php if (!defined('ABSPATH')) { exit; } class WC_API_Authentication { public function __construct() { add_filter('woocommerce_api_check_authentication', array($this, 'authenticate'), 0); } public function authenticate($user) { if ('/' === WC()->api->server->path) { return new WP_User(0); } try { if (is_ssl()) { $keys = $this->perform_ssl_authentication(); } else { $keys = $this->perform_oauth_authentication(); } $this->check_api_key_permissions($keys['permissions']); $user = $this->get_user_by_id($keys['user_id']); $this->update_api_key_last_access($keys['key_id']); } catch (Exception $e) { $user = new WP_Error('woocommerce_api_authentication_error', $e->getMessage(), array('status' => $e->getCode())); } return $user; } private function perform_ssl_authentication() { $params = WC()->api->server->params['GET']; if (!empty($params['consumer_key']) && !empty($params['consumer_secret'])) { $keys = $this->get_keys_by_consumer_key($params['consumer_key']); if (!$this->is_consumer_secret_valid($keys['consumer_secret'], $params['consumer_secret'])) { throw new Exception(__('Consumer secret is invalid.', 'woocommerce'), 401); } return $keys; } if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) { $this->exit_with_unauthorized_headers(); } $keys = $this->get_keys_by_consumer_key($_SERVER['PHP_AUTH_USER']); if (!$this->is_consumer_secret_valid($keys['consumer_secret'], $_SERVER['PHP_AUTH_PW'])) { $this->exit_with_unauthorized_headers(); } return $keys; } private function exit_with_unauthorized_headers() { $auth_message = __('WooCommerce API. Use a consumer key in the username field and a consumer secret in the password field.', 'woocommerce'); header('WWW-Authenticate: Basic realm="' . $auth_message . '"'); header('HTTP/1.0 401 Unauthorized'); throw new Exception(__('Consumer Secret is invalid.', 'woocommerce'), 401); } private function perform_oauth_authentication() { $params = WC()->api->server->params['GET']; $param_names = array('oauth_consumer_key', 'oauth_timestamp', 'oauth_nonce', 'oauth_signature', 'oauth_signature_method'); foreach ($param_names as $param_name) { if (empty($params[$param_name])) { throw new Exception(sprintf(__('%s parameter is missing', 'woocommerce'), $param_name), 404); } } $keys = $this->get_keys_by_consumer_key($params['oauth_consumer_key']); $this->check_oauth_signature($keys, $params); $this->check_oauth_timestamp_and_nonce($keys, $params['oauth_timestamp'], $params['oauth_nonce']); return $keys; } private function get_keys_by_consumer_key($consumer_key) { global $wpdb; $consumer_key = wc_api_hash(sanitize_text_field($consumer_key)); $keys = $wpdb->get_row($wpdb->prepare("\n\t\t\tSELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces\n\t\t\tFROM {$wpdb->prefix}woocommerce_api_keys\n\t\t\tWHERE consumer_key = '%s'\n\t\t", $consumer_key), ARRAY_A); if (empty($keys)) { throw new Exception(__('Consumer key is invalid.', 'woocommerce'), 401); } return $keys; } private function get_user_by_id($user_id) { $user = get_user_by('id', $user_id); if (!$user) { throw new Exception(__('API user is invalid', 'woocommerce'), 401); } return $user; } private function is_consumer_secret_valid($keys_consumer_secret, $consumer_secret) { return hash_equals($keys_consumer_secret, $consumer_secret); } private function check_oauth_signature($keys, $params) { $http_method = strtoupper(WC()->api->server->method); $server_path = WC()->api->server->path; if (isset($_SERVER['REDIRECT_URL']) && '/' === substr($_SERVER['REDIRECT_URL'], -1)) { $server_path .= '/'; } $base_request_uri = rawurlencode(untrailingslashit(get_woocommerce_api_url('')) . $server_path); $consumer_signature = rawurldecode(str_replace(' ', '+', $params['oauth_signature'])); unset($params['oauth_signature']); if (!uksort($params, 'strcmp')) { throw new Exception(__('Invalid signature - failed to sort parameters.', 'woocommerce'), 401); } $params = $this->normalize_parameters($params); $query_parameters = array(); foreach ($params as $param_key => $param_value) { if (is_array($param_value)) { foreach ($param_value as $param_key_inner => $param_value_inner) { $query_parameters[] = $param_key . '%255B' . $param_key_inner . '%255D%3D' . $param_value_inner; } } else { $query_parameters[] = $param_key . '%3D' . $param_value; } } $query_string = implode('%26', $query_parameters); $string_to_sign = $http_method . '&' . $base_request_uri . '&' . $query_string; if ('HMAC-SHA1' !== $params['oauth_signature_method'] && 'HMAC-SHA256' !== $params['oauth_signature_method']) { throw new Exception(__('Invalid signature - signature method is invalid.', 'woocommerce'), 401); } $hash_algorithm = strtolower(str_replace('HMAC-', '', $params['oauth_signature_method'])); $secret = $keys['consumer_secret'] . '&'; $signature = base64_encode(hash_hmac($hash_algorithm, $string_to_sign, $secret, true)); if (!hash_equals($signature, $consumer_signature)) { throw new Exception(__('Invalid signature - provided signature does not match.', 'woocommerce'), 401); } } private function normalize_parameters($parameters) { $keys = WC_API_Authentication::urlencode_rfc3986(array_keys($parameters)); $values = WC_API_Authentication::urlencode_rfc3986(array_values($parameters)); $parameters = array_combine($keys, $values); return $parameters; } public static function urlencode_rfc3986($value) { if (is_array($value)) { return array_map(array('WC_API_Authentication', 'urlencode_rfc3986'), $value); } else { return str_replace('%', '%25', rawurlencode(rawurldecode($value))); } } private function check_oauth_timestamp_and_nonce($keys, $timestamp, $nonce) { global $wpdb; $valid_window = 15 * 60; if ($timestamp < time() - $valid_window || $timestamp > time() + $valid_window) { throw new Exception(__('Invalid timestamp.', 'woocommerce'), 401); } $used_nonces = maybe_unserialize($keys['nonces']); if (empty($used_nonces)) { $used_nonces = array(); } if (in_array($nonce, $used_nonces)) { throw new Exception(__('Invalid nonce - nonce has already been used.', 'woocommerce'), 401); } $used_nonces[$timestamp] = $nonce; foreach ($used_nonces as $nonce_timestamp => $nonce) { if ($nonce_timestamp < time() - $valid_window) { unset($used_nonces[$nonce_timestamp]); } } $used_nonces = maybe_serialize($used_nonces); $wpdb->update($wpdb->prefix . 'woocommerce_api_keys', array('nonces' => $used_nonces), array('key_id' => $keys['key_id']), array('%s'), array('%d')); } public function check_api_key_permissions($key_permissions) { switch (WC()->api->server->method) { case 'HEAD': case 'GET': if ('read' !== $key_permissions && 'read_write' !== $key_permissions) { throw new Exception(__('The API key provided does not have read permissions.', 'woocommerce'), 401); } break; case 'POST': case 'PUT': case 'PATCH': case 'DELETE': if ('write' !== $key_permissions && 'read_write' !== $key_permissions) { throw new Exception(__('The API key provided does not have write permissions.', 'woocommerce'), 401); } break; } } private function update_api_key_last_access($key_id) { global $wpdb; $wpdb->update($wpdb->prefix . 'woocommerce_api_keys', array('last_access' => current_time('mysql')), array('key_id' => $key_id), array('%s'), array('%d')); } }