From 6b125bba7c9315ee6cd1212d485be1e6515c5573 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Fri, 10 Oct 2025 11:52:45 -0700 Subject: [PATCH] reject user if no policies match and remove root user in auto provision --- server/routers/idp/validateOidcCallback.ts | 36 +++++++++++++++++-- .../(private)/idp/[idpId]/general/page.tsx | 2 +- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/server/routers/idp/validateOidcCallback.ts b/server/routers/idp/validateOidcCallback.ts index 0ecf08b0..98bdfe44 100644 --- a/server/routers/idp/validateOidcCallback.ts +++ b/server/routers/idp/validateOidcCallback.ts @@ -1,6 +1,6 @@ import { Request, Response, NextFunction } from "express"; import { z } from "zod"; -import { db } from "@server/db"; +import { db, Org } from "@server/db"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; @@ -32,6 +32,7 @@ import { decrypt } from "@server/lib/crypto"; import { UserType } from "@server/types/UserTypes"; import { FeatureId } from "@server/lib/billing"; import { usageService } from "@server/lib/billing/usageService"; +import { build } from "@server/build"; const ensureTrailingSlash = (url: string): string => { return url; @@ -255,7 +256,18 @@ export async function validateOidcCallback( ); if (existingIdp.idp.autoProvision) { - const allOrgs = await db.select().from(orgs); + let allOrgs: Org[] = []; + + if (build === "saas") { + const idpOrgs = await db + .select() + .from(idpOrg) + .where(eq(idpOrg.idpId, existingIdp.idp.idpId)) + .innerJoin(orgs, eq(orgs.orgId, idpOrg.orgId)); + allOrgs = idpOrgs.map((o) => o.orgs); + } else { + allOrgs = await db.select().from(orgs); + } const defaultRoleMapping = existingIdp.idp.defaultRoleMapping; const defaultOrgMapping = existingIdp.idp.defaultOrgMapping; @@ -292,6 +304,8 @@ export async function validateOidcCallback( } } + // user could be allowed in this org, now find the role + const roleMapping = idpOrgRes?.roleMapping || defaultRoleMapping; if (roleMapping) { @@ -336,6 +350,24 @@ export async function validateOidcCallback( let existingUserId = existingUser?.userId; + if (!userOrgInfo.length) { + if (existingUser) { + // delete the user + // cascade will also delete org users + + await db + .delete(users) + .where(eq(users.userId, existingUser.userId)); + } + + return next( + createHttpError( + HttpCode.UNAUTHORIZED, + `No policies matched for ${userIdentifier}. This user must be added to an organization before logging in.` + ) + ); + } + const orgUserCounts: { orgId: string; userCount: number }[] = []; // sync the user with the orgs and roles diff --git a/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx b/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx index a5be3c83..1d0a682f 100644 --- a/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx +++ b/src/app/[orgId]/settings/(private)/idp/[idpId]/general/page.tsx @@ -829,7 +829,7 @@ export default function GeneralPage() { {t( "idpJmespathAboutDescription" - )} + )}{" "}