From 35d974fb04e08abb5200917cf3c7fed2ba5c7843 Mon Sep 17 00:00:00 2001 From: Graham May Date: Mon, 21 Mar 2016 11:22:54 +0000 Subject: [PATCH 1/6] Fixed PHP Fast CGI issue where PHP_AUTH_USER and PHP_AUTH_PW headers are not set --- basic-auth.php | 91 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/basic-auth.php b/basic-auth.php index 805918c..cffe50d 100644 --- a/basic-auth.php +++ b/basic-auth.php @@ -8,55 +8,72 @@ * Plugin URI: https://github.com/WP-API/Basic-Auth */ -function json_basic_auth_handler( $user ) { - global $wp_json_basic_auth_error; +function json_basic_auth_handler($user) +{ - $wp_json_basic_auth_error = null; + global $wp_json_basic_auth_error; - // Don't authenticate twice - if ( ! empty( $user ) ) { - return $user; - } + $wp_json_basic_auth_error = null; - // Check that we're trying to authenticate - if ( !isset( $_SERVER['PHP_AUTH_USER'] ) ) { - return $user; - } + // Don't authenticate twice + if (!empty($user)) { + return $user; + } - $username = $_SERVER['PHP_AUTH_USER']; - $password = $_SERVER['PHP_AUTH_PW']; + if (!isset($_SERVER['PHP_AUTH_USER']) && (isset($_SERVER['HTTP_AUTHORIZATION']) || isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))) { + if (isset($_SERVER['HTTP_AUTHORIZATION'])) { + $header = $_SERVER['HTTP_AUTHORIZATION']; + } else { + $header = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } - /** - * 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', 'json_basic_auth_handler', 20 ); + list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($header, 6))); + } - $user = wp_authenticate( $username, $password ); + // Check that we're trying to authenticate + if (!isset($_SERVER['PHP_AUTH_USER'])) { + return $user; + } - add_filter( 'determine_current_user', 'json_basic_auth_handler', 20 ); + $username = $_SERVER['PHP_AUTH_USER']; + $password = $_SERVER['PHP_AUTH_PW']; - if ( is_wp_error( $user ) ) { - $wp_json_basic_auth_error = $user; - return null; - } + /** + * 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', 'json_basic_auth_handler', 20); - $wp_json_basic_auth_error = true; + $user = wp_authenticate($username, $password); - return $user->ID; + add_filter('determine_current_user', 'json_basic_auth_handler', 20); + + if (is_wp_error($user)) { + $wp_json_basic_auth_error = $user; + + return null; + } + + $wp_json_basic_auth_error = true; + + return $user->ID; } -add_filter( 'determine_current_user', 'json_basic_auth_handler', 20 ); -function json_basic_auth_error( $error ) { - // Passthrough other errors - if ( ! empty( $error ) ) { - return $error; - } +add_filter('determine_current_user', 'json_basic_auth_handler', 20); - global $wp_json_basic_auth_error; +function json_basic_auth_error($error) +{ - return $wp_json_basic_auth_error; + // Passthrough other errors + if (!empty($error)) { + return $error; + } + + global $wp_json_basic_auth_error; + + return $wp_json_basic_auth_error; } -add_filter( 'json_authentication_errors', 'json_basic_auth_error' ); + +add_filter('json_authentication_errors', 'json_basic_auth_error'); From 4ddbb3a1484767102726d87181299da339a18f48 Mon Sep 17 00:00:00 2001 From: Graham May Date: Mon, 21 Mar 2016 11:25:21 +0000 Subject: [PATCH 2/6] Formatting changed to match original repo --- basic-auth.php | 83 +++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/basic-auth.php b/basic-auth.php index cffe50d..a03651c 100644 --- a/basic-auth.php +++ b/basic-auth.php @@ -8,17 +8,15 @@ * Plugin URI: https://github.com/WP-API/Basic-Auth */ -function json_basic_auth_handler($user) -{ +function json_basic_auth_handler( $user ) { + global $wp_json_basic_auth_error; - global $wp_json_basic_auth_error; + $wp_json_basic_auth_error = null; - $wp_json_basic_auth_error = null; - - // Don't authenticate twice - if (!empty($user)) { - return $user; - } + // Don't authenticate twice + if ( ! empty( $user ) ) { + return $user; + } if (!isset($_SERVER['PHP_AUTH_USER']) && (isset($_SERVER['HTTP_AUTHORIZATION']) || isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))) { if (isset($_SERVER['HTTP_AUTHORIZATION'])) { @@ -29,51 +27,46 @@ function json_basic_auth_handler($user) list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($header, 6))); } + + // Check that we're trying to authenticate + if ( !isset( $_SERVER['PHP_AUTH_USER'] ) ) { + return $user; + } - // Check that we're trying to authenticate - if (!isset($_SERVER['PHP_AUTH_USER'])) { - return $user; - } - - $username = $_SERVER['PHP_AUTH_USER']; - $password = $_SERVER['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', 'json_basic_auth_handler', 20); + $username = $_SERVER['PHP_AUTH_USER']; + $password = $_SERVER['PHP_AUTH_PW']; - $user = wp_authenticate($username, $password); + /** + * 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', 'json_basic_auth_handler', 20 ); - add_filter('determine_current_user', 'json_basic_auth_handler', 20); + $user = wp_authenticate( $username, $password ); - if (is_wp_error($user)) { - $wp_json_basic_auth_error = $user; + add_filter( 'determine_current_user', 'json_basic_auth_handler', 20 ); - return null; - } + if ( is_wp_error( $user ) ) { + $wp_json_basic_auth_error = $user; + return null; + } - $wp_json_basic_auth_error = true; + $wp_json_basic_auth_error = true; - return $user->ID; + return $user->ID; } +add_filter( 'determine_current_user', 'json_basic_auth_handler', 20 ); -add_filter('determine_current_user', 'json_basic_auth_handler', 20); - -function json_basic_auth_error($error) -{ +function json_basic_auth_error( $error ) { + // Passthrough other errors + if ( ! empty( $error ) ) { + return $error; + } - // Passthrough other errors - if (!empty($error)) { - return $error; - } + global $wp_json_basic_auth_error; - global $wp_json_basic_auth_error; - - return $wp_json_basic_auth_error; + return $wp_json_basic_auth_error; } - -add_filter('json_authentication_errors', 'json_basic_auth_error'); +add_filter( 'json_authentication_errors', 'json_basic_auth_error' ); From c6932183fb7faa7779f7ab8d26f342af80d77ebf Mon Sep 17 00:00:00 2001 From: Graham May Date: Mon, 21 Mar 2016 11:33:36 +0000 Subject: [PATCH 3/6] Wrapped list() in !empty --- basic-auth.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/basic-auth.php b/basic-auth.php index a03651c..37abc25 100644 --- a/basic-auth.php +++ b/basic-auth.php @@ -18,14 +18,16 @@ function json_basic_auth_handler( $user ) { return $user; } - if (!isset($_SERVER['PHP_AUTH_USER']) && (isset($_SERVER['HTTP_AUTHORIZATION']) || isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))) { - if (isset($_SERVER['HTTP_AUTHORIZATION'])) { + if ( !isset( $_SERVER['PHP_AUTH_USER'] ) && ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) || isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) ) { + if ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { $header = $_SERVER['HTTP_AUTHORIZATION']; } else { $header = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } - list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($header, 6))); + if ( !empty( $header ) ) { + list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode( ':', base64_decode(substr( $header, 6 ) ) ); + } } // Check that we're trying to authenticate From c1a5e9524ea9107aadcf5dfdc04d45b32240d76c Mon Sep 17 00:00:00 2001 From: graham73may Date: Sat, 30 Jun 2018 17:15:27 +0100 Subject: [PATCH 4/6] Update README.md --- README.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/README.md b/README.md index fbbabc1..039ee6a 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,63 @@ $args = array( [oauth]: https://github.com/WP-API/OAuth1 [RFC2617]: https://tools.ietf.org/html/rfc2617 + +--- + +## Forcing all API requests to require authorisation + +A few notes on making this work on servers with php-cgi. + +### .htaccess +If you're using php-cgi you'll need to tweak the .htaccess file slightly. (more info about the issue: https://github.com/LearningLocker/learninglocker/issues/131) + +Change the Wordpress block in .htaccess in the root folder to: + +``` +# BEGIN WordPress + +RewriteEngine On +RewriteBase / +RewriteRule ^index\.php$ - [L] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . /index.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] + + +# END WordPress +``` + +Then you'll want to stop Wordpress from overwriting this if you save permalinks. + +Add this to your functions.php file: (You'll still be able to update your permalinks don't worry...) + +``` +// Stop WordPress from modifying .htaccess permalink rules +add_filter('flush_rewrite_rules_hard','__return_false'); +``` + +### Check for authorisation + +Now we're able to get the right headers when running php-cgi, add this to your functions.php file: + +What we're doing here is returning the result if they are logging in, or returning an error if they are not logged in. + +``` +// Check user is logged in before returning API results +add_filter('rest_pre_dispatch', function ($result) { + + global $DI; + + if (is_user_logged_in()) { + return $result; + } else { + return [ + 'error_code' => 'rest_requires_authentication', + 'message' => 'Using REST requires authentication.', + 'status' => '403' + ]; + } +}); + + +``` From 137db375645a44a31d7dea59da5156ed982dbccb Mon Sep 17 00:00:00 2001 From: Graham May Date: Wed, 27 Nov 2024 12:57:38 +0000 Subject: [PATCH 5/6] Applying code changes from Tug --- basic-auth.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/basic-auth.php b/basic-auth.php index 37abc25..514f801 100644 --- a/basic-auth.php +++ b/basic-auth.php @@ -18,20 +18,20 @@ function json_basic_auth_handler( $user ) { return $user; } - if ( !isset( $_SERVER['PHP_AUTH_USER'] ) && ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) || isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) ) { + if ( ! isset( $_SERVER['PHP_AUTH_USER'] ) && ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) || isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) ) { if ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { - $header = $_SERVER['HTTP_AUTHORIZATION']; + $authorization_header = $_SERVER['HTTP_AUTHORIZATION']; } else { - $header = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + $authorization_header = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; } - if ( !empty( $header ) ) { - list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode( ':', base64_decode(substr( $header, 6 ) ) ); + if ( 'Basic ' === substr( $authorization_header, 0, 6 ) ) { + list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode( ':', base64_decode( substr( $authorization_header, 6 ) ), 2 ); } } - + // Check that we're trying to authenticate - if ( !isset( $_SERVER['PHP_AUTH_USER'] ) ) { + if ( ! isset( $_SERVER['PHP_AUTH_USER'] ) ) { return $user; } From e9074d016fe7c0103f900e5552bb4b5d6783e1d6 Mon Sep 17 00:00:00 2001 From: Graham May Date: Wed, 27 Nov 2024 13:01:39 +0000 Subject: [PATCH 6/6] Applying code changes from Tug --- README.md | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 65ac360..e71cad1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Basic Authentication handler + This plugin adds Basic Authentication to a WordPress site. Note that this plugin requires sending your username and password with every @@ -7,10 +8,12 @@ development and testing. Without SSL we strongly recommend using the [OAuth 1.0a][oauth] authentication handler in production environments. ## Installing + 1. Download the plugin into your plugins directory 2. Enable in the WordPress admin ## Using + This plugin adds support for Basic Authentication, as specified in [RFC2617][]. Most HTTP clients will allow you to use this authentication natively. Some examples are listed below. @@ -35,7 +38,7 @@ $args = array( ```js const WPAPI = require('./wpapi') -const wp = new WPAPI({ +const wp = new WPAPI({ endpoint: 'https://example.com/wp-json', username: 'editor', password: 'password' @@ -43,7 +46,9 @@ const wp = new WPAPI({ ``` [oauth]: https://github.com/WP-API/OAuth1 + [RFC2617]: https://tools.ietf.org/html/rfc2617 + [node-wpapi]: http://wp-api.org/node-wpapi/ --- @@ -53,9 +58,10 @@ const wp = new WPAPI({ A few notes on making this work on servers with php-cgi. ### .htaccess + If you're using php-cgi you'll need to tweak the .htaccess file slightly. (more info about the issue: https://github.com/LearningLocker/learninglocker/issues/131) -Change the Wordpress block in .htaccess in the root folder to: +Change the WordPress block in .htaccess in the root folder to: ``` # BEGIN WordPress @@ -71,7 +77,7 @@ RewriteRule . /index.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] # END WordPress ``` -Then you'll want to stop Wordpress from overwriting this if you save permalinks. +Then you'll want to stop WordPress from overwriting this if you save permalinks. Add this to your functions.php file: (You'll still be able to update your permalinks don't worry...) @@ -79,29 +85,3 @@ Add this to your functions.php file: (You'll still be able to update your permal // Stop WordPress from modifying .htaccess permalink rules add_filter('flush_rewrite_rules_hard','__return_false'); ``` - -### Check for authorisation - -Now we're able to get the right headers when running php-cgi, add this to your functions.php file: - -What we're doing here is returning the result if they are logging in, or returning an error if they are not logged in. - -``` -// Check user is logged in before returning API results -add_filter('rest_pre_dispatch', function ($result) { - - global $DI; - - if (is_user_logged_in()) { - return $result; - } else { - return [ - 'error_code' => 'rest_requires_authentication', - 'message' => 'Using REST requires authentication.', - 'status' => '403' - ]; - } -}); - - -```