@@ -37,6 +37,14 @@ async def read_root(
37
37
except HTTPException as e :
38
38
logger .info (f"Authentication failed at root route: { e .detail } , redirecting to login" )
39
39
return RedirectResponse (url = "/login" , status_code = 302 )
40
+
41
+ from ..auth .dependencies import user_has_ui_permission_for_service
42
+
43
+ # Helper function for templates
44
+ def can_perform_action (permission : str , service_name : str ) -> bool :
45
+ """Check if user has UI permission for a specific service"""
46
+ return user_has_ui_permission_for_service (permission , service_name , user_context .get ('ui_permissions' , {}))
47
+
40
48
service_data = []
41
49
search_query = query .lower () if query else ""
42
50
@@ -55,10 +63,18 @@ async def read_root(
55
63
key = lambda p : all_servers [p ]["server_name" ]
56
64
)
57
65
66
+ # Filter services based on UI permissions
67
+ accessible_services = user_context .get ('accessible_services' , [])
68
+
58
69
for path in sorted_server_paths :
59
70
server_info = all_servers [path ]
60
71
server_name = server_info ["server_name" ]
61
72
73
+ # Check if user can list this service
74
+ if 'all' not in accessible_services and server_name not in accessible_services :
75
+ logger .debug (f"Filtering out service '{ server_name } ' - user doesn't have list_service permission" )
76
+ continue
77
+
62
78
# Include description and tags in search
63
79
searchable_text = f"{ server_name .lower ()} { server_info .get ('description' , '' ).lower ()} { ' ' .join (server_info .get ('tags' , []))} "
64
80
if not search_query or search_query in searchable_text :
@@ -88,7 +104,8 @@ async def read_root(
88
104
"request" : request ,
89
105
"services" : service_data ,
90
106
"username" : user_context ['username' ],
91
- "user_context" : user_context # Pass full user context to template
107
+ "user_context" : user_context , # Pass full user context to template
108
+ "can_perform_action" : can_perform_action # Helper function for permission checks
92
109
},
93
110
)
94
111
@@ -100,25 +117,28 @@ async def toggle_service_route(
100
117
enabled : Annotated [str | None , Form ()] = None ,
101
118
user_context : Annotated [dict , Depends (enhanced_auth )] = None ,
102
119
):
103
- """Toggle a service on/off (requires modification permissions )."""
120
+ """Toggle a service on/off (requires toggle_service UI permission )."""
104
121
from ..search .service import faiss_service
105
122
from ..health .service import health_service
106
123
from ..core .nginx_service import nginx_service
107
-
108
- # Check if user can modify servers
109
- if not user_context ['can_modify_servers' ]:
110
- logger .warning (f"User { user_context ['username' ]} attempted to toggle service { service_path } without modify permissions" )
111
- raise HTTPException (
112
- status_code = status .HTTP_403_FORBIDDEN ,
113
- detail = "You do not have permission to modify servers"
114
- )
124
+ from ..auth .dependencies import user_has_ui_permission_for_service
115
125
116
126
if not service_path .startswith ("/" ):
117
127
service_path = "/" + service_path
118
128
119
129
server_info = server_service .get_server_info (service_path )
120
130
if not server_info :
121
131
raise HTTPException (status_code = 404 , detail = "Service path not registered" )
132
+
133
+ service_name = server_info ["server_name" ]
134
+
135
+ # Check if user has toggle_service permission for this specific service
136
+ if not user_has_ui_permission_for_service ('toggle_service' , service_name , user_context .get ('ui_permissions' , {})):
137
+ logger .warning (f"User { user_context ['username' ]} attempted to toggle service { service_name } without toggle_service permission" )
138
+ raise HTTPException (
139
+ status_code = status .HTTP_403_FORBIDDEN ,
140
+ detail = f"You do not have permission to toggle { service_name } "
141
+ )
122
142
123
143
# For non-admin users, check if they have access to this specific server
124
144
if not user_context ['is_admin' ]:
@@ -194,17 +214,21 @@ async def register_service(
194
214
license_str : Annotated [str , Form (alias = "license" )] = "N/A" ,
195
215
user_context : Annotated [dict , Depends (enhanced_auth )] = None ,
196
216
):
197
- """Register a new service (requires modification permissions )."""
217
+ """Register a new service (requires register_service UI permission )."""
198
218
from ..search .service import faiss_service
199
219
from ..health .service import health_service
200
220
from ..core .nginx_service import nginx_service
221
+ from ..auth .dependencies import user_has_ui_permission_for_service
222
+
223
+ # Check if user has register_service permission for any service
224
+ ui_permissions = user_context .get ('ui_permissions' , {})
225
+ register_permissions = ui_permissions .get ('register_service' , [])
201
226
202
- # Check if user can modify servers
203
- if not user_context ['can_modify_servers' ]:
204
- logger .warning (f"User { user_context ['username' ]} attempted to register service without modify permissions" )
227
+ if not register_permissions :
228
+ logger .warning (f"User { user_context ['username' ]} attempted to register service without register_service permission" )
205
229
raise HTTPException (
206
230
status_code = status .HTTP_403_FORBIDDEN ,
207
- detail = "You do not have permission to register new servers "
231
+ detail = "You do not have permission to register new services "
208
232
)
209
233
210
234
logger .info (f"Service registration request from user '{ user_context ['username' ]} '" )
@@ -270,14 +294,8 @@ async def edit_server_form(
270
294
service_path : str ,
271
295
user_context : Annotated [dict , Depends (enhanced_auth )]
272
296
):
273
- """Show edit form for a service (requires modification permissions)."""
274
- # Check if user can modify servers
275
- if not user_context ['can_modify_servers' ]:
276
- logger .warning (f"User { user_context ['username' ]} attempted to access edit form for { service_path } without modify permissions" )
277
- raise HTTPException (
278
- status_code = status .HTTP_403_FORBIDDEN ,
279
- detail = "You do not have permission to edit servers"
280
- )
297
+ """Show edit form for a service (requires modify_service UI permission)."""
298
+ from ..auth .dependencies import user_has_ui_permission_for_service
281
299
282
300
if not service_path .startswith ('/' ):
283
301
service_path = '/' + service_path
@@ -286,6 +304,16 @@ async def edit_server_form(
286
304
if not server_info :
287
305
raise HTTPException (status_code = 404 , detail = "Service path not found" )
288
306
307
+ service_name = server_info ["server_name" ]
308
+
309
+ # Check if user has modify_service permission for this specific service
310
+ if not user_has_ui_permission_for_service ('modify_service' , service_name , user_context .get ('ui_permissions' , {})):
311
+ logger .warning (f"User { user_context ['username' ]} attempted to access edit form for { service_name } without modify_service permission" )
312
+ raise HTTPException (
313
+ status_code = status .HTTP_403_FORBIDDEN ,
314
+ detail = f"You do not have permission to modify { service_name } "
315
+ )
316
+
289
317
# For non-admin users, check if they have access to this specific server
290
318
if not user_context ['is_admin' ]:
291
319
if not server_service .user_can_access_server_path (service_path , user_context ['accessible_servers' ]):
@@ -319,24 +347,29 @@ async def edit_server_submit(
319
347
is_python : Annotated [bool | None , Form ()] = False ,
320
348
license_str : Annotated [str , Form (alias = "license" )] = "N/A" ,
321
349
):
322
- """Handle server edit form submission (requires modification permissions )."""
350
+ """Handle server edit form submission (requires modify_service UI permission )."""
323
351
from ..search .service import faiss_service
324
352
from ..core .nginx_service import nginx_service
325
-
326
- # Check if user can modify servers
327
- if not user_context ['can_modify_servers' ]:
328
- logger .warning (f"User { user_context ['username' ]} attempted to edit service { service_path } without modify permissions" )
329
- raise HTTPException (
330
- status_code = status .HTTP_403_FORBIDDEN ,
331
- detail = "You do not have permission to edit servers"
332
- )
353
+ from ..auth .dependencies import user_has_ui_permission_for_service
333
354
334
355
if not service_path .startswith ('/' ):
335
356
service_path = '/' + service_path
336
357
337
- # Check if the server exists
338
- if not server_service .get_server_info (service_path ):
358
+ # Check if the server exists and get service name
359
+ server_info = server_service .get_server_info (service_path )
360
+ if not server_info :
339
361
raise HTTPException (status_code = 404 , detail = "Service path not found" )
362
+
363
+ service_name = server_info ["server_name" ]
364
+
365
+ # Check if user has modify_service permission for this specific service
366
+ if not user_has_ui_permission_for_service ('modify_service' , service_name , user_context .get ('ui_permissions' , {})):
367
+ logger .warning (f"User { user_context ['username' ]} attempted to edit service { service_name } without modify_service permission" )
368
+ raise HTTPException (
369
+ status_code = status .HTTP_403_FORBIDDEN ,
370
+ detail = f"You do not have permission to modify { service_name } "
371
+ )
372
+
340
373
341
374
# For non-admin users, check if they have access to this specific server
342
375
if not user_context ['is_admin' ]:
@@ -537,18 +570,29 @@ async def refresh_service(
537
570
service_path : str ,
538
571
user_context : Annotated [dict , Depends (enhanced_auth )]
539
572
):
540
- """Refresh service health and tool information (requires read access )."""
573
+ """Refresh service health and tool information (requires health_check_service permission )."""
541
574
from ..search .service import faiss_service
542
575
from ..health .service import health_service
543
576
from ..core .mcp_client import mcp_client_service
544
577
from ..core .nginx_service import nginx_service
578
+ from ..auth .dependencies import user_has_ui_permission_for_service
545
579
546
580
if not service_path .startswith ('/' ):
547
581
service_path = '/' + service_path
548
582
549
583
server_info = server_service .get_server_info (service_path )
550
584
if not server_info :
551
585
raise HTTPException (status_code = 404 , detail = "Service path not registered" )
586
+
587
+ service_name = server_info ["server_name" ]
588
+
589
+ # Check if user has health_check_service permission for this specific service
590
+ if not user_has_ui_permission_for_service ('health_check_service' , service_name , user_context .get ('ui_permissions' , {})):
591
+ logger .warning (f"User { user_context ['username' ]} attempted to refresh service { service_name } without health_check_service permission" )
592
+ raise HTTPException (
593
+ status_code = status .HTTP_403_FORBIDDEN ,
594
+ detail = f"You do not have permission to refresh { service_name } "
595
+ )
552
596
553
597
# For non-admin users, check if they have access to this specific server
554
598
if not user_context ['is_admin' ]:
0 commit comments