From 4ecd4b35f1c75db65a05a09deea270ffa21db614 Mon Sep 17 00:00:00 2001 From: wolfkill <27876473+wolfkill@users.noreply.github.com> Date: Mon, 18 May 2026 15:12:55 +0800 Subject: [PATCH] fix: use members SSO endpoints for webapp auth --- .../external-member-sso-auth.spec.tsx | 84 +++++++++++++++++++ .../components/external-member-sso-auth.tsx | 8 +- 2 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 web/app/(shareLayout)/webapp-signin/components/__tests__/external-member-sso-auth.spec.tsx diff --git a/web/app/(shareLayout)/webapp-signin/components/__tests__/external-member-sso-auth.spec.tsx b/web/app/(shareLayout)/webapp-signin/components/__tests__/external-member-sso-auth.spec.tsx new file mode 100644 index 00000000000000..e5ed112e5f0e39 --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/components/__tests__/external-member-sso-auth.spec.tsx @@ -0,0 +1,84 @@ +import { useSuspenseQuery } from '@tanstack/react-query' +import { render, waitFor } from '@testing-library/react' +import { + fetchMembersOAuth2SSOUrl, + fetchMembersOIDCSSOUrl, + fetchMembersSAMLSSOUrl, + fetchWebOAuth2SSOUrl, + fetchWebOIDCSSOUrl, + fetchWebSAMLSSOUrl, +} from '@/service/share' +import { SSOProtocol } from '@/types/feature' +import ExternalMemberSSOAuth from '../external-member-sso-auth' + +const mockPush = vi.fn() +const mockUseSearchParams = vi.fn() + +vi.mock('@tanstack/react-query', () => ({ + useSuspenseQuery: vi.fn(), +})) + +vi.mock('@/app/components/base/app-unavailable', () => ({ + default: () =>
, +})) + +vi.mock('@/app/components/base/loading', () => ({ + default: () =>
, +})) + +vi.mock('@/next/navigation', () => ({ + useRouter: () => ({ push: mockPush }), + useSearchParams: () => mockUseSearchParams(), +})) + +vi.mock('@/service/share', () => ({ + fetchMembersOAuth2SSOUrl: vi.fn(), + fetchMembersOIDCSSOUrl: vi.fn(), + fetchMembersSAMLSSOUrl: vi.fn(), + fetchWebOAuth2SSOUrl: vi.fn(), + fetchWebOIDCSSOUrl: vi.fn(), + fetchWebSAMLSSOUrl: vi.fn(), +})) + +vi.mock('@/service/system-features', () => ({ + systemFeaturesQueryOptions: () => ({}), +})) + +const mockUseSuspenseQuery = vi.mocked(useSuspenseQuery) + +const setSSOProtocol = (protocol: SSOProtocol) => { + mockUseSuspenseQuery.mockReturnValue({ + data: { + webapp_auth: { + sso_config: { + protocol, + }, + }, + }, + } as ReturnType) +} + +describe('ExternalMemberSSOAuth', () => { + beforeEach(() => { + vi.clearAllMocks() + mockUseSearchParams.mockReturnValue(new URLSearchParams('redirect_url=%2Fchat%2Fapp-code')) + }) + + it.each([ + [SSOProtocol.SAML, fetchMembersSAMLSSOUrl, fetchWebSAMLSSOUrl], + [SSOProtocol.OIDC, fetchMembersOIDCSSOUrl, fetchWebOIDCSSOUrl], + [SSOProtocol.OAuth2, fetchMembersOAuth2SSOUrl, fetchWebOAuth2SSOUrl], + ])('uses members SSO endpoint for external webapp %s auth', async (protocol, membersFetch, webFetch) => { + setSSOProtocol(protocol) + vi.mocked(membersFetch).mockResolvedValue({ url: `https://app.example/${protocol}` }) + vi.mocked(webFetch).mockResolvedValue({ url: `https://console.example/${protocol}` }) + + render() + + await waitFor(() => { + expect(membersFetch).toHaveBeenCalledWith('app-code', '/chat/app-code') + }) + expect(webFetch).not.toHaveBeenCalled() + expect(mockPush).toHaveBeenCalledWith(`https://app.example/${protocol}`) + }) +}) diff --git a/web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx index 003aab4cabab24..e7d2804930b625 100644 --- a/web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx +++ b/web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx @@ -6,7 +6,7 @@ import { useCallback, useEffect } from 'react' import AppUnavailable from '@/app/components/base/app-unavailable' import Loading from '@/app/components/base/loading' import { useRouter, useSearchParams } from '@/next/navigation' -import { fetchWebOAuth2SSOUrl, fetchWebOIDCSSOUrl, fetchWebSAMLSSOUrl } from '@/service/share' +import { fetchMembersOAuth2SSOUrl, fetchMembersOIDCSSOUrl, fetchMembersSAMLSSOUrl } from '@/service/share' import { systemFeaturesQueryOptions } from '@/service/system-features' import { SSOProtocol } from '@/types/feature' @@ -41,17 +41,17 @@ const ExternalMemberSSOAuth = () => { switch (systemFeatures.webapp_auth.sso_config.protocol) { case SSOProtocol.SAML: { - const samlRes = await fetchWebSAMLSSOUrl(appCode, redirectUrl) + const samlRes = await fetchMembersSAMLSSOUrl(appCode, redirectUrl) router.push(samlRes.url) break } case SSOProtocol.OIDC: { - const oidcRes = await fetchWebOIDCSSOUrl(appCode, redirectUrl) + const oidcRes = await fetchMembersOIDCSSOUrl(appCode, redirectUrl) router.push(oidcRes.url) break } case SSOProtocol.OAuth2: { - const oauth2Res = await fetchWebOAuth2SSOUrl(appCode, redirectUrl) + const oauth2Res = await fetchMembersOAuth2SSOUrl(appCode, redirectUrl) router.push(oauth2Res.url) break }