Hey,
I’ve been using this awesome plugin lately while developing a custom endpoint in the API for a WooCommerce based site, and discovered that it prevents basic authentication to working using the WooCommerce consumer key/secret (as the username/password combination) , which is possible when this plugin is disabled.
To overcome that, I opted to edit the swaggerauth.php and updated the login handler to also try authentication using consumer key/secret method, similar to how the original woocommerce/includes/class-wc-rest-authentication.php file does this.
Here’s how the updated swaggerauth.php file looked:
<?php
class SwaggerAuth {
private $error = null;
// woocommerce/includes/class-wc-rest-authentication.php -> get_user_data_by_consumer_key function
private function get_user_data_by_consumer_key( $consumer_key ) {
global $wpdb;
$consumer_key = wc_api_hash( sanitize_text_field( $consumer_key ) );
$user = $wpdb->get_row(
$wpdb->prepare(
"
SELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces
FROM {$wpdb->prefix}woocommerce_api_keys
WHERE consumer_key = %s
",
$consumer_key
)
);
return $user;
}
public function handler( $user_id ) {
// Don't authenticate twice
if ( ! empty( $user_id ) ) {
return $user_id;
}
$server = new SwaggerBag( $_SERVER );
// Check that we're trying to authenticate
if ( ! $server->has( 'PHP_AUTH_USER' ) ) {
$user_pass = $server->get( 'REDIRECT_HTTP_AUTHORIZATION' );
if ( $server->has( 'REDIRECT_HTTP_AUTHORIZATION' ) && ! empty( $user_pass ) ) {
list($username, $password) = explode( ':', base64_decode( substr( $user_pass, 6 ) ) );
$server->set( 'PHP_AUTH_USER', $username );
$server->set( 'PHP_AUTH_PW', $password );
} else {
return $user_id;
}
}
$username = $server->get( 'PHP_AUTH_USER' );
$password = $server->get( 'PHP_AUTH_PW' );
/**
* In multi-site, wp_authenticate_spam_check filter is run on authentication. This filter calls
* get_currentuserinfo which in turn calls the determine_current_user filter. This leads to infinite
* recursion and a stack overflow unless the current function is removed from the determine_current_user
* filter during authentication.
*/
remove_filter( 'determine_current_user', [ $this, 'handler' ], 20 );
$user = wp_authenticate( $username, $password );
add_filter( 'determine_current_user', [ $this, 'handler' ], 20 );
if ( is_wp_error( $user ) ) {
// If WooCommerce enabled, try using consumer key/secret to authenticate
if (class_exists( 'woocommerce' )) {
$this->user = $this->get_user_data_by_consumer_key( $username );
if ( empty( $this->user ) ) {
$this->error = $user;
return null;
}
// Validate user secret.
if ( ! hash_equals( $this->user->consumer_secret, $password ) ) { // @codingStandardsIgnoreLine
$this->error = $user;
return null;
}
} else {
$this->error = $user;
return null;
}
}
$this->error = true;
return $user->ID;
}
public function error( $error ) {
if ( ! empty( $error ) ) {
return $error;
}
return $this->error;
}
public function appendSwaggerAuth( $auth ) {
if ( ! is_array( $auth ) ) {
$auth = [];
}
$auth['basic'] = array(
'type' => 'basic'
);
return $auth;
}
}
$basic = new SwaggerAuth();
add_filter( 'determine_current_user', [ $basic, 'handler' ] );
add_filter( 'rest_authentication_errors', [ $basic, 'error' ] );
add_filter( 'swagger_api_security_definitions', [ $basic, 'appendSwaggerAuth' ] );
You can also view a gist of this here: https://gist.github.com/ouija/0d111feed63bfaa118a0d3ecd20666d0
Hope this helps anyone else looking to achieve something similar.