diff --git a/packages/frontend/editor-ui/src/app/init.test.ts b/packages/frontend/editor-ui/src/app/init.test.ts index c27f0a8fb29..04713bfa1cd 100644 --- a/packages/frontend/editor-ui/src/app/init.test.ts +++ b/packages/frontend/editor-ui/src/app/init.test.ts @@ -134,6 +134,40 @@ describe('Init', () => { }); }); + it('should re-initialize ssoStore in login hook with authenticated settings', async () => { + const saml = { loginEnabled: false, loginLabel: '' }; + const ldap = { loginEnabled: false, loginLabel: '' }; + const oidc = { + loginEnabled: false, + loginUrl: 'http://localhost:5678/rest/sso/oidc/login', + callbackUrl: 'http://localhost:5678/rest/sso/oidc/callback', + }; + + settingsStore.userManagement.authenticationMethod = UserManagementAuthenticationMethod.Oidc; + settingsStore.settings.sso = { managedByEnv: false, saml, ldap, oidc }; + settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Oidc] = true; + + usersStore.registerLoginHook.mockImplementation(async (hook) => { + await hook(mock({ id: 'userId' })); + }); + + await initializeCore(); + + // ssoStore.initialize should be called twice: + // once during initializeCore and once during the login hook + expect(ssoStore.initialize).toHaveBeenCalledTimes(2); + expect(ssoStore.initialize).toHaveBeenLastCalledWith({ + authenticationMethod: UserManagementAuthenticationMethod.Oidc, + managedByEnv: false, + config: { managedByEnv: false, saml, ldap, oidc }, + features: { + saml: false, + ldap: false, + oidc: true, + }, + }); + }); + it('should initialize ssoStore with settings SSO configuration', async () => { const saml = { loginEnabled: true, loginLabel: '' }; const ldap = { loginEnabled: false, loginLabel: '' }; diff --git a/packages/frontend/editor-ui/src/app/init.ts b/packages/frontend/editor-ui/src/app/init.ts index 08b9c9975b7..dddde55d7f3 100644 --- a/packages/frontend/editor-ui/src/app/init.ts +++ b/packages/frontend/editor-ui/src/app/init.ts @@ -237,11 +237,27 @@ function registerAuthenticationHooks() { const telemetry = useTelemetry(); const RBACStore = useRBACStore(); const settingsStore = useSettingsStore(); + const ssoStore = useSSOStore(); const favoritesStore = useFavoritesStore(); usersStore.registerLoginHook(async (user) => { await settingsStore.getSettings(); + // Re-initialize SSO store with authenticated settings. + // Before login, public settings omit callbackUrl, leaving it empty. + // Without this, navigating to SSO settings after login shows an empty redirect URL. + ssoStore.initialize({ + authenticationMethod: settingsStore.userManagement + .authenticationMethod as UserManagementAuthenticationMethod, + managedByEnv: settingsStore.settings.sso.managedByEnv, + config: settingsStore.settings.sso, + features: { + saml: settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Saml], + ldap: settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Ldap], + oidc: settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.Oidc], + }, + }); + RBACStore.setGlobalScopes(user.globalScopes ?? []); telemetry.identify({ instanceId: rootStore.instanceId, diff --git a/packages/frontend/editor-ui/src/features/settings/sso/sso.test.ts b/packages/frontend/editor-ui/src/features/settings/sso/sso.test.ts index 4944f148c5e..fd5abe36eb0 100644 --- a/packages/frontend/editor-ui/src/features/settings/sso/sso.test.ts +++ b/packages/frontend/editor-ui/src/features/settings/sso/sso.test.ts @@ -41,6 +41,36 @@ describe('SSO store', () => { }, ); + describe('OIDC callbackUrl after re-initialization', () => { + it('should populate callbackUrl when re-initialized with authenticated settings', () => { + // Simulate public settings (before login) — no callbackUrl + ssoStore.initialize({ + authenticationMethod: 'oidc' as UserManagementAuthenticationMethod, + config: { + oidc: { loginEnabled: false, loginUrl: 'http://localhost:5678/rest/sso/oidc/login' }, + }, + features: { saml: false, ldap: false, oidc: true }, + }); + + expect(ssoStore.oidc.callbackUrl).toBe(''); + + // Simulate authenticated settings (after login) — includes callbackUrl + ssoStore.initialize({ + authenticationMethod: 'oidc' as UserManagementAuthenticationMethod, + config: { + oidc: { + loginEnabled: false, + loginUrl: 'http://localhost:5678/rest/sso/oidc/login', + callbackUrl: 'http://localhost:5678/rest/sso/oidc/callback', + }, + }, + features: { saml: false, ldap: false, oidc: true }, + }); + + expect(ssoStore.oidc.callbackUrl).toBe('http://localhost:5678/rest/sso/oidc/callback'); + }); + }); + describe('Protocol Selection Initialization', () => { beforeEach(() => { setActivePinia(createPinia());