fixed connections access
This commit is contained in:
parent
33adccf87d
commit
1b59810e0d
4 changed files with 91 additions and 84 deletions
|
|
@ -89,6 +89,11 @@ async def createActionDefinitionPrompt(context, service) -> str:
|
||||||
docRefs = service.getDocumentReferenceList()
|
docRefs = service.getDocumentReferenceList()
|
||||||
connRefs = service.getConnectionReferenceList()
|
connRefs = service.getConnectionReferenceList()
|
||||||
|
|
||||||
|
# Debug logging for connections
|
||||||
|
logging.debug(f"Connection references retrieved: {connRefs}")
|
||||||
|
logging.debug(f"Connection references type: {type(connRefs)}")
|
||||||
|
logging.debug(f"Connection references length: {len(connRefs) if connRefs else 0}")
|
||||||
|
|
||||||
# Get documents from current round (chat) and entire workflow history
|
# Get documents from current round (chat) and entire workflow history
|
||||||
current_round_docs = docRefs.get('chat', [])
|
current_round_docs = docRefs.get('chat', [])
|
||||||
workflow_history_docs = docRefs.get('history', [])
|
workflow_history_docs = docRefs.get('history', [])
|
||||||
|
|
|
||||||
|
|
@ -443,12 +443,23 @@ class ServiceCenter:
|
||||||
"""Get list of all UserConnection objects as references with enhanced state information"""
|
"""Get list of all UserConnection objects as references with enhanced state information"""
|
||||||
connections = []
|
connections = []
|
||||||
# Get user connections through AppObjects interface
|
# Get user connections through AppObjects interface
|
||||||
|
logger.debug(f"getConnectionReferenceList: Service center user ID: {self.user.id}")
|
||||||
|
logger.debug(f"getConnectionReferenceList: Service center user type: {type(self.user)}")
|
||||||
|
logger.debug(f"getConnectionReferenceList: Service center user object: {self.user}")
|
||||||
|
|
||||||
user_connections = self.interfaceApp.getUserConnections(self.user.id)
|
user_connections = self.interfaceApp.getUserConnections(self.user.id)
|
||||||
|
logger.debug(f"getConnectionReferenceList: User ID: {self.user.id}")
|
||||||
|
logger.debug(f"getConnectionReferenceList: Raw user connections: {user_connections}")
|
||||||
|
logger.debug(f"getConnectionReferenceList: User connections type: {type(user_connections)}")
|
||||||
|
logger.debug(f"getConnectionReferenceList: User connections length: {len(user_connections) if user_connections else 0}")
|
||||||
|
|
||||||
for conn in user_connections:
|
for conn in user_connections:
|
||||||
# Get enhanced connection reference with state information
|
# Get enhanced connection reference with state information
|
||||||
enhanced_ref = self.getConnectionReferenceFromUserConnection(conn)
|
enhanced_ref = self.getConnectionReferenceFromUserConnection(conn)
|
||||||
|
logger.debug(f"getConnectionReferenceList: Enhanced ref for connection {conn.id}: {enhanced_ref}")
|
||||||
connections.append(enhanced_ref)
|
connections.append(enhanced_ref)
|
||||||
# Sort by connection reference
|
# Sort by connection reference
|
||||||
|
logger.debug(f"getConnectionReferenceList: Final connections list: {connections}")
|
||||||
return sorted(connections)
|
return sorted(connections)
|
||||||
|
|
||||||
def getConnectionReferenceFromUserConnection(self, connection: UserConnection) -> str:
|
def getConnectionReferenceFromUserConnection(self, connection: UserConnection) -> str:
|
||||||
|
|
@ -461,6 +472,8 @@ class ServiceCenter:
|
||||||
if token:
|
if token:
|
||||||
if hasattr(token, 'expiresAt') and token.expiresAt:
|
if hasattr(token, 'expiresAt') and token.expiresAt:
|
||||||
current_time = get_utc_timestamp()
|
current_time = get_utc_timestamp()
|
||||||
|
logger.debug(f"getConnectionReferenceFromUserConnection: Current time: {current_time}")
|
||||||
|
logger.debug(f"getConnectionReferenceFromUserConnection: Token expires at: {token.expiresAt}")
|
||||||
if current_time > token.expiresAt:
|
if current_time > token.expiresAt:
|
||||||
token_status = "expired"
|
token_status = "expired"
|
||||||
else:
|
else:
|
||||||
|
|
@ -476,6 +489,7 @@ class ServiceCenter:
|
||||||
base_ref = f"connection:{connection.authority.value}:{connection.externalUsername}:{connection.id}"
|
base_ref = f"connection:{connection.authority.value}:{connection.externalUsername}:{connection.id}"
|
||||||
state_info = f" [status:{connection.status.value}, token:{token_status}]"
|
state_info = f" [status:{connection.status.value}, token:{token_status}]"
|
||||||
|
|
||||||
|
logger.debug(f"getConnectionReferenceFromUserConnection: Built reference: {base_ref + state_info}")
|
||||||
return base_ref + state_info
|
return base_ref + state_info
|
||||||
|
|
||||||
def getUserConnectionFromConnectionReference(self, connectionReference: str) -> Optional[UserConnection]:
|
def getUserConnectionFromConnectionReference(self, connectionReference: str) -> Optional[UserConnection]:
|
||||||
|
|
|
||||||
|
|
@ -277,13 +277,21 @@ class AppObjects:
|
||||||
def getUserConnections(self, userId: str) -> List[UserConnection]:
|
def getUserConnections(self, userId: str) -> List[UserConnection]:
|
||||||
"""Returns all connections for a user."""
|
"""Returns all connections for a user."""
|
||||||
try:
|
try:
|
||||||
|
logger.debug(f"getUserConnections: Looking for connections for user ID: {userId}")
|
||||||
|
logger.debug(f"getUserConnections: Current database context userId: {self.db.userId}")
|
||||||
|
logger.debug(f"getUserConnections: Current interface userId: {self.userId}")
|
||||||
|
|
||||||
# Get connections for this user
|
# Get connections for this user
|
||||||
connections = self.db.getRecordset("connections", recordFilter={"userId": userId})
|
connections = self.db.getRecordset("connections", recordFilter={"userId": userId})
|
||||||
|
logger.debug(f"getUserConnections: Raw database connections: {connections}")
|
||||||
|
logger.debug(f"getUserConnections: Database connections type: {type(connections)}")
|
||||||
|
logger.debug(f"getUserConnections: Database connections length: {len(connections) if connections else 0}")
|
||||||
|
|
||||||
# Convert to UserConnection objects
|
# Convert to UserConnection objects
|
||||||
result = []
|
result = []
|
||||||
for conn_dict in connections:
|
for conn_dict in connections:
|
||||||
try:
|
try:
|
||||||
|
logger.debug(f"getUserConnections: Processing connection dict: {conn_dict}")
|
||||||
# Create UserConnection object
|
# Create UserConnection object
|
||||||
connection = UserConnection(
|
connection = UserConnection(
|
||||||
id=conn_dict["id"],
|
id=conn_dict["id"],
|
||||||
|
|
@ -297,11 +305,13 @@ class AppObjects:
|
||||||
lastChecked=conn_dict.get("lastChecked"),
|
lastChecked=conn_dict.get("lastChecked"),
|
||||||
expiresAt=conn_dict.get("expiresAt")
|
expiresAt=conn_dict.get("expiresAt")
|
||||||
)
|
)
|
||||||
|
logger.debug(f"getUserConnections: Created UserConnection object: {connection}")
|
||||||
result.append(connection)
|
result.append(connection)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error converting connection dict to object: {str(e)}")
|
logger.error(f"Error converting connection dict to object: {str(e)}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
logger.debug(f"getUserConnections: Final result: {result}")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
"""
|
"""
|
||||||
Connection routes for the backend API.
|
Connection routes for the backend API.
|
||||||
Implements the endpoints for connection management.
|
Implements the endpoints for connection management.
|
||||||
|
|
||||||
|
SECURITY NOTE:
|
||||||
|
- Regular connections endpoint (/api/connections/) only returns connections for the current user
|
||||||
|
- Admin endpoint (/api/connections/admin/all) provides access to all connections for management purposes
|
||||||
|
- This prevents security vulnerabilities where admin users could see other users' connections
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, Depends, Body, Path, Request, Response
|
from fastapi import APIRouter, HTTPException, Depends, Body, Path, Request, Response
|
||||||
|
|
@ -30,23 +35,20 @@ async def get_connections(
|
||||||
request: Request,
|
request: Request,
|
||||||
currentUser: User = Depends(getCurrentUser)
|
currentUser: User = Depends(getCurrentUser)
|
||||||
) -> List[UserConnection]:
|
) -> List[UserConnection]:
|
||||||
"""Get all connections for the current user or all connections if admin"""
|
"""Get all connections for the current user
|
||||||
|
|
||||||
|
SECURITY: This endpoint is secure - users can only see their own connections.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
interface = getInterface(currentUser)
|
interface = getInterface(currentUser)
|
||||||
|
|
||||||
# Clear connections cache to ensure fresh data
|
# Clear connections cache to ensure fresh data
|
||||||
interface.db.clearTableCache("connections")
|
interface.db.clearTableCache("connections")
|
||||||
|
|
||||||
if currentUser.privilege in ['admin', 'sysadmin']:
|
# SECURITY FIX: All users (including admins) can only see their own connections
|
||||||
# Admins can see all connections
|
# This prevents admin from seeing other users' connections and causing confusion
|
||||||
users = interface.getAllUsers()
|
return interface.getUserConnections(currentUser.id)
|
||||||
connections = []
|
|
||||||
for user in users:
|
|
||||||
connections.extend(interface.getUserConnections(user.id))
|
|
||||||
return connections
|
|
||||||
else:
|
|
||||||
# Regular users can only see their own connections
|
|
||||||
return interface.getUserConnections(currentUser.id)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error getting connections: {str(e)}")
|
logger.error(f"Error getting connections: {str(e)}")
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -61,6 +63,11 @@ async def create_connection(
|
||||||
connection_data: Dict[str, Any] = Body(...),
|
connection_data: Dict[str, Any] = Body(...),
|
||||||
currentUser: User = Depends(getCurrentUser)
|
currentUser: User = Depends(getCurrentUser)
|
||||||
) -> UserConnection:
|
) -> UserConnection:
|
||||||
|
"""Create a new connection for the current user
|
||||||
|
|
||||||
|
SECURITY: This endpoint is secure - it always creates connections for the current user
|
||||||
|
and cannot be used to create connections for other users.
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
interface = getInterface(currentUser)
|
interface = getInterface(currentUser)
|
||||||
|
|
@ -120,30 +127,22 @@ async def update_connection(
|
||||||
connection_data: Dict[str, Any] = Body(...),
|
connection_data: Dict[str, Any] = Body(...),
|
||||||
currentUser: User = Depends(getCurrentUser)
|
currentUser: User = Depends(getCurrentUser)
|
||||||
) -> UserConnection:
|
) -> UserConnection:
|
||||||
"""Update an existing connection"""
|
"""Update an existing connection for the current user
|
||||||
|
|
||||||
|
SECURITY: This endpoint is secure - users can only update their own connections.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
interface = getInterface(currentUser)
|
interface = getInterface(currentUser)
|
||||||
|
|
||||||
# Find the connection
|
# Find the connection
|
||||||
connection = None
|
connection = None
|
||||||
if currentUser.privilege in ['admin', 'sysadmin']:
|
# SECURITY FIX: All users (including admins) can only update their own connections
|
||||||
# Admins can update any connection
|
# This prevents admin from updating other users' connections and causing confusion
|
||||||
users = interface.getAllUsers()
|
connections = interface.getUserConnections(currentUser.id)
|
||||||
for user in users:
|
for conn in connections:
|
||||||
connections = interface.getUserConnections(user.id)
|
if conn.id == connectionId:
|
||||||
for conn in connections:
|
connection = conn
|
||||||
if conn.id == connectionId:
|
break
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
if connection:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# Regular users can only update their own connections
|
|
||||||
connections = interface.getUserConnections(currentUser.id)
|
|
||||||
for conn in connections:
|
|
||||||
if conn.id == connectionId:
|
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
|
|
||||||
if not connection:
|
if not connection:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -184,30 +183,23 @@ async def connect_service(
|
||||||
connectionId: str = Path(..., description="The ID of the connection to connect"),
|
connectionId: str = Path(..., description="The ID of the connection to connect"),
|
||||||
currentUser: User = Depends(getCurrentUser)
|
currentUser: User = Depends(getCurrentUser)
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
"""Connect a service for the current user
|
||||||
|
|
||||||
|
SECURITY: This endpoint is secure - users can only connect their own connections.
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
interface = getInterface(currentUser)
|
interface = getInterface(currentUser)
|
||||||
|
|
||||||
# Find the connection
|
# Find the connection
|
||||||
connection = None
|
connection = None
|
||||||
if currentUser.privilege in ['admin', 'sysadmin']:
|
# SECURITY FIX: All users (including admins) can only connect their own connections
|
||||||
# Admins can connect any connection
|
# This prevents admin from connecting other users' connections and causing confusion
|
||||||
users = interface.getAllUsers()
|
connections = interface.getUserConnections(currentUser.id)
|
||||||
for user in users:
|
for conn in connections:
|
||||||
connections = interface.getUserConnections(user.id)
|
if conn.id == connectionId:
|
||||||
for conn in connections:
|
connection = conn
|
||||||
if conn.id == connectionId:
|
break
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
if connection:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# Regular users can only connect their own connections
|
|
||||||
connections = interface.getUserConnections(currentUser.id)
|
|
||||||
for conn in connections:
|
|
||||||
if conn.id == connectionId:
|
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
|
|
||||||
if not connection:
|
if not connection:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -257,30 +249,23 @@ async def disconnect_service(
|
||||||
connectionId: str = Path(..., description="The ID of the connection to disconnect"),
|
connectionId: str = Path(..., description="The ID of the connection to disconnect"),
|
||||||
currentUser: User = Depends(getCurrentUser)
|
currentUser: User = Depends(getCurrentUser)
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
"""Disconnect a service for the current user
|
||||||
|
|
||||||
|
SECURITY: This endpoint is secure - users can only disconnect their own connections.
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
interface = getInterface(currentUser)
|
interface = getInterface(currentUser)
|
||||||
|
|
||||||
# Find the connection
|
# Find the connection
|
||||||
connection = None
|
connection = None
|
||||||
if currentUser.privilege in ['admin', 'sysadmin']:
|
# SECURITY FIX: All users (including admins) can only disconnect their own connections
|
||||||
# Admins can disconnect any connection
|
# This prevents admin from disconnecting other users' connections and causing confusion
|
||||||
users = interface.getAllUsers()
|
connections = interface.getUserConnections(currentUser.id)
|
||||||
for user in users:
|
for conn in connections:
|
||||||
connections = interface.getUserConnections(user.id)
|
if conn.id == connectionId:
|
||||||
for conn in connections:
|
connection = conn
|
||||||
if conn.id == connectionId:
|
break
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
if connection:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# Regular users can only disconnect their own connections
|
|
||||||
connections = interface.getUserConnections(currentUser.id)
|
|
||||||
for conn in connections:
|
|
||||||
if conn.id == connectionId:
|
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
|
|
||||||
if not connection:
|
if not connection:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -316,30 +301,23 @@ async def delete_connection(
|
||||||
connectionId: str = Path(..., description="The ID of the connection to delete"),
|
connectionId: str = Path(..., description="The ID of the connection to delete"),
|
||||||
currentUser: User = Depends(getCurrentUser)
|
currentUser: User = Depends(getCurrentUser)
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
"""Delete a connection for the current user
|
||||||
|
|
||||||
|
SECURITY: This endpoint is secure - users can only delete their own connections.
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
interface = getInterface(currentUser)
|
interface = getInterface(currentUser)
|
||||||
|
|
||||||
# Find the connection
|
# Find the connection
|
||||||
connection = None
|
connection = None
|
||||||
if currentUser.privilege in ['admin', 'sysadmin']:
|
# SECURITY FIX: All users (including admins) can only delete their own connections
|
||||||
# Admins can delete any connection
|
# This prevents admin from deleting other users' connections and causing confusion
|
||||||
users = interface.getAllUsers()
|
connections = interface.getUserConnections(currentUser.id)
|
||||||
for user in users:
|
for conn in connections:
|
||||||
connections = interface.getUserConnections(user.id)
|
if conn.id == connectionId:
|
||||||
for conn in connections:
|
connection = conn
|
||||||
if conn.id == connectionId:
|
break
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
if connection:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# Regular users can only delete their own connections
|
|
||||||
connections = interface.getUserConnections(currentUser.id)
|
|
||||||
for conn in connections:
|
|
||||||
if conn.id == connectionId:
|
|
||||||
connection = conn
|
|
||||||
break
|
|
||||||
|
|
||||||
if not connection:
|
if not connection:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue