diff --git a/inc/sso/class-sso.php b/inc/sso/class-sso.php index 5555d75d1..ca0fbd326 100644 --- a/inc/sso/class-sso.php +++ b/inc/sso/class-sso.php @@ -648,7 +648,7 @@ private function get_sso_return_url(string $fallback = ''): string { parse_str($parsed, $query_params); if ( ! empty($query_params['return_url']) ) { - $return_url = $query_params['return_url']; + $return_url = esc_url_raw($query_params['return_url']); } } } @@ -807,7 +807,7 @@ public function handle_already_logged_in_on_login_page(): void { } // Check if this is an SSO flow (sso param or return_url param present) - $sso_action = $this->input('sso', ''); + $sso_action = $this->input($this->get_url_path(), ''); $return_url = $this->get_sso_return_url(); // Check for SSO flow - either sso param or return_url pointing to different domain diff --git a/tests/WP_Ultimo/SSO/SSO_Test.php b/tests/WP_Ultimo/SSO/SSO_Test.php index 3b2bc40f3..bc1738b00 100644 --- a/tests/WP_Ultimo/SSO/SSO_Test.php +++ b/tests/WP_Ultimo/SSO/SSO_Test.php @@ -44,6 +44,8 @@ protected function tearDown(): void { unset($_REQUEST['return_type']); unset($_REQUEST['broker']); unset($_REQUEST['sso_verify']); + unset($_REQUEST['return_url']); + unset($_REQUEST['redirect_to']); unset($_COOKIE['wu_sso_denied']); parent::tearDown(); @@ -128,6 +130,43 @@ function () { $this->assertSame('mysso-grant', $sso->get_url_path('grant')); } + /** + * Test nested return_url values are extracted from redirect_to. + */ + public function test_get_sso_return_url_extracts_nested_return_url_from_redirect_to(): void { + $sso = SSO::get_instance(); + $return_url = 'https://customer.example.com/wp/wp-admin/'; + + $_REQUEST['redirect_to'] = add_query_arg( + 'return_url', + $return_url, + home_url('/wp-login.php') + ); + + $method = new \ReflectionMethod($sso, 'get_sso_return_url'); + $method->setAccessible(true); + + $this->assertSame($return_url, $method->invoke($sso)); + } + + /** + * Test nested return_url values are sanitized when extracted from redirect_to. + */ + public function test_get_sso_return_url_sanitizes_nested_return_url_from_redirect_to(): void { + $sso = SSO::get_instance(); + + $_REQUEST['redirect_to'] = add_query_arg( + 'return_url', + 'javascript:alert(1)', + home_url('/wp-login.php') + ); + + $method = new \ReflectionMethod($sso, 'get_sso_return_url'); + $method->setAccessible(true); + + $this->assertSame('', $method->invoke($sso)); + } + // ------------------------------------------------------------------ // encode / decode // ------------------------------------------------------------------