Allow oAuth1.0a authentication using headers

This commit is contained in:
Claudio Sanches 2016-08-22 17:39:41 -03:00
parent 7a0c5bc19b
commit eb55096a32
1 changed files with 134 additions and 11 deletions

View File

@ -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;
}