
    h                     	   d Z ddlZddlmZmZmZmZmZmZm	Z	 ddl
mZmZmZmZmZmZmZmZ ddl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  ddl!m"Z" dd	l#m$Z$ dd
l%m&Z& ddl'm(Z(m)Z)m*Z* ddl+m,Z,m-Z- ddl.  G d d      Z/ G d de	      Z0 eddg ee,      g      Z1d Z2de3fdZ4de3fdZ5de6de0fdZ7dhdee3   dee3   dee8   dee3ef   fd Z9d!e:dee3   fd"Z;d#ee3   dee<   fd$Z=de3d%ee3   d&ee3   ddfd'Z>d(efd)Z?e1j                  d*eAd+ ee"       ee?      g,      d-efd.       ZBe1j                  d/eCd+ ee"       ee?      g,       ed0d01       ed2d0d34       ed      fd5eDd6eDd7ee3   fd8       ZEe1j                  d9e6d+ ee"       ee?      g,       ed:d;<      fde3fd=       ZFe1j                  d/e6d> ee"       ee?      g,       ed:      fde6fd?       ZHe1j                  d9e6d+ ee"       ee?      g,       ed:d;<       ed:      fde3de6fd@       ZJe1j                  d9dA ee"      gB       ed:d;<      fde3fdC       ZLdDedee3   fdEZMdFe3dDedGee3ef   ddfdHZNdFe3dDedGee3ef   ddfdIZOdFe3dDedJee3ef   ddfdKZPdLe3dFe3dDedMee3ef   ddf
dNZQdFe3dDedOee3   deee3      fdPZRdLe3dFe3dDedJee3ef   ddf
dQZSdRedSeTdeee3ef   ee3   f   fdTZUde3dUee3   dVee3   de8fdWZVe1j                  d9e6d+ ee"       ee?      g,       ed:d;<       ed:      fde3dSeTfdX       ZXe1j                  dYeCd+ ee"       ee?      g,       ed0d01       ed2d0d34       ed      fd5eDd6eDd7ee3   fdZ       ZYe1j                  d[e:d+ ee"       ee?      g,       ed:d\<      fd]e3fd^       ZZe1j                  dYe:d> ee"       ee?      g,       ed:      fd!e:fd_       Z[e1j                  d[e:d+ ee"       ee?      g,       ed:d\<       ed:      fd]e3d!e:fd`       Z\e1j                  d[dA ee"      gB       ed:d\<      fd]e3fda       Z]dSeTdeee3ef   ee3   f   fdbZ^d]e3dGee3ef   dcee3   fddZ_d]e3deee3   dcee3   fdfZ`e1j                  d[e:d+ ee"       ee?      g,       ed:d\<       ed:      fd]e3dSeTfdg       Zay)iu   
✨ SCIM v2 Endpoints for LiteLLM Proxy using Internal User/Team Management

This is an enterprise feature and requires a premium license.
    N)AnyDictListOptionalSetTuple	TypedDict)	APIRouterBodyDependsHTTPExceptionPathQueryRequestResponse)verbose_proxy_logger
safe_dumps)LiteLLM_UserTableLitellmUserRolesMemberNewTeamRequestNewUserRequestTeamMemberAddRequestTeamMemberDeleteRequestUserAPIKeyAuth)user_api_key_auth)new_user)ScimTransformations)new_teamteam_member_addteam_member_delete)_premium_user_checkhandle_exception_on_proxy)*c                   0    e Zd ZdZededee   fd       Zy)UserProvisionerHelpersz0Helper methods for user provisioning operations.new_user_requestreturnc           
        K   |j                   sy| j                  j                  j                  d|j                   i       d{   }|sy| j                  j                  j	                  d|j
                  i|j
                  |j                   |j                  |j                  t        |j                        d       d{   }t        j                  |       d{   S 7 7 #7 w)a<  
        Check if a user with the given email already exists and update them if found.
        
        Args:
            prisma_client: Database client
            new_user_request: New user request data
            
        Returns:
            SCIMUser if user was updated, None if no existing user found
        N
user_emailwhereuser_id)r.   r+   
user_aliasteamsmetadatar-   data)r+   dblitellm_usertable
find_firstupdater.   r/   r0   r   r1   r   #transform_litellm_user_to_scim_user)prisma_clientr(   existing_userupdated_users       k/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/management_endpoints/scim/scim_v2.pyhandle_existing_user_by_emailz4UserProvisionerHelpers.handle_existing_user_by_email3   s       **+..@@KK!1!<!<= L 
 
  +--??FFm334+33.99.99)//&'7'@'@A G 	
 	
 )LL\ZZZ'
	
 [s7   AC,C&A>C,C(C,!C*"C,(C,*C,N)	__name__
__module____qualname____doc__staticmethodr   r   SCIMUserr=        r<   r'   r'   0   s2    :$[($[ 
(	$[ $[rE   r'   c                       e Zd ZU dZee   ed<   ee   ed<   ee   ed<   ee   ed<   ee   ed<   ee   ed<   ee   ed<   y	)
ScimUserDataz-Typed structure for extracted SCIM user data.r+   r/   sso_user_idr0   
given_namefamily_nameactiveN)	r>   r?   r@   rA   r   str__annotations__r   boolrD   rE   r<   rG   rG   [   sK    7#9#TNrE   rG   z/scim/v2u   ✨ SCIM v2 (Enterprise Only))prefixtagsdependenciesc                  <   K   ddl m}  | t        dddi      | S w)z>Check if database is connected and raise HTTPException if not.r   r9   i  errorzNo database connectedstatus_codedetail)litellm.proxy.proxy_serverr9   r   rS   s    r<   %_get_prisma_client_or_raise_exceptionrY   n   s(     8W>U4VWWs   r.   c                    K   t                d{   }|j                  j                  j                  d| i       d{   }|st	        ddd|  i      |S 7 J7 w)z=Check if user exists and return user, raise 404 if not found.Nr.   r,     rT   zUser not found with ID: rU   )rY   r4   r5   find_uniquer   )r.   r9   users      r<   _check_user_existsr^   w   sw     ?AAM!!33??'" @  D W0H	.R$S
 	
 K B!   AA/A AAAteam_idc                    K   t                d{   }|j                  j                  j                  d| i       d{   }|st	        ddd|  i      |S 7 J7 w)z=Check if team exists and return team, raise 404 if not found.Nr`   r,   r[   rT   zGroup not found with ID: rU   )rY   r4   litellm_teamtabler\   r   )r`   r9   teams      r<   _check_team_existsrd      sw     ?AAM!!33??'" @  D W0I'.S$T
 	
 K Br_   r]   r)   c                 $   d}| j                   r1t        | j                         dkD  r| j                   d   j                  }d}| j                  r,| j                  j                  r| j                  j                  }g }| j
                  r#| j
                  D cg c]  }|j                   }}||| j                  || j                  r| j                  j                  nd| j                  r| j                  j                  nd| j                  dS c c}w )z)Extract common data from SCIMUser object.Nr   )r+   r/   rH   r0   rI   rJ   rK   )	emailslenvaluename	givenNamegroups
externalId
familyNamerK   )r]   r+   r/   r0   groups        r<   _extract_scim_user_dataro      s    J{{s4;;'!+[[^))
JyyTYY((YY((
E{{*.++666 ! -1YYdii))D/3yytyy++d++  7s   DrI   rJ   rK   c                 N    dt        | |      j                         i}|||d<   |S )z)Build metadata dictionary with SCIM data.scim_metadata)rj   rm   scim_active)LiteLLM_UserScimMetadata
model_dump)rI   rJ   rK   r1   s       r<   _build_scim_metadataru      s<     	1 "
 *,	 H "(OrE   rn   c                 (  K   t                d{   }g }| j                  ri| j                  D ]Z  }|j                  j                  j	                  d|j
                  i       d{   }|s@|j                  |j
                         \ |S 7 }7 (w)z?Extract valid member IDs from SCIMGroup, verifying users exist.Nr.   r,   )rY   membersr4   r5   r\   rh   append)rn   r9   
member_idsmemberr]   s        r<   _extract_group_member_idsr{      s     ?AAMJ}}mmF&));;GG &,,/ H  D !!&,,/ $  Bs(   BBAB'B(B/ BBry   c                 2  K   t                d{   }g }| D ]u  }|j                  j                  j                  d|i       d{   }|s6|j                  xs |j
                  }|j                  t        |j
                  |             w |S 7 7 Mw)zCGet SCIMMember objects with display names for a list of member IDs.Nr.   r,   )rh   display)rY   r4   r5   r\   r+   r.   rx   
SCIMMember)ry   r9   rw   	member_idr]   display_names         r<   _get_team_members_displayr      s     ?AAM "G	"%%77CCi( D 
 
 ??:dllLNN:DLL,OP   N B
s(   BB6BBBABBexisting_teams	new_teamsc                    K   t        |      }t        |      }||z
  }||z
  }|s|r)t        | t        |      t        |             d{    yy7 w)z8Handle adding/removing user from teams based on changes.r.   teams_ids_to_add_user_toteams_ids_to_remove_user_fromN)setpatch_team_membershiplist)r.   r   r   existing_teams_setnew_teams_setteams_to_addteams_to_removes          r<   _handle_team_membership_changesr      sc     ^,	NM #55L(=8O#%),%7*.*?
 	
 	
 '	
s   AA
AAresponsec                 *   K   d| j                   d<   yw)z5Sets the Content-Type header to application/scim+jsonzapplication/scim+jsonzContent-TypeN)headers)r   s    r<   set_scim_content_typer      s      (?H^$s   z/ServiceProviderConfig   )response_modelrV   rQ   requestc                 R   K   dt        | j                        d}t        |      S w)z+Return SCIM Service Provider Configuration.ServiceProviderConfig)resourceTypelocation)meta)rL   urlSCIMServiceProviderConfig)r   r   s     r<   get_service_provider_configr      s+      0$D %$//s   %'z/Users   )ge
   d   )r   le
startIndexcountfilterc           
        K   	 t                d{   }i }|rYd|v r)|j                  d      d   j                  d      }||d<   n,d|v r(|j                  d      d   j                  d      }||d	<   |j                  j                  j                  || dz
  |d
di       d{   }|j                  j                  j                  |       d{   }g }	|D ]1  }
t        j                  |
       d{   }|	j                  |       3 t        || t        |t        |	            |	      S 7  7 7 c7 @# t        $ r}t        |      d}~ww xY ww)z;
    Get a list of users according to SCIM v2 protocol
    NzuserName eqzuserName eq r   "'r.   zemails.value eqzemails.value eq r+   
created_atdescr-   skiptakeorderr,   r]   totalResultsr   itemsPerPage	Resources)rY   splitstripr4   r5   	find_manyr   r   r8   rx   SCIMListResponseminrg   	Exceptionr$   )r   r   r   r9   where_conditionsr.   emailuserstotal_count
scim_usersr]   	scim_useres                r<   	get_usersr     s    ,+CEE& ,,~6q9??F.5 +"f,%78;AA%H16 .  ""44>>& 1n#V,	 ?   	 *,,>>DD" E 
 

 &(
D1UU I i(	   $!UC
O4 	
 	
G F
  +'**+so   ED: D1BD: $D4%-D: D6$D: 7D888D: 0E1D: 4D: 6D: 8D: :	EEEEz/Users/{user_id}.zUser ID)titlec                    K   	 t        |        d{   }t        j                  |       d{   }|S 7 #7 # t        $ r}t	        |      d}~ww xY ww)z?
    Get a single user by ID according to SCIM v2 protocol
    N)r^   r   r8   r   r$   )r.   r]   r   r   s       r<   get_userr   E  s\     +'00 .QQRVWW		 1 X  +'**+s=   A: 6: 8: A: : 	AAAA   c           	        K   	 t        j                  d|        t                d{   }t        |       }| j                  rX|j
                  j                  j                  d| j                  i       d{   }|rt        ddd| j                   i      | j                  xs t        t        j                               }t        |d	   |d
         }t        j                  }t        j                   rt        j                   j#                  d      }t%        ||d   |d   |d   |d|      }t&        j)                  ||       d{   }|r|S t+        |       d{   }	t-        j.                  |	       d{   }
|
S 7 b7 7 B7 ,7 # t        $ r}|d}~wt0        $ r}t3        |      d}~ww xY ww)z5
    Create a user according to SCIM v2 protocol
    zSCIM CREATE USER request: %sNr.   r,     rT   z#User already exists with username: rU   rI   rJ   	user_roler+   r/   r0   F)r.   r+   r/   r0   r1   auto_create_keyr   )r9   r(   )r3   r   )r   debugrY   ro   userNamer4   r5   r\   r   rL   uuiduuid4ru   r   INTERNAL_USER_VIEW_ONLYlitellmdefault_internal_user_paramsgetr   r'   r=   r   r   r8   r   r$   )r]   r9   	user_datar:   r.   r1   default_roler(   existing_user_scimcreated_userr   r   s               r<   create_userr   [  s    ?+""#A4HCEE ,D1	 =="/"2"2"D"D"P"P $--0 #Q # M # ##'J4==/%Z[  --43tzz|#4'	,(?=AYZ 44 	 //"??CCKPL) . .G$!"
 $:#W#W'- $X $
 

 %%%!
 
 .QQ
 
	 s FF


   +'**+s   F?#F F	AF 8F9CF FF F?F $F%F FF F?	F F F F F 	F<F  F<,F77F<<F?c                 |  K   t        j                  d|       	 t                d{   }t        |        d{   }t	        |      }t        |d   |d   |d         }t        | |j                  xs g |d          d{    |d   |d	   |d
   |d   |d}d|v r't        |d   t              rddl
m}  ||d         |d<   |j                  j                  j                  d| i|       d{   }t        j                   |       d{   }	|	S 7 7 7 7 )7 # t"        $ r}
t%        |
      d}
~
ww xY ww)zH
    Update a user according to SCIM v2 protocol (full replacement)
    zSCIM PUT USER request: %sNrI   rJ   rK   r0   r.   r   r   r+   r/   rH   )r+   r/   rH   r0   r1   r1   r   r   r.   r2   )r   r   rY   r^   ro   ru   r   r0   
isinstancedict*litellm.litellm_core_utils.safe_json_dumpsr   r4   r5   r7   r   r8   r   r$   )r.   r]   r9   r:   r   r1   update_datar   r;   r   r   s              r<   update_userr     sv     :DA.+CEE099 ,D1	 (l#m$h
 .(..4"(
 	
 	
 $L1#L1$]3w' 
 $K
4KT)RM&0Z1H&IK
#*--??FFg& G 
 
 .QQR^__	U F9	
(
 `  +'**+s   D<D  DD  DAD  DA/D  2D3D  DD  D<D  D  D  D  D   	D9)D44D99D<   )rV   rQ   c                   K   	 t                d{   }t        |        d{   }g }|j                  rU|j                  D ]F  }|j                  j                  j                  d|i       d{   }|s6|j                  |       H |D ]i  }|j                  xs g }| |v s|D cg c]
  }|| k7  s	| }}|j                  j                  j                  d|j                  id|i       d{    k |j                  j                  j                  d| i       d{    t        d      S 7 %7 7 c c}w 7 O7 # t        $ r}	t        |	      d}	~	ww xY ww)	z5
    Delete a user according to SCIM v2 protocol
    Nr`   r,   rw   r2   r.   r   rV   )rY   r^   r0   r4   rb   r\   rx   rw   r7   r`   r5   deleter   r   r$   )
r.   r9   r:   r0   r`   rc   current_membersmnew_membersr   s
             r<   delete_userr     sn    +CEE099 (..*--??KK$g. L   LL& / D"ll0bO/)*9JQQ'\qJJ#&&88??$dll39k:R @   	  0077y'>R7SSSC((3 F9 K
 	T  +'**+s   E#E D6E D9AE 1D<2E 9,E &E *
D>5D>9:E 3E41E %E&E 5E#6E 9E <E >E E 	E EE  E#rh   c                    g }t        | t              rv| D ]o  }t        |t              r;|j                  d      r*|j	                  t        |j                  d                   Nt        |t
              s_|j	                  |       q |S t        | t              r<| j                  d      r)|j	                  t        | j                  d                   |S t        | t
              r|j	                  |        |S )z)Return group ids from a SCIM patch value.rh   )r   r   r   r   rx   rL   )rh   group_valuesvs      r<   _extract_group_valuesr     s     L%A!T"quuW~##Cg$78As###A&	   
E4	 99WEIIg$6 78  
E3	E"rE   op_typer   c                 6    | dk(  rd|d<   yt        |      |d<   y)zHandle displayname updates.removeNr/   rL   r   rh   r   s      r<   _handle_displayname_updater   $  s"    ($(L!$'JL!rE   c                 6    | dk(  rd|d<   yt        |      |d<   y)zHandle externalid updates.r   NrH   r   r   s      r<   _handle_externalid_updater   ,  s"    (%)M"%(ZM"rE   r1   c                     | dk(  r|j                  dd       y|}t        |t              r|j                         dk(  }nt	        |      }||d<   y)zHandle active status updates.r   rr   Ntrue)popr   rL   lowerrN   )r   rh   r1   bool_vals       r<   _handle_active_updater   4  sJ    (]D)eS!{{}.HE{H"*rE   pathrq   c                     | dk(  r'|dk(  r|j                  dd       yt        |      |d<   y| dk(  r'|dk(  r|j                  dd       yt        |      |d<   yy)z2Handle name field updates (givenName, familyName).name.givennamer   rj   Nname.familynamerm   )r   rL   )r   r   rh   rq   s       r<   _handle_name_updater   A  se    hk40),UM+&	"	"hlD1*-e*M,'	 
#rE   	teams_setc                     t        |      }| dk(  rt        |      S | dk(  r|j                  |       y| dk(  r|D ]  }|j                  |        y)z(Handle group/team membership operations.replaceaddr   N)r   r   r7   discard)r   rh   r   r   gids        r<   _handle_group_operationsr  O  s_    (/L)<  	E	&  
H	Cc"  rE   c                 >    |dk(  r|j                  | d       y||| <   y)z5Handle generic metadata operations for unknown paths.r   N)r   )r   r   rh   r1   s       r<   _handle_generic_metadatar  \  s!    (T4 rE   r:   	patch_opsc                 2   i }| j                   xs i }|j                  di       }t        | j                  xs g       }d}|j                  D ]  }|j
                  xs dj                         }|j                  }	|j                  }
|dk(  rt        |
|	|       L|dk(  rt        |
|	|       _|dk(  rt        |
|	|       r|dv rt        ||
|	|       |j                  d      rt        |
|	|      }||}t        ||
|	|        ||n|}||d<   ||d	<   ||fS )
zAApply patch operations and return update data and final team set.rq   N displayname
externalidrK   )r   r   rk   r1   )r1   r   r   r0   
Operationsr   r   rh   opr   r   r   r   
startswithr  r  )r:   r  r   r1   rq   r   replace_team_setr  r   rh   r   new_replace_setfinal_team_sets                r<   _apply_patch_opsr  d  s1   
 #%K%%+HLL"5Mm117R8I+/""2$$&%%= &w{C\!%gukBX!'5(;::gumD__X&6wyQO*#2 $T7E8D% #( *:)E%9N -H_&K
&&rE   r   r   c           
        K   |D ]F  }	 t        t        |t        | d            t        t        j
                               d{    H |D ];  }	 t        t        || 	      t        t        j
                               d{    = y7 G# t        $ r%}t        j                  d| d|        Y d}~d}~ww xY w7 :# t        $ r%}t        j                  d
| d|        Y d}~d}~ww xY ww)z'
    Add or remove user from teams
    r]   r.   role)r`   rz   r   )r3   user_api_key_dictNzError adding user to team z: )r`   r.   zError removing user from team T)r!   r   r   r   r   PROXY_ADMINr   r   	exceptionr"   r   )r.   r   r   _team_idr   s        r<   r   r     s     -	]%- (%gFC '5?O?[?[&\   - 2	]$,XwO"0;K;W;W"X   2 )  ]$..1KH:UWXYWZ/[\\]
  	] **-KH:UWXYWZ+[\\	]s|   C5>BBBC53CCCC5B	B?B:5C5:B??C5C	C2C-(C5-C22C5c                 Z  K   t        j                  d|       	 t                d{   }t        |        d{   }t	        ||      \  }}t        | |j                  xs g t        |             d{    t        |      |d<   d|v r't        |d   t              rddl
m}  ||d         |d<   |j                  j                  j                  d	| i|
       d{   }t        j                   |       d{   }|S 7 7 7 7 )7 # t"        $ r}	t%        |	      d}	~	ww xY ww)z4
    Patch a user according to SCIM v2 protocol
    zSCIM PATCH USER request: %sN)r:   r  r   r0   r1   r   r   r.   r2   )r   r   rY   r^   r  r   r0   r   r   r   r   r   r4   r5   r7   r   r8   r   r$   )
r.   r  r9   r:   r   r  r   r;   r   r   s
             r<   
patch_userr    s?     <iH!+CEE099&6''
#^ .(..4">*
 	
 	
  $N3G $K
4KT)RM&0Z1H&IK
#*--??FFg& G 
 

 .QQR^__	; F9	


 `  +'**+s   D+D DD D<D 7D	8A)D !D"D >D?D D+D D 	D D D 	D(D##D((D+z/Groupsc                   K   	 t                d{   }i }|r,d|v r(|j                  d      d   j                  d      }||d<   |j                  j                  j                  || dz
  |ddi	       d{   }|j                  j                  j                  |
       d{   }g }|D ]  }	t        |	j                  xs g        d{   }
t        j                  d|
        t        |	d|	j                        }|	j                  r|	j                  j                         nd}|	j                  r|	j                  j                         nd}t!        dg|	j                  ||
d||d      }|j#                  |        t        j                  d|        t%        || t'        |t)        |            |      S 7 7 I7 7 # t*        $ r}t-        |      d}~ww xY ww)z<
    Get a list of groups according to SCIM v2 protocol
    NzdisplayName eqzdisplayName eq r   r   
team_aliasr   r   r   r,   zSCIM GET GROUPS members: +urn:ietf:params:scim:schemas:core:2.0:GroupGroupr   createdlastModifiedschemasiddisplayNamerw   r   zSCIM GET GROUPS response: r   )rY   r   r   r4   rb   r   r   r   rw   r   r   getattrr`   r   	isoformat
updated_at	SCIMGrouprx   r   r   rg   r   r$   )r   r   r   r9   r   r  r0   r   scim_groupsrc   rw   team_created_atteam_updated_at
scim_groupr   s                  r<   
get_groupsr/    s    7+CEE6)#\\*;<Q?EEeL
1; . $&&88BB"q.(	 C 
 
 *,,>>DD" E 
 

 D5dll6HbIIG &&)B7)'LM |T\\BJ=A__doo779RVO=A__doo779RVO"FG<<&$+.$3
J z*' * 	""%?}#MN$!UC$45!	
 	
] F

 J6  +'**+sp   G$G F=A%G 7G 8-G %G&'G GC.G <G$=G  G G G 	G!GG!!G$z/Groups/{group_id}zGroup IDgroup_idc                    K   	 t        |        d{   }t        j                  |       d{   }t        j                  d|        |S 7 ;7  # t
        $ r}t        |      d}~ww xY ww)z@
    Get a single group by ID according to SCIM v2 protocol
    NzSCIM GET GROUP response: )rd   r   $transform_litellm_team_to_scim_groupr   r   r   r$   )r0  rc   r.  r   s       r<   	get_groupr3  %  su     
+'11.SS
 

 	""%>zl#KL 2
  +'**+sH   A.A AA AA A.A A 	A+A&&A++A.c                   K   	 t                d{   }| j                  xs t        t        j                               }|j
                  j                  j                  d|i       d{   }|rt        ddd| i      t        |        d{   }|D cg c]  }t        |d	       }}t        t        || j                  |
      t        ddd      t        t         j"                               d{   }t%        j&                  |       d{   }|S 7 7 7 c c}w 7 /7 # t(        $ r}	t+        |	      d}	~	ww xY ww)z6
    Create a group according to SCIM v2 protocol
    Nr`   r,   r   rT   zGroup already exists with ID: rU   r]   r  )r`   r  members_with_roleshttpz/scim/v2/Groups)typer   )scoper  )r3   http_requestr  )rY   r%  rL   r   r   r4   rb   r\   r   r{   r   r    r   r&  r   r   r   r  r   r2  r   r$   )
rn   r9   r`   existing_teamry   r   r5  created_teamr.  r   s
             r<   create_groupr<  >  sW    %+CEE ((/c$**,/ ,..@@LLg& M 
 
 #A'!KL  5U;;
V`afYVDaa & ,,#5
 !@Q'RS,7G7S7ST
 
 /SS
 

 E F
 <a

  +'**+s   ED2 D"AD2 ,D%-&D2 D'D2 D)0AD2 >D.?D2 D0D2 !E"D2 %D2 'D2 )D2 0D2 2	E;EEEc           
      >  K   	 t                d{   }t        |        d{   }t        |       d{   }|j                  r|j                  ni }|j                  j
                  j                  d| i|j                  |i |d|j                         id       d{   }|j                  xs g }|D ]  }||vs|j                  j                  j                  d|i       d{   }	|	s;|	j                  xs g }
| |
vsP|j                  j                  j                  d|idd	| ii       d{     |D ]  }||vs|j                  j                  j                  d|i       d{   }	|	s;|	j                  xs g }
| |
v sP|
D cg c]
  }|| k7  s	| }}|j                  j                  j                  d|id|i       d{     t        |       d{   }|j                  r|j                  j                         nd}|j                   r|j                   j                         nd}t#        d
g| |j$                  xs | |d||d      S 7 S7 C7 37 7 7 87 c c}w 7 7 # t&        $ r}t)        |      d}~ww xY ww)z6
    Update a group according to SCIM v2 protocol
    Nr`   	scim_data)r  rw   r1   r2   r.   r,   r0   pushr  r  r   r#  )rY   rd   r{   r1   r4   rb   r7   r&  rt   rw   r5   r\   r0   r   r   r(  r)  r*  r  r   r$   )r0  rn   r9   r:  ry   existing_metadataupdated_teamr   r   r]   current_user_teamstr   rw   r,  r-  r   s                    r<   update_grouprD  r  s    H+CEE0:: 5U;;
 7D6L6LM22RT*--??FFh'#//%R0R+u?O?O?QR G 
 
 (//52 $I/*--??KK$i0 L   )-)9r&'99+..@@GG#,i"8")FH+=!> H    $ )I
**--??KK$i0 L   )-)9r&#550B$T1a8mQ$T	$T+..@@GG#,i"8?S H    ) 2*== 4@3J3JL##--/PT 	 4@3J3JL##--/PT 	 BC$//;8 '* /

 
	
u F: <
 %U
 >*  +'**+s   JJ I$J I'J I*A,J $I-%J +J .I0/J 6J 0J ;I3<J +J 7I68J ?J J 
I8#I8'0J I=J ,I?-A6J #J$J 'J *J -J 0J 3J 6J 8J ?J 	J
JJJc                 n  K   	 t                d{   }t        |        d{   }|j                  xs g D ]  }|j                  j                  j                  d|i       d{   }|s6|j                  xs g }| |v sK|D cg c]
  }|| k7  s	| }}|j                  j                  j                  d|id|i       d{     |j                  j                  j                  d| i       d{    t        d      S 7 7 7 c c}w 7 M7 # t        $ r}t        |      d}~ww xY ww)	z6
    Delete a group according to SCIM v2 protocol
    Nr.   r,   r0   r2   r`   r   r   )rY   rd   rw   r4   r5   r\   r0   r7   rb   r   r   r   r$   )	r0  r9   r:  r   r]   current_teamsrC  r   r   s	            r<   delete_grouprG    sL    +CEE0:: '..4"4I&));;GG ), H  D  $

 0b},,9 KqQ(] KI K'**<<CC()4GY;O D    5 0077y(>S7TTTC((' F: !L
 	U  +'**+s   D5D D
D DAD 'D(D /D D 
DD0D D1D 9D:D 	D5
D D D D D 	D2"D--D22D5c                   K   i }|j                   xs i }|rt        |      ni }t        |j                  xs g       }|j	                         }| j
                  D ]U  }|j                  xs dj                         }	|j                  }
|j                  }|	dk(  r|dk(  rd|d<   Jt        |
      |d<   Y|	dk(  r'|dk(  r|j                  dd       vt        |
      |d<   |	j                  d      rt        |
      }g }|D ]F  }|j                  j                  j!                  d	|i
       d{   }|s6|j#                  |       H |dk(  rt        |      }|dk(  r|j%                  |       |dk(  s|D ]  }|j'                  |        8|dk(  r|j                  |	d       Q|
||	<   X |r||d<   ||fS 7 w)zNProcess patch operations for a group and return update data and final members.r  r	  r   Nr  r
  rl   rw   r.   r,   r   r   r1   )r1   r   r   rw   copyr  r   r   rh   r  rL   r   r  r   r4   r5   r\   rx   r7   r  )r  r:  r9   r   r@  r1   r   final_membersr  r   rh   r   member_valuesvalid_membersr   r]   s                   r<   _process_group_patch_operationsrM    s     #%K &..4"*;t%&H -//526O#((*M ""2$$&%%= (",0L),/JL)\!("\40),U&__Y'1%8MM*	*--??KK$i0 L   !((3 + )# #M 2E!$$]3H$!.I!)))4 "/ ("T4(!&O #T "*J%%1s    D*F?,F=-F?4AF?7AF?rJ  c                    K   d|v r$t        |d   t              rt        |d         |d<   t        |      |d<   |j                  j
                  j                  d| i|       d{   }|S 7 w)z1Apply patch updates to the group in the database.r1   rw   r`   r2   N)r   r   r   r   r4   rb   r7   )r0  r   rJ  r9   rA  s        r<   _apply_group_patch_updatesrO  0  s      [ ZJ0G%N",[-D"EJ "-0K	 '));;BB(# C  L
 s   A#A.%A,&A.r   c                    K   ||z
  }||z
  }t        j                  d|        t        j                  d|        |D ]  }t        || gg        d{     |D ]  }t        |g | g       d{     y7 %7 	w)z.Handle adding/removing members from the group.zmembers_to_add: zmembers_to_remove: r   N)r   r   r   )r0  r   rJ  members_to_addmembers_to_remover   s         r<    _handle_group_membership_changesrS  G  s      #_4N'-7!1.1ABC!45F4GHI $	#&.Z*,
 	
 	
 $ '	#%'+3*
 	
 	
 '	
	
s$   AA>A:A>2A<3A><A>c                   K   t        j                  d|       	 t                d{   }t        |        d{   }t	        |||       d{   \  }}t        |j                  xs g       }t        | |||       d{   }t        | ||       d{    t        j                  |       d{   }|S 7 7 7 n7 >7 +7 # t        $ r}	t        |	      d}	~	ww xY ww)z5
    Patch a group according to SCIM v2 protocol
    zSCIM PATCH GROUP request: %sN)r   r   rY   rd   rM  r   rw   rO  rS  r   r2  r   r$   )
r0  r  r9   r:  r   rJ  r   rA  r.  r   s
             r<   patch_grouprU  c  s      =yI+CEE0:: ,K}m,
 &
"]
 m339r: 8k=-
 

 /o}
 	
 	

 /SS
 

 3 F:&


	



  +'**+s   C"C B:C B<C B>1C C C CC 3C4C 9C":C <C >C  C C C 	CCCC")N)brA   r   typingr   r   r   r   r   r   r	   fastapir
   r   r   r   r   r   r   r   r   litellm._loggingr   r   r   litellm.proxy._typesr   r   r   r   r   r   r   r   $litellm.proxy.auth.user_api_key_authr   :litellm.proxy.management_endpoints.internal_user_endpointsr   <litellm.proxy.management_endpoints.scim.scim_transformationsr   1litellm.proxy.management_endpoints.team_endpointsr    r!   r"   litellm.proxy.utilsr#   r$   0litellm.types.proxy.management_endpoints.scim_v2r'   rG   scim_routerrY   rL   r^   rd   rC   ro   rN   ru   r*  r{   r~   r   r   r   r   r   r   r   intr   r   postr   putr   r   r   r   r   r   r   r   r  r  SCIMPatchOpr  r   patchr  r/  r3  r<  rD  rG  rM  rO  rS  rU  rD   rE   r<   <module>rf     sF    C C C	 	 	  1 A	 	 	 C O 
 O >([ ([V9  
)	*-./c  c  ( | 2Xc] # X`aeXf rvwz|w  sA 9 c "S	 d:>N  
3 
S	 
^bcf^g 
lp 
"?( ? ,+,g6K.LM	  0w 00 #+,g6K.LM	   A!nraC(!$K4+4+4+ SM4+4+n +,g6K.LM	   9-+++  +,g6K.LM	   #YE+
E+E+P +,g6K.LM	   9-#Y7+7+
7+7+t +,-   9-"+"+
"+J c "/ /C /d3PS8n /Y] /0s 03 0T#s(^ 0X\ 0
+3 
+s 
+d38n 
+QU 
+5c 5C 5 5DQTVYQYN 5_c 5
c 
# 
#c( 
xX[\_X`Oa 
3  S DQTVYQYN _c #'$#'#' 4S>3s8#$#'J"3i $(9 
	@ +,g6K.LM	   9-!#Y*+*+*+*+\ #+,g6K.LM	   A!nraC(!$K?+?+?+ SM?+?+D +,g6K.LM	   J/+++& +,g6K.LM	   Cy++++++\ +,g6K.LM	   J/CyO+O+O+O+d +,-   J/++
+@>&>& 4S>3s8#$	>&Bc3h s8.

X
 s8
8 +,g6K.LM	   J/!#Y&+&+&+&+rE   