From 5a272ec782aec422f3986c7c587b729fa5d5b3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 3 Apr 2024 19:59:57 +0200 Subject: [PATCH] Just match existing users on request, don't create new ones. (#414) * Just match existing users on request, don't create new ones. Useful if you want to use discourse primarily as a sso solution. * Add consistent naming, linting and a unit test --------- Co-authored-by: Angus McLeod --- admin/sso-settings.php | 26 ++++++++++++++++++++++++++ lib/discourse.php | 1 + lib/sso-client/client.php | 29 +++++++++++++++++++---------- tests/phpunit/test-sso-client.php | 14 ++++++++++++++ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/admin/sso-settings.php b/admin/sso-settings.php index 0d5c533f..d4d85a91 100644 --- a/admin/sso-settings.php +++ b/admin/sso-settings.php @@ -261,6 +261,17 @@ public function register_sso_settings() { 'discourse_sso_client_settings_section' ); + add_settings_field( + 'discourse_sso_disable_create_user', + __( 'Disable user creation', 'wp-discourse' ), + array( + $this, + 'sso_client_disable_create_user_checkbox', + ), + 'discourse_sso_client', + 'discourse_sso_client_settings_section' + ); + add_settings_field( 'discourse_sso_client_sync_logout', __( 'Sync Logout with Discourse', 'wp-discourse' ), @@ -584,6 +595,21 @@ public function discourse_sso_login_form_redirect_url_input() { ); } + /** + * Outputs markup for sso-client-disable-create-user checkbox. + */ + public function sso_client_disable_create_user_checkbox() { + $this->form_helper->checkbox_input( + 'sso-client-disable-create-user', + 'discourse_sso_client', + __( 'Disable creation of new WordPress users', 'wp-discourse' ), + __( + 'Only Discourse users with an email or id matching an existing WordPress user will be allowed to log in with Discourse.', + 'wp-discourse' + ) + ); + } + /** * Outputs markup for sso-client-sync-by-email checkbox. */ diff --git a/lib/discourse.php b/lib/discourse.php index 6f2ea427..894ad34a 100644 --- a/lib/discourse.php +++ b/lib/discourse.php @@ -164,6 +164,7 @@ class Discourse { 'sso-client-login-form-change' => 0, 'sso-client-login-form-redirect' => '', 'sso-client-sync-by-email' => 0, + 'sso-client-disable-create-user' => 0, 'sso-client-sync-logout' => 0, ); diff --git a/lib/sso-client/client.php b/lib/sso-client/client.php index 2d8ca912..58d8cbdc 100644 --- a/lib/sso-client/client.php +++ b/lib/sso-client/client.php @@ -190,7 +190,7 @@ private function is_valid_signature() { * * For non-logged-in users, the function checks if there's an existing user with the payload's 'discourse_sso_user_id', * if there isn't, there is an optional check for a user with a matching email address. If both checks fail, a new user - * is created. + * is created if not prohibited by configuration. * * @return int|\WP_Error */ @@ -231,18 +231,22 @@ private function get_user_id() { } } + if ( empty( $user_query_results ) && ! empty( $this->options['sso-client-disable-create-user'] ) ) { + return new \WP_Error( 'no_matching_user' ); + } + if ( empty( $user_query_results ) ) { - $user_password = wp_generate_password( 12, true ); + $user_password = wp_generate_password( 12, true ); - $user_id = wp_create_user( - $this->get_sso_response( 'username' ), - $user_password, - $this->get_sso_response( 'email' ) - ); + $user_id = wp_create_user( + $this->get_sso_response( 'username' ), + $user_password, + $this->get_sso_response( 'email' ) + ); - do_action( 'wpdc_sso_client_after_create_user', $user_id ); + do_action( 'wpdc_sso_client_after_create_user', $user_id ); - return $user_id; + return $user_id; } return $user_query_results[0]->ID; @@ -364,7 +368,12 @@ public function handle_login_errors( $errors ) { case 'existing_user_login': $message = __( 'There is already an account registered with the username supplied by Discourse. If this is you, login through WordPress and visit your profile page to sync your account with Discourse', 'wp-discourse' ); $errors->add( 'existing_user_login', $message ); - break; + break; + + case 'no_matching_user': + $message = __( 'No WordPress user matches your Discourse user.', 'wp-discourse' ); + $errors->add( 'discourse_sso_no_matching_user', $message ); + break; default: $message = __( 'Unhandled Error', 'wp-discourse' ); diff --git a/tests/phpunit/test-sso-client.php b/tests/phpunit/test-sso-client.php index b41bc7bb..bfc8b4d8 100644 --- a/tests/phpunit/test-sso-client.php +++ b/tests/phpunit/test-sso-client.php @@ -204,6 +204,20 @@ public function test_parse_request_update_user_failed() { remove_filter( 'wpdc_sso_client_updated_user', array( $this, 'invalid_update_user_filter' ), 10 ); } + /** + * parse_request does not create new users if user creation is disabled. + */ + public function test_parse_request_disable_create_user() { + self::$plugin_options['sso-client-disable-create-user'] = 1; + $this->sso_client->setup_options( self::$plugin_options ); + + $parse_result = $this->sso_client->parse_request(); + + $log = $this->get_last_log(); + $this->assertMatchesRegularExpression( '/sso_client.ERROR: parse_request.get_user_id/', $log ); + $this->assertMatchesRegularExpression( '/"code":"no_matching_user"/', $log ); + } + public function invalid_update_user_filter( $updated_user, $query ) { $updated_user['ID'] = 23; return $updated_user;