diff --git a/README.md b/README.md index 1e0090f..d8f2d19 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Authenticate WordPress user via json web token from Laravel Application. - Admin settings page - Custom invalid token page - Optional debug mode with full exception details and stack traces +- Configurable role for users created through Mahak authentication Debug mode is disabled by default. An administrator can enable it from **Settings > Mahak Authentication** while troubleshooting. The debug page includes server clock/timezone data, safe JWT timing claims, and a Copy Markdown report. JWT contents, secrets, request parameters, and stack-trace arguments are omitted. Because diagnostic pages still expose server paths and other technical details to visitors of the login URL, disable it again after diagnosing the problem. @@ -16,7 +17,9 @@ Debug mode is disabled by default. An administrator can enable it from **Setting Administrators can check for and install published releases from **Settings > Mahak Authentication**. Updates also appear in WordPress's standard **Plugins** and **Updates** screens. -To publish an update, change the plugin `Version` header and `MAHAK_AUTHENTICATE_BRIDGE_VERSION` constant to the same version, commit the change, and push a matching tag such as `v2.3.0` to Mahgit. The Gitea Actions workflow builds and attaches the ZIP required by the WordPress updater. +The **New user role** setting defaults to WordPress Default, using the site's current global new-user role without changing it. Administrators can select a different role only for accounts created by this plugin; existing users keep their current roles. + +To publish an update, change the plugin `Version` header and `MAHAK_AUTHENTICATE_BRIDGE_VERSION` constant to the same version, commit the change, and push a matching tag such as `v2.4.0` to Mahgit. The Gitea Actions workflow builds and attaches the ZIP required by the WordPress updater. ## Usage diff --git a/dabestaniha-authenticate-bridge.php b/dabestaniha-authenticate-bridge.php index 6135bca..c3a26cd 100644 --- a/dabestaniha-authenticate-bridge.php +++ b/dabestaniha-authenticate-bridge.php @@ -4,7 +4,7 @@ * Plugin Name: Mahak Authenticate Bridge * Plugin URI: https://mahgit.ir/dabestaniha/mahak-authenticate-bridge * Description: Authenticate WordPress user via json web token from Mahakiha Application. - * Version: 2.2.3 + * Version: 2.3.1 * Requires PHP: 7.4 * Update URI: https://mahgit.ir/dabestaniha/mahak-authenticate-bridge * Author: Dabestaniha @@ -18,7 +18,7 @@ use Dabestaniha\AuthenticateBridge\App\Http\Controllers\SettingsPageMenuControll use Dabestaniha\AuthenticateBridge\App\Http\Controllers\SettingsPageFormController; use Dabestaniha\AuthenticateBridge\App\Support\PluginUpdater; -define('MAHAK_AUTHENTICATE_BRIDGE_VERSION', '2.2.3'); +define('MAHAK_AUTHENTICATE_BRIDGE_VERSION', '2.3.1'); define('MAHAK_AUTHENTICATE_BRIDGE_FILE', __FILE__); require_once __DIR__.'/src/Autoloader.php'; diff --git a/src/app/Http/Controllers/AuthenticateController.php b/src/app/Http/Controllers/AuthenticateController.php index 88b94ec..9fdb07d 100644 --- a/src/app/Http/Controllers/AuthenticateController.php +++ b/src/app/Http/Controllers/AuthenticateController.php @@ -64,7 +64,20 @@ class AuthenticateController extends InvocableController $username .= '_'.wp_generate_password(4, false); } - $user_id = wp_create_user($username, $random_password, $email); + $configured_role = sanitize_key((string) get_configured_option('new-user-role', 'wordpress_default')); + + if ($configured_role === 'wordpress_default') { + $configured_role = sanitize_key((string) get_option('default_role', 'subscriber')); + } + + $role = get_role($configured_role) === null ? 'subscriber' : $configured_role; + $user_id = wp_insert_user([ + 'user_login' => $username, + 'user_pass' => $random_password, + 'user_email' => $email, + 'display_name' => $name, + 'role' => $role, + ]); if (is_wp_error($user_id)) { throw new RuntimeException( @@ -72,16 +85,8 @@ class AuthenticateController extends InvocableController ); } - $updated_user_id = wp_update_user([ - 'ID' => $user_id, - 'display_name' => $name, - ]); - - if (is_wp_error($updated_user_id)) { - throw new RuntimeException( - 'WordPress could not update the user: '.$updated_user_id->get_error_message() - ); - } + // Enforce the configured role after user_register callbacks from other plugins have completed. + (new \WP_User($user_id))->set_role($role); return $user_id; } diff --git a/src/app/Http/Controllers/SettingsPageFormController.php b/src/app/Http/Controllers/SettingsPageFormController.php index c784a0c..4fba413 100644 --- a/src/app/Http/Controllers/SettingsPageFormController.php +++ b/src/app/Http/Controllers/SettingsPageFormController.php @@ -14,6 +14,9 @@ class SettingsPageFormController extends InvocableController return (int) filter_var($value, FILTER_VALIDATE_BOOLEAN); }; $args['default'] = 0; + } elseif ($configured === 'new-user-role') { + $args['sanitize_callback'] = fn ($value): string => $this->sanitize_new_user_role($value); + $args['default'] = 'wordpress_default'; } register_setting(config('mahak.settings-group'), $options_key, $args); @@ -58,6 +61,14 @@ class SettingsPageFormController extends InvocableController config('mahak.section-id') ); + add_settings_field( + config('mahak.options.new-user-role'), + config('mahak.translations.new-user-role'), + fn () => $this->new_user_role(), + config('mahak.settings-page'), + config('mahak.section-id') + ); + add_settings_field( config('mahak.options.debug-mode'), config('mahak.translations.debug-mode'), @@ -130,4 +141,54 @@ class SettingsPageFormController extends InvocableController echo "'; } + + public function new_user_role(): void + { + $name = config('mahak.options.new-user-role'); + $value = sanitize_key((string) get_option($name, 'wordpress_default')); + $roles = wp_roles()->get_names(); + + if ($value !== 'wordpress_default' && !isset($roles[$value])) { + $value = 'wordpress_default'; + } + + echo "'; + echo '
'.esc_html(config('mahak.translations.new-user-role-description')).'
'; + } + + public function sanitize_new_user_role($value): string + { + $role = sanitize_key((string) $value); + + if ($role === 'wordpress_default') { + return $role; + } + + if (get_role($role) !== null) { + return $role; + } + + add_settings_error( + config('mahak.options.new-user-role'), + 'mahak_invalid_new_user_role', + 'نقش انتخابشده معتبر نیست. نقش پیشفرض وردپرس استفاده شد.' + ); + + return 'wordpress_default'; + } } diff --git a/src/configs/mahak.php b/src/configs/mahak.php index 900b20b..4f53695 100644 --- a/src/configs/mahak.php +++ b/src/configs/mahak.php @@ -11,6 +11,7 @@ return [ 'user-identifier' => 'mahak_user_identifier', 'login-route' => 'mahak_login_route', 'after-login-route' => 'mahak_after_login_route', + 'new-user-role' => 'mahak_new_user_role', 'debug-mode' => 'mahak_debug_mode', ], @@ -38,6 +39,9 @@ return [ 'user-identifier' => 'فیلد شناسایی کاربر', 'login-route' => 'مسیر لاگین ماهک', 'after-login-route' => 'مسیر بعد از لاگین', + 'new-user-role' => 'نقش کاربر جدید', + 'wordpress-default-role' => 'پیشفرض وردپرس', + 'new-user-role-description' => 'در حالت پیشفرض وردپرس، نقش عمومی کاربران جدید استفاده میشود. نقش انتخابی دیگر فقط به کاربران ساختهشده توسط این افزونه اختصاص مییابد.', 'debug-mode' => 'حالت اشکالزدایی', 'debug-mode-description' => 'در صورت بروز خطا، جزئیات کامل فنی در صفحه نمایش داده شود. این گزینه را فقط هنگام عیبیابی فعال کنید.', diff --git a/test/integration-authentication.php b/test/integration-authentication.php index 9a7b2c4..28e4728 100644 --- a/test/integration-authentication.php +++ b/test/integration-authentication.php @@ -7,6 +7,7 @@ const TEST_PLUGIN = 'mahak-authenticate-bridge/dabestaniha-authenticate-bridge.p const TEST_SECRET = 'integration-test-secret'; const TEST_EMAIL = 'mahak-auth-user@example.test'; const TEST_NAME = 'Mahak Auth User'; +const TEST_ROLE_EMAIL = 'mahak-role-user@example.test'; function fail(string $message): void { @@ -86,6 +87,8 @@ function activate_and_configure_plugin(): void update_option('mahak_user_identifier', 'email'); update_option('mahak_login_route', 'mahak/login'); update_option('mahak_after_login_route', 'wp-admin/profile.php'); + update_option('default_role', 'subscriber'); + update_option('mahak_new_user_role', 'wordpress_default'); pass('Plugin activated and configured'); } @@ -213,6 +216,10 @@ function test_valid_authentication(): void assert_true($user !== false, 'Authenticated user was not created.'); assert_true($user->display_name === TEST_NAME, 'Authenticated user display name was not saved.'); + assert_true( + $user->roles === ['subscriber'], + 'New user did not receive the plugin-configured Subscriber role.' + ); $cookieHeader = cookie_header_from_response($response['headers']); $profileResponse = http_request(TEST_SITE_URL.'/wp-admin/profile.php', $cookieHeader); @@ -222,7 +229,38 @@ function test_valid_authentication(): void 'Issued cookies did not authenticate a follow-up WordPress admin request.' ); - pass('Valid JWT creates/logs in user and issued cookies authenticate follow-up request'); + pass('Valid JWT creates a Subscriber and issued cookies authenticate follow-up requests'); +} + +function test_configured_new_user_role_is_enforced(): void +{ + $smsRoleOverride = function (int $userId): void { + (new WP_User($userId))->set_role('administrator'); + }; + add_action('user_register', $smsRoleOverride); + + $controller = new Dabestaniha\AuthenticateBridge\App\Http\Controllers\AuthenticateController(); + $userId = $controller->find_or_create_user('email', TEST_ROLE_EMAIL, 'Role Test User'); + + remove_action('user_register', $smsRoleOverride); + + $user = get_userdata($userId); + assert_true( + $user !== false && $user->roles === ['subscriber'], + 'Configured role was not enforced after another plugin changed the role during user_register.' + ); + + $user->set_role('author'); + $existingUserId = $controller->find_or_create_user('email', TEST_ROLE_EMAIL, 'Role Test User'); + $existingUser = get_userdata($existingUserId); + + assert_true($existingUserId === $userId, 'Existing user was not reused.'); + assert_true( + $existingUser !== false && $existingUser->roles === ['author'], + 'Existing user role was changed during authentication.' + ); + + pass('Configured role overrides creation hooks without changing existing users'); } function test_invalid_authentication(): void @@ -310,7 +348,7 @@ function test_debug_error_details(): void function test_plugin_update_discovery(): void { - $packageUrl = 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/download/v2.3.0/mahak-authenticate-bridge.zip'; + $packageUrl = 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/download/v2.4.0/mahak-authenticate-bridge.zip'; $mockRelease = function ($response, array $request, string $url) use ($packageUrl) { if ($url !== 'https://mahgit.ir/api/v1/repos/dabestaniha/mahak-authenticate-bridge/releases/latest') { return $response; @@ -319,8 +357,8 @@ function test_plugin_update_discovery(): void return [ 'headers' => [], 'body' => json_encode([ - 'tag_name' => 'v2.3.0', - 'html_url' => 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/tag/v2.3.0', + 'tag_name' => 'v2.4.0', + 'html_url' => 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/tag/v2.4.0', 'body' => 'Test release', 'draft' => false, 'prerelease' => false, @@ -346,7 +384,7 @@ function test_plugin_update_discovery(): void remove_filter('pre_http_request', $mockRelease, 10); assert_true(isset($updates->response[TEST_PLUGIN]), 'A newer Mahgit release was not offered as a WordPress update.'); - assert_true($updates->response[TEST_PLUGIN]->new_version === '2.3.0', 'The offered plugin version was incorrect.'); + assert_true($updates->response[TEST_PLUGIN]->new_version === '2.4.0', 'The offered plugin version was incorrect.'); assert_true($updates->response[TEST_PLUGIN]->package === $packageUrl, 'The release package URL was incorrect.'); pass('Published Mahgit releases are discovered by the WordPress updater'); @@ -357,6 +395,7 @@ install_wordpress(); activate_and_configure_plugin(); wait_for_http(); test_valid_authentication(); +test_configured_new_user_role_is_enforced(); test_invalid_authentication(); test_debug_error_details(); test_plugin_update_discovery();