
    )#hT0                         d Z ddlZddl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 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 ddlmZ  G d d      Zy)z
Supports using JWT's for authenticating into the proxy. 

Currently only supports admin. 

JWT token must have 'litellm_proxy_admin' in scope. 
    N)ListOptionalcast)x509)default_backend)serialization)verbose_proxy_logger)	DualCache)HTTPHandler)JWKKeyValue
JWTKeyItemLiteLLM_JWTAuthLitellmUserRoles)PrismaClientc                      e Zd ZU dZee   ed<   eed<   	 	 d#dZ	 d$dee   dede	de
ddf
d	Zd
efdZd
edee   fdZdedefdZd
edee   fdZd
edee   dee   fdZdefdZdefdZd
edee   dee   fdZd%dee   defdZd
edee   dee   fdZd
edee   dee   fdZd
edee   dee   fdZd
edefdZdee   defdZde dee   dee!   fdZ"dedefd Z#d
edefd!Z$d" Z%y)&
JWTHandlerz
    - treat the sub id passed in as the user id
    - return an error if id making request doesn't exist in proxy user table
    - track spend against the user id
    - if role="litellm_proxy_user" -> allow making calls + info. Can not edit budgets
    prisma_clientuser_api_key_cachereturnNc                 0    t               | _        d| _        y )Nr   )r   http_handlerleewayselfs    Z/var/www/html/sandstorm/venv/lib/python3.12/site-packages/litellm/proxy/auth/handle_jwt.py__init__zJWTHandler.__init__(   s     (M    litellm_jwtauthr   c                 <    || _         || _        || _        || _        y N)r   r   r   r   )r   r   r   r   r   s        r   update_environmentzJWTHandler.update_environment.   s#     +"4.r   tokenc                 @    |j                  d      }t        |      dk(  S )N.   )splitlen)r   r"   partss      r   is_jwtzJWTHandler.is_jwt:   s    C 5zQr   c                     | j                  |      }| j                  |      }|rt        j                  S | j	                  |d      t        j
                  S | j                  |d      t        j                  S y)a^  
        Returns the RBAC role the token 'belongs' to.

        RBAC roles allowed to make requests:
        - PROXY_ADMIN: can make requests to all routes
        - TEAM: can make requests to routes associated with a team
        - INTERNAL_USER: can make requests to routes associated with a user

        Resolves: https://github.com/BerriAI/litellm/issues/6793

        Returns:
        - PROXY_ADMIN: if token is admin
        - TEAM: if token is associated with a team
        - INTERNAL_USER: if token is associated with a user
        - None: if token is not associated with a team or user
        )r"   )scopesN)r"   default_value)
get_scopesis_adminr   PROXY_ADMINget_team_idTEAMget_user_idINTERNAL_USER)r   r"   r+   r.   s       r   get_rbac_rolezJWTHandler.get_rbac_role>   sz    " u-===/#///E>J#(((E>J#111r   r+   c                 6    | j                   j                  |v ryy)NTF)r   admin_jwt_scope)r   r+   s     r   r.   zJWTHandler.is_adminZ   s    //69r   c                 d    | j                   j                  || j                   j                     S g S r    )r   team_ids_jwt_field)r   r"   s     r   get_team_ids_from_jwtz JWTHandler.get_team_ids_from_jwt_   s0    22>--@@AA	r   r,   c                     	 | j                   j                  || j                   j                     }|S d }	 |S # t        $ r |}Y |S w xY wr    )r   end_user_id_jwt_fieldKeyErrorr   r"   r,   user_ids       r   get_end_user_idzJWTHandler.get_end_user_idd   s_    	$##99E 4 4 J JK 	    	$#G	$   /8 8 AAc                 2    | j                   j                  yy)z`
        Returns:
        - True: if 'team_id_jwt_field' is set
        - False: if not
        FT)r   team_id_jwt_fieldr   s    r   is_required_team_idzJWTHandler.is_required_team_idr   s     119r   c                 z    | j                   j                  %t        | j                   j                  t              ryy)z
        Returns:
        - True: if 'user_allowed_email_domain' is set
        - False: if 'user_allowed_email_domain' is None
        TF)r   user_allowed_email_domain
isinstancestrr   s    r   is_enforced_email_domainz#JWTHandler.is_enforced_email_domain|   s7     99E*  ::CK
 r   c                     	 | j                   j                  || j                   j                     }|S | j                   j                  | j                   j                  }|S d }	 |S # t        $ r |}Y |S w xY wr    )r   rB   team_id_defaultr<   )r   r"   r,   team_ids       r   r0   zJWTHandler.get_team_id   s    	$##55A 4 4 F FG  %%55A..>>
     	$#G	$s   /A& ,A& !A& &A54A5valid_user_emailc                 8    |du ry| j                   j                  S )z
        Returns:
        - True: if 'user_id_upsert' is set AND valid_user_email is not False
        - False: if not
        F)r   user_id_upsert)r   rL   s     r   is_upsert_user_idzJWTHandler.is_upsert_user_id   s!     u$##222r   c                     	 | j                   j                  || j                   j                     }|S |}	 |S # t        $ r |}Y |S w xY wr    )r   user_id_jwt_fieldr<   r=   s       r   r2   zJWTHandler.get_user_id   s_    	$##55A 4 4 F FG
  (   	$#G	$r@   c                     	 | j                   j                  || j                   j                     }|S d }	 |S # t        $ r |}Y |S w xY wr    )r   user_email_jwt_fieldr<   )r   r"   r,   
user_emails       r   get_user_emailzJWTHandler.get_user_email   sb    	'##88D"4#7#7#L#LM

  "
   	'&J	'r@   c                     	 | j                   j                  || j                   j                     }|S d }	 |S # t        $ r |}Y |S w xY wr    )r   org_id_jwt_fieldr<   )r   r"   r,   org_ids       r   
get_org_idzJWTHandler.get_org_id   s_    	###44@t33DDE
     	#"F	#r@   c                     	 t        |d   t              r|d   j                         }|S t        |d   t              r|d   }|S t	        dt        |d          d      # t        $ r g }Y |S w xY w)NscopezUnmapped scope type - z. Supported types - list, str.)rF   rG   r&   list	Exceptiontyper<   )r   r"   r+   s      r   r-   zJWTHandler.get_scopes   s    	%.#.w--/  E'ND1w   ,T%.-A,BB`a   	F	s   &A A A A.-A.kidc                 B  K   t        j                  d      }|t        d      | j                  j	                  d       d {   }|| j
                  j                  |       d {   }|j                         }d|v r|j                         d   }n|}| j                  j                  d|| j                  j                         d {    n|}| j                  ||      }| t        d| d| d	| d
t        |             t        t        |      S 7 7 7 Pw)NJWT_PUBLIC_KEY_URLz,Missing JWT Public Key URL from environment.litellm_jwt_auth_keyskeys)keyvaluettl)rc   r_   z"No matching public key found. kid=z, keys_url=z, cached_keys=z, len(keys)=)osgetenvr]   r   async_get_cacher   getjsonasync_set_cacher   public_key_ttl
parse_keysr'   r   dict)r   r_   keys_urlcached_keysresponseresponse_jsonrc   
public_keys           r   get_public_keyzJWTHandler.get_public_key   s@    9912JKK 33CC#
 
 !..228<<H$MMOM&$,MMOF$;$))99+((77 :    D__$C_8
4SEXJn]h\iiuvyz~v  vA  B  D*%%3
 =s8   ADD$D(D)A#DDADDDrc   c                    d }t        |      dk(  r\t        |t              r|j                  dd       |k(  s||}|S t        |t              r|d   j                  dd       |k(  s||d   }|S t        |      dkD  rK|D ]F  }t        |t              r|j                  dd       }nd }|+t        |t              s<|?||k(  sE|}H |S )N   r_   r   )r'   rF   ro   rj   r\   )r   rc   r_   rt   rd   key_kids         r   rn   zJWTHandler.parse_keys   s    +/
t9>$%488E4+@C+G3;!
& % D$'QE4(C/3;!!W
  Y] %c4(!ggeT2G"GO"3-+3!$J% r   rT   c                     | j                   j                  y|j                  d      d   }|| j                   j                  k(  ryy)NT@F)r   rE   r&   )r   rT   email_domains      r   is_allowed_domainzJWTHandler.is_allowed_domain	  sF    99A!'',R04//IIIr   c                   K   g d}t        j                  d      }d }|ddi}dd l}ddlm} |j                  |      }t        j                  d|       |j                  dd       }| j                  |	       d {   }	|	t        |	t              rzi }
d
|	v r|	d
   |
d
<   d|	v r|	d   |
d<   d|	v r|	d   |
d<   d|	v r|	d   |
d<   |j                  t        j                  |
            }	 |j                  |||||| j                         }|S |	t        |	t&              r	 t)        j*                  |	j-                         t/                     }|j1                         j3                  t4        j6                  j8                  t4        j:                  j<                        }|j                  |||||      }|S t%        d      7 C# |j"                  $ r t%        d      t$        $ r}t%        dt'        |             d }~ww xY w# |j"                  $ r t%        d      t$        $ r}t%        dt'        |             d }~ww xY ww)N)RS256RS384RS512PS256PS384PS512JWT_AUDIENCE
verify_audFr   )RSAAlgorithmz
header: %sr_   )r_   ktyne)
algorithmsoptionsaudiencer   zToken ExpiredzValidation fails: )r   r   r   zInvalid JWT Submitted)rg   rh   jwtjwt.algorithmsr   get_unverified_headerr	   debugrj   ru   rF   ro   from_jwkrk   dumpsdecoder   ExpiredSignatureErrorr]   rG   r   load_pem_x509_certificateencoder   rt   public_bytesr   EncodingPEMPublicFormatSubjectPublicKeyInfo)r   r"   r   r   decode_optionsr   r   headerr_   rt   jwkpublic_key_rsapayloadr   certrd   s                   r   auth_jwtzJWTHandler.auth_jwt  sc     L
99^,*E2N/**51""<8jj%..3.77
!jT&BC
"'.E

"'.E
j %c?Cj %c?C)224::c?CN?**")*%;; %   #
:s(C?55%%'):
 oo'44!**..!..CC **)%* %   /00y 86 ,, 100 ?"4SVH =>>?0 ,, 100 ?"4SVH =>>?s\   A:I<F?=A,I*"G I BH 3I"H $G;;H  I"I%H<<IIc                 T   K   | j                   j                          d {    y 7 wr    )r   closer   s    r   r   zJWTHandler.closee  s     %%'''s   (&()r   N)r   r    )&__name__
__module____qualname____doc__r   r   __annotations__r
   r   r   intr!   rG   r)   ro   r   r4   r\   boolr.   r   r9   r?   rC   rH   r0   rO   r2   rU   rY   r-   ru   r   r   rn   r}   r   r    r   r   r   r      s    L))!!	 
-
 &
 )	

 
 

C 4 H5E,F 8t  
4 DI 
*23-	#T $ 
 
hsm 
QT 
3(4. 3D 3 hsm QT 

*23-
	#
 Xc] xPS}    &  &$  &D{ # 8JCW 2C D P1C P1D P1d(r   r   )r   rk   rg   typingr   r   r   cryptographyr   cryptography.hazmat.backendsr   cryptography.hazmat.primitivesr   litellm._loggingr	   litellm.caching.cachingr
   'litellm.llms.custom_httpx.httpx_handlerr   litellm.proxy._typesr   r   r   r   litellm.proxy.utilsr   r   r   r   r   <module>r      sE     	 ' '  8 8 1 - ?  -I( I(r   