forked from phoenix/litellm-mirror
(proxy ui sso flow) - fix invite user sso flow (#6093)
* return if sso setup on ui_settings * use helper to get invite link
This commit is contained in:
parent
a7628317cd
commit
51af0d5d94
4 changed files with 58 additions and 5 deletions
|
@ -23,6 +23,7 @@ from litellm.proxy._types import (
|
||||||
SSOUserDefinedValues,
|
SSOUserDefinedValues,
|
||||||
UserAPIKeyAuth,
|
UserAPIKeyAuth,
|
||||||
)
|
)
|
||||||
|
from litellm.proxy.auth.auth_utils import _has_user_setup_sso
|
||||||
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
||||||
from litellm.proxy.common_utils.admin_ui_utils import (
|
from litellm.proxy.common_utils.admin_ui_utils import (
|
||||||
admin_ui_disabled,
|
admin_ui_disabled,
|
||||||
|
@ -640,6 +641,7 @@ async def get_ui_settings(request: Request):
|
||||||
|
|
||||||
_proxy_base_url = os.getenv("PROXY_BASE_URL", None)
|
_proxy_base_url = os.getenv("PROXY_BASE_URL", None)
|
||||||
_logout_url = os.getenv("PROXY_LOGOUT_URL", None)
|
_logout_url = os.getenv("PROXY_LOGOUT_URL", None)
|
||||||
|
_is_sso_enabled = _has_user_setup_sso()
|
||||||
|
|
||||||
default_team_disabled = general_settings.get("default_team_disabled", False)
|
default_team_disabled = general_settings.get("default_team_disabled", False)
|
||||||
if "PROXY_DEFAULT_TEAM_DISABLED" in os.environ:
|
if "PROXY_DEFAULT_TEAM_DISABLED" in os.environ:
|
||||||
|
@ -650,4 +652,5 @@ async def get_ui_settings(request: Request):
|
||||||
"PROXY_BASE_URL": _proxy_base_url,
|
"PROXY_BASE_URL": _proxy_base_url,
|
||||||
"PROXY_LOGOUT_URL": _logout_url,
|
"PROXY_LOGOUT_URL": _logout_url,
|
||||||
"DEFAULT_TEAM_DISABLED": default_team_disabled,
|
"DEFAULT_TEAM_DISABLED": default_team_disabled,
|
||||||
|
"SSO_ENABLED": _is_sso_enabled,
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
userCreateCall,
|
userCreateCall,
|
||||||
modelAvailableCall,
|
modelAvailableCall,
|
||||||
invitationCreateCall,
|
invitationCreateCall,
|
||||||
|
getProxyBaseUrlAndLogoutUrl,
|
||||||
} from "./networking";
|
} from "./networking";
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
|
@ -27,12 +28,21 @@ interface CreateuserProps {
|
||||||
possibleUIRoles: null | Record<string, Record<string, string>>;
|
possibleUIRoles: null | Record<string, Record<string, string>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define an interface for the UI settings
|
||||||
|
interface UISettings {
|
||||||
|
PROXY_BASE_URL: string | null;
|
||||||
|
PROXY_LOGOUT_URL: string | null;
|
||||||
|
DEFAULT_TEAM_DISABLED: boolean;
|
||||||
|
SSO_ENABLED: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const Createuser: React.FC<CreateuserProps> = ({
|
const Createuser: React.FC<CreateuserProps> = ({
|
||||||
userID,
|
userID,
|
||||||
accessToken,
|
accessToken,
|
||||||
teams,
|
teams,
|
||||||
possibleUIRoles,
|
possibleUIRoles,
|
||||||
}) => {
|
}) => {
|
||||||
|
const [uiSettings, setUISettings] = useState<UISettings | null>(null);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
const [apiuser, setApiuser] = useState<string | null>(null);
|
const [apiuser, setApiuser] = useState<string | null>(null);
|
||||||
|
@ -70,11 +80,19 @@ const Createuser: React.FC<CreateuserProps> = ({
|
||||||
|
|
||||||
// Assuming modelDataResponse.data contains an array of model names
|
// Assuming modelDataResponse.data contains an array of model names
|
||||||
setUserModels(availableModels);
|
setUserModels(availableModels);
|
||||||
|
|
||||||
|
// get ui settings
|
||||||
|
const uiSettingsResponse = await getProxyBaseUrlAndLogoutUrl(accessToken);
|
||||||
|
console.log("uiSettingsResponse:", uiSettingsResponse);
|
||||||
|
|
||||||
|
setUISettings(uiSettingsResponse);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching model data:", error);
|
console.error("Error fetching model data:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fetchData(); // Call the function to fetch model data when the component mounts
|
fetchData(); // Call the function to fetch model data when the component mounts
|
||||||
}, []); // Empty dependency array to run only once
|
}, []); // Empty dependency array to run only once
|
||||||
|
|
||||||
|
@ -105,10 +123,33 @@ const Createuser: React.FC<CreateuserProps> = ({
|
||||||
console.log("user create Response:", response);
|
console.log("user create Response:", response);
|
||||||
setApiuser(response["key"]);
|
setApiuser(response["key"]);
|
||||||
const user_id = response.data?.user_id || response.user_id;
|
const user_id = response.data?.user_id || response.user_id;
|
||||||
invitationCreateCall(accessToken, user_id).then((data) => {
|
|
||||||
setInvitationLinkData(data);
|
// only do invite link flow if sso is not enabled
|
||||||
|
if (!uiSettings?.SSO_ENABLED) {
|
||||||
|
invitationCreateCall(accessToken, user_id).then((data) => {
|
||||||
|
data.has_user_setup_sso = false;
|
||||||
|
setInvitationLinkData(data);
|
||||||
|
setIsInvitationLinkModalVisible(true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// create an InvitationLink Object for this user for the SSO flow
|
||||||
|
// for SSO the invite link is the proxy base url since the User just needs to login
|
||||||
|
const invitationLink: InvitationLink = {
|
||||||
|
id: crypto.randomUUID(), // Generate a unique ID
|
||||||
|
user_id: user_id,
|
||||||
|
is_accepted: false,
|
||||||
|
accepted_at: null,
|
||||||
|
expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // Set expiry to 7 days from now
|
||||||
|
created_at: new Date(),
|
||||||
|
created_by: userID, // Assuming userID is the current user creating the invitation
|
||||||
|
updated_at: new Date(),
|
||||||
|
updated_by: userID,
|
||||||
|
has_user_setup_sso: true,
|
||||||
|
};
|
||||||
|
setInvitationLinkData(invitationLink);
|
||||||
setIsInvitationLinkModalVisible(true);
|
setIsInvitationLinkModalVisible(true);
|
||||||
});
|
}
|
||||||
|
|
||||||
message.success("API user Created");
|
message.success("API user Created");
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
localStorage.removeItem("userData" + userID);
|
localStorage.removeItem("userData" + userID);
|
||||||
|
|
|
@ -21,6 +21,7 @@ export interface InvitationLink {
|
||||||
created_by: string;
|
created_by: string;
|
||||||
updated_at: Date;
|
updated_at: Date;
|
||||||
updated_by: string;
|
updated_by: string;
|
||||||
|
has_user_setup_sso: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnboardingProps {
|
interface OnboardingProps {
|
||||||
|
@ -47,6 +48,13 @@ const OnboardingModal: React.FC<OnboardingProps> = ({
|
||||||
setIsInvitationLinkModalVisible(false);
|
setIsInvitationLinkModalVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getInvitationUrl = () => {
|
||||||
|
if (invitationLinkData?.has_user_setup_sso) {
|
||||||
|
return `${baseUrl}/ui`;
|
||||||
|
}
|
||||||
|
return `${baseUrl}/ui?invitation_id=${invitationLinkData?.id}`;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="Invitation Link"
|
title="Invitation Link"
|
||||||
|
@ -67,13 +75,13 @@ const OnboardingModal: React.FC<OnboardingProps> = ({
|
||||||
<div className="flex justify-between pt-5 pb-2">
|
<div className="flex justify-between pt-5 pb-2">
|
||||||
<Text>Invitation Link</Text>
|
<Text>Invitation Link</Text>
|
||||||
<Text>
|
<Text>
|
||||||
{baseUrl}/ui?invitation_id={invitationLinkData?.id}
|
<Text>{getInvitationUrl()}</Text>
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end mt-5">
|
<div className="flex justify-end mt-5">
|
||||||
<div></div>
|
<div></div>
|
||||||
<CopyToClipboard
|
<CopyToClipboard
|
||||||
text={`${baseUrl}/ui?invitation_id=${invitationLinkData?.id}`}
|
text={getInvitationUrl()}
|
||||||
onCopy={() => message.success("Copied!")}
|
onCopy={() => message.success("Copied!")}
|
||||||
>
|
>
|
||||||
<Button variant="primary">Copy invitation link</Button>
|
<Button variant="primary">Copy invitation link</Button>
|
||||||
|
|
|
@ -32,6 +32,7 @@ export interface ProxySettings {
|
||||||
PROXY_BASE_URL: string | null;
|
PROXY_BASE_URL: string | null;
|
||||||
PROXY_LOGOUT_URL: string | null;
|
PROXY_LOGOUT_URL: string | null;
|
||||||
DEFAULT_TEAM_DISABLED: boolean;
|
DEFAULT_TEAM_DISABLED: boolean;
|
||||||
|
SSO_ENABLED: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCookie(name: string) {
|
function getCookie(name: string) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue