-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
fix: Unlinking auth provider triggers auth data validation #10045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: alpha
Are you sure you want to change the base?
Conversation
|
🚀 Thanks for opening this pull request! |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAvoids validating or contacting code-based auth adapters when unlinking providers by treating Changes
Sequence DiagramsequenceDiagram
actor Client
participant RestWrite
participant Auth as Auth.findUsersWithAuthData
participant Adapter as BaseCodeAuthAdapter
participant Storage as PostgresStorageAdapter
participant DB
Client->>RestWrite: Request update with authData[provider]=null
RestWrite->>RestWrite: isUpdate = true (query present)
RestWrite->>Auth: findUsersWithAuthData(..., isUpdate=true)
Auth->>Auth: Detect provider authData === null or echoed-back without credentials
Auth->>Adapter: (skips) beforeFind/validation for removed/empty credentials
Auth-->>RestWrite: Return no validation lookups for removed provider
RestWrite->>Storage: updateObjectsByQuery with authData removal instruction
Storage->>Storage: generateRemove(...) for JSONB key deletion
Storage->>DB: Execute UPDATE removing provider key from authData
DB-->>Storage: Ack
Storage-->>RestWrite: Update complete
RestWrite-->>Client: Provider unlinked (no external adapter validation)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 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 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## alpha #10045 +/- ##
==========================================
+ Coverage 83.72% 92.57% +8.84%
==========================================
Files 191 191
Lines 15573 15589 +16
Branches 176 176
==========================================
+ Hits 13039 14432 +1393
+ Misses 2518 1145 -1373
+ Partials 16 12 -4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@spec/AuthenticationAdaptersV2.spec.js`:
- Around line 1449-1452: Test calls to Parse.User.logInWith('gpgames') are
missing the redirect_uri in authData which the gpgames adapter's
getAccessTokenFromCode expects; update the test where user is created (the
logInWith call) to include authData.redirect_uri with the same redirect value
used earlier in the spec (so authData includes id, code, and redirect_uri) to
keep the test consistent with the initial link flow and prevent false positives
if mocks are tightened.
- Line 1411: The test is accidentally using Jasmine's focused runner: replace
the focused test declaration `fit` with a normal test declaration `it` for the
test titled "should unlink one code-based provider while echoing back another
unchanged" so the entire suite runs; locate the `fit('should unlink one
code-based provider while echoing back another unchanged', async () => {` and
change `fit` to `it`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Auth.js (1)
462-501:⚠️ Potential issue | 🟡 Minor
hasMutatedAuthDatatreats empty provider objects as unmutated — add clarifying documentation.Lines 490-493: The subset check using
incomingKeys.some()correctly handles echoed-back data. However, ifproviderDatais an empty object{}, the loop never executes andhasChangesremainsfalse, meaning the provider is silently treated as unmutated. This behavior mirrors the pattern infindUsersWithAuthData(lines 432-436), which explicitly skips authData with "only id or empty" credentials. While this appears intentional for ignoring echoed-back/credential-less updates, thehasMutatedAuthDatafunction lacks an explicit comment or test confirming this edge case. Add a clarifying comment explaining why empty objects are treated as unmutated, or document this behavior in tests.
🧹 Nitpick comments (1)
src/Adapters/Auth/BaseCodeAuthAdapter.js (1)
75-82: Consider clarifying the error message or extracting the shared guard.The guard
if (!authData?.access_token)throws"code is required."— this is technically checking foraccess_token, notcode. While users do submit acode(whichbeforeFindexchanges foraccess_token), a developer debugging adapter internals may find this confusing since the validated field doesn't match the message.Also, the identical guard is copy-pasted across
validateLogin,validateSetUp, andvalidateUpdate.♻️ Optional: extract shared guard and align the message
+ _requireAccessToken(authData) { + if (!authData?.access_token) { + throw new Parse.Error( + Parse.Error.VALIDATION_ERROR, + `${this.adapterName} code is required.` + ); + } + } + validateLogin(authData) { - if (!authData?.access_token) { - throw new Parse.Error(Parse.Error.VALIDATION_ERROR, `${this.adapterName} code is required.`); - } + this._requireAccessToken(authData); return { id: authData.id, } } validateSetUp(authData) { - if (!authData?.access_token) { - throw new Parse.Error(Parse.Error.VALIDATION_ERROR, `${this.adapterName} code is required.`); - } + this._requireAccessToken(authData); return { id: authData.id, } } validateUpdate(authData) { - if (!authData?.access_token) { - throw new Parse.Error(Parse.Error.VALIDATION_ERROR, `${this.adapterName} code is required.`); - } + this._requireAccessToken(authData); return { id: authData.id, } }Also applies to: 84-91, 99-106
|
@Moumouls if you want to take a quick look at this, just a sanity check, if you see anything fishy in these changes before we merge... |
|
@coderabbitai review this PR again for any potential security issues, given the sensitive nature of the changes in authData validation. |
🧩 Analysis chain
🏁 Script executed: Length of output: 26282 🏁 Script executed: Length of output: 5888 🏁 Script executed: Length of output: 5330 🏁 Script executed: Length of output: 1426 🏁 Script executed: Length of output: 2069 🏁 Script executed: Length of output: 4620
✅ Security Controls Verified1. Authorization Enforcement
Result: Unauthorized users cannot unlink providers from other users' accounts. 2. Unlink Operation Detection
Result: Unlink operations are correctly differentiated from link/update operations. 3. Credential vs Echo-Back Detection
Result: Echoing back existing authData doesn't trigger unnecessary validation, but actual credential changes do. 4. Cross-User Attack Prevention
Result: Cannot hijack another user's authentication provider. 5. Database Layer Security
Result: Database operations are secure. 🟡 Minor Observations (Not Security Issues)1. isUpdate Flag Simplicity 2. filteredObjectsByACL Implementation 3. Test Coverage
🔒 Security ConclusionNo security vulnerabilities identified. The changes properly:
The fix correctly addresses the original issue (unlink triggering validation) while maintaining security boundaries. The The sensitive nature of authData validation is well-handled through multiple layers of security:
Recommendation: Merge approved from a security perspective. 🎯 ✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Fixes a regression where unlinking an auth provider via authData[provider] = null incorrectly triggers adapter validation (notably for OAuth code-based adapters), and aligns Postgres authData updates with the intended “remove key” semantics.
Changes:
- Pass an “is update” signal into authData user-lookup to skip
beforeFindfor echoed-back{ id }authData during updates and skip unlinked (null) providers. - Update Postgres JSONB authData updates to remove provider keys (instead of leaving
nullvalues) for bothnulland__op: 'Delete'. - Add specs that ensure unlinking doesn’t trigger external adapter/network validation and preserves other linked providers.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/RestWrite.js |
Treats authData handling as update vs login/signup when calling authData lookup. |
src/Auth.js |
Skips beforeFind for unlinked providers and for echoed-back { id } authData during updates. |
src/Adapters/Storage/Postgres/PostgresStorageAdapter.js |
Removes JSONB authData keys on unlink instead of setting them to null. |
src/Adapters/Auth/BaseCodeAuthAdapter.js |
Adds/updates documentation comments around validation hooks for code-based adapters. |
spec/AuthenticationAdaptersV2.spec.js |
Adds tests for unlink behavior without triggering network validation and preserving other providers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…e-server into fix/authData-unlink
Pull Request
Issue
Unlinking auth provider triggers auth data validation.
Closes: #9856
Closes: #9855
Approach
Without the fix, the added test fails:
This is a significant simplification over #9856.
The change in
src/Adapters/Storage/Postgres/PostgresStorageAdapter.jsalso fixes a bug for Postgres (unrelated to the issue reported in #9855, but apparent with the fix implemented here). The change fixes unlinking auth data in Postgres by properly removing JSON keys instead of setting them to null. Before, when auth data had__op: 'Delete', it set the value tonullin the JSONB field using json_object_set_key — the key remained with anullvalue. After, it uses a newgenerateRemovehelper that uses Postgres's operator (jsonb - key) to actually remove the key from the JSONB object. Both explicit__op: 'Delete'andnullvalues trigger key removal.Summary by CodeRabbit
New Features
Tests
Improvements
Documentation