
    gz                        d Z ddlZddlZddlZddlmZmZmZmZm	Z	m
Z
 ddlmZ ddlZddlmZ ddlmZ ddlmZ ddlmZmZmZmZmZmZmZmZmZmZmZ dd	l m!Z! dd
l"m#Z#m$Z$m%Z% ddl&m'Z' ddl(m)Z) ddl*m+Z+ er	ddl,m-Z. e.Z-neZ- ed      Z/dZ0ejb                  jd                  ejf                  jd                  z   Z4de5fdZ6de7de
e   de
e   de
e   de
e8   de7de9de
e'   de5fdZ:de9de;de5fd Z<d!e	ejz                  ej|                  ej~                  f   de9d"ede5fd#Z@d$ed%e
e9   de5fd&ZAde;de;fd'ZBe%	 	 dRd(e
e9   d)e
e#   d*ed+e
e-   d,e
e$   de
e   fd-       ZCd.e9d/e
ee9      de
e'   de5fd0ZDd1e9d2ed3eEde5fd4ZFd1e9d5e
e   d2efd6ZGe%	 	 dRd7e9d)e
e#   d*ed8e5d+e
e-   d,e
e$   de
e   fd9       ZHd1e9d5ed*ed,e
e$   fd:ZId;e9d<ed*ed,e
e$   fd=ZJd>e9d?ed*ed,e
e$   fd@ZKd>e9d*ed,e
e$   fdAZLe%d;e9d)e#fdB       ZMd;e9d)e#fdCZNd;e9d)e#d*ed2ed3eEd,e
e$   d1e9defdDZOd1e9d,e
e$   d*ed+e
e-   de
e   f
dEZP	 	 	 	 dSd;e9d)e
e#   d*ed+e
e-   d,e
e$   dFe
e5   dGe
e5   defdHZQe%	 	 	 dTd>e9d)e
e#   d*ed+e
e-   d,e
e$   dFe
e5   defdI       ZRdJeSdefdKZTe%	 	 dRdLe9d)e
e#   d*ed+e
e-   d,e
e$   f
dM       ZUd.e9dNe
e;   dOede
ejN                     de	dP   f
dQZVy)Uz
Got Valid Token from Cache, DB
Run checks for: 

1. If user can call model
2. If user is in budget 
3. If end_user ('user' passed to /chat/completions, /embeddings endpoint) is in budget 
    N)TYPE_CHECKINGAnyDictListLiteralOptional)	BaseModel)verbose_proxy_logger)	DualCache)LimitedSizeOrderedDict)DB_CONNECTION_ERROR_TYPESCommonProxyErrorsLiteLLM_EndUserTableLiteLLM_JWTAuthLiteLLM_OrganizationTableLiteLLM_TeamTableLiteLLM_TeamTableCachedObjLiteLLM_UserTableLiteLLMRoutesLitellmUserRolesUserAPIKeyAuth)RouteChecks)PrismaClientProxyLogginglog_db_metrics)Router)ServiceTypes   )$organization_role_based_access_check)Spand   )max_size   returnc                     ddl m}  t        j                         d   }|j                  }|j
                  j                  j                  |      }d}t        j                  |       }|t        |      st        d| d      t        j                  |      }||k7  r)t        d| dt        j                  j                         ||k7  r)t        d	| d
t        j                  j                         y)Nr   )user_api_key_auth   r&   zCaller function z is not callablezThe function 'z@' does not match the required signature of 'user_api_key_auth'. z'This function can only be imported by 'z'. T)$litellm.proxy.auth.user_api_key_authr&   inspectstackfunctionframe	f_globalsget	signaturecallable	Exception	TypeErrorr   not_premium_uservalueImportError)r&   caller_framecaller_functioncaller_function_callableallowed_functionallowed_signaturecaller_signatures          S/var/www/openai/venv/lib/python3.12/site-packages/litellm/proxy/auth/auth_checks.py_allowed_import_checkr=   9   s   F ==?1%L"++O+11;;??P*))*;<'x8P/Q*?*;;KLMM(()AB,,_--mn  oQ  oQ  oW  oW  nX  Y
 	
 **56F5GsK\KmKmKsKsJtu
 	
     request_bodyteam_objectuser_objectend_user_objectglobal_proxy_spendgeneral_settingsroute
llm_routerc           
         t                | j                  dd      }|'|j                  du rt        d|j                   d      |||j
                  t        |j
                        dkD  r||j
                  vrud|j
                  v sd|j
                  v sd	|j
                  v rnJt        ||j
                  |
      du rn/|rd|v rn(t        d|j                   d| d|j
                         ||j                  x|j                  l|j                  |j                  kD  rSt        j                  |j                  |j                  d|j                   d|j                   d|j                         ||j                  h|f|j                  Z|j                  }	|	|j                  k  r?t        j                  |j                  |	d|j                   d|j                   d|	       |r|j                  f|j                  j                  }
|
N|j                  |
kD  r?t        j                  |j                  |
d|j                   d|j                   d|
       |j                  dd      2|d   du r+t        j                  |      rd| vrt        d|d          t        j                  dkD  rZ|Xt        j                  |      rB|dk7  r=|dk7  r8|t        j                  kD  r%t        j                  |t        j                        | j                  di       xs i }|j                  d      r$ddlm}  ||      }|du rddlm}  |ddd i!      t)        ||| "       y)#a  
    Common checks across jwt + key-based auth.

    1. If team is blocked
    2. If team can call model
    3. If team is in budget
    4. If user passed in (JWT or key.user_id) - is in budget
    5. If end_user (either via JWT or 'user' passed to /chat/completions, /embeddings endpoint) is in budget
    6. [OPTIONAL] If 'enforce_end_user' enabled - did developer pass in 'user' param for openai endpoints
    7. [OPTIONAL] If 'litellm.max_budget' is set (>0), is proxy under budget
    8. [OPTIONAL] If guardrails modified - is request allowed to change this
    9. Check if request body is safe
    10. [OPTIONAL] Organization checks - is user_object.organization_id is set, run these checks
    modelNTzTeam=z6 is blocked. Update via `/team/unblock` if your admin.r   zall-proxy-models*zopenai/*)rH   team_modelsrF   z not allowed to call model=z. Allowed team models = z over budget. Spend=z	, Budget=)current_cost
max_budgetmessagezExceededBudget: User=zExceededBudget: End User=enforce_user_param)rE   userz1'user' param not passed in. 'enforce_user_param'=z
/v1/modelsz/modelsrK   rL   metadata
guardrails)can_modify_guardrailsF)HTTPExceptioni  errorz8Your team does not have permission to modify guardrails.)status_codedetail)rA   rE   r?   )r=   r.   blockedr1   team_idmodelslenmodel_in_access_grouprL   spendlitellmBudgetExceededErroruser_idlitellm_budget_tabler   is_llm_api_route*litellm.proxy.guardrails.guardrail_helpersrS   fastapirT   r   )r?   r@   rA   rB   rC   rD   rE   rF   _modeluser_budgetend_user_budget_request_metadatarS   
can_modifyrT   s                  r<   common_checksrj   T   s   0 gt,F;#6#6$#>K''((^_
 	

 	#*""#a'+,,, +"4"44k((([///  "+*<*< 
 v++,,GxOghshzhzg{| 
 	"".) 6 66))$**"--K//00D[EVEVDWW`alawaw`xy
 	
 
	 3 3 ;#"".!,,***--(..&/0C0C/DDXYdYjYjXkkt  vA  uB  C  "'K'K'W)>>II&?+@+@?+R--,22*3O4K4K3LL`apavav`w  xA  BQ  AR  S  	148D12d:''e4|9SCDTUiDjCkl 
 	Q* ((u5\!Y 2 22--/G<N<N  +..z2>D"\*T0=
-W  )u< r>   
user_routeallowed_routesc                 r    |D ]2  }|t         j                  v r| t         |   j                  v r y|| k(  s2 y y)a	  
    Return if a user is allowed to access route. Helper function for `allowed_routes_check`.

    Parameters:
    - user_route: str - the route the user is trying to call
    - allowed_routes: List[str|LiteLLMRoutes] - the list of allowed routes for the user.
    TF)r   __members__r4   )rk   rl   allowed_routes      r<   _allowed_routes_checkrp      sB     (]666mM:@@@j( ( r>   	user_rolelitellm_proxy_rolesc                    | t         j                  k(  rt        ||j                        }|S | t         j                  k(  rC|j
                  	 t        |ddg      }|S |j
                  t        ||j
                        }|S y)zE
    Check if user -> not admin - allowed to access these routes
    )rk   rl   openai_routesinfo_routesF)r   PROXY_ADMINrp   admin_allowed_routesTEAMteam_allowed_routes)rq   rk   rr   
is_alloweds       r<   allowed_routes_checkr{      s     $000*!.CC

 	&++	+22: /%6VJ  44@.%2FFJ r>   user_api_key_dictrequested_user_idc                     d}| j                   t        j                  k7  r| j                   t        j                  k7  rd}|| j                  | j                  |k(  rd}|S )NTF)rq   r   rv   PROXY_ADMIN_VIEW_ONLYr`   )r|   r}   ret_vals      r<    allowed_route_check_inside_router     sc     G##'7'C'CC''+;+Q+QQ$):)B)B)N$$(99GNr>   c                     g }| D ]  }	 t         |   j                  }||z   } |S # t        $ r |j                  |       Y <w xY wN)r   r4   KeyErrorappend)rl   actual_routes
route_nameroute_values       r<   get_actual_routesr   -  sW    M$
	-'
399K)K7M %   	-  ,	-s   %AAend_user_idprisma_clientuser_api_key_cacheparent_otel_spanproxy_logging_objc                   K   |t        d      | ydj                  |       }dt        fd}|j                  |       d{   }|Ct	        |t
              rt        di |} ||       |S t	        |t              r|} ||       |S 	 |j                  j                  j                  d| id	d
i       d{   }	|	t         |j                  dj                  |       |	       d{    t        di |	j                         }
 ||
       |
S 7 7 \7 ,# t         $ r&}t	        |t        j                        r|Y d}~yd}~ww xY ww)af  
    Returns end user object, if in db.

    Do a isolated check for end user in table vs. doing a combined key + team + user + end-user check, as key might come in frequently for different end-users. Larger call will slowdown query time. This way we get to cache the constant (key/team/user info) and only update based on the changing value (end-user).
    NNo db connectedzend_user_id:{}end_user_objc                     | j                   y | j                   j                  }|1| j                  |kD  r!t        j                  | j                  |      y y )NrP   )ra   rL   r]   r^   r_   )r   rg   s     r<   check_in_budgetz,get_end_user_object.<locals>.check_in_budgetL  s\    ,,4&;;FF&<+=+=+O--)//O  ,P&r>   key)r   r`   ra   Twhereincluder   r4    )r1   formatr   async_get_cache
isinstancedictdblitellm_endusertablefind_uniqueasync_set_cacher^   r_   )r   r   r   r   r   _keyr   cached_user_obj
return_objresponse	_responsees               r<   get_end_user_objectr   8  sw     )**"";/D&:  />>4>HHO"ot,-@@J4)=>(J4&))>>JJk*+T2 K 
 

 O !00 ''4H 1 
 	
 	
 );8==?;	Y/; I
	
  a445Gsa   AEDA	E.D <D=1D .D/'D ED D 	E&EEEErH   rJ   c                     ddl m} |y| |v ry |t              }|r|j                  |       }t	        |      dkD  rt        |      D ]  \  }}||v s y |D cg c]	  }||vs| }}| |v ryyc c}w )Nr   defaultdictT
model_nameF)collectionsr   listget_model_access_groupsr[   	enumerate)rH   rJ   rF   r   access_groupsidxmfiltered_modelss           r<   r\   r\   z  s     (*5d*;M"::e:L
=A
FC M!	
 #.H+Q-1Gq+OH Is   	A0$A0r   last_db_access_timedb_cache_expiryc                 p    t        j                          }| |vry||    d   y||    d   |||    z
  |k\  ryy)zM
    Prevent calling db repeatedly for items that don't exist in the db.
    Tr   Ftime)r   r   r   current_times       r<   _should_check_dbr     sW     99;L
%%C #/	S	!!	$	,-c22oEr>   r4   c                 6    |t        j                          f|| <   y r   r   r   r4   r   s      r<   _update_last_db_access_timer     s     !&tyy{3r>   r`   user_id_upsertc                   K   | y|j                  |        d{   }|-t        |t              rt        di |S t        |t              r|S |t	        d      	 dj                  |       }t        |t        t              }|r4|j                  j                  j                  d| iddi	       d{   }	nd}	|	<|r4|j                  j                  j                  d| iddi
       d{   }	nt        |	j                  Ht        |	j                        dkD  r0|	j                  D 
cg c]  }
|
|
j                          }}
||	_        t        di t        |	      }|j                         }|j!                  | |       d{    t#        ||t               |S 7 7 7 c c}
w 7 $# t        $ r}t%        d|  d|       d}~ww xY ww)z
    - Check if user id in proxy User Table
    - if valid, return LiteLLM_UserTable object with defined limits
    - if not, then raise an error
    Nr   r   z
user_id:{}r   r   r   r`   organization_membershipsTr   )datar   r   r   r   z$User doesn't exist in db. 'user_id'=z0. Create user via `/user/new` call. Got error - r   )r   r   r   r   r1   r   r   r   r   r   litellm_usertabler   creater   r[   
model_dumpr   r   
ValueError)r`   r   r   r   r   r   r   db_access_time_keyshould_check_dbr   
membership_dumped_membershipsr   response_dictr   s                  r<   get_user_objectr     s$      />>7>KKO"ot,$777):;"")**5
)009*" 3+
 *--??KK '*5OQU4V L  H H!.!1!1!C!C!J!J#W-7> "K " 
   --9H556:
 #+"C"C#"CJ) %%'"C   #
 1DH-%7X7	!,,. !00WM0RRR 	$" 3	
 u L$# 	S  
27);klmkno
 	

sx   GF!A GAF/ 4F$59F/ .F&/=F/ ,F(AF/ F-	F/  G$F/ &F/ (F/ /	G8G		GGc                 F   K   |j                  | |       d {    y 7 w)Nr   )r   r   r4   r   r   s       r<   _cache_management_objectr     s!      
,
,E
,
BBBs   !!rY   
team_tablec                    K   dj                  |       }t        j                         |_        t        ||||       d {    y 7 w)N
team_id:{}r   )r   r   last_refreshed_atr   )rY   r   r   r   r   s        r<   _cache_team_objectr     sF      

g
&C $(99;J 
"-+	  s   =AA Ahashed_tokenuser_api_key_objc                 t   K   | }t        j                          |_        t        ||||       d {    y 7 w)Nr   )r   r   r   )r   r   r   r   r   s        r<   _cache_key_objectr   "  s<      C *.&
"-+	  s   .868c                    K   | }|j                  |       |/|j                  j                  j                  |       d {    y y 7 w)Nr   )delete_cacheinternal_usage_cache
dual_cacheasync_delete_cache)r   r   r   r   s       r<   _delete_cache_key_objectr   5  s]     
 C###, $44??RR S 
 	
 	
 %	
s   A AA	Ac                 n   K   |j                   j                  j                  d| i       d {   S 7 wNrY   r   r   litellm_teamtabler   rY   r   s     r<   _get_team_db_checkr   E  s=     !!33??'" @       ,535c                 n   K   |j                   j                  j                  d| i       d {   S 7 wr   r   r   s     r<   _get_team_object_from_dbr   L  s=     !!33??'" @    r   c                    K   |}t        |||      }|rt        | |       d {   }	nd }	|	t        t        di |	j	                         }
t        | |
||       d {    t        ||
|       |
S 7 O7 w)Nr   r   )rY   r   r   r   r   r   )r   r   r1   r   r   r   r   )rY   r   r   r   r   r   r   r   r   r   r   s              r<   (_get_team_object_from_user_api_key_cacher   R  s      &/'O
 +=
 
 *=X]]_=I
-+	    / 5
s!   #A9A5:A9 A7!A97A9c                 <  K   d }|E|j                   j                  r/|j                   j                  j                  | |       d {   }||j                  |        d {   }|-t        |t              rt        di |S t        |t
              r|S y 7 P7 6w)N)r   r   r   r   )r   r   r   r   r   r   )r   r   r   r   cached_team_objs        r<   _get_team_object_from_cacher     s      =AO 	%22== $88CCSS*: T   	  2 B Bs B KK"ot,-@@@)CD"" Ls$   ABBB#B$5BBcheck_cache_onlycheck_db_onlyc           	      (  K   |t        d      dj                  |       }|s,t        ||||       d{   }||S |rt        d|  d      	 t        | |||t        t
        |       d{   S 7 <7 # t         $ r t        d|  d	      w xY ww)

    - Check if team id in proxy Team Table
    - if valid, return LiteLLM_TeamTable object with defined limits
    - if not, then raise an error
    NFNo DB Connected. See - https://docs.litellm.ai/docs/proxy/virtual_keysr   )r   r   r   r   z:Team doesn't exist in cache + check_cache_only=True. Team=.)rY   r   r   r   r   r   r   zTeam doesn't exist in db. Team=z#. Create team via `/team/new` call.)r1   r   r   r   r   r   )	rY   r   r   r   r   r   r   r   r   s	            r<   get_team_objectr     s      T
 	

 

g
&C ;/1-	!
 
 &""LWIUVW 

='1/ 3+
 
 	
#
"
  
-gY6YZ
 	

s9   3BA2BA6 -A4.A6 1B4A6 6BBc                 H  K   |t        d      | }|j                  |       d{   }|-t        |t              rt	        di |S t        |t              r|S |rt        d| d      	 |j                  | d||       d{   }|t         t	        di |j                  d	      }	t        | |	||
       d{    |	S 7 7 B7 
# t        $ r}
t        |
       d{  7  cY d}
~
S d}
~
wt         $ r$ t        j                          t        d|  d      w xY ww)r   Nr   r   z8Key doesn't exist in cache + check_cache_only=True. key=r   combined_view)token
table_namer   r   T)exclude_none)r   r   r   r   )r   zKey doesn't exist in db. key=z&. Create key via `/key/generate` call.r   )r1   r   r   r   r   get_datar   r   r   /_handle_failed_db_connection_for_get_key_object	traceback	print_exc)r   r   r   r   r   r   r   cached_key_obj_valid_tokenr   r   s              r<   get_key_objectr    sn     T
 	

 C5G5W5W 6X 6 0N !nd+!3N337!!Fse1M
 	


2?2H2H&-/	 3I 3
 -
 O"P\%<%<$%<%OP	  %&1/	
 	
 	
 K0"-
	
 % JDqIIII 
+L>9_`
 	

sp   %D"CAD"-C C9C ?C
 C D"C 
C 	DC/$C'%C/)D*D"/0DD"r   c                    K   ddl m}m}m} |j	                  dd      du r;|j
                  j                  t        j                  d| d       t        d	d	|
      S | w)a<  
    Handles httpx.ConnectError when reading a Virtual Key from LiteLLM DB

    Use this if you don't want failed DB queries to block LLM API reqiests

    Returns:
        - UserAPIKeyAuth: If general_settings.allow_requests_on_db_unavailable is True

    Raises:
        - Orignal Exception in all other cases
    r   )rD   litellm_proxy_admin_namer    allow_requests_on_db_unavailableFTr  g        )service	call_typerU   durationzfailed-to-connect-to-db)key_namer   r`   )
litellm.proxy.proxy_serverrD   r  r   r.   service_logging_objservice_failure_hookr   DBr   )r   rD   r  r   s       r<   r   r     sq       >F$N--BB OO&	 	C 	
 .+,
 	
 s   AAorg_idc                 d  K   |t        d      |j                  dj                  |             }|$t        |t              r|S t        |t
              r|S 	 |j                  j                  j                  d| i       d{   }|t         |S 7 # t         $ r t        d|  d      w xY ww)	z
    - Check if org id in proxy Org Table
    - if valid, return LiteLLM_OrganizationTable object
    - if not, then raise an error
    Nr   z	org_id:{}r   organization_idr   z/Organization doesn't exist in db. Organization=z3. Create organization via `/organization/new` call.)	r1   r   r   r   r   r   r   litellm_organizationtabler   )r  r   r   r   r   cached_org_objr   s          r<   get_org_objectr  C  s      T
 	

 (77K<N<Nv<V7WN!nd+!!(AB!!
&))CCOO$f- P 
 
 O
  
=fXExy
 	

s0   AB0+B BB B0B B--B0llm_model_listvalid_tokenTc                   K   | t         j                  v rt         j                  |    } t        j                  d|        ddlm}  |t              }|r|j                  |       }t        |      dkD  r%|#t        |j                        D ]  \  }}||v s y |j                  D cg c]	  }||vs| }}t        j                  d|  d|        d}	t        |      dk(  rt        |j                        dk(  sd	|v rd}	| #| |vr|	du rt        d
|j                   d|        ||_
        t        j                  d| d|j                          yc c}w w)z
    Checks if token can call a given model

    Returns:
        - True: if token allowed to call model

    Raises:
        - Exception: If token not allowed to call model
    z'LLM Model List pre access group check: r   r   r   Tzmodel: z; allowed_models: FrI   zGAPI Key not allowed to access model. This token can only access models=z. Tried to access zfiltered allowed_models: z; valid_token.models: )r^   model_alias_mapr
   debugr   r   r   r   r[   r   rZ   r   )
rH   r  r  rF   r   r   r   r   r   all_model_accesss
             r<   can_key_call_modelr  l  s     '''''. 
1.1AB (*5d*;M"::e:LMQ:#9
FC M!	
 #."4"4O"4Q8Nq"4OO/A/ARST" 	O!c+*<*<&=&B		U/9>NRW>WUVaVhVhUii{  }B  |C  D
 	
 )K
#O#44J;K]K]J^_ ' Ps   BEE'	E1E5B"E)NN)NNNN)NNN)W__doc__r)   r   r   typingr   r   r   r   r   r   pydanticr	   r^   litellm._loggingr
   litellm.caching.cachingr   litellm.caching.dual_cacher   litellm.proxy._typesr   r   r   r   r   r   r   r   r   r   r   litellm.proxy.auth.route_checksr   litellm.proxy.utilsr   r   r   litellm.routerr   litellm.types.servicesr   auth_checks_organizationr   opentelemetry.tracer    _Spanr   r   rt   r4   management_routes
all_routesboolr=   r   floatstrrj   r   rp   rv   rx   INTERNAL_USERr{   r   r   r   r\   intr   r   r   r   r   r   r   r   r   r   r   r   r  r1   r   r  r  r   r>   r<   <module>r1     sN      D D   1 - =    8 J J ! / J1DD -c: ((..1P1P1V1VV
t 6MM+,M +,M 23	M
 !M M M  M 
M`c 4 D &#$$&&	(# # )# 
#L%} 
 d t  
 (,04>#>L)> "> tn	>
  -> "#> >B%d3i0>Fv>N	<	#9LO	(4	4c]49O4  (,04P
P
L)P
 "P
 	P

 tnP
  -P
  P
 P
fC	CC "C  -	C* "  -	&$ "  -	&

!
  -
  c ,  C  *** "* 0	*
 *  -* 
*  *Z	- " tn	
 ()H (,04'+$(4
4
L)4
 "4
 tn	4

  -4
 tn4
 D>4
  4
n 
 (,04'+A
A
L)A
 "A
 tn	A

  -A
 tnA
 A
 A
H%%%P 
 (,04%
%
L)%
 "%
 tn	%

  -%
 %
P88TN8  8 (	8
 T]8r>   