fix(sso): clear broker session on customer logout#1329
Conversation
📝 WalkthroughWalkthroughSSO now implements a background cross-domain logout flow. The startup registers logout-related hooks, route handling decorates logout redirects with signaling parameters, main-site and broker endpoints validate tokens and log out users, and existing auth/script flows integrate to enqueue and execute background logout calls. ChangesSSO Background Logout
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
🔨 Build Complete - Ready for Testing!📦 Download Build Artifact (Recommended)Download the zip build, upload to WordPress and test:
🌐 Test in WordPress Playground (Very Experimental)Click the link below to instantly test this PR in your browser - no installation needed! Login credentials: |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
tests/WP_Ultimo/SSO/SSO_Test.php (1)
128-145: ⚡ Quick winAdd a replay assertion for the logout token.
This only checks the happy path. Since the transient is the replay guard, it would be good to mirror the cookie-less token test here and assert that the same logout token is rejected on a second validation.
Suggested test update
- $result = $validate->invoke($sso, $generate->invoke($sso, $user_id)); + $token = $generate->invoke($sso, $user_id); + $result = $validate->invoke($sso, $token); $this->assertIsArray($result); $this->assertSame($user_id, $result['user_id']); $this->assertNotEmpty($result['jti']); - - delete_site_transient('wu_sso_logout_' . $result['jti']); + + $second_result = $validate->invoke($sso, $token); + $this->assertWPError($second_result); + $this->assertSame('invalid_token', $second_result->get_error_code());🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/WP_Ultimo/SSO/SSO_Test.php` around lines 128 - 145, The test currently only verifies a successful logout token validation; add a replay assertion by invoking validate_sso_logout_token a second time with the same token and asserting it is rejected (e.g., returns false/null or a non-array result) to ensure the transient-based replay guard works, then keep the existing delete_site_transient('wu_sso_logout_' . $result['jti']) cleanup; reference the generate_sso_logout_token and validate_sso_logout_token reflection calls to locate where to add the second validation and its assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@inc/sso/class-sso.php`:
- Around line 857-868: The logout-token validation currently leaves the
transient intact; after confirming $jti and $user_id and matching
get_site_transient('wu_sso_logout_' . $jti) === $user_id, immediately invalidate
the transient to make the token single-use (e.g. delete_site_transient or
overwrite it) before returning the ['user_id'=>$user_id,'jti'=>$jti]; reference
the $jti/$user_id variables, the get_site_transient('wu_sso_logout_' . $jti)
check in this method, and note that handle_server_logout() must no longer be
relied on to perform the one-time invalidation.
---
Nitpick comments:
In `@tests/WP_Ultimo/SSO/SSO_Test.php`:
- Around line 128-145: The test currently only verifies a successful logout
token validation; add a replay assertion by invoking validate_sso_logout_token a
second time with the same token and asserting it is rejected (e.g., returns
false/null or a non-array result) to ensure the transient-based replay guard
works, then keep the existing delete_site_transient('wu_sso_logout_' .
$result['jti']) cleanup; reference the generate_sso_logout_token and
validate_sso_logout_token reflection calls to locate where to add the second
validation and its assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 94e5e191-8507-4981-a0b6-5b31ef35ec59
📒 Files selected for processing (2)
inc/sso/class-sso.phptests/WP_Ultimo/SSO/SSO_Test.php
| if (empty($jti) || $user_id <= 0 || (int) get_site_transient('wu_sso_logout_' . $jti) !== $user_id) { | ||
| return new \WP_Error('invalid_token', __('SSO logout token has already been used or is invalid.', 'ultimate-multisite')); | ||
| } | ||
|
|
||
| if ( ! get_user_by('id', $user_id)) { | ||
| return new \WP_Error('user_not_found', __('User not found.', 'ultimate-multisite')); | ||
| } | ||
|
|
||
| return [ | ||
| 'user_id' => $user_id, | ||
| 'jti' => $jti, | ||
| ]; |
There was a problem hiding this comment.
Make the logout token single-use as soon as it validates.
This token is only invalidated later in handle_server_logout(), and only when the current main-site session matches $user_id. If the background request arrives after that session is already gone, the transient survives for the rest of the 5-minute TTL and the same URL can still log the user out later on replay.
Suggested fix
if (empty($jti) || $user_id <= 0 || (int) get_site_transient('wu_sso_logout_' . $jti) !== $user_id) {
return new \WP_Error('invalid_token', __('SSO logout token has already been used or is invalid.', 'ultimate-multisite'));
}
+
+ delete_site_transient('wu_sso_logout_' . $jti);
if ( ! get_user_by('id', $user_id)) {
return new \WP_Error('user_not_found', __('User not found.', 'ultimate-multisite'));
}📝 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 (empty($jti) || $user_id <= 0 || (int) get_site_transient('wu_sso_logout_' . $jti) !== $user_id) { | |
| return new \WP_Error('invalid_token', __('SSO logout token has already been used or is invalid.', 'ultimate-multisite')); | |
| } | |
| if ( ! get_user_by('id', $user_id)) { | |
| return new \WP_Error('user_not_found', __('User not found.', 'ultimate-multisite')); | |
| } | |
| return [ | |
| 'user_id' => $user_id, | |
| 'jti' => $jti, | |
| ]; | |
| if (empty($jti) || $user_id <= 0 || (int) get_site_transient('wu_sso_logout_' . $jti) !== $user_id) { | |
| return new \WP_Error('invalid_token', __('SSO logout token has already been used or is invalid.', 'ultimate-multisite')); | |
| } | |
| delete_site_transient('wu_sso_logout_' . $jti); | |
| if ( ! get_user_by('id', $user_id)) { | |
| return new \WP_Error('user_not_found', __('User not found.', 'ultimate-multisite')); | |
| } | |
| return [ | |
| 'user_id' => $user_id, | |
| 'jti' => $jti, | |
| ]; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@inc/sso/class-sso.php` around lines 857 - 868, The logout-token validation
currently leaves the transient intact; after confirming $jti and $user_id and
matching get_site_transient('wu_sso_logout_' . $jti) === $user_id, immediately
invalidate the transient to make the token single-use (e.g.
delete_site_transient or overwrite it) before returning the
['user_id'=>$user_id,'jti'=>$jti]; reference the $jti/$user_id variables, the
get_site_transient('wu_sso_logout_' . $jti) check in this method, and note that
handle_server_logout() must no longer be relied on to perform the one-time
invalidation.
Summary
Verification
Notes
Merged via PR #1329 to main. aidevops.sh v3.20.5 spent 12m on this as a headless bash routine. |
Summary
/sso-logoutendpoint in the background with a short-lived signed token.wu_sso_deniedfor 5 minutes after logout to prevent immediate SSO re-login, and clear it on successful normal or SSO login.SSO_Test.Verification
vendor/bin/phpcs inc/sso/class-sso.php tests/WP_Ultimo/SSO/SSO_Test.php— 0 errors; existing warnings only.vendor/bin/phpunit --filter SSO_Test— OK (81 tests, 132 assertions).Notes
pre-clean-sso-background-logout-pr; this PR is based on currentorigin/mainand includes only SSO logout changes.Summary by CodeRabbit
New Features
Tests