From 39bcee3f7baa640c9618c6fcd72f0b0c0d5a25df Mon Sep 17 00:00:00 2001 From: Dieu <113346171+dieu-bis@users.noreply.github.com> Date: Sun, 13 Jul 2025 23:24:32 +0200 Subject: [PATCH] remove ui config --- backend/open_webui/routers/configs.py | 217 ----------- src/lib/apis/scim/index.ts | 200 ---------- src/lib/components/admin/Settings.svelte | 35 -- src/lib/components/admin/Settings/SCIM.svelte | 364 ------------------ 4 files changed, 816 deletions(-) delete mode 100644 src/lib/apis/scim/index.ts delete mode 100644 src/lib/components/admin/Settings/SCIM.svelte diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 5829199f12..1bc257c233 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -328,220 +328,3 @@ async def get_banners( return request.app.state.config.BANNERS -############################ -# SCIM Configuration -############################ - - -class SCIMConfigForm(BaseModel): - enabled: bool - token: Optional[str] = None - token_created_at: Optional[str] = None - token_expires_at: Optional[str] = None - - -class SCIMTokenRequest(BaseModel): - expires_in: Optional[int] = None # seconds until expiration, None = never - - -class SCIMTokenResponse(BaseModel): - token: str - created_at: str - expires_at: Optional[str] = None - - -class SCIMStats(BaseModel): - total_users: int - total_groups: int - last_sync: Optional[str] = None - - -# In-memory storage for SCIM tokens (in production, use database) -scim_tokens = {} - - -def generate_scim_token(length: int = 48) -> str: - """Generate a secure random token for SCIM authentication""" - alphabet = string.ascii_letters + string.digits + "-_" - return "".join(secrets.choice(alphabet) for _ in range(length)) - - -@router.get("/scim", response_model=SCIMConfigForm) -async def get_scim_config(request: Request, user=Depends(get_admin_user)): - """Get current SCIM configuration""" - # Get token info from storage - token_info = None - scim_token = getattr(request.app.state.config, "SCIM_TOKEN", None) - # Handle both PersistentConfig and direct value - if hasattr(scim_token, 'value'): - scim_token = scim_token.value - - if scim_token and scim_token in scim_tokens: - token_info = scim_tokens[scim_token] - - scim_enabled = getattr(request.app.state.config, "SCIM_ENABLED", False) - print(f"Getting SCIM config - raw SCIM_ENABLED: {scim_enabled}, type: {type(scim_enabled)}") - # Handle both PersistentConfig and direct value - if hasattr(scim_enabled, 'value'): - scim_enabled = scim_enabled.value - - print(f"Returning SCIM config: enabled={scim_enabled}, token={'set' if scim_token else 'not set'}") - - return SCIMConfigForm( - enabled=scim_enabled, - token="***" if scim_token else None, # Don't expose actual token - token_created_at=token_info.get("created_at") if token_info else None, - token_expires_at=token_info.get("expires_at") if token_info else None, - ) - - -@router.post("/scim", response_model=SCIMConfigForm) -async def update_scim_config(request: Request, config: SCIMConfigForm, user=Depends(get_admin_user)): - """Update SCIM configuration""" - if not WEBUI_AUTH: - raise HTTPException(400, detail="Authentication must be enabled for SCIM") - - print(f"Updating SCIM config: enabled={config.enabled}") - - # Import here to avoid circular import - from open_webui.config import save_config, get_config - - # Get current config data - config_data = get_config() - - # Update SCIM settings in config data - if "scim" not in config_data: - config_data["scim"] = {} - - config_data["scim"]["enabled"] = config.enabled - - # Save config to database - save_config(config_data) - - # Also update the runtime config - scim_enabled_attr = getattr(request.app.state.config, "SCIM_ENABLED", None) - if scim_enabled_attr: - if hasattr(scim_enabled_attr, 'value'): - # It's a PersistentConfig object - print(f"Updating PersistentConfig SCIM_ENABLED from {scim_enabled_attr.value} to {config.enabled}") - scim_enabled_attr.value = config.enabled - else: - # Direct assignment - print(f"Direct assignment SCIM_ENABLED to {config.enabled}") - request.app.state.config.SCIM_ENABLED = config.enabled - else: - # Create if doesn't exist - print(f"Creating SCIM_ENABLED with value {config.enabled}") - request.app.state.config.SCIM_ENABLED = config.enabled - - # Return updated config - return await get_scim_config(request=request, user=user) - - -@router.post("/scim/token", response_model=SCIMTokenResponse) -async def generate_scim_token_endpoint( - request: Request, token_request: SCIMTokenRequest, user=Depends(get_admin_user) -): - """Generate a new SCIM bearer token""" - token = generate_scim_token() - created_at = datetime.utcnow() - expires_at = None - - if token_request.expires_in: - expires_at = created_at + timedelta(seconds=token_request.expires_in) - - # Store token info - token_info = { - "token": token, - "created_at": created_at.isoformat(), - "expires_at": expires_at.isoformat() if expires_at else None, - } - scim_tokens[token] = token_info - - # Import here to avoid circular import - from open_webui.config import save_config, get_config - - # Get current config data - config_data = get_config() - - # Update SCIM token in config data - if "scim" not in config_data: - config_data["scim"] = {} - - config_data["scim"]["token"] = token - - # Save config to database - save_config(config_data) - - # Also update the runtime config - scim_token_attr = getattr(request.app.state.config, "SCIM_TOKEN", None) - if scim_token_attr: - if hasattr(scim_token_attr, 'value'): - # It's a PersistentConfig object - scim_token_attr.value = token - else: - # Direct assignment - request.app.state.config.SCIM_TOKEN = token - else: - # Create if doesn't exist - request.app.state.config.SCIM_TOKEN = token - - return SCIMTokenResponse( - token=token, - created_at=token_info["created_at"], - expires_at=token_info["expires_at"], - ) - - -@router.delete("/scim/token") -async def revoke_scim_token(request: Request, user=Depends(get_admin_user)): - """Revoke the current SCIM token""" - # Get current token - scim_token = getattr(request.app.state.config, "SCIM_TOKEN", None) - if hasattr(scim_token, 'value'): - scim_token = scim_token.value - - # Remove from storage - if scim_token and scim_token in scim_tokens: - del scim_tokens[scim_token] - - # Import here to avoid circular import - from open_webui.config import save_config, get_config - - # Get current config data - config_data = get_config() - - # Remove SCIM token from config data - if "scim" in config_data: - config_data["scim"]["token"] = None - - # Save config to database - save_config(config_data) - - # Also update the runtime config - scim_token_attr = getattr(request.app.state.config, "SCIM_TOKEN", None) - if scim_token_attr: - if hasattr(scim_token_attr, 'value'): - # It's a PersistentConfig object - scim_token_attr.value = None - else: - # Direct assignment - request.app.state.config.SCIM_TOKEN = None - - return {"detail": "SCIM token revoked successfully"} - - -@router.get("/scim/stats", response_model=SCIMStats) -async def get_scim_stats(request: Request, user=Depends(get_admin_user)): - """Get SCIM statistics""" - users = Users.get_users() - groups = Groups.get_groups() - - # Get last sync time (in production, track this properly) - last_sync = None - - return SCIMStats( - total_users=len(users), - total_groups=len(groups) if groups else 0, - last_sync=last_sync, - ) diff --git a/src/lib/apis/scim/index.ts b/src/lib/apis/scim/index.ts deleted file mode 100644 index f1de34e95d..0000000000 --- a/src/lib/apis/scim/index.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { WEBUI_API_BASE_URL } from '$lib/constants'; - -// SCIM API endpoints -const SCIM_BASE_URL = `${WEBUI_API_BASE_URL}/scim/v2`; - -export interface SCIMConfig { - enabled: boolean; - token?: string; - token_created_at?: string; - token_expires_at?: string; -} - -export interface SCIMStats { - total_users: number; - total_groups: number; - last_sync?: string; -} - -export interface SCIMToken { - token: string; - created_at: string; - expires_at?: string; -} - -// Get SCIM configuration -export const getSCIMConfig = async (token: string): Promise => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/configs/scim`, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}` - } - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .catch((err) => { - console.error(err); - error = err.detail; - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -// Update SCIM configuration -export const updateSCIMConfig = async (token: string, config: Partial): Promise => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/configs/scim`, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}` - }, - body: JSON.stringify(config) - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .catch((err) => { - console.error(err); - error = err.detail; - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -// Generate new SCIM token -export const generateSCIMToken = async (token: string, expiresIn?: number): Promise => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/configs/scim/token`, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}` - }, - body: JSON.stringify({ expires_in: expiresIn }) - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .catch((err) => { - console.error(err); - error = err.detail; - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -// Revoke SCIM token -export const revokeSCIMToken = async (token: string): Promise => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/configs/scim/token`, { - method: 'DELETE', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}` - } - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return true; - }) - .catch((err) => { - console.error(err); - error = err.detail; - return false; - }); - - if (error) { - throw error; - } - - return res; -}; - -// Get SCIM statistics -export const getSCIMStats = async (token: string): Promise => { - let error = null; - - const res = await fetch(`${WEBUI_API_BASE_URL}/configs/scim/stats`, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}` - } - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return res.json(); - }) - .catch((err) => { - console.error(err); - error = err.detail; - return null; - }); - - if (error) { - throw error; - } - - return res; -}; - -// Test SCIM connection -export const testSCIMConnection = async (token: string, scimToken: string): Promise => { - let error = null; - - // Test by calling the SCIM service provider config endpoint - const res = await fetch(`${SCIM_BASE_URL}/ServiceProviderConfig`, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: `Bearer ${scimToken}` - } - }) - .then(async (res) => { - if (!res.ok) throw await res.json(); - return true; - }) - .catch((err) => { - console.error(err); - error = err.detail || 'Connection failed'; - return false; - }); - - if (error) { - throw error; - } - - return res; -}; \ No newline at end of file diff --git a/src/lib/components/admin/Settings.svelte b/src/lib/components/admin/Settings.svelte index e51fe84a53..66ac296fbd 100644 --- a/src/lib/components/admin/Settings.svelte +++ b/src/lib/components/admin/Settings.svelte @@ -15,7 +15,6 @@ import Interface from './Settings/Interface.svelte'; import Models from './Settings/Models.svelte'; import Connections from './Settings/Connections.svelte'; - import SCIM from './Settings/SCIM.svelte'; import Documents from './Settings/Documents.svelte'; import WebSearch from './Settings/WebSearch.svelte'; @@ -36,7 +35,6 @@ selectedTab = [ 'general', 'connections', - 'scim', 'models', 'evaluations', 'tools', @@ -139,30 +137,6 @@
{$i18n.t('Connections')}
- - - - -
- -
- - -
-

- {$i18n.t('Use this URL in your identity provider\'s SCIM configuration')} -

-
- - -
- - - {#if scimToken} -
-
-
- -
-

{$i18n.t('Created')}: {formatDate(scimTokenCreatedAt)}

- {#if scimTokenExpiresAt} -

{$i18n.t('Expires')}: {formatDate(scimTokenExpiresAt)}

- {:else} -

{$i18n.t('Expires')}: {$i18n.t('Never')}

- {/if} -
- -
- - - -
-
- {:else} -
-
- - -
- - -
- {/if} -
- - - {#if scimStats} -
-

{$i18n.t('SCIM Statistics')}

-
-
- {$i18n.t('Total Users')}: - {scimStats.total_users} -
-
- {$i18n.t('Total Groups')}: - {scimStats.total_groups} -
- {#if scimStats.last_sync} -
- {$i18n.t('Last Sync')}: - {formatDate(scimStats.last_sync)} -
- {/if} -
-
- {/if} - - - {/if} - \ No newline at end of file