diff --git a/apps/dokploy/components/proprietary/sso/register-oidc-dialog.tsx b/apps/dokploy/components/proprietary/sso/register-oidc-dialog.tsx index f66256b10..2b7400e61 100644 --- a/apps/dokploy/components/proprietary/sso/register-oidc-dialog.tsx +++ b/apps/dokploy/components/proprietary/sso/register-oidc-dialog.tsx @@ -101,14 +101,10 @@ export function RegisterOidcDialog({ children }: RegisterOidcDialogProps) { const scopes = data.scopes.filter(Boolean).length ? data.scopes.filter(Boolean) : DEFAULT_SCOPES; - const domain = data.domains - .map((d) => d.trim()) - .filter(Boolean) - .join(","); await mutateAsync({ providerId: data.providerId, issuer: data.issuer, - domain, + domains: data.domains, oidcConfig: { clientId: data.clientId, clientSecret: data.clientSecret, diff --git a/apps/dokploy/components/proprietary/sso/register-saml-dialog.tsx b/apps/dokploy/components/proprietary/sso/register-saml-dialog.tsx index 009dcbc6a..839ff1dbc 100644 --- a/apps/dokploy/components/proprietary/sso/register-saml-dialog.tsx +++ b/apps/dokploy/components/proprietary/sso/register-saml-dialog.tsx @@ -95,14 +95,10 @@ export function RegisterSamlDialog({ children }: RegisterSamlDialogProps) { const onSubmit = async (data: SamlProviderForm) => { try { - const domain = data.domains - .map((d) => d.trim()) - .filter(Boolean) - .join(","); await mutateAsync({ providerId: data.providerId, issuer: data.issuer, - domain, + domains: data.domains, samlConfig: { entryPoint: data.entryPoint, cert: data.cert, diff --git a/apps/dokploy/server/api/routers/proprietary/sso.ts b/apps/dokploy/server/api/routers/proprietary/sso.ts index 064e41286..4f11f86c5 100644 --- a/apps/dokploy/server/api/routers/proprietary/sso.ts +++ b/apps/dokploy/server/api/routers/proprietary/sso.ts @@ -99,15 +99,34 @@ export const ssoRouter = createTRPCRouter({ .mutation(async ({ ctx, input }) => { const organizationId = ctx.session.activeOrganizationId; - const result = await auth.registerSSOProvider({ + const providers = await db.query.ssoProvider.findMany({ + columns: { + domain: true, + }, + }); + + for (const provider of providers) { + const providerDomains = provider.domain + .split(",") + .map((d) => d.trim().toLowerCase()); + for (const domain of input.domains) { + if (providerDomains.includes(domain)) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: `Domain ${domain} is already registered for another provider`, + }); + } + } + } + const domain = input.domains.join(","); + await auth.registerSSOProvider({ body: { ...input, organizationId, + domain, }, headers: requestToHeaders(ctx.req), }); - console.log(result); - return { success: true }; }), }); diff --git a/packages/server/src/db/schema/sso.ts b/packages/server/src/db/schema/sso.ts index 9dc55508b..58f21ffac 100644 --- a/packages/server/src/db/schema/sso.ts +++ b/packages/server/src/db/schema/sso.ts @@ -27,11 +27,22 @@ export const ssoProviderRelations = relations(ssoProvider, ({ one }) => ({ references: [user.id], }), })); - +const domainRegex = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/; export const ssoProviderBodySchema = z.object({ providerId: z.string({}), issuer: z.string({}), - domain: z.string({}), + domains: z + .string() + .array() + .transform((val) => + Array.from( + new Set(val.map((d) => d.trim().toLowerCase()).filter(Boolean)), + ), + ) + .refine((val) => val.every((d) => domainRegex.test(d)), { + message: "Invalid domain", + path: ["domains"], + }), oidcConfig: z .object({ clientId: z.string({}),