From 190ba2a3b9f84db14af58f2fa9dc2a96d5d3db18 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 31 May 2024 17:29:17 -0700 Subject: [PATCH 1/6] fix allow PROXY_ADMIN_VIEW_ONLY to create an account --- litellm/proxy/proxy_server.py | 29 +++++++++++++++++++++++++++++ litellm/proxy/utils.py | 11 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 4759ea8c4d2..3fdc6485c6a 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -97,6 +97,7 @@ from litellm.proxy.utils import ( _read_request_body, _is_valid_team_configs, _is_user_proxy_admin, + _get_user_role, _is_projected_spend_over_limit, _get_projected_spend_over_limit, update_spend, @@ -1273,6 +1274,8 @@ async def user_api_key_auth( if _end_user_object is not None: valid_token_dict.update(end_user_params) + _user_role = _get_user_role(user_id_information=user_id_information) + if not _is_user_proxy_admin(user_id_information): # if non-admin if route in LiteLLMRoutes.openai_routes.value: pass @@ -1326,6 +1329,32 @@ async def user_api_key_auth( ): pass + elif _user_role == LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY: + if route in LiteLLMRoutes.openai_routes.value: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=f"user not allowed to access this OpenAI routes, role= {_user_role}", + ) + if route in LiteLLMRoutes.management_routes.value: + # the Admin Viewer is only allowed to call /user/update for their own user_id and can only update + if route == "/user/update": + + # Check the Request params are valid for PROXY_ADMIN_VIEW_ONLY + if request_data is not None and isinstance( + request_data, dict + ): + _params_updated = request_data.keys() + for param in _params_updated: + if param not in ["user_email", "password"]: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=f"user not allowed to access this route, role= {_user_role}. Trying to access: {route} and updating invalid param: {param}. only user_email and password can be updated", + ) + else: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=f"user not allowed to access this route, role= {_user_role}. Trying to access: {route}", + ) else: user_role = "unknown" user_id = "unknown" diff --git a/litellm/proxy/utils.py b/litellm/proxy/utils.py index 86131991bfb..eed59664b11 100644 --- a/litellm/proxy/utils.py +++ b/litellm/proxy/utils.py @@ -2658,6 +2658,17 @@ def _is_user_proxy_admin(user_id_information: Optional[list]): return False +def _get_user_role(user_id_information: Optional[list]): + if user_id_information is None: + return None + + if len(user_id_information) == 0 or user_id_information[0] is None: + return None + + _user = user_id_information[0] + return _user.get("user_role") + + def encrypt_value(value: str, master_key: str): import hashlib import nacl.secret From c8ee205a21eea3923e6887102118fe8e753491a6 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 31 May 2024 17:30:42 -0700 Subject: [PATCH 2/6] invite - viewers on admin ui --- ui/litellm-dashboard/src/components/admins.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ui/litellm-dashboard/src/components/admins.tsx b/ui/litellm-dashboard/src/components/admins.tsx index b3606d8f518..fbcb20e5cc2 100644 --- a/ui/litellm-dashboard/src/components/admins.tsx +++ b/ui/litellm-dashboard/src/components/admins.tsx @@ -338,6 +338,15 @@ const AdminPanel: React.FC = ({ ); console.log(`response for team create call: ${response}`); // Checking if the team exists in the list and updating or adding accordingly + + // Give admin an invite link for inviting user to proxy + const user_id = response.data?.user_id || response.user_id; + invitationCreateCall(accessToken, user_id).then((data) => { + setInvitationLinkData(data); + setIsInvitationLinkModalVisible(true); + }); + + const foundIndex = admins.findIndex((user) => { console.log( `user.user_id=${user.user_id}; response.user_id=${response.user_id}` From 9b92ad96a61bbb480c8b6e47dfb07a03871c7e22 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 31 May 2024 17:39:58 -0700 Subject: [PATCH 3/6] fix - invirte users with invite links --- litellm/proxy/proxy_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 3fdc6485c6a..5939bab5245 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -11838,7 +11838,7 @@ async def onboarding(invite_link: str): response = await generate_key_helper_fn( **{ - "user_role": LitellmUserRoles.PROXY_ADMIN, + "user_role": user_obj.user_role, "duration": "2hr", "key_max_budget": 5, "models": [], @@ -11863,7 +11863,7 @@ async def onboarding(invite_link: str): "user_id": user_obj.user_id, "key": key, "user_email": user_obj.user_email, - "user_role": "app_owner", + "user_role": user_obj.user_role, "login_method": "username_password", "premium_user": premium_user, }, From c22dc05b5338e45a0210f0409316d8dadea69476 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 31 May 2024 17:42:37 -0700 Subject: [PATCH 4/6] only show proxy admin viewer uage panel --- ui/litellm-dashboard/src/components/leftnav.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ui/litellm-dashboard/src/components/leftnav.tsx b/ui/litellm-dashboard/src/components/leftnav.tsx index a23ebc72c1a..aa774088596 100644 --- a/ui/litellm-dashboard/src/components/leftnav.tsx +++ b/ui/litellm-dashboard/src/components/leftnav.tsx @@ -28,15 +28,6 @@ const Sidebar: React.FC = ({ } style={{ height: "100%", borderRight: 0 }} > - setPage("api-keys")}> - API Keys - - setPage("models")}> - Models - - setPage("llm-playground")}> - Chat UI - setPage("usage")}> Usage From e17db30b676b000c316d9e9dac0b9c03a599ef70 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 31 May 2024 17:45:37 -0700 Subject: [PATCH 5/6] fix - allow proxy_Admin_viewer /global/activity --- litellm/proxy/proxy_server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 5939bab5245..529c1f39e1e 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -1394,6 +1394,7 @@ async def user_api_key_auth( "/global/spend/keys", "/global/spend/models", "/global/predict/spend/logs", + "/global/activity", "/health/services", ] # check if the current route startswith any of the allowed routes From 5539833a56bceb7f1833a76a40b3a31d59d65449 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 31 May 2024 17:57:50 -0700 Subject: [PATCH 6/6] fix clean up flow for adding ui spend viewers --- litellm/proxy/proxy_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 529c1f39e1e..7038cb90393 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -1109,7 +1109,7 @@ async def user_api_key_auth( user_email: Optional[str] = None # Check if the token has any user id information - if user_id_information is not None: + if user_id_information is not None and len(user_id_information) > 0: specific_user_id_information = user_id_information[0] _user_email = specific_user_id_information.get("user_email", None) if _user_email is not None: @@ -1359,7 +1359,7 @@ async def user_api_key_auth( user_role = "unknown" user_id = "unknown" if user_id_information is not None and isinstance( - user_id_information, list + user_id_information, list and len(user_id_information) > 0 ): _user = user_id_information[0] user_role = _user.get("user_role", "unknown")