Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pressable-basic-authentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/*
Plugin Name: Hosting Basic Authentication
Description: Forces all users to authenticate using Basic Authentication before accessing any page.
Version: 1.0.1
Version: 1.0.2
License: GPL2
Text Domain: hosting-basic-authentication
*/
Expand Down
341 changes: 341 additions & 0 deletions pressable-basic-authentication/pressable-basic-authentication.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,341 @@
<?php
/**
* Hosting Basic Authentication
*
* @package HostingBasicAuthentication
*/

/*
Plugin Name: Hosting Basic Authentication
Description: Forces all users to authenticate using Basic Authentication before accessing any page.
Version: 1.0.2
License: GPL2
Text Domain: hosting-basic-authentication
*/

// If this file is called directly, abort.
if ( ! defined( 'ABSPATH' ) ) {
exit; // Prevent direct access
}

/**
* Main plugin class
*/
class Pressable_Basic_Auth {

/**
* Constructor
*/
public function __construct() {
// Hook into WordPress before anything is outputted.
add_action( 'plugins_loaded', array( $this, 'init' ), 1 );

// Add filter for logout URL.
add_filter( 'logout_url', array( $this, 'modify_logout_url' ), 10, 2 );

// Hook into login page early
add_action( 'login_init', array( $this, 'maybe_redirect_from_login_page' ), 0 );
}

/**
* Initialize the plugin
*/
public function init() {
// Skip if we're doing AJAX.
if ( $this->is_ajax_request() ) {
return;
}

// Skip if we're doing CRON.
if ( $this->is_cron_request() ) {
return;
}

// Skip if we're in CLI mode.
if ( $this->is_cli_request() ) {
return;
}

// Skip requests to excluded endpoints
if ($this->should_skip_auth()) {
return;
}

// Handle logout request.
if ( isset( $_GET['basic-auth-logout'] ) ) {
$this->handle_basic_auth_logout();
}
Comment on lines +65 to +67
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Add nonce validation for logout action.

The logout action triggered via GET parameter should be protected against CSRF attacks.

Consider implementing nonce validation:

 		// Handle logout request.
-		if ( isset( $_GET['basic-auth-logout'] ) ) {
+		if ( isset( $_GET['basic-auth-logout'] ) && isset( $_GET['_wpnonce'] ) && 
+		     wp_verify_nonce( $_GET['_wpnonce'], 'basic-auth-logout' ) ) {
 			$this->handle_basic_auth_logout();
 		}

And update the modify_logout_url method to include the nonce:

 	public function modify_logout_url( $logout_url, $redirect ) {
-		return add_query_arg( 'basic-auth-logout', '1', $logout_url );
+		$url = add_query_arg( 'basic-auth-logout', '1', $logout_url );
+		return wp_nonce_url( $url, 'basic-auth-logout' );
 	}

🏁 Script executed:

#!/bin/bash
# Locate all occurrences of the logout parameter and related methods
rg -n "basic-auth-logout" .
rg -n "function modify_logout_url" .
rg -n "wp_nonce_url" .
rg -n "wp_verify_nonce" .

Length of output: 802


Add nonce protection to the basic-auth logout action

To harden the logout endpoint against CSRF, we need to emit and verify a nonce:

• In pressable-basic-authentication/pressable-basic-authentication.php (line 65), update the GET check to verify the nonce before calling the handler
• In modify_logout_url (line 263), wrap the URL in a nonce

Proposed diff:

--- a/pressable-basic-authentication/pressable-basic-authentication.php
+++ b/pressable-basic-authentication/pressable-basic-authentication.php
@@ -62,7 +62,10 @@ class Pressable_Basic_Authentication {
 		// Handle logout request.
-		if ( isset( $_GET['basic-auth-logout'] ) ) {
+		if (
+			isset( $_GET['basic-auth-logout'], $_GET['_wpnonce'] )
+			&& wp_verify_nonce( $_GET['_wpnonce'], 'basic-auth-logout' )
+		) {
 			$this->handle_basic_auth_logout();
 		}
 
@@ -260,7 +263,10 @@ class Pressable_Basic_Authentication {
 	public function modify_logout_url( $logout_url, $redirect ) {
-		return add_query_arg( 'basic-auth-logout', '1', $logout_url );
+		// Add our flag and CSRF nonce to the logout URL.
+		$url = add_query_arg( 'basic-auth-logout', '1', $logout_url );
+		return wp_nonce_url( $url, 'basic-auth-logout' );
 	}
 }
🤖 Prompt for AI Agents
In pressable-basic-authentication/pressable-basic-authentication.php around
lines 65 to 67, add nonce verification to the basic-auth logout GET request by
checking the nonce before calling handle_basic_auth_logout. Then, in the
modify_logout_url function around line 263, update the logout URL to include a
nonce parameter generated with wp_nonce_url or a similar function. This will
protect the logout action from CSRF attacks by ensuring the request is valid.


// Redirect from wp-login.php when already authenticated via Basic Auth
$this->maybe_redirect_from_login_page();
Comment on lines +69 to +70
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove duplicate call to maybe_redirect_from_login_page().

This method is already hooked to login_init in the constructor (line 37). Calling it again here is redundant.

-		// Redirect from wp-login.php when already authenticated via Basic Auth
-		$this->maybe_redirect_from_login_page();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Redirect from wp-login.php when already authenticated via Basic Auth
$this->maybe_redirect_from_login_page();
🤖 Prompt for AI Agents
In pressable-basic-authentication/pressable-basic-authentication.php around
lines 69 to 70, remove the duplicate call to the method
maybe_redirect_from_login_page() since it is already hooked to the login_init
action in the constructor at line 37, making this explicit call redundant.


// Force authentication.
$this->force_basic_authentication();
}

/**
* Force Basic Authentication
*/
private function force_basic_authentication() {
// Prevent caching of authentication requests.
$this->prevent_caching();

// Extract credentials from headers.
$this->extract_basic_auth_credentials();

// Allow Super Admins to bypass authentication.
if ( is_multisite() && is_super_admin() ) {
return;
}

// Check if the user is already logged in.
if ( is_user_logged_in() ) {
return;
}

// Check for Basic Authentication credentials.
$auth_user = isset( $_SERVER['PHP_AUTH_USER'] ) ? sanitize_text_field( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) ) : null;
$auth_pass = isset( $_SERVER['PHP_AUTH_PW'] ) ? $_SERVER['PHP_AUTH_PW'] : null;

if ( ! $auth_user || ! $auth_pass ) {
$this->log_failed_auth( 'Missing credentials' );
$this->send_auth_headers();
}

// Validate credentials against WordPress users table.
$user = wp_authenticate( $auth_user, $auth_pass );
if ( is_wp_error( $user ) ) {
$this->log_failed_auth( "Invalid credentials for user: $auth_user" );
$this->send_auth_headers();
}

// Log the user in programmatically.
wp_set_current_user( $user->ID );
wp_set_auth_cookie( $user->ID );
}

/**
* Logs failed authentication attempts to the error log.
*
* @param string $message The message to log.
*/
private function log_failed_auth( $message ) {
error_log(
sprintf(
'[%s] Basic Auth Failed: %s',
gmdate( 'Y-m-d H:i:s' ),
$message
)
);
}

/**
* Check if the current request should skip authentication
*
* @return bool
*/
private function should_skip_auth() {
// List of endpoints to exclude from Basic Auth
$excluded_endpoints = array(
'xmlrpc.php',
'wp-json/jetpack',
'wp-json/wp/v2',
'wp-json/wp/v3'
);

// Get current request details
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
$script_name = $_SERVER['SCRIPT_NAME'] ?? '';

// Check if this is a direct xmlrpc.php request
if (basename($script_name) === 'xmlrpc.php') {
return true;
}

// Check all excluded endpoints
foreach ($excluded_endpoints as $endpoint) {
if (strpos($request_uri, $endpoint) !== false) {
return true;
}
}

// Check WordPress constants
if (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) {
return true;
}

if (defined('REST_REQUEST') && REST_REQUEST) {
return true;
}

return false;
}
Comment on lines +137 to +172
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Fix indentation and improve endpoint matching security.

  1. The entire method uses spaces instead of tabs
  2. Using strpos() for endpoint matching is insecure - it could match unintended paths
-    private function should_skip_auth() {
-        // List of endpoints to exclude from Basic Auth
-        $excluded_endpoints = array(
-            'xmlrpc.php',
-            'wp-json/jetpack',
-            'wp-json/wp/v2',
-            'wp-json/wp/v3'
-        );
-
-        // Get current request details
-        $request_uri = $_SERVER['REQUEST_URI'] ?? '';
-        $script_name = $_SERVER['SCRIPT_NAME'] ?? '';
-
-        // Check if this is a direct xmlrpc.php request
-        if (basename($script_name) === 'xmlrpc.php') {
-            return true;
-        }
-
-        // Check all excluded endpoints
-        foreach ($excluded_endpoints as $endpoint) {
-            if (strpos($request_uri, $endpoint) !== false) {
-                return true;
-            }
-        }
+	private function should_skip_auth() {
+		// List of endpoints to exclude from Basic Auth
+		$excluded_endpoints = array(
+			'xmlrpc.php',
+			'wp-json/jetpack',
+			'wp-json/wp/v2',
+			'wp-json/wp/v3'
+		);
+
+		// Get current request details
+		$request_uri = $_SERVER['REQUEST_URI'] ?? '';
+		$script_name = $_SERVER['SCRIPT_NAME'] ?? '';
+
+		// Check if this is a direct xmlrpc.php request
+		if ( basename( $script_name ) === 'xmlrpc.php' ) {
+			return true;
+		}
+
+		// Parse the request URI to get the path
+		$parsed_url = wp_parse_url( $request_uri );
+		$path = $parsed_url['path'] ?? '';
+
+		// Check all excluded endpoints
+		foreach ( $excluded_endpoints as $endpoint ) {
+			// Check if the path starts with or ends with the endpoint
+			if ( strpos( $path, '/' . $endpoint ) === 0 || 
+			     substr( $path, -strlen( $endpoint ) ) === $endpoint ) {
+				return true;
+			}
+		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private function should_skip_auth() {
// List of endpoints to exclude from Basic Auth
$excluded_endpoints = array(
'xmlrpc.php',
'wp-json/jetpack',
'wp-json/wp/v2',
'wp-json/wp/v3'
);
// Get current request details
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
$script_name = $_SERVER['SCRIPT_NAME'] ?? '';
// Check if this is a direct xmlrpc.php request
if (basename($script_name) === 'xmlrpc.php') {
return true;
}
// Check all excluded endpoints
foreach ($excluded_endpoints as $endpoint) {
if (strpos($request_uri, $endpoint) !== false) {
return true;
}
}
// Check WordPress constants
if (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) {
return true;
}
if (defined('REST_REQUEST') && REST_REQUEST) {
return true;
}
return false;
}
private function should_skip_auth() {
// List of endpoints to exclude from Basic Auth
$excluded_endpoints = array(
'xmlrpc.php',
'wp-json/jetpack',
'wp-json/wp/v2',
'wp-json/wp/v3'
);
// Get current request details
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
$script_name = $_SERVER['SCRIPT_NAME'] ?? '';
// Check if this is a direct xmlrpc.php request
if ( basename( $script_name ) === 'xmlrpc.php' ) {
return true;
}
// Parse the request URI to get the path
$parsed_url = wp_parse_url( $request_uri );
$path = $parsed_url['path'] ?? '';
// Check all excluded endpoints
foreach ( $excluded_endpoints as $endpoint ) {
// Check if the path starts with or ends with the endpoint
if ( strpos( $path, '/' . $endpoint ) === 0
|| substr( $path, -strlen( $endpoint ) ) === $endpoint
) {
return true;
}
}
// Check WordPress constants
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
return true;
}
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
return true;
}
return false;
}
🤖 Prompt for AI Agents
In pressable-basic-authentication/pressable-basic-authentication.php lines 137
to 172, fix the indentation by replacing spaces with tabs to match the project's
coding style. Replace the insecure strpos() checks for endpoint matching with a
more precise method such as using strict equality or regex to ensure only exact
or properly prefixed endpoints are matched, preventing unintended matches.


/**
* Sends authentication headers.
*/
private function send_auth_headers() {
header( 'WWW-Authenticate: Basic realm="Restricted Area"' );
header( 'HTTP/1.1 401 Unauthorized' );
echo '<h1>' . esc_html__( 'Authentication Required', 'pressable-basic-auth' ) . '</h1>';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix text domain inconsistency.

The text domain should match the one declared in the plugin header ('hosting-basic-authentication').

-		echo '<h1>' . esc_html__( 'Authentication Required', 'pressable-basic-auth' ) . '</h1>';
+		echo '<h1>' . esc_html__( 'Authentication Required', 'hosting-basic-authentication' ) . '</h1>';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo '<h1>' . esc_html__( 'Authentication Required', 'pressable-basic-auth' ) . '</h1>';
echo '<h1>' . esc_html__( 'Authentication Required', 'hosting-basic-authentication' ) . '</h1>';
🤖 Prompt for AI Agents
In pressable-basic-authentication/pressable-basic-authentication.php at line
180, the text domain used in esc_html__ is 'pressable-basic-auth' but it should
match the plugin header's text domain 'hosting-basic-authentication'. Update the
text domain string in esc_html__ to 'hosting-basic-authentication' to ensure
consistency.

exit;
}

/**
* Use getallheaders() for Servers That Strip Authorization Headers
*/
private function extract_basic_auth_credentials() {
if ( ! empty( $_SERVER['PHP_AUTH_USER'] ) && ! empty( $_SERVER['PHP_AUTH_PW'] ) ) {
return;
}

// Attempt to fetch credentials from Authorization header.
$auth_header = $this->get_authorization_header();

if ( ! $auth_header ) {
return;
}

if ( 0 === stripos( $auth_header, 'basic ' ) ) {
$auth_encoded = substr( $auth_header, 6 );
$auth_decoded = base64_decode( $auth_encoded );
if ( $auth_decoded && strpos( $auth_decoded, ':' ) !== false ) {
list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode( ':', $auth_decoded, 2 );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid direct modification of $_SERVER superglobal.

Directly modifying $_SERVER variables can lead to unexpected behavior and makes the code harder to test.

Consider storing extracted credentials in class properties instead:

+	private $extracted_user = null;
+	private $extracted_pass = null;

 	private function extract_basic_auth_credentials() {
 		if ( ! empty( $_SERVER['PHP_AUTH_USER'] ) && ! empty( $_SERVER['PHP_AUTH_PW'] ) ) {
 			return;
 		}
 		// ... existing code ...
 		if ( 0 === stripos( $auth_header, 'basic ' ) ) {
 			$auth_encoded = substr( $auth_header, 6 );
 			$auth_decoded = base64_decode( $auth_encoded );
 			if ( $auth_decoded && strpos( $auth_decoded, ':' ) !== false ) {
-				list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode( ':', $auth_decoded, 2 );
+				list( $this->extracted_user, $this->extracted_pass ) = explode( ':', $auth_decoded, 2 );
 			}
 		}
 	}

Then update the authentication check to use these properties alongside the $_SERVER values.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode( ':', $auth_decoded, 2 );
private $extracted_user = null;
private $extracted_pass = null;
private function extract_basic_auth_credentials() {
if ( ! empty( $_SERVER['PHP_AUTH_USER'] ) && ! empty( $_SERVER['PHP_AUTH_PW'] ) ) {
return;
}
// ... existing code ...
if ( 0 === stripos( $auth_header, 'basic ' ) ) {
$auth_encoded = substr( $auth_header, 6 );
$auth_decoded = base64_decode( $auth_encoded );
if ( $auth_decoded && strpos( $auth_decoded, ':' ) !== false ) {
list( $this->extracted_user, $this->extracted_pass ) = explode( ':', $auth_decoded, 2 );
}
}
}
🤖 Prompt for AI Agents
In pressable-basic-authentication/pressable-basic-authentication.php at line
203, avoid directly modifying the $_SERVER superglobal by not assigning the
exploded credentials back to $_SERVER['PHP_AUTH_USER'] and
$_SERVER['PHP_AUTH_PW']. Instead, extract the username and password from
$auth_decoded and store them in dedicated class properties. Then update any
authentication logic to use these new properties while preserving the original
$_SERVER values.

}
}
}

/**
* Get the authorization header
*
* @return string|null The authorization header value or null
*/
private function get_authorization_header() {
if ( function_exists( 'getallheaders' ) ) {
$headers = getallheaders();

// Check for Authorization header (case-insensitive).
foreach ( $headers as $key => $value ) {
if ( strtolower( $key ) === 'authorization' ) {
return $value;
}
}
}

// Try common alternative locations.
if ( isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
return wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] );
} elseif ( isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) {
return wp_unslash( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] );
}

return null;
}

/**
* Handles Basic Auth logout by forcing a 401 response and then redirecting.
*/
private function handle_basic_auth_logout() {
wp_logout(); // Log out from WordPress.

// Clear Basic Auth credentials by forcing a 401.
header( 'WWW-Authenticate: Basic realm="Restricted Area"' );
header( 'HTTP/1.1 401 Unauthorized' );

// Output a JavaScript-based redirect after the 401 response.
echo '<script>
setTimeout(function() {
window.location.href = "' . esc_url( home_url() ) . '";
}, 1000);
</script>';

// End execution to prevent further processing.
exit;
}

/**
* Modifies the default WordPress logout URL to trigger Basic Auth logout.
*
* @param string $logout_url The WordPress logout URL.
* @param string $redirect The redirect URL after logout.
* @return string Modified logout URL
*/
public function modify_logout_url( $logout_url, $redirect ) {
return add_query_arg( 'basic-auth-logout', '1', $logout_url );
}

/**
* Redirects from wp-login.php to home page when user is already authenticated via Basic Auth
*/
public function maybe_redirect_from_login_page() {
global $pagenow;

// Check if we're on the login page and have Basic Auth credentials
if ( 'wp-login.php' === $pagenow &&
! empty( $_SERVER['PHP_AUTH_USER'] ) &&
! empty( $_SERVER['PHP_AUTH_PW'] ) &&
! isset( $_GET['action'] ) &&
! isset( $_GET['loggedout'] ) &&
! isset( $_POST['log'] ) ) {

// Get appropriate home URL for either multisite or regular WordPress
if ( is_multisite() ) {
$redirect_url = network_home_url();

// If we can determine the current blog, go to its home instead
if ( isset( $_SERVER['HTTP_HOST'] ) ) {
$blog_details = get_blog_details( array( 'domain' => $_SERVER['HTTP_HOST'] ) );
if ( $blog_details ) {
$redirect_url = get_home_url( $blog_details->blog_id );
}
}
Comment on lines +286 to +291
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Validate HTTP_HOST before using in get_blog_details.

Using $_SERVER['HTTP_HOST'] directly without validation could lead to host header injection attacks.

 				// If we can determine the current blog, go to its home instead
 				if ( isset( $_SERVER['HTTP_HOST'] ) ) {
-					$blog_details = get_blog_details( array( 'domain' => $_SERVER['HTTP_HOST'] ) );
+					$host = sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) );
+					// Remove port if present
+					$host = preg_replace( '/:\d+$/', '', $host );
+					$blog_details = get_blog_details( array( 'domain' => $host ) );
 					if ( $blog_details ) {
 						$redirect_url = get_home_url( $blog_details->blog_id );
 					}
 				}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ( isset( $_SERVER['HTTP_HOST'] ) ) {
$blog_details = get_blog_details( array( 'domain' => $_SERVER['HTTP_HOST'] ) );
if ( $blog_details ) {
$redirect_url = get_home_url( $blog_details->blog_id );
}
}
// If we can determine the current blog, go to its home instead
if ( isset( $_SERVER['HTTP_HOST'] ) ) {
$host = sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) );
// Remove port if present
$host = preg_replace( '/:\d+$/', '', $host );
$blog_details = get_blog_details( array( 'domain' => $host ) );
if ( $blog_details ) {
$redirect_url = get_home_url( $blog_details->blog_id );
}
}
🤖 Prompt for AI Agents
In pressable-basic-authentication/pressable-basic-authentication.php around
lines 286 to 291, $_SERVER['HTTP_HOST'] is used directly without validation,
which risks host header injection. Before passing it to get_blog_details,
validate that HTTP_HOST contains only expected characters (e.g., alphanumeric,
dots, and hyphens) and reject or sanitize any suspicious input. This ensures
safe usage and prevents injection attacks.

} else {
$redirect_url = home_url();
}

// Safe redirect
wp_safe_redirect( $redirect_url );
exit;
}
}

/**
* Prevent caching of authentication requests
*/
private function prevent_caching() {
header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
header( 'Pragma: no-cache' );
header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
}

/**
* Check if the current request is an AJAX request
*
* @return bool
*/
private function is_ajax_request() {
return ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ||
( ! empty( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && 'xmlhttprequest' === strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) );
}

/**
* Check if the current request is a cron request
*
* @return bool
*/
private function is_cron_request() {
return defined( 'DOING_CRON' ) && DOING_CRON;
}

/**
* Check if the current request is a CLI request
*
* @return bool
*/
private function is_cli_request() {
return ( 'cli' === php_sapi_name() || ( defined( 'WP_CLI' ) && WP_CLI ) );
}
}

// Initialize the plugin.
new Pressable_Basic_Auth();
43 changes: 43 additions & 0 deletions pressable-basic-authentication/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
=== Pressable Basic Authentication ===
Contributors: pressable
Tags: pressable, basic auth, authentication, security
Requires at least: 6.7
Tested up to: 6.8
Requires PHP: 8.1
Stable tag: 1.0.2
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

== Description ==

The Pressable Basic Authentication plugin enforces HTTP Basic Authentication across your WordPress site, requiring users to authenticate before accessing any page. This is particularly useful for development environments, ensuring that only authorized users can view or interact with the site during development or testing phases.​

== FEATURES ==​

* Enforces HTTP Basic Authentication on all front-end and back-end pages.
* Installed on sites to restrict public access.
* Allows super administrators to bypass authentication for seamless management.
* Integrates with WordPress's authentication system for user verification.
* Provides a mechanism to log out of Basic Authentication sessions.​

== Frequently Asked Questions ==​

= How do I use this plugin? =​

No manual configuration is required. When accessing a protected site, you'll be prompted to enter your WordPress credentials.​

= Can I disable Basic Authentication on my site? =​

Basic Authentication is enforced on sites to protect your site during development. To remove this protection, you can promote your site to a live environment through the MyPressable Control Panel.​

= What credentials should I use to authenticate? =​

Use your WordPress username and password associated with the site. Ensure that your user account has the necessary permissions to access the site.​

== Installation ==​

No manual installation is necessary.​

== Screenshots ==​

* Initial release​
Loading