fix: Hide SAML/OIDC login button if no sso connection exists (Self hosted instance) (#10903)

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com>
pull/11769/head^2
Kiran K 2023-10-09 21:00:30 +05:30 committed by GitHub
parent d8f6400add
commit b5cf4e50a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 6 deletions

View File

@ -15,11 +15,12 @@ import { SAMLLogin } from "@calcom/features/auth/SAMLLogin";
import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode"; import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { isSAMLLoginEnabled, samlProductID, samlTenantID } from "@calcom/features/ee/sso/lib/saml"; import { isSAMLLoginEnabled, samlProductID, samlTenantID } from "@calcom/features/ee/sso/lib/saml";
import { WEBAPP_URL, WEBSITE_URL } from "@calcom/lib/constants"; import { WEBAPP_URL, WEBSITE_URL, HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl"; import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import prisma from "@calcom/prisma"; import prisma from "@calcom/prisma";
import { trpc } from "@calcom/trpc/react";
import { Alert, Button, EmailField, PasswordField } from "@calcom/ui"; import { Alert, Button, EmailField, PasswordField } from "@calcom/ui";
import { ArrowLeft, Lock } from "@calcom/ui/components/icon"; import { ArrowLeft, Lock } from "@calcom/ui/components/icon";
@ -160,6 +161,16 @@ export default function Login({
else setErrorMessage(errorMessages[res.error] || t("something_went_wrong")); else setErrorMessage(errorMessages[res.error] || t("something_went_wrong"));
}; };
const { data, isLoading } = trpc.viewer.public.ssoConnections.useQuery(undefined, {
onError: (err) => {
setErrorMessage(err.message);
},
});
const displaySSOLogin = HOSTED_CAL_FEATURES
? true
: isSAMLLoginEnabled && !isLoading && data?.connectionExists;
return ( return (
<div <div
style={ style={
@ -232,7 +243,7 @@ export default function Login({
</form> </form>
{!twoFactorRequired && ( {!twoFactorRequired && (
<> <>
{(isGoogleLoginEnabled || isSAMLLoginEnabled) && <hr className="border-subtle my-8" />} {(isGoogleLoginEnabled || displaySSOLogin) && <hr className="border-subtle my-8" />}
<div className="space-y-3"> <div className="space-y-3">
{isGoogleLoginEnabled && ( {isGoogleLoginEnabled && (
<Button <Button
@ -247,7 +258,7 @@ export default function Login({
{t("signin_with_google")} {t("signin_with_google")}
</Button> </Button>
)} )}
{isSAMLLoginEnabled && ( {displaySSOLogin && (
<SAMLLogin <SAMLLogin
samlTenantID={samlTenantID} samlTenantID={samlTenantID}
samlProductID={samlProductID} samlProductID={samlProductID}

View File

@ -15,7 +15,8 @@ test("Should display SAML Login button", async ({ page }) => {
// eslint-disable-next-line playwright/no-skipped-test // eslint-disable-next-line playwright/no-skipped-test
test.skip(!IS_SAML_LOGIN_ENABLED, "It should only run if SAML Login is installed"); test.skip(!IS_SAML_LOGIN_ENABLED, "It should only run if SAML Login is installed");
await page.goto(`/auth/login`); // TODO: Fix this later
// Button is visible only if there is a SAML connection exists (self-hosted)
await expect(page.locator(`[data-testid=saml]`)).toBeVisible(); // await page.goto(`/auth/login`);
// await expect(page.locator(`[data-testid=saml]`)).toBeVisible();
}); });

View File

@ -49,4 +49,11 @@ export const publicViewerRouter = router({
const handler = await importHandler(namespaced("event"), () => import("./event.handler")); const handler = await importHandler(namespaced("event"), () => import("./event.handler"));
return handler(opts); return handler(opts);
}), }),
ssoConnections: publicProcedure.query(async () => {
const handler = await importHandler(
namespaced("ssoConnections"),
() => import("./ssoConnections.handler")
);
return handler();
}),
}); });

View File

@ -0,0 +1,31 @@
import jackson from "@calcom/features/ee/sso/lib/jackson";
import { samlProductID, samlTenantID } from "@calcom/features/ee/sso/lib/saml";
import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
import { TRPCError } from "@trpc/server";
export const handler = async () => {
try {
if (HOSTED_CAL_FEATURES) {
return {
connectionExists: null,
};
}
const { connectionController } = await jackson();
const connections = await connectionController.getConnections({
tenant: samlTenantID,
product: samlProductID,
});
return {
connectionExists: connections.length > 0,
};
} catch (err) {
console.error("Error getting SSO connections", err);
throw new TRPCError({ code: "BAD_REQUEST", message: "Fetching SSO connections failed." });
}
};
export default handler;