2016-03-18 09:53:09 +00:00
< ? php
/**
* REST API Authentication
*
* @ package WooCommerce / API
* @ since 2.6 . 0
*/
2018-03-06 18:04:58 +00:00
defined ( 'ABSPATH' ) || exit ;
2016-03-18 09:53:09 +00:00
2018-03-06 18:04:58 +00:00
/**
* REST API authentication class .
*/
2016-03-18 09:53:09 +00:00
class WC_REST_Authentication {
2017-06-06 20:05:03 +00:00
/**
* Authentication error .
*
* @ var WP_Error
*/
protected $error = null ;
/**
* Logged in user data .
*
* @ var stdClass
*/
protected $user = null ;
/**
* Current auth method .
*
* @ var string
*/
protected $auth_method = '' ;
2016-03-18 09:53:09 +00:00
/**
* Initialize authentication actions .
*/
public function __construct () {
2017-02-10 17:33:07 +00:00
add_filter ( 'determine_current_user' , array ( $this , 'authenticate' ), 15 );
2016-03-18 09:53:09 +00:00
add_filter ( 'rest_authentication_errors' , array ( $this , 'check_authentication_error' ) );
2016-03-18 11:47:57 +00:00
add_filter ( 'rest_post_dispatch' , array ( $this , 'send_unauthorized_headers' ), 50 );
2017-06-06 20:05:03 +00:00
add_filter ( 'rest_pre_dispatch' , array ( $this , 'check_user_permissions' ), 10 , 3 );
2016-03-18 09:53:09 +00:00
}
2016-05-11 14:52:29 +00:00
/**
* Check if is request to our REST API .
*
* @ return bool
*/
protected function is_request_to_rest_api () {
if ( empty ( $_SERVER [ 'REQUEST_URI' ] ) ) {
return false ;
}
2016-06-30 21:25:39 +00:00
$rest_prefix = trailingslashit ( rest_get_url_prefix () );
2016-06-30 21:23:21 +00:00
2016-05-11 14:52:29 +00:00
// Check if our endpoint.
2018-03-06 18:04:58 +00:00
$woocommerce = ( false !== strpos ( $_SERVER [ 'REQUEST_URI' ], $rest_prefix . 'wc/' ) ); // @codingStandardsIgnoreLine
2016-05-11 14:52:29 +00:00
// Allow third party plugins use our authentication methods.
2018-03-06 18:04:58 +00:00
$third_party = ( false !== strpos ( $_SERVER [ 'REQUEST_URI' ], $rest_prefix . 'wc-' ) ); // @codingStandardsIgnoreLine
2016-05-11 14:52:29 +00:00
return apply_filters ( 'woocommerce_rest_is_request_to_rest_api' , $woocommerce || $third_party );
}
2016-03-18 09:53:09 +00:00
/**
* Authenticate user .
*
2016-03-18 12:50:54 +00:00
* @ param int | false $user_id User ID if one has been determined , false otherwise .
* @ return int | false
2016-03-18 09:53:09 +00:00
*/
public function authenticate ( $user_id ) {
2016-05-10 21:27:28 +00:00
// Do not authenticate twice and check if is a request to our endpoint in the WP REST API.
2016-05-11 14:52:29 +00:00
if ( ! empty ( $user_id ) || ! $this -> is_request_to_rest_api () ) {
2016-03-18 11:37:31 +00:00
return $user_id ;
}
2016-03-18 09:53:09 +00:00
if ( is_ssl () ) {
2018-05-15 22:51:59 +00:00
$user_id = $this -> perform_basic_authentication ();
}
if ( $user_id ) {
return $user_id ;
2016-03-18 09:53:09 +00:00
}
2018-04-19 05:04:44 +00:00
return $this -> perform_oauth_authentication ();
2016-03-18 09:53:09 +00:00
}
/**
* Check for authentication error .
*
2018-03-06 18:04:58 +00:00
* @ param WP_Error | null | bool $error Error data .
2016-03-18 09:53:09 +00:00
* @ return WP_Error | null | bool
*/
public function check_authentication_error ( $error ) {
2017-07-17 10:10:52 +00:00
// Pass through other errors.
2016-03-18 09:53:09 +00:00
if ( ! empty ( $error ) ) {
return $error ;
}
2017-06-06 20:05:03 +00:00
return $this -> get_error ();
}
/**
* Set authentication error .
*
2017-07-17 10:10:52 +00:00
* @ param WP_Error $error Authentication error data .
2017-06-06 20:05:03 +00:00
*/
protected function set_error ( $error ) {
// Reset user.
$this -> user = null ;
$this -> error = $error ;
}
/**
* Get authentication error .
*
* @ return WP_Error | null .
*/
protected function get_error () {
return $this -> error ;
2016-03-18 09:53:09 +00:00
}
/**
* Basic Authentication .
*
* SSL - encrypted requests are not subject to sniffing or man - in - the - middle
* attacks , so the request can be authenticated by simply looking up the user
* associated with the given consumer key and confirming the consumer secret
* provided is valid .
*
2016-03-18 12:50:54 +00:00
* @ return int | bool
2016-03-18 09:53:09 +00:00
*/
private function perform_basic_authentication () {
2017-06-06 20:05:03 +00:00
$this -> auth_method = 'basic_auth' ;
$consumer_key = '' ;
$consumer_secret = '' ;
2016-03-18 09:53:09 +00:00
// If the $_GET parameters are present, use those first.
if ( ! empty ( $_GET [ 'consumer_key' ] ) && ! empty ( $_GET [ 'consumer_secret' ] ) ) {
2018-03-06 18:04:58 +00:00
$consumer_key = $_GET [ 'consumer_key' ]; // WPCS: sanitization ok.
$consumer_secret = $_GET [ 'consumer_secret' ]; // WPCS: sanitization ok.
2016-03-18 09:53:09 +00:00
}
// If the above is not present, we will do full basic auth.
if ( ! $consumer_key && ! empty ( $_SERVER [ 'PHP_AUTH_USER' ] ) && ! empty ( $_SERVER [ 'PHP_AUTH_PW' ] ) ) {
2018-03-06 18:04:58 +00:00
$consumer_key = $_SERVER [ 'PHP_AUTH_USER' ]; // WPCS: sanitization ok.
$consumer_secret = $_SERVER [ 'PHP_AUTH_PW' ]; // WPCS: sanitization ok.
2016-03-18 09:53:09 +00:00
}
2016-03-18 13:18:44 +00:00
// Stop if don't have any key.
if ( ! $consumer_key || ! $consumer_secret ) {
return false ;
2016-03-18 09:53:09 +00:00
}
2016-03-18 13:18:44 +00:00
// Get user data.
2017-06-06 20:05:03 +00:00
$this -> user = $this -> get_user_data_by_consumer_key ( $consumer_key );
if ( empty ( $this -> user ) ) {
2016-03-18 12:50:54 +00:00
return false ;
2016-03-18 10:24:59 +00:00
}
2016-03-18 09:53:09 +00:00
// Validate user secret.
2018-03-06 18:04:58 +00:00
if ( ! hash_equals ( $this -> user -> consumer_secret , $consumer_secret ) ) { // @codingStandardsIgnoreLine
2017-06-06 20:05:03 +00:00
$this -> set_error ( new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Consumer secret is invalid.' , 'woocommerce' ), array ( 'status' => 401 ) ) );
2016-03-18 09:53:09 +00:00
2016-03-18 12:50:54 +00:00
return false ;
2016-03-18 10:24:59 +00:00
}
2017-06-06 20:05:03 +00:00
return $this -> user -> user_id ;
2016-03-18 09:53:09 +00:00
}
2016-08-22 20:39:41 +00:00
/**
* Parse the Authorization header into parameters .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-08-22 20:39:41 +00:00
*
* @ param string $header Authorization header value ( not including " Authorization: " prefix ) .
*
* @ return array Map of parameter values .
*/
public function parse_header ( $header ) {
if ( 'OAuth ' !== substr ( $header , 0 , 6 ) ) {
return array ();
}
// From OAuth PHP library, used under MIT license.
$params = array ();
if ( preg_match_all ( '/(oauth_[a-z_-]*)=(:?"([^"]*)"|([^,]*))/' , $header , $matches ) ) {
2016-08-27 03:23:21 +00:00
foreach ( $matches [ 1 ] as $i => $h ) {
2016-08-22 20:39:41 +00:00
$params [ $h ] = urldecode ( empty ( $matches [ 3 ][ $i ] ) ? $matches [ 4 ][ $i ] : $matches [ 3 ][ $i ] );
}
if ( isset ( $params [ 'realm' ] ) ) {
unset ( $params [ 'realm' ] );
}
}
return $params ;
}
/**
* Get the authorization header .
*
* On certain systems and configurations , the Authorization header will be
* stripped out by the server or PHP . Typically this is then used to
* generate `PHP_AUTH_USER` / `PHP_AUTH_PASS` but not passed on . We use
* `getallheaders` here to try and grab it out instead .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-08-22 20:39:41 +00:00
*
* @ return string Authorization header if set .
*/
public function get_authorization_header () {
if ( ! empty ( $_SERVER [ 'HTTP_AUTHORIZATION' ] ) ) {
2018-03-06 18:04:58 +00:00
return wp_unslash ( $_SERVER [ 'HTTP_AUTHORIZATION' ] ); // WPCS: sanitization ok.
2016-08-22 20:39:41 +00:00
}
if ( function_exists ( 'getallheaders' ) ) {
$headers = getallheaders ();
// Check for the authoization header case-insensitively.
foreach ( $headers as $key => $value ) {
if ( 'authorization' === strtolower ( $key ) ) {
return $value ;
}
}
}
return '' ;
}
/**
* Get oAuth parameters from $_GET , $_POST or request header .
*
2017-03-15 16:36:53 +00:00
* @ since 3.0 . 0
2016-08-22 20:39:41 +00:00
*
* @ return array | WP_Error
*/
public function get_oauth_parameters () {
2018-03-06 18:04:58 +00:00
$params = array_merge ( $_GET , $_POST ); // WPCS: CSRF ok.
2016-08-22 20:39:41 +00:00
$params = wp_unslash ( $params );
$header = $this -> get_authorization_header ();
if ( ! empty ( $header ) ) {
// Trim leading spaces.
2018-03-05 20:53:06 +00:00
$header = trim ( $header );
2016-08-22 20:39:41 +00:00
$header_params = $this -> parse_header ( $header );
if ( ! empty ( $header_params ) ) {
$params = array_merge ( $params , $header_params );
}
}
$param_names = array (
'oauth_consumer_key' ,
'oauth_timestamp' ,
'oauth_nonce' ,
'oauth_signature' ,
2016-08-27 02:08:49 +00:00
'oauth_signature_method' ,
2016-08-22 20:39:41 +00:00
);
$errors = array ();
$have_one = false ;
// Check for required OAuth parameters.
foreach ( $param_names as $param_name ) {
if ( empty ( $params [ $param_name ] ) ) {
$errors [] = $param_name ;
} else {
$have_one = true ;
}
}
// All keys are missing, so we're probably not even trying to use OAuth.
if ( ! $have_one ) {
return array ();
}
// If we have at least one supplied piece of data, and we have an error,
// then it's a failed authentication.
if ( ! empty ( $errors ) ) {
$message = sprintf (
2018-03-06 18:04:58 +00:00
/* translators: %s: amount of errors */
2016-09-01 20:50:14 +00:00
_n ( 'Missing OAuth parameter %s' , 'Missing OAuth parameters %s' , count ( $errors ), 'woocommerce' ),
2016-08-22 20:39:41 +00:00
implode ( ', ' , $errors )
);
2017-06-06 20:05:03 +00:00
$this -> set_error ( new WP_Error ( 'woocommerce_rest_authentication_missing_parameter' , $message , array ( 'status' => 401 ) ) );
2016-08-22 20:39:41 +00:00
return array ();
}
return $params ;
}
2016-03-18 11:37:31 +00:00
/**
* Perform OAuth 1.0 a " one-legged " ( http :// oauthbible . com / #oauth-10a-one-legged) authentication for non-SSL requests.
*
* This is required so API credentials cannot be sniffed or intercepted when making API requests over plain HTTP .
*
* This follows the spec for simple OAuth 1.0 a authentication ( RFC 5849 ) as closely as possible , with two exceptions :
*
* 1 ) There is no token associated with request / responses , only consumer keys / secrets are used .
*
* 2 ) The OAuth parameters are included as part of the request query string instead of part of the Authorization header ,
* This is because there is no cross - OS function within PHP to get the raw Authorization header .
*
* @ link http :// tools . ietf . org / html / rfc5849 for the full spec .
2016-03-18 12:50:54 +00:00
*
* @ return int | bool
2016-03-18 11:37:31 +00:00
*/
private function perform_oauth_authentication () {
2017-06-06 20:05:03 +00:00
$this -> auth_method = 'oauth1' ;
2016-03-18 11:37:31 +00:00
2016-08-22 20:39:41 +00:00
$params = $this -> get_oauth_parameters ();
if ( empty ( $params ) ) {
return false ;
2016-03-18 11:37:31 +00:00
}
2016-08-22 20:39:41 +00:00
// Fetch WP user by consumer key.
2017-06-06 20:05:03 +00:00
$this -> user = $this -> get_user_data_by_consumer_key ( $params [ 'oauth_consumer_key' ] );
2016-03-18 11:37:31 +00:00
2017-06-06 20:05:03 +00:00
if ( empty ( $this -> user ) ) {
$this -> set_error ( new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Consumer key is invalid.' , 'woocommerce' ), array ( 'status' => 401 ) ) );
2016-03-18 11:37:31 +00:00
2016-03-18 12:50:54 +00:00
return false ;
2016-03-18 11:37:31 +00:00
}
// Perform OAuth validation.
2017-06-06 20:05:03 +00:00
$signature = $this -> check_oauth_signature ( $this -> user , $params );
if ( is_wp_error ( $signature ) ) {
$this -> set_error ( $signature );
2016-03-18 12:50:54 +00:00
return false ;
2016-03-18 11:37:31 +00:00
}
2017-06-06 20:05:03 +00:00
$timestamp_and_nonce = $this -> check_oauth_timestamp_and_nonce ( $this -> user , $params [ 'oauth_timestamp' ], $params [ 'oauth_nonce' ] );
if ( is_wp_error ( $timestamp_and_nonce ) ) {
$this -> set_error ( $timestamp_and_nonce );
2016-03-18 12:50:54 +00:00
return false ;
2016-03-18 11:37:31 +00:00
}
2017-06-06 20:05:03 +00:00
return $this -> user -> user_id ;
2016-03-18 11:37:31 +00:00
}
/**
* Verify that the consumer - provided request signature matches our generated signature ,
* this ensures the consumer has a valid key / secret .
*
2018-03-06 18:04:58 +00:00
* @ param stdClass $user User data .
2018-03-05 20:53:06 +00:00
* @ param array $params The request parameters .
2017-05-15 11:50:52 +00:00
* @ return true | WP_Error
2016-03-18 11:37:31 +00:00
*/
private function check_oauth_signature ( $user , $params ) {
2018-03-06 18:04:58 +00:00
$http_method = isset ( $_SERVER [ 'REQUEST_METHOD' ] ) ? strtoupper ( $_SERVER [ 'REQUEST_METHOD' ] ) : '' ; // WPCS: sanitization ok.
$request_path = isset ( $_SERVER [ 'REQUEST_URI' ] ) ? parse_url ( $_SERVER [ 'REQUEST_URI' ], PHP_URL_PATH ) : '' ; // WPCS: sanitization ok.
2016-03-18 11:37:31 +00:00
$wp_base = get_home_url ( null , '/' , 'relative' );
if ( substr ( $request_path , 0 , strlen ( $wp_base ) ) === $wp_base ) {
$request_path = substr ( $request_path , strlen ( $wp_base ) );
}
2017-09-07 14:32:29 +00:00
$base_request_uri = rawurlencode ( get_home_url ( null , $request_path , is_ssl () ? 'https' : 'http' ) );
2016-03-18 11:37:31 +00:00
// Get the signature provided by the consumer and remove it from the parameters prior to checking the signature.
2017-03-16 17:23:45 +00:00
$consumer_signature = rawurldecode ( str_replace ( ' ' , '+' , $params [ 'oauth_signature' ] ) );
2016-03-18 11:37:31 +00:00
unset ( $params [ 'oauth_signature' ] );
// Sort parameters.
if ( ! uksort ( $params , 'strcmp' ) ) {
2016-10-12 10:16:30 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Invalid signature - failed to sort parameters.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 11:37:31 +00:00
}
// Normalize parameter key/values.
2017-06-06 20:05:03 +00:00
$params = $this -> normalize_parameters ( $params );
$query_string = implode ( '%26' , $this -> join_with_equals_sign ( $params ) ); // Join with ampersand.
2016-03-18 11:37:31 +00:00
$string_to_sign = $http_method . '&' . $base_request_uri . '&' . $query_string ;
2016-09-09 00:14:28 +00:00
if ( 'HMAC-SHA1' !== $params [ 'oauth_signature_method' ] && 'HMAC-SHA256' !== $params [ 'oauth_signature_method' ] ) {
2016-10-12 10:16:30 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Invalid signature - signature method is invalid.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 11:37:31 +00:00
}
$hash_algorithm = strtolower ( str_replace ( 'HMAC-' , '' , $params [ 'oauth_signature_method' ] ) );
2016-03-31 19:14:18 +00:00
$secret = $user -> consumer_secret . '&' ;
$signature = base64_encode ( hash_hmac ( $hash_algorithm , $string_to_sign , $secret , true ) );
2016-03-18 11:37:31 +00:00
2018-03-06 18:04:58 +00:00
if ( ! hash_equals ( $signature , $consumer_signature ) ) { // @codingStandardsIgnoreLine
2016-10-12 10:16:30 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Invalid signature - provided signature does not match.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 11:37:31 +00:00
}
return true ;
}
2017-06-06 20:05:03 +00:00
/**
* Creates an array of urlencoded strings out of each array key / value pairs .
*
* @ param array $params Array of parameters to convert .
* @ param array $query_params Array to extend .
2018-03-06 18:04:58 +00:00
* @ param string $key Optional Array key to append .
* @ return string Array of urlencoded strings .
2017-06-06 20:05:03 +00:00
*/
private function join_with_equals_sign ( $params , $query_params = array (), $key = '' ) {
foreach ( $params as $param_key => $param_value ) {
if ( $key ) {
$param_key = $key . '%5B' . $param_key . '%5D' ; // Handle multi-dimensional array.
}
if ( is_array ( $param_value ) ) {
$query_params = $this -> join_with_equals_sign ( $param_value , $query_params , $param_key );
} else {
2018-03-05 20:53:06 +00:00
$string = $param_key . '=' . $param_value ; // Join with equals sign.
2017-06-06 20:05:03 +00:00
$query_params [] = wc_rest_urlencode_rfc3986 ( $string );
}
}
return $query_params ;
}
2016-03-18 11:37:31 +00:00
/**
* Normalize each parameter by assuming each parameter may have already been
* encoded , so attempt to decode , and then re - encode according to RFC 3986.
*
* Note both the key and value is normalized so a filter param like :
*
* 'filter[period]' => 'week'
*
* is encoded to :
*
2017-06-06 20:05:03 +00:00
* 'filter%255Bperiod%255D' => 'week'
2016-03-18 11:37:31 +00:00
*
* This conforms to the OAuth 1.0 a spec which indicates the entire query string
* should be URL encoded .
*
* @ see rawurlencode ()
2017-06-06 20:05:03 +00:00
* @ param array $parameters Un - normalized parameters .
2016-03-18 11:37:31 +00:00
* @ return array Normalized parameters .
*/
private function normalize_parameters ( $parameters ) {
2016-03-31 19:14:18 +00:00
$keys = wc_rest_urlencode_rfc3986 ( array_keys ( $parameters ) );
$values = wc_rest_urlencode_rfc3986 ( array_values ( $parameters ) );
2016-03-18 11:37:31 +00:00
$parameters = array_combine ( $keys , $values );
return $parameters ;
}
/**
* Verify that the timestamp and nonce provided with the request are valid . This prevents replay attacks where
* an attacker could attempt to re - send an intercepted request at a later time .
*
* - A timestamp is valid if it is within 15 minutes of now .
* - A nonce is valid if it has not been used within the last 15 minutes .
*
2018-03-06 18:04:58 +00:00
* @ param stdClass $user User data .
* @ param int $timestamp The unix timestamp for when the request was made .
* @ param string $nonce A unique ( for the given user ) 32 alphanumeric string , consumer - generated .
2016-03-18 11:37:31 +00:00
* @ return bool | WP_Error
*/
private function check_oauth_timestamp_and_nonce ( $user , $timestamp , $nonce ) {
global $wpdb ;
$valid_window = 15 * 60 ; // 15 minute window.
if ( ( $timestamp < time () - $valid_window ) || ( $timestamp > time () + $valid_window ) ) {
2016-03-18 11:51:48 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Invalid timestamp.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 11:37:31 +00:00
}
$used_nonces = maybe_unserialize ( $user -> nonces );
if ( empty ( $used_nonces ) ) {
$used_nonces = array ();
}
if ( in_array ( $nonce , $used_nonces ) ) {
2016-03-18 11:51:48 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Invalid nonce - nonce has already been used.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 11:37:31 +00:00
}
$used_nonces [ $timestamp ] = $nonce ;
// Remove expired nonces.
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' => $user -> key_id ),
array ( '%s' ),
array ( '%d' )
);
return true ;
}
2016-03-18 09:53:09 +00:00
/**
* Return the user data for the given consumer_key .
*
2018-03-06 18:04:58 +00:00
* @ param string $consumer_key Consumer key .
2016-03-18 09:53:09 +00:00
* @ return array
*/
private function get_user_data_by_consumer_key ( $consumer_key ) {
global $wpdb ;
$consumer_key = wc_api_hash ( sanitize_text_field ( $consumer_key ) );
2018-03-05 20:53:06 +00:00
$user = $wpdb -> get_row (
$wpdb -> prepare (
"
2016-03-18 09:53:09 +00:00
SELECT key_id , user_id , permissions , consumer_key , consumer_secret , nonces
FROM { $wpdb -> prefix } woocommerce_api_keys
2016-04-05 19:58:18 +00:00
WHERE consumer_key = % s
2018-03-05 20:53:06 +00:00
" , $consumer_key
)
);
2016-03-18 09:53:09 +00:00
return $user ;
}
2016-03-18 10:24:59 +00:00
/**
* Check that the API keys provided have the proper key - specific permissions to either read or write API resources .
*
2017-06-06 20:05:03 +00:00
* @ param string $method Request method .
* @ return bool | WP_Error
2016-03-18 10:24:59 +00:00
*/
2017-06-06 20:05:03 +00:00
private function check_permissions ( $method ) {
$permissions = $this -> user -> permissions ;
2016-03-18 10:24:59 +00:00
2017-06-06 20:05:03 +00:00
switch ( $method ) {
2018-03-05 20:53:06 +00:00
case 'HEAD' :
case 'GET' :
2016-03-18 10:24:59 +00:00
if ( 'read' !== $permissions && 'read_write' !== $permissions ) {
2017-06-06 20:05:03 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'The API key provided does not have read permissions.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 10:24:59 +00:00
}
break ;
2018-03-05 20:53:06 +00:00
case 'POST' :
case 'PUT' :
case 'PATCH' :
case 'DELETE' :
2016-03-18 10:24:59 +00:00
if ( 'write' !== $permissions && 'read_write' !== $permissions ) {
2017-06-06 20:05:03 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'The API key provided does not have write permissions.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 10:24:59 +00:00
}
break ;
2018-03-05 20:53:06 +00:00
case 'OPTIONS' :
2017-07-13 18:19:17 +00:00
return true ;
2017-06-06 20:05:03 +00:00
2018-03-05 20:53:06 +00:00
default :
2017-06-06 20:05:03 +00:00
return new WP_Error ( 'woocommerce_rest_authentication_error' , __ ( 'Unknown request method.' , 'woocommerce' ), array ( 'status' => 401 ) );
2016-03-18 10:24:59 +00:00
}
2017-06-06 20:05:03 +00:00
return true ;
2016-03-18 10:24:59 +00:00
}
2016-03-18 11:37:31 +00:00
/**
* Updated API Key last access datetime .
*/
2017-06-06 20:05:03 +00:00
private function update_last_access () {
2016-03-18 11:37:31 +00:00
global $wpdb ;
$wpdb -> update (
$wpdb -> prefix . 'woocommerce_api_keys' ,
array ( 'last_access' => current_time ( 'mysql' ) ),
2017-06-06 20:05:03 +00:00
array ( 'key_id' => $this -> user -> key_id ),
2016-03-18 11:37:31 +00:00
array ( '%s' ),
array ( '%d' )
);
}
2016-03-18 11:47:57 +00:00
/**
* If the consumer_key and consumer_secret $_GET parameters are NOT provided
* and the Basic auth headers are either not present or the consumer secret does not match the consumer
* key provided , then return the correct Basic headers and an error message .
*
* @ param WP_REST_Response $response Current response being served .
* @ return WP_REST_Response
*/
public function send_unauthorized_headers ( $response ) {
2017-06-06 20:05:03 +00:00
if ( is_wp_error ( $this -> get_error () ) && 'basic_auth' === $this -> auth_method ) {
2016-10-11 01:39:13 +00:00
$auth_message = __ ( 'WooCommerce API. Use a consumer key in the username field and a consumer secret in the password field.' , 'woocommerce' );
2016-03-18 11:47:57 +00:00
$response -> header ( 'WWW-Authenticate' , 'Basic realm="' . $auth_message . '"' , true );
}
return $response ;
}
2017-06-06 20:05:03 +00:00
/**
* Check for user permissions and register last access .
*
* @ param mixed $result Response to replace the requested version with .
* @ param WP_REST_Server $server Server instance .
* @ param WP_REST_Request $request Request used to generate the response .
* @ return mixed
*/
public function check_user_permissions ( $result , $server , $request ) {
if ( $this -> user ) {
// Check API Key permissions.
$allowed = $this -> check_permissions ( $request -> get_method () );
if ( is_wp_error ( $allowed ) ) {
return $allowed ;
}
// Register last access.
$this -> update_last_access ();
}
return $result ;
}
2016-03-18 09:53:09 +00:00
}
new WC_REST_Authentication ();