fix(auth): clear token cache after login#808
Conversation
|
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request improves the authentication lifecycle by ensuring that token caches are properly invalidated upon login. By reusing a centralized cleanup mechanism, the changes prevent issues where stale access tokens or cached account data persist after a user re-authenticates with different scopes or accounts, resolving a known issue with API call failures. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request centralizes token cache management by introducing a clear_token_caches helper function, which is now utilized during both login and logout processes to prevent the use of stale credentials. Review feedback highlighted security concerns regarding unsanitized error messages in terminal output and potential TOCTOU race conditions in file removal logic; it is recommended to sanitize output and handle file deletion more robustly by catching specific I/O errors instead of pre-checking existence.
| fn clear_token_caches() -> Result<Vec<PathBuf>, GwsError> { | ||
| let mut removed = Vec::new(); | ||
| for path in token_cache_paths() { | ||
| if path.exists() { | ||
| std::fs::remove_file(&path).map_err(|e| { | ||
| GwsError::Validation(format!("Failed to remove {}: {e}", path.display())) | ||
| })?; | ||
| removed.push(path); | ||
| } | ||
| } | ||
| Ok(removed) | ||
| } |
There was a problem hiding this comment.
The error message generated when failing to remove a cache file is not sanitized, which violates the general rule to prevent escape sequence injection in terminal output. Additionally, using path.exists() followed by remove_file introduces a TOCTOU (time-of-check to time-of-use) race condition. It is more robust to attempt the removal directly and handle the NotFound error case. Please acknowledge and document potential TOCTOU race conditions as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.
fn clear_token_caches() -> Result<Vec<PathBuf>, GwsError> {
let mut removed = Vec::new();
for path in token_cache_paths() {
match std::fs::remove_file(&path) {
Ok(_) => removed.push(path),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => {
return Err(GwsError::Validation(crate::output::sanitize_for_terminal(
&format!("Failed to remove {}: {e}", path.display()),
)));
}
}
}
Ok(removed)
}References
- Sanitize error strings printed to the terminal to prevent escape sequence injection.
- When implementing file path validation, acknowledge and document potential Time-of-check to time-of-use (TOCTOU) race conditions as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.
| if path.exists() { | ||
| std::fs::remove_file(path).map_err(|e| { | ||
| GwsError::Validation(format!("Failed to remove {}: {e}", path.display())) | ||
| })?; | ||
| removed.push(path.display().to_string()); | ||
| } |
There was a problem hiding this comment.
This loop lacks error string sanitization and contains a TOCTOU race condition. Following the pattern suggested for the clear_token_caches helper, you should sanitize the error message and handle the NotFound case explicitly instead of checking for existence beforehand. Note that potential TOCTOU race conditions should be acknowledged as a known limitation if full mitigation is out of scope.
match std::fs::remove_file(path) {
Ok(_) => removed.push(path.display().to_string()),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => {
return Err(GwsError::Validation(crate::output::sanitize_for_terminal(
&format!("Failed to remove {}: {e}", path.display()),
)));
}
}References
- Sanitize error strings printed to the terminal to prevent escape sequence injection.
- When implementing file path validation, acknowledge and document potential Time-of-check to time-of-use (TOCTOU) race conditions as a known limitation if a full mitigation (e.g., using openat(O_NOFOLLOW)) is considered out of scope.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces centralized logic for clearing token caches during the login and logout processes. It adds helper functions token_cache_paths, remove_file_if_exists, and clear_token_caches to auth_commands.rs, along with unit tests for these new utilities. The review feedback highlights a potential issue where using the ? operator on clear_token_caches during login could cause the command to report failure even if credentials were saved successfully. It is recommended to handle cache-clearing errors gracefully to avoid a confusing user experience.
|
|
||
| // Access tokens in the cache may belong to the previous account or scope set. | ||
| // Force the next API call to mint a token from the newly saved credentials. | ||
| let _ = clear_token_caches()?; |
There was a problem hiding this comment.
Using the ? operator here causes the entire login command to fail if clearing the token caches fails (e.g., due to a permission issue). However, at this point, the new credentials have already been successfully encrypted and saved to disk (lines 668-669). Failing the command here prevents the success message and account details from being printed (lines 676-687), which leads to a confusing user experience where the tool reports failure despite the authentication actually succeeding.
Since clearing the cache is a secondary cleanup step, it is better to handle any errors gracefully (e.g., by logging a warning) so that the login process can complete successfully and the user is informed of their current status.
if let Err(e) = clear_token_caches() {
eprintln!("Warning: {e}");
}|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces logic to clear token caches during both login and logout processes to ensure that stale access tokens do not persist. It adds helper functions token_cache_paths, remove_file_if_exists, and clear_token_caches to handle the removal of user and service account token caches, including error message sanitization. The handle_login_inner and handle_logout functions were updated to utilize these helpers, and new unit tests were included to verify the functionality. I have no feedback to provide.
Summary
gws auth loginauth logoutWhy
After re-authenticating with different scopes or a different account, the existing
token_cache.jsoncan still contain an access token minted from the previous credentials. That makesauth statusshow the new scopes while API calls keep failing with stale-token permissions until the user manually deletes the cache.Fixes #764.
Tests
cargo fmt --checkcargo test -p google-workspace-cli clear_token_caches_removes_user_and_service_account_cachescargo check -p google-workspace-cligit diff --check