Skip to content

fix: clear stale connectionId after impersonation changes - #121

Merged
venkateshsakamuri-lab merged 2 commits into
mainfrom
cursor/view-as-connection-403-d535
Sep 23, 2026
Merged

venkateshsakamuri-lab merged 2 commits into
mainfrom
cursor/view-as-connection-403-d535

Conversation

@venkateshsakamuri-lab

@venkateshsakamuri-lab venkateshsakamuri-lab commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Problem

When an admin uses "View as" to impersonate a user who doesn't have access to the currently selected connection, the UI shows a 403 error ("chat and editor access denied for this connection").

Reproduction Steps

  1. Admin selects aws-rds-master connection (only Arun/Gaurav have grants)
  2. Admin uses "View as" to switch to a user without access to that connection
  3. User sees 403 error in Agent/Editor/other connection-scoped sections

User Experience

The user is stuck on a connection they cannot access, with no clear way to recover. The connection appears selected in the sidebar, but all API calls fail with 403.

Root Cause

The frontend's useConnectionManager hook had an early return when connectionId was set, without validating that the connection was actually in the current user's connections array.

When impersonation changes:

  1. Backend correctly returns only connections visible to the target user via ConnectionAccessService.getVisibleConnections()
  2. Frontend receives the new (filtered) connection list
  3. Bug: The hook's useEffect returned early if connectionId was set, keeping the stale connection
  4. Section components then made API calls with the stale connectionId, getting 403
// Before (buggy):
useEffect(() => {
  if (connections.length === 0) return
  if (connectionId) return  // Early return without validation!
  // ...auto-select logic
}, [connections, connectionId, ...])

Fix

1. Core fix in useConnectionManager.js

Added validation that connectionId exists in the connections array. If not, clear it and auto-select from valid options:

// After (fixed):
if (connectionId) {
  const stillValid = connections.some((c) => c.id === connectionId)
  if (stillValid) return
  // Clear the stale connection
  localStorage.removeItem('selectedConnectionId')
  setConnectionId(null)
}

2. Defensive guards in section components

Added guards in all connection-scoped sections to prevent rendering with invalid connections:

  • Check isLoading first - prevents rendering during connection list refresh
  • Check both connectionId AND selectedConnection - ensures the connection is valid

This pattern was applied to all affected sections:

  • AgentChatSection
  • EditorSection
  • DashboardsSection
  • SchemaSection
  • SchemaDocsSection
  • SlowQueriesSection
  • DigestSection
  • CompanyKnowledgeSection
  • MonitorSection

3. Backend test added

Added impersonatingUserWithoutAccessDeniesConnection() test to verify the backend correctly denies access when an admin views as a user who lacks access to a connection.

Security Considerations

This fix does NOT weaken security:

  • The backend grant model remains unchanged
  • Admin bypass for connection access is preserved
  • All API authorization checks (assertCanReadConnectionContent, assertCanUseChatEditor, etc.) remain in place
  • This fix only ensures the UI doesn't present inaccessible connections as usable

Testing

The fix ensures:

  1. When impersonation changes, stale connections are cleared
  2. Users see a proper "no connection selected" state instead of 403 errors
  3. Auto-selection picks from the effective user's accessible connections

Scenarios Covered

  • ✅ Admin can access any connection (admin bypass preserved)
  • ✅ Granted user can access assigned connections
  • ✅ User without grant sees empty/appropriate state
  • ✅ Impersonation where target user lacks access to admin's selected connection

Test Results

  • AccessControlServiceTest passes (including new impersonation test)
  • Frontend lint passes (no new errors introduced)

Note for Stayflexi Deployment

On Stayflexi, only Arun and Gaurav have grants on the aws-rds-master connection. Other users viewing as them or accessing that connection will now see a proper "no connection selected" state rather than a confusing 403 error. If broader access is needed, connection grants should be added via Manage Connections → Share.

Files Changed

File Purpose
src/lib/hooks/useConnectionManager.js Core fix: validate connectionId against connections array
src/components/sections/*.jsx Add isLoading and selectedConnection guards
src/components/sections/*.module.css Add loading spinner animation
backend/.../AccessControlServiceTest.java Add test for impersonation with inaccessible connection
Open in Web Open in Cursor 

cursoragent and others added 2 commits September 23, 2026 18:47
Root cause: When an admin uses 'View as' to impersonate a user,
the backend correctly returns only the connections visible to the
target user. However, the frontend's useConnectionManager hook
had an early return when connectionId was set, without validating
that the connection was actually in the new list.

This caused the UI to keep a stale connectionId from before the
impersonation, resulting in 403 errors when chat/agent/editor
APIs were called with a connection the effective user cannot access.

Fix:
1. In useConnectionManager.js: Added validation that connectionId
   exists in the connections array. If not, clear it and auto-select
   from valid options.

2. In all section components using useConnectionManager:
   - Added isLoading check to prevent rendering during connection refresh
   - Added selectedConnection validation alongside connectionId check
   - This ensures we never render a section with a stale connection
     that's not in the effective user's accessible list

Affected sections:
- AgentChatSection
- EditorSection
- DashboardsSection
- SchemaSection
- SchemaDocsSection
- SlowQueriesSection
- DigestSection
- CompanyKnowledgeSection
- MonitorSection

Co-authored-by: Venkat SF <venkatesh.sakamuri@stayflexi.com>
Verifies that when an admin uses 'View as' to impersonate a user who
lacks access to a connection, the backend correctly denies access to
that connection. This is the backend counterpart to the frontend fix -
both layers must refuse access to ensure the security model holds.

Co-authored-by: Venkat SF <venkatesh.sakamuri@stayflexi.com>
@venkateshsakamuri-lab
venkateshsakamuri-lab marked this pull request as ready for review September 23, 2026 18:51
@venkateshsakamuri-lab
venkateshsakamuri-lab requested a review from a team as a code owner September 23, 2026 18:51
@venkateshsakamuri-lab
venkateshsakamuri-lab merged commit 27d07ea into main Sep 23, 2026
9 checks passed
@venkateshsakamuri-lab
venkateshsakamuri-lab deleted the cursor/view-as-connection-403-d535 branch September 23, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants