From 873dc6628fdd965fb49539c29ab3b8a43e6f4dc7 Mon Sep 17 00:00:00 2001 From: chuckbutkus Date: Fri, 13 Mar 2026 16:57:34 -0400 Subject: [PATCH] Add Enterprise SSO login button to V1 login page (#13390) Co-authored-by: openhands --- .../features/auth/login-content.test.tsx | 69 +++++++++++++++++++ .../features/auth/login-content.tsx | 30 ++++++++ 2 files changed, 99 insertions(+) diff --git a/frontend/__tests__/components/features/auth/login-content.test.tsx b/frontend/__tests__/components/features/auth/login-content.test.tsx index efedb93164..a331ee2378 100644 --- a/frontend/__tests__/components/features/auth/login-content.test.tsx +++ b/frontend/__tests__/components/features/auth/login-content.test.tsx @@ -15,6 +15,7 @@ vi.mock("#/hooks/use-auth-url", () => ({ bitbucket: "https://bitbucket.org/site/oauth2/authorize", bitbucket_data_center: "https://bitbucket-dc.example.com/site/oauth2/authorize", + enterprise_sso: "https://auth.example.com/realms/test/protocol/openid-connect/auth", }; if (config.appMode === "saas") { return urls[config.identityProvider] || null; @@ -117,6 +118,74 @@ describe("LoginContent", () => { ).not.toBeInTheDocument(); }); + it("should display Enterprise SSO button when configured", () => { + render( + + + , + ); + + expect( + screen.getByRole("button", { name: /ENTERPRISE_SSO\$CONNECT_TO_ENTERPRISE_SSO/i }), + ).toBeInTheDocument(); + }); + + it("should display Enterprise SSO alongside other providers when all configured", () => { + render( + + + , + ); + + expect( + screen.getByRole("button", { name: "GITHUB$CONNECT_TO_GITHUB" }), + ).toBeInTheDocument(); + expect( + screen.getByRole("button", { name: "GITLAB$CONNECT_TO_GITLAB" }), + ).toBeInTheDocument(); + expect( + screen.getByRole("button", { name: /BITBUCKET\$CONNECT_TO_BITBUCKET/i }), + ).toBeInTheDocument(); + expect( + screen.getByRole("button", { name: /ENTERPRISE_SSO\$CONNECT_TO_ENTERPRISE_SSO/i }), + ).toBeInTheDocument(); + }); + + it("should redirect to Enterprise SSO auth URL when Enterprise SSO button is clicked", async () => { + const user = userEvent.setup(); + const mockUrl = "https://auth.example.com/realms/test/protocol/openid-connect/auth"; + + render( + + + , + ); + + const enterpriseSsoButton = screen.getByRole("button", { + name: /ENTERPRISE_SSO\$CONNECT_TO_ENTERPRISE_SSO/i, + }); + await user.click(enterpriseSsoButton); + + await waitFor(() => { + expect(window.location.href).toContain(mockUrl); + }); + }); + it("should display message when no providers are configured", () => { render( diff --git a/frontend/src/components/features/auth/login-content.tsx b/frontend/src/components/features/auth/login-content.tsx index 30da67c301..fbae5df4ea 100644 --- a/frontend/src/components/features/auth/login-content.tsx +++ b/frontend/src/components/features/auth/login-content.tsx @@ -1,4 +1,5 @@ import { useTranslation } from "react-i18next"; +import { FaUserShield } from "react-icons/fa"; import { I18nKey } from "#/i18n/declaration"; import OpenHandsLogoWhite from "#/assets/branding/openhands-logo-white.svg?react"; import GitHubLogo from "#/assets/branding/github-logo.svg?react"; @@ -65,6 +66,12 @@ export function LoginContent({ authUrl, }); + const enterpriseSsoAuthUrl = useAuthUrl({ + appMode: appMode || null, + identityProvider: "enterprise_sso", + authUrl, + }); + const handleAuthRedirect = async ( redirectUrl: string, provider: Provider, @@ -127,6 +134,12 @@ export function LoginContent({ } }; + const handleEnterpriseSsoAuth = () => { + if (enterpriseSsoAuthUrl) { + handleAuthRedirect(enterpriseSsoAuthUrl, "enterprise_sso"); + } + }; + const showGithub = providersConfigured && providersConfigured.length > 0 && @@ -143,6 +156,10 @@ export function LoginContent({ providersConfigured && providersConfigured.length > 0 && providersConfigured.includes("bitbucket_data_center"); + const showEnterpriseSso = + providersConfigured && + providersConfigured.length > 0 && + providersConfigured.includes("enterprise_sso"); const noProvidersConfigured = !providersConfigured || providersConfigured.length === 0; @@ -261,6 +278,19 @@ export function LoginContent({ )} + + {showEnterpriseSso && ( + + )} )}