
    hH                       d Z ddlZddlZddl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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! 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-m.Z. ddl/m0Z0m1Z1 ddl2m3Z3 ddl4m5Z5 ddl6m7Z7 ddl8m9Z9m:Z: ddl;m<Z< ddl=m>Z> ddl?m@Z@mAZA ddlBmCZCmDZD ddlEmFZF ddlGmHZHmIZImJZJmKZK ddlLmMZMmNZN ddlO erddlPmQZQ nddlmZQ  e       ZReRj                  ddgd      	 	 	 dVded eeT   d!eeT   d"eeT   fd#       ZUeRj                  d$dgd      	 dWded eeT   d!eeT   fd%       ZV	 dXd&e5d'ee5   fd(ZWded&e5d'ee5   d)eTd*eTd+eeeQeXf   eeX   f   fd,ZYd- ZZd.ee)e$f   d/e
eT   fd0Z[d1 Z\d2eeT   d3eeT   d4eHd5ed6eId+ee$   fd7Z]	 dXd8eeFeQeXf   d4eHd5ed6eId3eeT   d9ee,   d:eeT   d+eee$e)f      fd;Z^d.eee$e)f      d9ee,   d+ee,   fd<Z_d=eTd2eTd4eeH   fd>Z`eRj                  d?dgd      dXded@eeT   fdA       ZadXded!eeT   fdBZbeRj                  dCdgd      dDeTfdE       Zc	 dXdFeeeQeXf      d9ee,   d+e)fdGZdeRj                  dHdgd ee7      gI      defdJ       Ze G dK dL      Zf G dM dN      Zg G dO dP      ZheRj                  dQdgd      defdR       ZieRj                  dSdgd      defdT       ZjeRj                  ddgd      defdU       Zly)Ya^  
Has all /sso/* routes

/sso/key/generate - handles user signing in with SSO and redirects to /sso/callback
/sso/callback - returns JWT Redirect Response that redirects to LiteLLM UI

/sso/debug/login - handles user signing in with SSO and redirects to /sso/debug/callback
/sso/debug/callback - returns the OpenID object returned by the SSO provider
    N)deepcopy)TYPE_CHECKINGAnyDictListOptionalTupleUnioncast)	APIRouterDependsHTTPExceptionRequeststatus)RedirectResponse)verbose_proxy_logger)	DualCache)MAX_SPENDLOG_ROWS_TO_QUERY)AsyncHTTPHandlerget_async_httpx_clienthttpxSpecialProvider)CommonProxyErrorsLiteLLM_UserTableLitellmUserRolesMemberNewTeamRequestNewUserRequestNewUserResponseProxyErrorTypesProxyExceptionSSOUserDefinedValuesTeamMemberAddRequestUserAPIKeyAuth)ExperimentalUIJWTTokenget_user_object)_has_user_setup_sso
JWTHandler)user_api_key_auth)admin_ui_disabledshow_missing_vars_in_env)jwt_display_template)new_user)check_is_admin_only_accesshas_admin_ui_access)new_teamteam_member_add)CustomOpenID)PrismaClientProxyLoggingget_custom_urlget_server_root_path)get_secret_boolstr_to_bool)*)OpenID)r   /sso/key/generateexperimentalF)tagsinclude_in_schemarequestsourcekeyerrorc                   K   ddl m} t        j                  dd      }t        j                  dd      }t        j                  dd      }t        j                  d      }|t	        |      }	|	r
t               S d	}
||||d
u rd
}
t               }||S d}|dk(  rd}d}|
rd}t        t        | j                        d      }d| d| d| d}ddl
m}  ||d      S w)aW  
    Create Proxy API Keys using Google Workspace SSO. Requires setting PROXY_BASE_URL in .env
    PROXY_BASE_URL should be the your deployed proxy endpoint, e.g. PROXY_BASE_URL="https://litellm-production-7002.up.railway.app/"
    Example:
    Serves a unified login page with options for both normal
    username/password login and SSO.
    r   premium_userMICROSOFT_CLIENT_IDNGOOGLE_CLIENT_IDGENERIC_CLIENT_IDDISABLE_ADMIN_UI)valueFT 1u  
        <div style="
            background-color: #fef2f2;
            border-left: 4px solid #dc2626;
            border-radius: 6px;
            padding: 16px;
            margin-bottom: 20px;
            color: #dc2626;
            font-size: 14px;
            font-weight: 500;
        ">
            ⚠️ Invalid username or password. Please try again.
        </div>
        u  
        <div style="
            margin-top: 20px;
            padding-top: 20px;
            border-top: 1px solid #e2e8f0;
            text-align: center;
        ">
            <p style="
                color: #64748b;
                font-size: 14px;
                margin-bottom: 16px;
            ">or</p>
            <a href="/sso/login" style="
                display: inline-block;
                background-color: #f8fafc;
                border: 1px solid #e2e8f0;
                color: #374151;
                padding: 10px 20px;
                border-radius: 6px;
                text-decoration: none;
                font-weight: 500;
                transition: all 0.2s;
                font-size: 14px;
            " onmouseover="this.style.backgroundColor='#f1f5f9'; this.style.borderColor='#cbd5e1';" 
               onmouseout="this.style.backgroundColor='#f8fafc'; this.style.borderColor='#e2e8f0';">
                🔐 Login with SSO
            </a>
        </div>
        loginrequest_base_urlroutea  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>LiteLLM Login</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            background-color: #f8fafc;
            margin: 0;
            padding: 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            color: #333;
        }

        form {
            background-color: #fff;
            padding: 40px;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            width: 450px;
            max-width: 100%;
        }
        
        .logo-container {
            text-align: center;
            margin-bottom: 30px;
        }
        
        .logo {
            font-size: 24px;
            font-weight: 600;
            color: #1e293b;
        }
        
        h2 {
            margin: 0 0 10px;
            color: #1e293b;
            font-size: 28px;
            font-weight: 600;
            text-align: center;
        }
        
        .subtitle {
            color: #64748b;
            margin: 0 0 20px;
            font-size: 16px;
            text-align: center;
        }

        .info-box {
            background-color: #f1f5f9;
            border-radius: 6px;
            padding: 20px;
            margin-bottom: 30px;
            border-left: 4px solid #2563eb;
        }
        
        .info-header {
            display: flex;
            align-items: center;
            margin-bottom: 12px;
            color: #1e40af;
            font-weight: 600;
            font-size: 16px;
        }
        
        .info-header svg {
            margin-right: 8px;
        }
        
        .info-box p {
            color: #475569;
            margin: 8px 0;
            line-height: 1.5;
            font-size: 14px;
        }

        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: #334155;
            font-size: 14px;
        }
        
        .required {
            color: #dc2626;
            margin-left: 2px;
        }

        input[type="text"],
        input[type="password"] {
            width: 100%;
            padding: 10px 14px;
            margin-bottom: 20px;
            box-sizing: border-box;
            border: 1px solid #e2e8f0;
            border-radius: 6px;
            font-size: 15px;
            color: #1e293b;
            background-color: #fff;
            transition: border-color 0.2s, box-shadow 0.2s;
        }
        
        input[type="text"]:focus,
        input[type="password"]:focus {
            outline: none;
            border-color: #3b82f6;
            box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
        }

        .toggle-password {
            display: flex;
            align-items: center;
            margin-top: -15px;
            margin-bottom: 20px;
        }
        
        .toggle-password input[type="checkbox"] {
            margin-right: 8px;
            vertical-align: middle;
            width: 16px;
            height: 16px;
        }
        
        .toggle-password label {
            margin-bottom: 0;
            font-size: 14px;
            cursor: pointer;
            line-height: 1;
        }

        input[type="submit"] {
            background-color: #6466E9;
            color: #fff;
            cursor: pointer;
            font-weight: 500;
            border: none;
            padding: 10px 16px;
            transition: background-color 0.2s;
            border-radius: 6px;
            margin-top: 10px;
            font-size: 14px;
            width: 100%;
        }

        input[type="submit"]:hover {
            background-color: #4138C2;
        }
        
        a {
            color: #3b82f6;
            text-decoration: none;
        }

        a:hover {
            text-decoration: underline;
        }
        
        code {
            background-color: #f1f5f9;
            padding: 2px 4px;
            border-radius: 4px;
            font-family: monospace;
            font-size: 13px;
            color: #334155;
        }
    </style>
</head>
<body>
    <form action="u   " method="post">
        <div class="logo-container">
            <div class="logo">
                🚅 LiteLLM
            </div>
        </div>
        <h2>Login</h2>
        <p class="subtitle">Access your LiteLLM Admin UI.</p>
        
        a  
        
        <div class="info-box">
            <div class="info-header">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <circle cx="12" cy="12" r="10"></circle>
                    <line x1="12" y1="16" x2="12" y2="12"></line>
                    <line x1="12" y1="8" x2="12.01" y2="8"></line>
                </svg>
                Default Credentials
            </div>
            <p>By default, Username is <code>admin</code> and Password is your set LiteLLM Proxy <code>MASTER_KEY</code>.</p>
            <p>Need to set UI credentials or SSO? <a href="https://docs.litellm.ai/docs/proxy/ui" target="_blank">Check the documentation</a>.</p>
        </div>
        
        <label for="username">Username<span class="required">*</span></label>
        <input type="text" id="username" name="username" required placeholder="Enter your username" autocomplete="username">
        
        <label for="password">Password<span class="required">*</span></label>
        <input type="password" id="password" name="password" required placeholder="Enter your password" autocomplete="current-password">
        <div class="toggle-password">
            <input type="checkbox" id="show-password" onclick="togglePasswordVisibility()">
            <label for="show-password">Show password</label>
        </div>
        <input type="submit" value="Login">
        
        a  
    </form>
    <script>
        function togglePasswordVisibility() {
            var passwordField = document.getElementById("password");
            passwordField.type = passwordField.type === "password" ? "text" : "password";
        }
    </script>
</body>
</html>
    HTMLResponse   contentstatus_code)litellm.proxy.proxy_serverrE   osgetenvr8   r*   r+   r5   strbase_urlfastapi.responsesrR   )r?   r@   rA   rB   rE   microsoft_client_idgoogle_client_idgeneric_client_id_disable_ui_flagis_disabledsso_availablemissing_env_varserror_message
sso_buttonform_actionunified_login_htmlrR   s                    e/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/management_endpoints/ui_sso.pyserve_login_pageri   N   s5     8))$94@yy!3T:		"5t< yy!34#!(89$&& M''(4 M 01# M| J
> !#g6F6F2GwWKp` - 	 	 
 	4 
 
g]~ / 2DDs   CC!z
/sso/loginc                   K   ddl m}m} t        j                  dd      }t        j                  dd      }t        j                  dd      }|||/|dur+t        dt        j                  d	t        j                  
      t        j                  | d      }t        j                  ||      }	|!	 ddlm}
 |
j                  |        d{   S t        j%                  |||      du r:t'        j(                  d|        t        j+                  |||||	       d{   S t-        dd      S 7 e# t         $ r t#        d      w xY w7 +w)zY
    Handles SSO login redirect - this is what the "Login with SSO" button points to
    r   )rE   "user_custom_ui_sso_sign_in_handlerrF   NrG   rH   T}  You must be a LiteLLM Enterprise user to use SSO. If you have a license please set `LITELLM_LICENSE` in your env. If you want to obtain a license meet with us here: https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat You are seeing this error message because You set one of `MICROSOFT_CLIENT_ID`, `GOOGLE_CLIENT_ID`, or `GENERIC_CLIENT_ID` in your env. Please unset thisrE   messagetypeparamcodesso/callbackr?   sso_callback_route)r@   rA   )EnterpriseCustomSSOHandler)r?   zYEnterprise features are not available. Custom UI SSO sign-in requires LiteLLM Enterprise.r]   r^   r_   zRedirecting to SSO login for )redirect_urlr]   r^   r_   stater;   /  urlrV   )rW   rE   rk   rX   rY   r    r   
auth_errorr   HTTP_403_FORBIDDENSSOAuthenticationHandlerget_redirect_url_for_sso_get_cli_state0litellm_enterprise.proxy.auth.custom_sso_handlerru   handle_custom_ui_sso_sign_inImportError
ValueErrorshould_use_sso_handlerr   infoget_sso_login_redirectr   )r?   r@   rA   rE   rk   r]   r^   r_   rw   	cli_stateru   s              rh   sso_login_redirectr     s    
 ))$94@yy!3T:		"5t< 	''(t#  X$//$..	  ,DD) E L  8FF  G  I *5	 4PP Q    	!77 3-/ 	8 	

 	 	!!$A,"PQ-DD% 3-/ E 
 
 	
  $7SII7  	k 	
s=   B0E3D6 D4D6 AE"E#E4D6 6EEjwt_handlersso_jwt_handlerc           
         t        j                  dd      }t        j                  dd      }t        j                  dd      }t        j                  dd      }t        j                  d	d
      }t        j                  dd      }t        j                  d| d|        g }	|0|j	                  t        t        |             }
|	j                  |
       |j	                  t        t        |             }
|	j                  |
       t        | j                  |      | j                  |      | j                  |      | j                  |      | j                  |      | j                  |      |	      S )NGENERIC_USER_ID_ATTRIBUTEpreferred_username#GENERIC_USER_DISPLAY_NAME_ATTRIBUTEsubGENERIC_USER_EMAIL_ATTRIBUTEemail!GENERIC_USER_FIRST_NAME_ATTRIBUTE
first_name GENERIC_USER_LAST_NAME_ATTRIBUTE	last_nameGENERIC_USER_PROVIDER_ATTRIBUTEproviderz! generic_user_id_attribute_name: z%
 generic_user_email_attribute_name: )iddisplay_namer   r   r   r   team_ids)
rX   rY   r   debugget_team_ids_from_jwtr   dictextendr2   get)responser   r   generic_user_id_attribute_name(generic_user_display_name_attribute_name!generic_user_email_attribute_name&generic_user_first_name_attribute_name%generic_user_last_name_attribute_namegeneric_provider_attribute_name	all_teamsr   s              rh   generic_response_convertorr     sl   
 &(YY#%9&" 02yy-u0, )+		&)% .0YY+\.* -/II*K-) ')ii):'# 
+,J+KKq  sT  rU  	V I""88dH9MN"00dH1EFHX<<67\\"JKll<=<< FG,,DE=>     r_   rw   returnc                 d  K   ddl m} ddlm} d t	        j
                  dd       }t	        j
                  dd      j                  d      }t	        j
                  dd       }	t	        j
                  d	d       }
t	        j
                  d
d       }t	        j
                  dd      j                         dk(  }|+t        dt        j                  dt        j                        |	+t        dt        j                  dt        j                        |
+t        dt        j                  d	t        j                        |+t        dt        j                  d
t        j                        t        j                  d|	 d|
 d|        t        j                  d| d| d        ||	|
|      }fd} |d||      } ||||d|      }t        j                  d       t	        j
                  d d       }i }|D|j                  d!      }|D ].  }|j                         }|s|j                  d"      \  }}|||<   0 	 |j!                  | d#|i|$       d {   }t        j                  d'|       |xs i fS 7 "# t"        $ r"}t        j$                  d%| d&|        |d }~ww xY ww)(Nr   DiscoveryDocumentcreate_providerGENERIC_CLIENT_SECRETGENERIC_SCOPEopenid email profile GENERIC_AUTHORIZATION_ENDPOINTGENERIC_TOKEN_ENDPOINTGENERIC_USERINFO_ENDPOINTGENERIC_INCLUDE_CLIENT_IDfalsetrue2GENERIC_CLIENT_SECRET not set. Set it in .env filerm   ;GENERIC_AUTHORIZATION_ENDPOINT not set. Set it in .env file3GENERIC_TOKEN_ENDPOINT not set. Set it in .env file6GENERIC_USERINFO_ENDPOINT not set. Set it in .env fileauthorization_endpoint: 
token_endpoint: 
userinfo_endpoint: GENERIC_REDIRECT_URI: 
GENERIC_CLIENT_ID: 
authorization_endpointtoken_endpointuserinfo_endpointc                 $    | t        |       S )N)r   r   r   )r   )r   clientr   received_responser   s     rh   response_convertorz4get_generic_sso_response.<locals>.response_convertorO  s    $)#+
 	
r   oidc)namediscovery_documentr   T	client_idclient_secretredirect_uriallow_insecure_httpscopez&calling generic_sso.verify_and_processGENERIC_SSO_HEADERS,=include_client_id)paramsheadersz,Error verifying and processing generic SSO: z. Passed in headers: zgeneric result: %s)fastapi_sso.sso.baser   fastapi_sso.sso.genericr   rX   rY   splitlowerr    r   r|   r   HTTP_500_INTERNAL_SERVER_ERRORr   r   stripverify_and_process	Exception	exception)r?   r   r   r_   rw   r   r   generic_client_secretgeneric_scopegeneric_authorization_endpointgeneric_token_endpointgeneric_userinfo_endpointgeneric_include_client_id	discoveryr   SSOProvidergeneric_ssoadditional_generic_sso_headers#additional_generic_sso_headers_dict$additional_generic_sso_headers_splitheaderrA   rJ   resulter   s    ``                      @rh   get_generic_sso_responser     s     77(,II&=tDIIo/EFLLSQM%'YY/OQU%V"YY'?F "		*Et L
		-w7==?6I  $H ++)66	
 	
 &-Q ++266	
 	
 %I ++*66	
 	
 !(L ++-66	
 	
 
"#A"BBTUkTl  mB  C\  B]  	^ 
 .CDUCVVXY "=-3I
 "$-K
 #+! K GH%'YYt&" +-'%1/M/S/STW/X,:F\\^F#\\#.
U;@3C8	 ;
"55')BC7 6 
 
 3V<<R***

  &&:1#=RSvRwx	
 	sB   H"J0(J0J J J "J0 J 	J-J((J--J0c                   K   	 t        |j                  d      }t        ||       }t        |t	        t
        j                               d{   S 7 # t        $ r"}t        j                  d|        Y d}~yd}~ww xY ww)z,Create a task for adding a member to a team.user)user_idrole)memberteam_id	user_roledatauser_api_key_dictN3[Non-Blocking] Error trying to add sso user to db: )
r   r   r"   r1   r#   r   PROXY_ADMINr   r   r   )r   	user_infor   team_member_add_requestr   s        rh   create_team_member_add_taskr    s     
	 1 1?"6#
 %(,7G7S7ST
 
 	
 
  
""A!E	
 	

sA   BAA AA BA 	B A=8B=BBr  	sso_teamsc                 T  K   | j                   yt        |      t        | j                         z
  }t        |      }g }|D cg c]  }t        ||        }}	 t	        j
                  |  d{    yc c}w 7 
# t        $ r"}t        j                  d|        Y d}~yd}~ww xY ww)zq
    - Get missing teams (diff b/w user_info.team_ids and sso_teams)
    - Add missing user to missing teams
    Nr   )	teamssetlistr  asynciogatherr   r   r   )r  r  missing_teamsmissing_teams_listtasksr   r   s          rh   add_missing_team_memberr    s      	NS%99Mm,E * 	$GY7E 

nne$$$ 	% 
""A!E	
 	

sN   A B(A3B(A: -A8.A: 2B(8A: :	B%B B( B%%B(c                      t         j                  } | y| j                  d      xs i }|j                  d      xs g }t        d|v       S )NFpersonal_key_generationallowed_user_rolesproxy_admin)litellmkey_generation_settingsr   bool)r  r  r  s      rh   ,get_disabled_non_admin_personal_key_creationr    sZ    %==&##$=>D"  1445IJPb!3344r   r   
user_emailprisma_clientuser_api_key_cacheproxy_logging_objc           
         K   	 t        | |||dd ||        d {   }|S 7 # t        $ r%}t        j                  d|        d }Y d }~|S d }~ww xY ww)NF)r   r  r  r  user_id_upsertparent_otel_spanr  sso_user_idzError getting user object: )r%   r   r   r   )r   r  r  r  r  r  r   s          rh   get_existing_user_info_from_dbr     sq     )!'1 !/	
 	
	 	
  ""%@#DE		s6   A# !# A# 	AAAAAr   user_defined_valuesalternate_user_idc                   K   	 g }||j                  |       t        | t              s1t        | dd       }|Wt        |t              rG|j                  |       n5| j                  dd       }|!t        |t              r|j                  |       t        | t              st        | dd       n| j                  dd       }d }	|D ]  }
t        |
||||       d {   }	|	 n t        j                  d|	 dt        j                          |	"t        j                  | |	|||       d {   }	t        j                  | |	       d {    |	S 7 x7 '7 
# t        $ r"}t        j                  d|        Y d }~y d }~ww xY ww)	Nr   r   )r   r  r  r  r  zuser_info: z(; litellm.default_internal_user_params: )r   r  r  r!  r  )r   r  r   )append
isinstancer   getattrrZ   r   r   r   r   r  default_internal_user_paramsr~   upsert_sso_user#add_user_to_teams_from_sso_responser   r   )r   r  r  r  r  r!  r"  potential_user_ids_idr  r   r   s               rh   get_user_info_from_dbr,    s    8
(%%&78&$'&$-C:c3#7"))#.**T4(C:c3#7"))#. fd+ FGT*GT* 	 JN	)G<%+#5"3 I $ * 	"")$LWMqMqLrs	
 6FF#%$7+ G  I 'JJ K 
 	
 	

 ="	
  
&&A!E	
 	
 
sl   FCE EE  AE +E,E 
EE FE E E 	F E=8F=FFc                     |y | | j                   | j                   |d<   | | j                  t        j                  |d<   |S | j                  |d<   |S )Nr   r   )r   r   r   INTERNAL_USER_VIEW_ONLYr  r!  s     rh   1apply_user_info_values_to_sso_user_defined_valuesr0    sr     "!2!2!>)2):):I&I//7+;+S+SK(  ,5+>+>K(r   r   c                 Z  K   t        j                  d      }|||k(  r| r| t        j                  j                  k(  r| S |rK|j
                  j                  j                  d|idt        j                  j                  i       d{    t        j                  j                  } | S 7  w)z`
    - Check if user role in DB is admin
    - If not, update user role in DB to admin role
    PROXY_ADMIN_IDNr   r   wherer   )rX   rY   r   r  rJ   dblitellm_usertableupdate)r   r   r  proxy_admin_ids       rh   "check_and_update_if_proxy_admin_idr9  &  s      YY/0N!n&?&6&B&B&H&HH""44;; '*!#3#?#?#E#EF <   
 %0066	s   BB+B)	!B+z/sso/callbackrx   c           
        K   t        j                  d|        ddlm} |rV|j	                  | d      rB|j                  dd      d   }t        j                  d|        t        | |       d{   S dd	lm} dd
l	m
} ddlm}m}m}m}	m}
 |	%t#        dt$        j&                  j(                        d}|j+                  dd      }|St-        |t.              rC |       }|j1                  |	|
 ||j+                  di       j+                  dd            d       t3        j4                  dd      }t3        j4                  dd      }t3        j4                  dd      }d}|+t7        dt8        j:                  dt<        j>                        t@        jC                  | d      }t        j                  d|        d}|!tD        jG                  | ||       d{   }n@|!tH        jK                  | ||       d{   }n|tM        | ||||       d{   \  }}|t#        dd      t@        jO                  || |||        d{   S 7 7 y7 X7 ?7 w)!zVerify loginz"Starting SSO callback with state: r   ) LITELLM_CLI_SESSION_TOKEN_PREFIX:   z#CLI SSO callback detected for key: )rA   NLiteLLM_JWTAuthr'   )general_settingsr   
master_keyr  r    rV   detailui_access_modesso_group_jwt_fieldteam_ids_jwt_fieldr  r  litellm_jwtauthleewayrF   rG   rH   zMaster Key not set for Proxy. Please set Master Key to use Admin UI. Set `LITELLM_MASTER_KEY` in .env or set general_settings:master_key in config.yaml.  https://docs.litellm.ai/docs/proxy/virtual_keys. If set, use `--detailed_debug` to debug issue.rA  rm   rr   rs   Redirecting to )r?   r^   rw   )r?   r]   rw   r?   r   r_   rw   r     z$Result not returned by SSO provider.)r   r?   r   r_   rE  )(r   r   litellm.constantsr;  
startswithr   cli_sso_callbacklitellm.proxy._typesr?  litellm.proxy.auth.handle_jwtr(   rW   r@  r   rA  r  r  r   r   db_not_connected_errorrJ   r   r%  r   update_environmentrX   rY   r    r   r|   r   r   r~   r   GoogleSSOHandlerget_google_callback_responseMicrosoftSSOHandlerget_microsoft_callback_responser   !get_redirect_response_from_openid)r?   rx   r;  key_idr?  r(   r@  r   rA  r  r  r   rE  r]   r^   r_   r   rw   r   s                      rh   auth_callbackr\  =  s      B5'JK C!!%E$Fa"HIS!$Q'!!$Gx"PQ%g6:::48  $5$L$L$R$R
 	
 -1O%))*:DAN!j&F$,**'1+#3#7#78H"#M#Q#Q)4$
  	+ 		
 ))$94@yy!3T:		"5t<(, P ++66	
 	
 ,DDN E L ~>?F#'DD-% E 
 

 
	(*JJ 3% K 
 

 
	&*B#/%++
 %
!! ~9
 	

 *KK++% L   [ ;f

%
s[   A2I$4I5E-I$"I#"I$II$ I !3I$I"I$I$I$ I$"I$c                 "  K   t        j                  d|        ddlm} ddlm} |r|j                  d      st        dd      |%t        d
t        j                  j                        	  |ddt        j                  i i ddd|	       d	{    t        j                  d|        ddlm} ddlm}  |       } ||d      S 7 9# t"        $ r6}t        j$                  d|        t        d
dt'        |             d	}~ww xY ww)z:CLI SSO callback - generates the key with pre-specified IDzCLI SSO callback for key: r   )generate_key_helper_fnr  sk-  zAInvalid key parameter. Must be a valid key ID starting with 'sk-'rC  NrB  rA   24hrzlitellm-cli)	request_typedurationkey_max_budgetaliasesconfigspendr   
table_nametokenzGenerated CLI key: rQ   )render_cli_sso_success_pagerS   rT   zError generating CLI key: zFailed to generate key: )r   r   ;litellm.proxy.management_endpoints.key_management_endpointsr^  rW   r  rP  r   r   rT  rJ   r  max_ui_session_budgetr\   rR   5litellm.proxy.common_utils.html_forms.cli_sso_successrk  r   rB   rZ   )r?   rA   r^  r  rR   rk  html_contentr   s           rh   rQ  rQ    s(     :3%@A 9cnnU+V
 	

 $5$L$L$R$R
 	

Y$"88!

 
	
 
	
 	!!$7u"=> 	3	
 34LcBB-
	
0  Y""%?s#CD6NsSTvh4WXXYs<   A,D/"C C8C 
DC 	D1DDDz/sso/cli/poll/{key_id}r[  c                   K   ddl m} | j                  d      st        dd      |%t        dt        j
                  j                        	 dd	lm}  ||       }|j                  j                  j                  d
|i       d{   }|rt        j                  d|         d| dS ddiS 7 '# t        $ r6}t        j                  d|        t        ddt!        |             d}~ww xY ww)z1CLI polling endpoint - checks if key exists in DBr   r_  r`  ra  zInvalid key ID formatrC  NrB  )
hash_tokenrj  r4  zCLI key found: ready)r   rA   r   pendingzError polling for CLI key: zError checking key status: )rW   r  rP  r   r   rT  rJ   litellm.proxy.utilsrq  r5  litellm_verificationtokenfind_uniquer   r   r   rB   rZ   )r[  r  rq  hashed_tokenkey_objr   s         rh   cli_poll_keyrz    s     9U#4KLL$5$L$L$R$R
 	

2!&)%((BBNNL) O 
 
  %%x&@A%f55i((
  
""%@#DE&A#a&$J
 	

sH   AC49B2 B0	"B2 +C4,B2 /C40B2 2	C1;1C,,C11C4result_openidc           	        K   t        j                  d|        | t        d      t        | t              rt        di | } |t        d      t        j                  r|j                  t        j                         |j                  d      t        j                  j                  k(  rH|j                  d      t        j                  |d<   |j                  d      t        j                  |d<   |d   t        j                  |d<   t!        |d   |d	   |d   |d   |d   |d   d
      }| rd| j"                  i|_        t'        |t)        t        j*                               d{   }|S 7 w)ar  
    Helper function to create a New User in LiteLLM DB after a successful SSO login

    Args:
        result_openid (OpenID): User information in OpenID format if the login was successful.
        user_defined_values (Optional[SSOUserDefinedValues], optional): LiteLLM SSOValues / fields that were read

    Returns:
        Tuple[str, str]: User ID and User Role
    z)Inserting SSO user into DB. User values: Nzresult_openid is Nonezuser_defined_values is Noner   
max_budgetbudget_durationr   r  F)r   r  r   r}  r~  r  auto_create_keyauth_providerr   r    )r   r   r   r%  r   r:   r  r'  r7  r   r   INTERNAL_USERrJ   max_internal_user_budgetinternal_user_budget_durationr.  r   r   metadatar-   r#   r  )r{  r!  new_user_requestr   s       rh   insert_sso_userr    s     
34G3HI 011-&//"677++""7#G#GH {+/?/M/M/S/SS""<08070P0P-""#45=55   12 ;'/+;+S+SK(%#I.&|4%k2&|4+,=>'	2 %4m6L6L$M!(3C3O3OP H
 Os   E*E5,E3-E5z/sso/get/ui_settings)r=   r>   dependenciesc                 z  K   ddl m}m} t        j                  dd       }t        j                  dd       }t               }|j                  d      t        kD  }|j                  dd      }dt        j                  v r&t        j                  d   j                         d	k(  rd
}|||||j                  d      |dS w)Nr   )r@  proxy_statePROXY_BASE_URLPROXY_LOGOUT_URLspend_logs_row_countdefault_team_disabledFPROXY_DEFAULT_TEAM_DISABLEDr   T)r  r  DEFAULT_TEAM_DISABLEDSSO_ENABLEDNUM_SPEND_LOGS_ROWSDISABLE_EXPENSIVE_DB_QUERIES)rW   r@  r  rX   rY   r&   get_proxy_state_variabler   r   environr   )r?   r@  r  _proxy_base_url_logout_url_is_sso_enableddisable_expensive_db_queriesr  s           rh   get_ui_settingsr  3  s      Iii 0$7O)).5K)+O,,-CD
$	% ! -001H%P$

2::34::<F$(! *'!6&*CC" 
 )E	 	s   B9B;c                   j   e Zd ZdZe	 	 	 	 d$dedee   dee   dee   dee   dee   fd	       Ze	 	 	 d%dee   dee   dee   de	fd
       Z
edededefd       Zedeeeeef      deeeef      dee   dee   def
d       Zedeeeeef      deeeef      fd       Zededeeeeef      dee   ded   fd       Ze	 d&dedee   fd       Ze	 d&deeef   dededee   def
d       Zedee   d ee   dee   fd!       Ze	 	 	 d%deeeef   dedee   dee   d"ee   defd#       Zy)'r~   zA
    Handler for SSO Authentication across all SSO providers
    Nrw   r^   r]   r_   rx   r   c                   K   |ddl m} t        j                  dd      }|+t	        dt
        j                  dt        j                         ||||       }t        j                  d|  d	|        |5  |j                  |
       d{   cddd       S |ddlm} t        j                  dd      }	t        j                  dd      }
|	+t	        dt
        j                  dt        j                         |||	|
| d      }|5  |j                  |
       d{   cddd       S |ddlm} ddlm} t        j                  dd      }t        j                  dd      j%                  d      }t        j                  dd      }t        j                  dd      }t        j                  dd      }|+t	        dt
        j                  dt        j                        |+t	        dt
        j                  dt        j                        |+t	        dt
        j                  dt        j                        |+t	        dt
        j                  dt        j                        t        j&                  d| d| d |        t        j&                  d!|  d"| d#        ||||$      } |d%|&      } |||| d|'      }|5  i }t        j                  d(d      }|r||d)<   n%d*|v r!t)        j*                         j,                  |d)<    |j                  d,i | d{   cddd       S t/        d+      7 # 1 sw Y   t/        d+      xY w7 9# 1 sw Y   t/        d+      xY w7 J# 1 sw Y   t/        d+      xY ww)-aS  
        Step 1. Call Get Login Redirect for the SSO provider. Send the redirect response to `redirect_url`

        Args:
            redirect_url (str): The URL to redirect the user to after login
            google_client_id (Optional[str], optional): The Google Client ID. Defaults to None.
            microsoft_client_id (Optional[str], optional): The Microsoft Client ID. Defaults to None.
            generic_client_id (Optional[str], optional): The Generic Client ID. Defaults to None.

        Returns:
            RedirectResponse: The redirect response from the SSO provider
        Nr   	GoogleSSOGOOGLE_CLIENT_SECRET1GOOGLE_CLIENT_SECRET not set. Set it in .env filerm   )r   r   r   z5In /google-login/key/generate, 
GOOGLE_REDIRECT_URI: z
GOOGLE_CLIENT_ID: )rx   MicrosoftSSOMICROSOFT_CLIENT_SECRETMICROSOFT_TENANT4MICROSOFT_CLIENT_SECRET not set. Set it in .env fileTr   r   tenantr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   r   GENERIC_CLIENT_STATErx   oktazfUnknown SSO provider. Please setup SSO with client IDs https://docs.litellm.ai/docs/proxy/admin_ui_ssor  )fastapi_sso.sso.googler  rX   rY   r    r   r|   r   r   r   r   get_login_redirectfastapi_sso.sso.microsoftr  r   r   r   r   r   r   uuiduuid4hexr   )rw   r^   r]   r_   rx   r  google_client_secret
google_ssor  microsoft_client_secretmicrosoft_tenantmicrosoft_ssor   r   r   r   r   r   r   r   r   r   redirect_paramss                          rh   r   z/SSOAuthenticationHandler.get_sso_login_redirectY  s    * '8#%99-CT#J #+$O(330>>	  #*2)J
 !%%HVjk{j|}  H':::GGH H !,>&(ii0I4&P#!yy);TB&.$R(333>>	  )-5')$(M  K*==E=JJK K*>?$&II.Et$L!IIo7MNTTM .0YY0$.* &(YY/G%N"(*		2Mt(T%$,$P(331>>	  .5$Y(33:>>	  &-$Q(332>>	  )0$T(335>>	  !&&*+I*JJ\]s\t  uJ  Kd  Je  f !&&(6KL]K^^`a *'E5";I
 *v)TK%+3)$(#K  O
 #%		"8$?/4OG,==

(( $G, <[;;NoNNO O t
 	
E HHF t
 	
Y KKZ t
 	
 OO t
 	
s   A4N
6MM MA:N

M M!M$F(N
AM4'M2(M4+N
 MMN
MM/!N
2M44N9N
c                     | ||yy)NTFr  )r^   r]   r_   s      rh   r   z/SSOAuthenticationHandler.should_use_sso_handler  s     (". ,r   r?   rt   c                     ddl m}  |t        | j                              }|j	                  d      r||z  }|S |d|z   z  }|S )z.
        Get the redirect URL for SSO
        r   )r5   )rO   /)ru  r5   rZ   r[   endswith)r?   rt   r5   rw   s       rh   r   z1SSOAuthenticationHandler.get_redirect_url_for_sso  sU     	7%s7;K;K7LM  %..L  C"444Lr   r   r  r  r!  r  c                 R  K   	 |A|j                   }|j                  j                  j                  d|id|i       d{    |S t	        j
                  d       t        | |       d{   }|S 7 27 # t        $ r$}t	        j                  d|        |cY d}~S d}~ww xY ww)z
        Connects the SSO Users to the User Table in LiteLLM DB

        - If user on LiteLLM DB, update the user_email with the SSO user_email
        - If user not on LiteLLM DB, insert the user into LiteLLM DB
        Nr   r  r3  z.user not in DB, inserting user into LiteLLM DB)r{  r!  z*Error upserting SSO user into LiteLLM DB: )	r   r5  r6  update_manyr   r   r  r   rB   )r   r  r  r!  r  r   r   s          rh   r(  z(SSOAuthenticationHandler.upsert_sso_user  s     	$#++#&&88DD$g.lJ5O E     %))D #2"((;# 	 
  	 &&)STUSV'WX	sd   B'<A7  A3A7 B'%A7 ,A5-A7 2B'3A7 5A7 7	B$ BB$B'B$$B'c                    K   |t        j                  d       yt        | dg       }t        ||       d{    y7 w)z
        Adds the user as a team member to the teams specified in the SSO responses `team_ids` field


        The `team_ids` field is populated by litellm after processing the SSO response
        Nz;User not found in LiteLLM DB, skipping team member additionr   )r  r  )r   r   r&  r  )r   r  r  s      rh   r)  z<SSOAuthenticationHandler.add_user_to_teams_from_sso_response)  sB       &&M FJ3	%	YOOOs   6A >A r@  r   Tc                 f   t        t        t        t        t        f      | j                  d            }|yt        |t              ryt        |dg       }|j                  d      dk(  rI|j                  d      }||vr4t        d| d| d| t        j                  dt        j                  	      y)
a  
        when ui_access_mode.type == "restricted_sso_group":

        - result.team_ids should contain the restricted_sso_group
        - if not, raise a ProxyException
        - if so, return True
        - if result.team_ids is None, return False
        - if result.team_ids is an empty list, return False
        - if result.team_ids is a list, return True if the restricted_sso_group is in the list, otherwise return False
        rE  Tr   ro   restricted_sso_groupz)User is not in the restricted SSO group: z. User groups: z. Received SSO response: rm   )r   r   r
   r   rZ   r   r%  r&  r    r   r|   r   r}   )r@  r   r   rE  r   r  s         rh   #verify_user_in_restricted_sso_groupz<SSOAuthenticationHandler.verify_user_in_restricted_sso_group<  s    " U49%&(8(<(<=M(N
 !nc*6:r2f%)??#1#5#56L#M #83$GH\G]]lmulv  wP  Qb  Pc  d(33022	  r   litellm_team_idlitellm_team_namec           	        K   ddl m} |+t        dt        j                  dt
        j                        	 |j                  j                  j                  d| i       d{   }t        j                  d	|        |rt        j                  d
|  d|        yt        | |      }t        j                  r't        j!                  t        j                  | ||      }t#        |t%        ddd      t'        ddt(        j*                                d{    y7 7 # t,        $ r"}t        j.                  d|        Y d}~yd}~ww xY ww)aj  
        Creates a Litellm Team from a SSO Group ID

        Your SSO provider might have groups that should be created on LiteLLM

        Use this helper to create a Litellm Team from a SSO Group ID

        Args:
            litellm_team_id (str): The ID of the Litellm Team
            litellm_team_name (Optional[str]): The name of the Litellm Team
        r   r_  Nz;Prisma client not found. Set it in the proxy_server.py filer  rm   r   rr  zTeam object: zTeam already exists: z - )r   
team_alias)default_team_paramsr  r  team_requesthttpPOST)ro   method)r   rK   zlitellm.)rj  	key_alias)r   http_requestr   zError creating Litellm Team: )rW   r  r    r   r|   r   r   r5  litellm_teamtable
find_firstr   r   r   r  r  r~   ._cast_and_deepcopy_litellm_default_team_paramsr0   r   r#   rX  __name__r   r   )r  r  r  team_objr  r   s         rh   "create_litellm_team_from_sso_groupz;SSOAuthenticationHandler.create_litellm_team_from_sso_groupb  sh      	=  U$//%::	 #	P*--??JJ /2 K  H !&&xj'AB $**+O+<C@Q?RS +9',,L **7ff(/(C(C$3&7!-	  g   !$Ff+MN"0 ()<)E)E(FG#	  10  	P **-J1#+NOO	Ps_   4E+D% "D!#9D% EA>D% D#D%  E!D% #D% %	E.EEEEr  r  c                 0   t        | t              r"t        |       }||d<   ||d<   t        di |}|S t        t        j
                  t              rEt        t        j
                        }|j                         }|j                  |       t        di |}|S )ac  
        Casts and deepcopies the litellm.default_team_params to a NewTeamRequest object

        - Ensures we create a new DefaultTeamSSOParams object
        - Handle the case where litellm.default_team_params is a dict or a DefaultTeamSSOParams object
        - Adds the litellm_team_id and litellm_team_name to the DefaultTeamSSOParams object
        r   r  r  )	r%  r   r   r   r  r  DefaultTeamSSOParams
model_dumpr7  )r  r  r  r  _team_request_default_team_params_new_team_requests          rh   r  zGSSOAuthenticationHandler._cast_and_deepcopy_litellm_default_team_params  s     )40$%89M'6M)$*;M,'):M:L  335IJ#+G,G,G#H  , 7 7 9$$%9:)>,=>Lr   r@   rA   c                 2    ddl m}m} | |k(  r	|r| d| S dS )z
        Checks the request 'source' if a cli state token was passed in

        This is used to authenticate through the CLI login flow
        r   )r;  LITELLM_CLI_SOURCE_IDENTIFIERr<  N)rO  r;  r  )r@   rA   r;  r  s       rh   r   z'SSOAuthenticationHandler._get_cli_state  s4    	
 663 00#7	
 	
r   rE  c                   K   dd l }ddlm}m}m}m}	m}
m}m} ddl	m
}m} ddlm}  |d      }t        j                  d|         t!        | dd       }| t!        | dd       nd }|pt#        j$                  d	      [|j'                  d
      d   }t#        j$                  d	      j'                  d      }||vrt)        dddj+                  ||      i      |?| =t#        j$                  dd      }t!        | dd       }t!        | dd       }t!        | |d       }|)| 't!        | dd      xs d}t!        | dd      xs d}||z   }||t-        |      dk(  r|}d }g }t.        j0                  }t.        j2                  }dt.        j4                  i i ddd}d }|1t7        j8                  |      r ||        d {   }nt;        d      |t=        ||||d |      }t>        jA                  || |       tC        | |||
|||       d {   }tE        ||      }|tG        d      t        j                  d|        |jI                  |       d |d!<    |d>i |d"d i d {   }|d#   } |d$   }|d%   xs tJ        jL                  jN                  }|r&tQ        |tR              rtU        |||&       d {   }t        jV                  d'| d(|        tY        |xs i       }!|!r"t[        |      }"|"st)        dd)d*| d+| i      t]               }# |tS        |j^                        d,-      }$ta        d.      rVd }%|,|d$   'tc        |d$   |d%   xs |g t.        j4                  /      }%|%t)        dd)d0i      te        jf                  |%      }  |ti        tR        |      | ||d1|	|jk                  d2d3      |#tm               4	      }&|jo                  ti        tp        |&      |xs dd56      }'t        j                  d7| d8|'        |tQ        |tR              r|$d9z  }$t        j                  d:|$        ts        |$d;<      }(|(ju                  d#|'=       |(S 7 7 V7 7 w)?Nr   )r@  r^  rA  rE   r  r  user_custom_sso)r5   get_prisma_client_or_throw)ReturnedUITokenObjectz7Prisma client is None, connect a database to your proxyzSSO callback result: r   r   ALLOWED_EMAIL_DOMAINS@r=  r   rN  rn   zZThe email domain={}, is not an allowed email domain={}. Contact your admin to change this.rC  GENERIC_USER_ROLE_ATTRIBUTEr   r   rK   r   rb  zlitellm-dashboard)rd  re  rf  rg  rh  r   z,user_custom_sso must be a coroutine function)modelsr   r  r}  r   r~  )r@  r   r   )r   r  r  r  r  r!  r"  r/  zUnable to map user identity to known values. 'user_defined_values' is None. File an issue - https://github.com/BerriAI/litellm/issuesz)user_defined_values for creating ui key: rA   rc  ri  rj  r   r   )r   r   r  zuser_role: z; ui_access_mode: rB   z,User not allowed to access proxy. User role=z, proxy mode=zui/rN   EXPERIMENTAL_UI_LOGIN)r   r   r  r}  z6User Information is required for experimental UI loginssolitellm_key_header_nameAuthorization)	r   rA   r  r   login_methodrE   auth_header_name(disabled_non_admin_personal_key_creationserver_root_pathHS256)	algorithmz	user_id: z; jwt_token: z?login=successrL  ry   rz   )rA   rJ   r  );jwtrW   r@  r^  rA  rE   r  r  r  ru  r5   r  litellm.types.proxy.ui_ssor  r   r   r&  rX   rY   r   r   formatlenr  r  r  rm  r
  iscoroutinefunctionr   r!   r~   r  r,  r0  r   r7  r   r.  rJ   r%  rZ   r9  r   r.   r/   r  r[   r7   r   r$   (get_experimental_ui_login_jwt_auth_tokenr   r   r6   encoder   r   
set_cookie))r   r?   r   r_   rE  r  r@  r^  rA  rE   r  r  r  r5   r  r  r  r  r   email_domainallowed_domains generic_user_role_attribute_namer   _first_name
_last_namer  user_id_modelsr  r  default_ui_key_valuesr!  r   rA   is_admin_only_access
has_accessr  litellm_dashboard_ui
_user_inforeturned_ui_token_object	jwt_tokenredirect_responses)                                            rh   rZ  z:SSOAuthenticationHandler.get_redirect_response_from_openid  ss     		
 	
 	
 	SD2E

 	!!$9&"BC$+FGT$B
+1+=GFD$'4 	 !bii0G&H&T%++C03L ii(?@FFsKO?2# #!#  $G  $G(/$  (V-?/1yy-v0, fdD1G $7J(H$OI?v1!&,;ArK b9?RJ!J.G!w#g,!:K G	!#*#C#C (/(M(M%
 %;;*1
 ?C&**?;,;F,C&C# !OPP "6%%3 =# 	!DD-/ 	E 	
 0'1/! 3%
 
	 P5H
 & X  	!!78K7LM	
 	$$%8905n-/ 
#

 

 w9%  , >77== 	 z'3/@#WM I 	"")$6~6FG	
  :.:NBO,Y7J# ##OPY{Zghvgw!x  9: 	1  . !1!12% 
 236:J#/'	2>./	:1+>K)&<<	
 !# #!Y  )QQC $9g&!%-11)? 6^13$
  JJ/0"  
	
 	!!IgYmI;"OP:gs#; $44 !!O4H3I"JK,1ESVW$$	$B  K 'D(
2
sL   F4Q&6Q7AQ&QAQ&#Q $AQ&6Q#7F$Q&Q& Q&#Q&)NNNNNNNN) r  
__module____qualname____doc__staticmethodrZ   r   r   r   r  r   r   r   r
   r2   r:   r   r   r   r!   r3   r(  r)  r   Literalr  r  r  r   r  r   rZ  r  r   rh   r~   r~   T  s8     +/-1+/#L
L
"3-L
 &c]L
 $C=	L

 }L
 
"	#L
 L
\ *.-1+/"3-%c] $C= 
	   
   |VT9:;E/3D"DEF SM &&:;	
 $ B P|VT9:;PE/3D"DEFP P$ ##|VT9:;# $D># 
	# #J  ,0;P;P#C=;P ;Pz 
 ,0	"#7#=>$  $C=	
 
 2 
x} 
8C= 
Xc] 
 
"  -1+/)-W!fdL01W!W! $D>W! $C=	W!
 !W! 
W! W!r   r~   c                      e Zd ZdZdZe dZ	 dZdZe	 dde	de
de
d	ed
eeeef   f
d       Zedee   dee
   d
efd       Ze	 ddee
   d
ee
   fd       Zede
deded
eee
   ee
   f   fd       Zeded
ee
   fd       Zeded
efd       Ze	 dde
dedee
   d
eee
   ee   f   fd       Zedee   fd       Zy)rX  zS
    Handles Microsoft SSO callback response and returns a CustomOpenID object
     https://graph.microsoft.com/v1.0z/me/memberOfrS   graph_api_user_groupsr?   r]   rw   return_raw_sso_responser   c                 :  K   ddl m} t        j                  dd      }t        j                  dd      }|+t	        dt
        j                  dt        j                        |+t	        dt
        j                  dt        j                         |||||d	
      }|j                  | d       d{   xs i }t        j                  |j                         d{   }	|r|	|t        j                  <   |xs i S t        j                  ||	      }
|
S 7 d7 :w)z
        Get the Microsoft SSO callback response

        Args:
            return_raw_sso_response: If True, return the raw SSO response
        r   r  r  Nr  r  rm   z-MICROSOFT_TENANT not set. Set it in .env fileTr  Fr?   convert_response)access_token)r   r   )r  r  rX   rY   r    r   r|   r   r   r   rX  get_user_groups_from_graph_apir  GRAPH_API_RESPONSE_KEYopenid_from_response)r?   r]   rw   r  r  r  r  r  original_msft_resultuser_team_idsr   s              rh   rY  z3MicrosoftSSOHandler.get_microsoft_callback_response  sJ     	;"$)),Et"L99%7>"* N$///::	  # G$//(::	  %)1#% $
  22!& 3     	 2PP&33 Q 
 

 # !!4!K!KL (-2-$99)" : 
 -
s$   B0D2D3+DD9DDr   r   c           
      R   | xs i } t        j                  d|         t        | j                  d      xs | j                  d      | j                  d      d| j                  d      | j                  d      | j                  d      |	      }t        j                  d
|        |S )Nz!Microsoft SSO Callback Response: userPrincipalNamemaildisplayName	microsoftr   	givenNamesurname)r   r   r   r   r   r   r   zMicrosoft SSO OpenID Response: )r   r   r2   r   )r   r   openid_responses      rh   r  z(MicrosoftSSOHandler.openid_from_response  s     >r""%Fxj#QR&,,23Kx||F7K!m4 ||D!||K0ll9-
 	""%D_DU#VWr   Nr  c                 ~  K   	 t        t        j                        }t        j                  dd      }g }g }|rgt
        j                  |||        d{   \  }}t        j                  d|        t        |      dkD  rt
        j                  |       d{    g }t
        j                  }dd	|  i}d}|b|t
        j                  k  rOt
        j                  |||
       d{   \  }	}|j                  |	       |dz  }||t
        j                  k  rO|:|t
        j                  k\  r't        j                  dt
        j                   d       |r!t        |      dkD  r|D 
cg c]  }
|
|v r|

 }}
|S 7 ,7 7 c c}
w # t         $ r$}t        j"                  d|        g cY d}~S d}~ww xY ww)a  
        Returns a list of `team_ids` the user belongs to from the Microsoft Graph API

        Args:
            access_token (Optional[str]): Microsoft Graph API access token

        Returns:
            List[str]: List of group IDs the user belongs to
        )llm_providerMICROSOFT_SERVICE_PRINCIPAL_IDN)service_principal_idasync_clientr  zService principal group IDs: r   )service_principal_teamsr  Bearer )r{   r   r!  r=  zReached maximum page limit of z". Some groups may not be included.z4Error getting user groups from Microsoft Graph API: )r   r   SSO_HANDLERrX   rY   rX  $get_group_ids_from_service_principalr   r   r  4create_litellm_teams_from_service_principal_team_idsgraph_api_user_groups_endpointMAX_GRAPH_API_PAGESfetch_and_parse_groupsr   warningr   rB   )r  r!  r   service_principal_group_idsr"  all_group_ids	next_linkauth_headers
page_count	group_idsgroup_idr   s               rh   r  z2MicrosoftSSOHandler.get_user_groups_from_graph_api  s     B	11==L
 $&99-Mt#T ?A'UW## .RR)=!-!- S  /+ %**34O3PQ 23a7-bb0G c   
 M#BB  ,w|n-EFLJ %!4!H!HH-@-W-W!<l .X . ($	9 $$Y/a
 %!4!H!HH %"5"I"II$,,45H5\5\4]]  A
 +s3N/ORS/S %2! #>> ! ! ! _ ( !  	 &&FqcJ I		s   F=AF FAF FAF ,F-2F  AF 0F=F  F=F F F F 	F:F5/F:0F=5F::F=r{   r   r!  c                    K   |j                  | |       d{   }|j                         }t        j                  |       d{   }t        j	                  |      }||j                  d      fS 7 [7 /w)z8Helper function to fetch and parse group data from a URLr   N)r   odata_nextLink)r   jsonrX  _cast_graph_api_response_dict&_get_group_ids_from_graph_api_response)r{   r   r!  r   response_jsonresponse_typedr0  s          rh   r)  z*MicrosoftSSOHandler.fetch_and_parse_groupsY  s     
 &))#w)?? 2PP"  Q  
 
 (NN# O 
	 .,,-=>>> @
s!   A9A5-A9A7.A97A9c                     g }| j                  dg       xs g D ]'  }|j                  d      }||j                  |       ) |S )NrJ   r   )r   r$  )r   r0  _object	_group_ids       rh   r7  z:MicrosoftSSOHandler._get_group_ids_from_graph_api_responseh  sP     	||GR06B6GD)I$  + 7 r   c                   K   g }| j                  dg       D ]|  }|j                  t        |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d                   ~ t        | j                  d	      | j                  d
      |      S w)NrJ   z@odata.typer   deletedDateTimedescriptionr  roleTemplateId)
odata_typer   r>  r?  r  r@  z@odata.contextz@odata.nextLink)odata_contextr4  rJ   )r   r$  )MicrosoftGraphAPIUserGroupDirectoryObject"MicrosoftGraphAPIUserGroupResponse)r   directory_objectsr;  s      rh   r6  z1MicrosoftSSOHandler._cast_graph_api_response_dicts  s      NP||GR0G$$9&{{=9{{4($+KK0A$B 'M : 'M :#*;;/?#@	 1 2",,'78#<<(9:#
 	
s   C Cr   c           	        K   d}d|  d}||z   }d| dd}|j                  ||       d{   }|j                         }t        j                  d	|        g }	g }
|j                  d
g       D ]q  }|j                  d      dk(  s|	j	                  |j                  d             |
j	                  t        |j                  d      |j                  d                   s |	|
fS 7 w)z
        Gets the groups belonging to the Service Principal Application

        Service Principal Id is an `Enterprise Application` in Azure AD

        Users use Enterprise Applications to manage Groups and Users on Microsoft Entra ID
        r	  z/servicePrincipals/z/appRoleAssignedTor#  zapplication/json)r  zContent-Typer3  Nz6Response from service principal app role assigned to: rJ   principalTypeGroupprincipalIdprincipalDisplayName)rJ  rI  )r   r5  r   r   r$  MicrosoftServicePrincipalTeam)r   r!  r  r[   endpointr{   r   r   r8  r0  r"  r;  s               rh   r%  z8MicrosoftSSOHandler.get_group_ids_from_service_principal  s
     6()=(>>PQ!  '|n5.

 &))#w)?? ""D]OT	
  "	GI$(("5G{{?+w6  ]!;<'..1-4[[9O-P$+KK$> 6 111) @s   ,C+C)AC+	A!C+r"  c                   K   t        j                  d|         | D ]_  }|j                  d      }|j                  d      }|st        j                  d| d       At        j	                  ||       d{    a y7 w)z
        Creates Litellm Teams from the Service Principal Group IDs

        When a user sets a `SERVICE_PRINCIPAL_ID` in the env, litellm will fetch groups under that service principal and create Litellm Teams from them
        z5Creating Litellm Teams from Service Principal Teams: rI  rJ  zSkipping team creation for z because it has no principalId)r  r  N)r   r   r   r~   r  )r"  service_principal_teamr  r  s       rh   r&  zHMicrosoftSSOHandler.create_litellm_teams_from_service_principal_team_ids  s      	""CD[C\]	
 '>"-C-G-G-VO/E/I/I&0 #$**12C1DDbc *MM /"3 N    '>s   A6B8B 9BFr  )r  r  r  r  graph_api_base_urlr'  r(  r  r  r   rZ   r  r
   r2   r:   r   rY  r   r   r  r  r   r	   r)  rD  r7  r6  rK  r%  r&  r  r   rh   rX  rX    s    <(:';<%H"  5
 ).	<< < < "&	<
 
|VT)	*< <| 4.,0I	 " &*NsmN	cN N` ???/??	tCy(3-'	(? ? 4	c  

	+
 
*  '+*2!*2&*2 sm*2 
tCy$<==	>	*2 *2X !%&C!D r   rX  c                   D    e Zd ZdZe	 d	dededededee	e
f   f
d       Zy)
rV  zP
    Handles Google SSO callback response and returns a CustomOpenID object
    r?   r^   rw   r  r   c                 :  K   ddl m} t        j                  dd      }|+t	        dt
        j                  dt        j                         ||||      }|r|j                  | d	       d{   xs i S |j                  |        d{   }|xs i S 7 '7 w)
z
        Get the Google SSO callback response

        Args:
            return_raw_sso_response: If True, return the raw SSO response
        r   r  r  Nr  rm   )r   r   r   Fr  )
r  r  rX   rY   r    r   r|   r   r   r   )r?   r^   rw   r  r  r  r  r   s           rh   rW  z-GoogleSSOHandler.get_google_callback_response  s      	5!yy)?F' K$//,::	  &%.

 # 33#%* 4     "44W==| >s$   A-B/B0BBBBNrO  )r  r  r  r  r  r   rZ   r  r
   r:   r   rW  r  r   rh   rV  rV    sW     
 ).	''' ' "&	'
 
vt|	' 'r   rV  z/sso/debug/loginc                   K   ddl m} t        j                  dd      }t        j                  dd      }t        j                  dd      }|||/|dur+t	        dt
        j                  d	t        j                  
      t        j                  | d      }t        j                  |||      du r!t        j                  ||||       d{   S y7 w)z
    Create Proxy API Keys using Google Workspace SSO. Requires setting PROXY_BASE_URL in .env
    PROXY_BASE_URL should be the your deployed proxy endpoint, e.g. PROXY_BASE_URL="https://litellm-production-7002.up.railway.app/"
    Example:
    r   rD   rF   NrG   rH   Trl   rE   rm   sso/debug/callbackrs   rv   )rw   r]   r^   r_   )rW   rE   rX   rY   r    r   r|   r   r}   r~   r   r   r   )r?   rE   r]   r^   r_   rw   s         rh   debug_sso_loginrU    s     8))$94@yy!3T:		"5t< 	''(t#  X$//$..	  ,DD/ E L 	!77 3-/ 	8 	

 	 .DD% 3-/	 E 
 
 	
	
s   CCCC/sso/debug/callbackc           
        K   ddl }ddlm} ddlm} ddlm} ddlm}m	}m
}m} d}	|j                  dd      }
|
St        |
t              rC |       }	|	j                  || ||j                  di       j                  dd      	      d
       t!        j"                  dd      }t!        j"                  dd      }t!        j"                  dd      }t!        j"                  dt%        | j&                              }|j)                  d      r|dz  }n|dz  }d}|"t*        j-                  | ||d       d{   }nA|"t.        j1                  | ||d       d{   }n|t3        | ||||	       d{   \  }}|
 |dd      S t5        |d      r|j6                  }nt        |      }i }|j9                         D ]Q  \  }}|	|j;                  d      rt        |t$        t<        t>        t@        f      s||||<   C	 t%        |      ||<   S tE        jF                  dd|jI                  |d       d       } ||!      S 7 7 7 # tB        $ r}dt%        |       ||<   Y d}~d}~ww xY ww)"z@
    Returns the OpenID object returned by the SSO provider
    r   NrQ   r>  r'   )r@  r   r  r  rE  rF  rG  rI  rF   rG   rH   r  r  rT  rV  T)r?   r^   rw   r  )r?   r]   rw   r  rM  zT<h1>SSO Authentication Failed</h1><p>No data was returned from the SSO provider.</p>ra  rT   __dict___z!Complex value (not displayable): zconst userData = SSO_DATA;zconst userData =    )indent;)rU   )%r5  r\   rR   rR  r?  rS  r(   rW   r@  r   r  r  r   r%  r   rU  rX   rY   rZ   r[   r  rV  rW  rX  rY  r   hasattrrX  itemsrP  intfloatr  r   r,   replacedumps)r?   r5  rR   r?  r(   r@  r   r  r  r   rE  r]   r^   r_   rw   r   rY  result_dictfiltered_resultrA   rJ   r   ro  s                          rh   debug_sso_callbackre  5  s    
 .48  -1O%))*:DAN!j&F$,**'1+#3#7#78H"#M#Q#Q)4$
  	+ 		
 ))$94@yy!3T:		"5t<99-s73C3C/DELS!,,--F#'DD-%$(	 E 
 
 
	(*JJ 3%$(	 K 
 
 
	&2#/%+
 
	 ~j
 	
 vz"oo6l O!'')
US^^C%8%#sE4!89U]',$X+.u:OC( * (//$
DJJqJAB!DL
 --o


> ! X-NsSTvh+WOC(Xsm   D3I45I6#I4I	I44I5AI4I4(I4I7I4	I4I4	I1I,'I4,I11I4c                 L  K   	 | j                          d{   }|j                  d      }|j                  d      }|r|st        dd      S ddlm}  ||        d{   S 7 M7 # t
        $ r/}t        j                  d	|        t        dd      cY d}~S d}~ww xY ww)
zE
    Process username/password login from the unified login page
    Nusernamepasswordz/sso/key/generate?error=1ry   rz   r   )rM   zError processing login: )formr   r   rW   rM   r   r   rB   )r?   	form_datarg  rh  rM   r   s         rh   process_loginrk    s     
R!,,.(	==,==,x#(CQTUU 	5 7^## ) $ R""%=aS#AB$?SQQRsb   B$A) A%6A) B$A)  A'!A) $B$%A) 'A) )	B!2$BB!B$B!!B$r  )NNr  )mr  r
  rX   r  copyr   typingr   r   r   r   r   r	   r
   r   fastapir   r   r   r   r   r\   r   r  litellm._loggingr   litellm.cachingr   rO  r   &litellm.llms.custom_httpx.http_handlerr   r   r   rR  r   r   r   r   r   r   r   r   r    r!   r"   r#   litellm.proxy.auth.auth_checksr$   r%   litellm.proxy.auth.auth_utilsr&   rS  r(   $litellm.proxy.auth.user_api_key_authr)   )litellm.proxy.common_utils.admin_ui_utilsr*   r+   :litellm.proxy.common_utils.html_forms.jwt_display_templater,   :litellm.proxy.management_endpoints.internal_user_endpointsr-   3litellm.proxy.management_endpoints.sso_helper_utilsr.   r/   1litellm.proxy.management_endpoints.team_endpointsr0   r1   (litellm.proxy.management_endpoints.typesr2   ru  r3   r4   r5   r6   litellm.secret_managers.mainr7   r8   /litellm.types.proxy.management_endpoints.ui_ssor   r:   routerr   rZ   ri   r   r   r   r   r  r  r  r   r,  r0  r9  r\  rQ  rz  r  r  r~   rX  rV  rU  re  postrk  r  r   rh   <module>r     s    	   O O O F F .  1 % 8 
    S = 4 B P X A  F =+$	 ~&6%P !	EESME 
#E C=	E QED
 L/5IIMKJKJ&smKJ9A#KJ JKJb -1-- j)-`m+m+m+ m+ m+ m+ 5./m+`
$
_&778
EI#Y
25c]   "	
 $  @ (,C,,-CC "C $	C
 C ""67C  }C e%678CL/@AB!"67 "#" 19,1G. O>"2eL^ ^# ^ M^B0YG 0Y(3- 0Yf $N+;uU 
s  
 V 
J ;?:E&$,/0:!"67: :z 
	+,-	  7 6P	! P	!fi iX	- -` n%5O.
7 .
 P.
b !(8ERc.g c. Sc.L  '75QR R RRr   