Allow oAuth1.0a authentication using headers
This commit is contained in:
parent
7a0c5bc19b
commit
eb55096a32
|
@ -137,6 +137,133 @@ class WC_REST_Authentication {
|
|||
return $user->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Authorization header into parameters.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @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 ) ) {
|
||||
foreach ( $matches[ 1 ] as $i => $h ) {
|
||||
$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.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @return string Authorization header if set.
|
||||
*/
|
||||
public function get_authorization_header() {
|
||||
if ( ! empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
|
||||
return wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] );
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function get_oauth_parameters() {
|
||||
global $wc_rest_authentication_error;
|
||||
|
||||
$params = array_merge( $_GET, $_POST );
|
||||
$params = wp_unslash( $params );
|
||||
$header = $this->get_authorization_header();
|
||||
|
||||
if ( ! empty( $header ) ) {
|
||||
// Trim leading spaces.
|
||||
$header = trim( $header );
|
||||
$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',
|
||||
'oauth_signature_method'
|
||||
);
|
||||
|
||||
$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(
|
||||
_n(
|
||||
__( 'Missing OAuth parameter %s', 'woocommerce' ),
|
||||
__( 'Missing OAuth parameters %s', 'woocommerce' ),
|
||||
count( $errors )
|
||||
),
|
||||
implode( ', ', $errors )
|
||||
);
|
||||
|
||||
$wc_rest_authentication_error = new WP_Error( 'woocommerce_rest_authentication_missing_parameter', $message, array( 'status' => 401 ) );
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OAuth 1.0a "one-legged" (http://oauthbible.com/#oauth-10a-one-legged) authentication for non-SSL requests.
|
||||
*
|
||||
|
@ -156,17 +283,13 @@ class WC_REST_Authentication {
|
|||
private function perform_oauth_authentication() {
|
||||
global $wc_rest_authentication_error;
|
||||
|
||||
$params = array( 'oauth_consumer_key', 'oauth_timestamp', 'oauth_nonce', 'oauth_signature', 'oauth_signature_method' );
|
||||
|
||||
// Check for required OAuth parameters.
|
||||
foreach ( $params as $param ) {
|
||||
if ( empty( $_GET[ $param ] ) ) {
|
||||
return false;
|
||||
}
|
||||
$params = $this->get_oauth_parameters();
|
||||
if ( empty( $params ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch WP user by consumer key
|
||||
$user = $this->get_user_data_by_consumer_key( $_GET['oauth_consumer_key'] );
|
||||
// Fetch WP user by consumer key.
|
||||
$user = $this->get_user_data_by_consumer_key( $params['oauth_consumer_key'] );
|
||||
|
||||
if ( empty( $user ) ) {
|
||||
$wc_rest_authentication_error = new WP_Error( 'woocommerce_rest_authentication_error', __( 'Consumer Key is invalid.', 'woocommerce' ), array( 'status' => 401 ) );
|
||||
|
@ -175,12 +298,12 @@ class WC_REST_Authentication {
|
|||
}
|
||||
|
||||
// Perform OAuth validation.
|
||||
$wc_rest_authentication_error = $this->check_oauth_signature( $user, $_GET );
|
||||
$wc_rest_authentication_error = $this->check_oauth_signature( $user, $params );
|
||||
if ( is_wp_error( $wc_rest_authentication_error ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$wc_rest_authentication_error = $this->check_oauth_timestamp_and_nonce( $user, $_GET['oauth_timestamp'], $_GET['oauth_nonce'] );
|
||||
$wc_rest_authentication_error = $this->check_oauth_timestamp_and_nonce( $user, $params['oauth_timestamp'], $params['oauth_nonce'] );
|
||||
if ( is_wp_error( $wc_rest_authentication_error ) ) {
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue