feat(sso): Azure AD / Entra ID SAML 2.0 integration
- sso_service: fix process_callback for Azure AD claim URIs (email, role) - Default role_attr to full Azure role claim URI - Fallback email resolution via Azure email claim URI + NameID - Username defaults to full email (prevents collision with local accounts) - User lookup also tries email field for existing local accounts - Logs warning when unknown role received from IdP - frontend/api/sso.ts: new API module with getSsoStatus, getSsoConfig, updateSsoConfig - LoginPage: redesigned for SSO-first flow - Shows Azure SSO button as primary when SSO enabled+configured - Local login collapsed under "Emergency admin access" section - Falls back to normal local login form when SSO is disabled - SystemPage: new SsoConfigSection component (guided 5-step wizard) - Step 1: Copy SP Entity ID and ACS URL for IT team + metadata XML download - Step 2: Azure App Roles reference table (6 roles with exact values) - Step 3: Tenant ID field auto-fills idp_entity_id and idp_sso_url - Step 4: X.509 certificate paste field - Step 5: Attribute mapping pre-filled with Azure AD claim URIs - Enable/disable toggle + save
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import client from "./client";
|
||||
|
||||
export interface SsoStatus {
|
||||
enabled: boolean;
|
||||
provider_name: string | null;
|
||||
configured: boolean;
|
||||
login_url: string | null;
|
||||
}
|
||||
|
||||
export interface SsoConfig {
|
||||
id: string;
|
||||
is_enabled: boolean;
|
||||
provider_name: string | null;
|
||||
sp_entity_id: string | null;
|
||||
sp_acs_url: string | null;
|
||||
sp_slo_url: string | null;
|
||||
sp_certificate: string | null;
|
||||
idp_entity_id: string | null;
|
||||
idp_sso_url: string | null;
|
||||
idp_slo_url: string | null;
|
||||
idp_certificate: string | null;
|
||||
attr_email: string | null;
|
||||
attr_username: string | null;
|
||||
attr_role: string | null;
|
||||
default_role: string | null;
|
||||
auto_provision: boolean;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
}
|
||||
|
||||
export interface SsoConfigUpdate {
|
||||
is_enabled: boolean;
|
||||
provider_name?: string | null;
|
||||
sp_entity_id?: string | null;
|
||||
sp_acs_url?: string | null;
|
||||
sp_slo_url?: string | null;
|
||||
sp_certificate?: string | null;
|
||||
sp_private_key?: string | null;
|
||||
idp_entity_id?: string | null;
|
||||
idp_sso_url?: string | null;
|
||||
idp_slo_url?: string | null;
|
||||
idp_certificate?: string | null;
|
||||
attr_email?: string | null;
|
||||
attr_username?: string | null;
|
||||
attr_role?: string | null;
|
||||
default_role?: string | null;
|
||||
auto_provision?: boolean;
|
||||
}
|
||||
|
||||
/** Public — used by LoginPage to decide which login to show. */
|
||||
export async function getSsoStatus(): Promise<SsoStatus> {
|
||||
const { data } = await client.get<SsoStatus>("/sso/status");
|
||||
return data;
|
||||
}
|
||||
|
||||
/** Admin-only — full config. Returns 404 if never configured. */
|
||||
export async function getSsoConfig(): Promise<SsoConfig> {
|
||||
const { data } = await client.get<SsoConfig>("/sso/config");
|
||||
return data;
|
||||
}
|
||||
|
||||
/** Admin-only — create or replace SSO config. */
|
||||
export async function updateSsoConfig(payload: SsoConfigUpdate): Promise<SsoConfig> {
|
||||
const { data } = await client.put<SsoConfig>("/sso/config", payload);
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user