-
Notifications
You must be signed in to change notification settings - Fork 1
Johnluke/eng 3302 critical error pressable basic authentication plugin and php #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughA new WordPress plugin, "Pressable Basic Authentication," has been introduced to enforce HTTP Basic Authentication across all site pages. Supporting documentation was added, and version numbers were incremented in existing plugin and readme files. No other functional or code logic changes were made to previously existing files. Changes
Sequence Diagram(s)sequenceDiagram
participant Visitor
participant WebServer
participant WP_Core as WordPress Core
participant BasicAuth as Pressable_Basic_Auth
Visitor->>WebServer: Request page
WebServer->>WP_Core: Pass request
WP_Core->>BasicAuth: Init plugin
BasicAuth->>BasicAuth: Check if request should skip auth
alt Should authenticate
BasicAuth->>Visitor: Request Basic Auth credentials (401)
Visitor->>WebServer: Resend with credentials
WebServer->>BasicAuth: Pass credentials
BasicAuth->>WP_Core: Validate credentials
alt Credentials valid
BasicAuth->>WP_Core: Log in user
WP_Core->>Visitor: Serve requested page
else Credentials invalid
BasicAuth->>Visitor: 401 Unauthorized
end
else Skip authentication
WP_Core->>Visitor: Serve requested page
end
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (3)
pressable-basic-authentication/pressable-basic-authentication.php (3)
9-9: Consider aligning plugin name with Pressable branding.The plugin name "Hosting Basic Authentication" and text domain "hosting-basic-authentication" don't match the "Pressable" branding used throughout the code and documentation.
Also applies to: 13-13
60-62: Fix indentation to use tabs.These lines use spaces instead of tabs, inconsistent with WordPress coding standards.
- if ($this->should_skip_auth()) { - return; - } + if ( $this->should_skip_auth() ) { + return; + }
245-250: Add fallback for JavaScript redirect.The JavaScript redirect might not execute if the browser immediately shows an auth dialog after the 401 response.
// Output a JavaScript-based redirect after the 401 response. echo '<script> setTimeout(function() { window.location.href = "' . esc_url( home_url() ) . '"; }, 1000); - </script>'; + </script>'; + echo '<noscript><meta http-equiv="refresh" content="2;url=' . esc_url( home_url() ) . '"></noscript>'; + echo '<p><a href="' . esc_url( home_url() ) . '">' . esc_html__( 'Click here if you are not redirected automatically.', 'hosting-basic-authentication' ) . '</a></p>';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
pressable-basic-authentication.php(1 hunks)pressable-basic-authentication/pressable-basic-authentication.php(1 hunks)pressable-basic-authentication/readme.txt(1 hunks)readme.txt(1 hunks)
🧰 Additional context used
🪛 LanguageTool
pressable-basic-authentication/readme.txt
[grammar] ~43-~43: Ensure spelling is correct
Context: ...essary. == Screenshots == * Initial release
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 PHPMD (2.15.0)
pressable-basic-authentication/pressable-basic-authentication.php
263-263: Avoid unused parameters such as '$redirect'. (Unused Code Rules)
(UnusedFormalParameter)
🔇 Additional comments (3)
pressable-basic-authentication.php (1)
11-11: Version update looks good.The version bump from 1.0.1 to 1.0.2 is correctly applied.
readme.txt (1)
7-7: Stable tag update is consistent.The stable tag correctly matches the plugin version 1.0.2.
pressable-basic-authentication/readme.txt (1)
1-43: Plugin documentation is well-structured.The readme file provides comprehensive information about the plugin's features, usage, and installation.
| 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>'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| // Redirect from wp-login.php when already authenticated via Basic Auth | ||
| $this->maybe_redirect_from_login_page(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| // 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.
| 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 ); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| $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 ); |
There was a problem hiding this comment.
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.
| 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.
| 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; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix indentation and improve endpoint matching security.
- The entire method uses spaces instead of tabs
- 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.
| 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.
| if ( isset( $_GET['basic-auth-logout'] ) ) { | ||
| $this->handle_basic_auth_logout(); | ||
| } |
There was a problem hiding this comment.
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.
Summary by CodeRabbit
New Features
Documentation
Chores