From 3ac0461d43c4ffd426539c889dd0381a532a9130 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Mon, 24 Feb 2025 23:42:04 -0800 Subject: [PATCH] (UI) Allow adding MSFT SSO on UI (#8779) * ui - allow adding SSO on ui * add msft sso to ui * sso on admin ui --- .../src/components/SSOModals.tsx | 215 ++++++++++++++++++ .../src/components/admins.tsx | 136 +++-------- 2 files changed, 248 insertions(+), 103 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/SSOModals.tsx diff --git a/ui/litellm-dashboard/src/components/SSOModals.tsx b/ui/litellm-dashboard/src/components/SSOModals.tsx new file mode 100644 index 00000000000..6e0c5740161 --- /dev/null +++ b/ui/litellm-dashboard/src/components/SSOModals.tsx @@ -0,0 +1,215 @@ +import React from "react"; +import { Modal, Form, Input, Button as Button2, Select } from "antd"; +import { Text, TextInput } from "@tremor/react"; + +interface SSOModalsProps { + isAddSSOModalVisible: boolean; + isInstructionsModalVisible: boolean; + handleAddSSOOk: () => void; + handleAddSSOCancel: () => void; + handleShowInstructions: (formValues: Record) => void; + handleInstructionsOk: () => void; + handleInstructionsCancel: () => void; + form: any; // Replace with proper Form type if available +} + +const ssoProviderLogoMap: Record = { + google: "https://artificialanalysis.ai/img/logos/google_small.svg", + microsoft: "https://upload.wikimedia.org/wikipedia/commons/a/a8/Microsoft_Azure_Logo.svg", + okta: "https://www.okta.com/sites/default/files/Okta_Logo_BrightBlue_Medium.png", + generic: "", +}; + +// Define the SSO provider configuration type +interface SSOProviderConfig { + envVarMap: Record; + fields: Array<{ + label: string; + name: string; + placeholder?: string; + }>; +} + +// Define configurations for each SSO provider +const ssoProviderConfigs: Record = { + google: { + envVarMap: { + google_client_id: 'GOOGLE_CLIENT_ID', + google_client_secret: 'GOOGLE_CLIENT_SECRET', + }, + fields: [ + { label: 'GOOGLE CLIENT ID', name: 'google_client_id' }, + { label: 'GOOGLE CLIENT SECRET', name: 'google_client_secret' }, + ], + }, + microsoft: { + envVarMap: { + microsoft_client_id: 'MICROSOFT_CLIENT_ID', + microsoft_client_secret: 'MICROSOFT_CLIENT_SECRET', + microsoft_tenant: 'MICROSOFT_TENANT', + }, + fields: [ + { label: 'MICROSOFT CLIENT ID', name: 'microsoft_client_id' }, + { label: 'MICROSOFT CLIENT SECRET', name: 'microsoft_client_secret' }, + { label: 'MICROSOFT TENANT', name: 'microsoft_tenant' }, + ], + }, + okta: { + envVarMap: { + generic_client_id: 'GENERIC_CLIENT_ID', + generic_client_secret: 'GENERIC_CLIENT_SECRET', + generic_authorization_endpoint: 'GENERIC_AUTHORIZATION_ENDPOINT', + generic_token_endpoint: 'GENERIC_TOKEN_ENDPOINT', + generic_userinfo_endpoint: 'GENERIC_USERINFO_ENDPOINT', + }, + fields: [ + { label: 'GENERIC CLIENT ID', name: 'generic_client_id' }, + { label: 'GENERIC CLIENT SECRET', name: 'generic_client_secret' }, + { label: 'AUTHORIZATION ENDPOINT', name: 'generic_authorization_endpoint', placeholder: 'https://your-okta-domain/authorize' }, + { label: 'TOKEN ENDPOINT', name: 'generic_token_endpoint', placeholder: 'https://your-okta-domain/token' }, + { label: 'USERINFO ENDPOINT', name: 'generic_userinfo_endpoint', placeholder: 'https://your-okta-domain/userinfo' }, + ], + }, + generic: { + envVarMap: { + generic_client_id: 'GENERIC_CLIENT_ID', + generic_client_secret: 'GENERIC_CLIENT_SECRET', + generic_authorization_endpoint: 'GENERIC_AUTHORIZATION_ENDPOINT', + generic_token_endpoint: 'GENERIC_TOKEN_ENDPOINT', + generic_userinfo_endpoint: 'GENERIC_USERINFO_ENDPOINT', + }, + fields: [ + { label: 'GENERIC CLIENT ID', name: 'generic_client_id' }, + { label: 'GENERIC CLIENT SECRET', name: 'generic_client_secret' }, + { label: 'AUTHORIZATION ENDPOINT', name: 'generic_authorization_endpoint' }, + { label: 'TOKEN ENDPOINT', name: 'generic_token_endpoint' }, + { label: 'USERINFO ENDPOINT', name: 'generic_userinfo_endpoint' }, + ], + }, +}; + +const SSOModals: React.FC = ({ + isAddSSOModalVisible, + isInstructionsModalVisible, + handleAddSSOOk, + handleAddSSOCancel, + handleShowInstructions, + handleInstructionsOk, + handleInstructionsCancel, + form, +}) => { + // Helper function to render provider fields + const renderProviderFields = (provider: string) => { + const config = ssoProviderConfigs[provider]; + if (!config) return null; + + return config.fields.map((field) => ( + + {field.name.includes('client') ? ( + + ) : ( + + )} + + )); + }; + + return ( + <> + +
+ <> + + + + + prevValues.sso_provider !== currentValues.sso_provider} + > + {({ getFieldValue }) => { + const provider = getFieldValue('sso_provider'); + return provider ? renderProviderFields(provider) : null; + }} + + + + + + + + + +
+ Save +
+
+
+ + +

Follow these steps to complete the SSO setup:

+ 1. DO NOT Exit this TAB + 2. Open a new tab, visit your proxy base url + + 3. Confirm your SSO is configured correctly and you can login on the new + Tab + + + 4. If Step 3 is successful, you can close this tab + +
+ Done +
+
+ + ); +}; + +export { ssoProviderConfigs }; // Export for use in other components +export default SSOModals; \ No newline at end of file diff --git a/ui/litellm-dashboard/src/components/admins.tsx b/ui/litellm-dashboard/src/components/admins.tsx index 5d5b8c2ccbc..cd0f34b7060 100644 --- a/ui/litellm-dashboard/src/components/admins.tsx +++ b/ui/litellm-dashboard/src/components/admins.tsx @@ -36,6 +36,9 @@ import { import { PencilAltIcon } from "@heroicons/react/outline"; import OnboardingModal from "./onboarding_link"; import { InvitationLink } from "./onboarding_link"; +import SSOModals from "./SSOModals"; +import { ssoProviderConfigs } from './SSOModals'; + interface AdminPanelProps { searchParams: any; accessToken: string | null; @@ -484,13 +487,27 @@ const AdminPanel: React.FC = ({ if (accessToken == null) { return; } - let payload = { - environment_variables: { - PROXY_BASE_URL: formValues.proxy_base_url, - GOOGLE_CLIENT_ID: formValues.google_client_id, - GOOGLE_CLIENT_SECRET: formValues.google_client_secret, - }, + + const provider = formValues.sso_provider; + const config = ssoProviderConfigs[provider]; + + const envVars: Record = { + PROXY_BASE_URL: formValues.proxy_base_url, }; + + // Add provider-specific environment variables using the configuration + if (config) { + Object.entries(config.envVarMap).forEach(([formKey, envKey]) => { + if (formValues[formKey]) { + envVars[envKey] = formValues[formKey]; + } + }); + } + + const payload = { + environment_variables: envVars, + }; + setCallbacksCall(accessToken, payload); }; console.log(`admins: ${admins?.length}`); @@ -512,103 +529,16 @@ const AdminPanel: React.FC = ({
- - -
- <> - - - - - - - - - - - - - - - -
- Save -
-
-
- -

Follow these steps to complete the SSO setup:

- 1. DO NOT Exit this TAB - - 2. Open a new tab, visit your proxy base url - - - 3. Confirm your SSO is configured correctly and you can login on - the new Tab - - - 4. If Step 3 is successful, you can close this tab - -
- Done -
-
+