@open-mercato/enterprise 0.4.6-develop-15c18897fc → 0.4.6-develop-34aa847ce6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/dist/modules/sso/acl.js +11 -0
- package/dist/modules/sso/acl.js.map +7 -0
- package/dist/modules/sso/api/admin-context.js +27 -0
- package/dist/modules/sso/api/admin-context.js.map +7 -0
- package/dist/modules/sso/api/callback/oidc/route.js +103 -0
- package/dist/modules/sso/api/callback/oidc/route.js.map +7 -0
- package/dist/modules/sso/api/config/[id]/activate/route.js +49 -0
- package/dist/modules/sso/api/config/[id]/activate/route.js.map +7 -0
- package/dist/modules/sso/api/config/[id]/domains/route.js +96 -0
- package/dist/modules/sso/api/config/[id]/domains/route.js.map +7 -0
- package/dist/modules/sso/api/config/[id]/route.js +103 -0
- package/dist/modules/sso/api/config/[id]/route.js.map +7 -0
- package/dist/modules/sso/api/config/[id]/test/route.js +41 -0
- package/dist/modules/sso/api/config/[id]/test/route.js.map +7 -0
- package/dist/modules/sso/api/config/route.js +83 -0
- package/dist/modules/sso/api/config/route.js.map +7 -0
- package/dist/modules/sso/api/error-handler.js +28 -0
- package/dist/modules/sso/api/error-handler.js.map +7 -0
- package/dist/modules/sso/api/hrd/route.js +52 -0
- package/dist/modules/sso/api/hrd/route.js.map +7 -0
- package/dist/modules/sso/api/initiate/route.js +66 -0
- package/dist/modules/sso/api/initiate/route.js.map +7 -0
- package/dist/modules/sso/api/scim/context.js +68 -0
- package/dist/modules/sso/api/scim/context.js.map +7 -0
- package/dist/modules/sso/api/scim/logs/route.js +65 -0
- package/dist/modules/sso/api/scim/logs/route.js.map +7 -0
- package/dist/modules/sso/api/scim/tokens/[id]/route.js +42 -0
- package/dist/modules/sso/api/scim/tokens/[id]/route.js.map +7 -0
- package/dist/modules/sso/api/scim/tokens/route.js +83 -0
- package/dist/modules/sso/api/scim/tokens/route.js.map +7 -0
- package/dist/modules/sso/api/scim/v2/ServiceProviderConfig/route.js +42 -0
- package/dist/modules/sso/api/scim/v2/ServiceProviderConfig/route.js.map +7 -0
- package/dist/modules/sso/api/scim/v2/Users/[id]/route.js +94 -0
- package/dist/modules/sso/api/scim/v2/Users/[id]/route.js.map +7 -0
- package/dist/modules/sso/api/scim/v2/Users/route.js +86 -0
- package/dist/modules/sso/api/scim/v2/Users/route.js.map +7 -0
- package/dist/modules/sso/backend/page.js +173 -0
- package/dist/modules/sso/backend/page.js.map +7 -0
- package/dist/modules/sso/backend/page.meta.js +31 -0
- package/dist/modules/sso/backend/page.meta.js.map +7 -0
- package/dist/modules/sso/backend/sso/config/[id]/page.js +749 -0
- package/dist/modules/sso/backend/sso/config/[id]/page.js.map +7 -0
- package/dist/modules/sso/backend/sso/config/[id]/page.meta.js +19 -0
- package/dist/modules/sso/backend/sso/config/[id]/page.meta.js.map +7 -0
- package/dist/modules/sso/backend/sso/config/new/page.js +381 -0
- package/dist/modules/sso/backend/sso/config/new/page.js.map +7 -0
- package/dist/modules/sso/backend/sso/config/new/page.meta.js +19 -0
- package/dist/modules/sso/backend/sso/config/new/page.meta.js.map +7 -0
- package/dist/modules/sso/data/entities.js +299 -0
- package/dist/modules/sso/data/entities.js.map +7 -0
- package/dist/modules/sso/data/validators.js +114 -0
- package/dist/modules/sso/data/validators.js.map +7 -0
- package/dist/modules/sso/di.js +26 -0
- package/dist/modules/sso/di.js.map +7 -0
- package/dist/modules/sso/events.js +24 -0
- package/dist/modules/sso/events.js.map +7 -0
- package/dist/modules/sso/i18n/de.json +146 -0
- package/dist/modules/sso/i18n/en.json +146 -0
- package/dist/modules/sso/i18n/es.json +146 -0
- package/dist/modules/sso/i18n/pl.json +146 -0
- package/dist/modules/sso/index.js +11 -0
- package/dist/modules/sso/index.js.map +7 -0
- package/dist/modules/sso/lib/domains.js +30 -0
- package/dist/modules/sso/lib/domains.js.map +7 -0
- package/dist/modules/sso/lib/oidc-provider.js +140 -0
- package/dist/modules/sso/lib/oidc-provider.js.map +7 -0
- package/dist/modules/sso/lib/registry.js +15 -0
- package/dist/modules/sso/lib/registry.js.map +7 -0
- package/dist/modules/sso/lib/scim-filter.js +43 -0
- package/dist/modules/sso/lib/scim-filter.js.map +7 -0
- package/dist/modules/sso/lib/scim-mapper.js +49 -0
- package/dist/modules/sso/lib/scim-mapper.js.map +7 -0
- package/dist/modules/sso/lib/scim-patch.js +63 -0
- package/dist/modules/sso/lib/scim-patch.js.map +7 -0
- package/dist/modules/sso/lib/scim-response.js +34 -0
- package/dist/modules/sso/lib/scim-response.js.map +7 -0
- package/dist/modules/sso/lib/scim-utils.js +9 -0
- package/dist/modules/sso/lib/scim-utils.js.map +7 -0
- package/dist/modules/sso/lib/state-cookie.js +67 -0
- package/dist/modules/sso/lib/state-cookie.js.map +7 -0
- package/dist/modules/sso/lib/types.js +1 -0
- package/dist/modules/sso/lib/types.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260219000000_sso.js +20 -0
- package/dist/modules/sso/migrations/Migration20260219000000_sso.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260222000000_sso_add_name.js +13 -0
- package/dist/modules/sso/migrations/Migration20260222000000_sso_add_name.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260222000001_sso_partial_unique_org.js +15 -0
- package/dist/modules/sso/migrations/Migration20260222000001_sso_partial_unique_org.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260223000000_scim_tables.js +22 -0
- package/dist/modules/sso/migrations/Migration20260223000000_scim_tables.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260224000000_sso_external_id.js +15 -0
- package/dist/modules/sso/migrations/Migration20260224000000_sso_external_id.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260224100000_sso_role_grants.js +17 -0
- package/dist/modules/sso/migrations/Migration20260224100000_sso_role_grants.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260224200000_drop_default_role_id.js +13 -0
- package/dist/modules/sso/migrations/Migration20260224200000_drop_default_role_id.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260225000000_sso_identities_partial_unique.js +23 -0
- package/dist/modules/sso/migrations/Migration20260225000000_sso_identities_partial_unique.js.map +7 -0
- package/dist/modules/sso/migrations/Migration20260305000000_sso_role_grants_org_id.js +14 -0
- package/dist/modules/sso/migrations/Migration20260305000000_sso_role_grants_org_id.js.map +7 -0
- package/dist/modules/sso/services/accountLinkingService.js +298 -0
- package/dist/modules/sso/services/accountLinkingService.js.map +7 -0
- package/dist/modules/sso/services/hrdService.js +18 -0
- package/dist/modules/sso/services/hrdService.js.map +7 -0
- package/dist/modules/sso/services/scimService.js +372 -0
- package/dist/modules/sso/services/scimService.js.map +7 -0
- package/dist/modules/sso/services/scimTokenService.js +94 -0
- package/dist/modules/sso/services/scimTokenService.js.map +7 -0
- package/dist/modules/sso/services/ssoConfigService.js +254 -0
- package/dist/modules/sso/services/ssoConfigService.js.map +7 -0
- package/dist/modules/sso/services/ssoService.js +125 -0
- package/dist/modules/sso/services/ssoService.js.map +7 -0
- package/dist/modules/sso/setup.js +47 -0
- package/dist/modules/sso/setup.js.map +7 -0
- package/dist/modules/sso/subscribers/user-deleted-cleanup.js +21 -0
- package/dist/modules/sso/subscribers/user-deleted-cleanup.js.map +7 -0
- package/dist/modules/sso/widgets/injection/login-sso/widget.client.js +106 -0
- package/dist/modules/sso/widgets/injection/login-sso/widget.client.js.map +7 -0
- package/dist/modules/sso/widgets/injection/login-sso/widget.js +16 -0
- package/dist/modules/sso/widgets/injection/login-sso/widget.js.map +7 -0
- package/dist/modules/sso/widgets/injection-table.js +14 -0
- package/dist/modules/sso/widgets/injection-table.js.map +7 -0
- package/package.json +5 -4
- package/src/index.ts +1 -1
- package/src/modules/sso/acl.ts +7 -0
- package/src/modules/sso/api/admin-context.ts +36 -0
- package/src/modules/sso/api/callback/oidc/route.ts +115 -0
- package/src/modules/sso/api/config/[id]/activate/route.ts +53 -0
- package/src/modules/sso/api/config/[id]/domains/route.ts +107 -0
- package/src/modules/sso/api/config/[id]/route.ts +114 -0
- package/src/modules/sso/api/config/[id]/test/route.ts +44 -0
- package/src/modules/sso/api/config/route.ts +88 -0
- package/src/modules/sso/api/error-handler.ts +36 -0
- package/src/modules/sso/api/hrd/route.ts +55 -0
- package/src/modules/sso/api/initiate/route.ts +70 -0
- package/src/modules/sso/api/scim/context.ts +85 -0
- package/src/modules/sso/api/scim/logs/route.ts +69 -0
- package/src/modules/sso/api/scim/tokens/[id]/route.ts +45 -0
- package/src/modules/sso/api/scim/tokens/route.ts +89 -0
- package/src/modules/sso/api/scim/v2/ServiceProviderConfig/route.ts +40 -0
- package/src/modules/sso/api/scim/v2/Users/[id]/route.ts +103 -0
- package/src/modules/sso/api/scim/v2/Users/route.ts +94 -0
- package/src/modules/sso/backend/page.meta.ts +29 -0
- package/src/modules/sso/backend/page.tsx +232 -0
- package/src/modules/sso/backend/sso/config/[id]/page.meta.ts +15 -0
- package/src/modules/sso/backend/sso/config/[id]/page.tsx +1024 -0
- package/src/modules/sso/backend/sso/config/new/page.meta.ts +15 -0
- package/src/modules/sso/backend/sso/config/new/page.tsx +463 -0
- package/src/modules/sso/data/entities.ts +240 -0
- package/src/modules/sso/data/validators.ts +140 -0
- package/src/modules/sso/di.ts +25 -0
- package/src/modules/sso/docs/entra-id-setup.md +281 -0
- package/src/modules/sso/docs/google-workspace-setup.md +174 -0
- package/src/modules/sso/docs/sso-overview.md +218 -0
- package/src/modules/sso/docs/sso-security-audit-2026-02-27.md +118 -0
- package/src/modules/sso/docs/zitadel-setup.md +195 -0
- package/src/modules/sso/events.ts +21 -0
- package/src/modules/sso/i18n/de.json +146 -0
- package/src/modules/sso/i18n/en.json +146 -0
- package/src/modules/sso/i18n/es.json +146 -0
- package/src/modules/sso/i18n/pl.json +146 -0
- package/src/modules/sso/index.ts +7 -0
- package/src/modules/sso/lib/domains.ts +31 -0
- package/src/modules/sso/lib/oidc-provider.ts +196 -0
- package/src/modules/sso/lib/registry.ts +13 -0
- package/src/modules/sso/lib/scim-filter.ts +62 -0
- package/src/modules/sso/lib/scim-mapper.ts +88 -0
- package/src/modules/sso/lib/scim-patch.ts +88 -0
- package/src/modules/sso/lib/scim-response.ts +40 -0
- package/src/modules/sso/lib/scim-utils.ts +5 -0
- package/src/modules/sso/lib/state-cookie.ts +79 -0
- package/src/modules/sso/lib/types.ts +50 -0
- package/src/modules/sso/migrations/.snapshot-open-mercato.json +912 -0
- package/src/modules/sso/migrations/Migration20260219000000_sso.ts +21 -0
- package/src/modules/sso/migrations/Migration20260222000000_sso_add_name.ts +13 -0
- package/src/modules/sso/migrations/Migration20260222000001_sso_partial_unique_org.ts +15 -0
- package/src/modules/sso/migrations/Migration20260223000000_scim_tables.ts +24 -0
- package/src/modules/sso/migrations/Migration20260224000000_sso_external_id.ts +15 -0
- package/src/modules/sso/migrations/Migration20260224100000_sso_role_grants.ts +18 -0
- package/src/modules/sso/migrations/Migration20260224200000_drop_default_role_id.ts +13 -0
- package/src/modules/sso/migrations/Migration20260225000000_sso_identities_partial_unique.ts +25 -0
- package/src/modules/sso/migrations/Migration20260305000000_sso_role_grants_org_id.ts +14 -0
- package/src/modules/sso/services/accountLinkingService.ts +386 -0
- package/src/modules/sso/services/hrdService.ts +22 -0
- package/src/modules/sso/services/scimService.ts +461 -0
- package/src/modules/sso/services/scimTokenService.ts +136 -0
- package/src/modules/sso/services/ssoConfigService.ts +337 -0
- package/src/modules/sso/services/ssoService.ts +167 -0
- package/src/modules/sso/setup.ts +56 -0
- package/src/modules/sso/subscribers/user-deleted-cleanup.ts +33 -0
- package/src/modules/sso/widgets/injection/login-sso/widget.client.tsx +130 -0
- package/src/modules/sso/widgets/injection/login-sso/widget.ts +16 -0
- package/src/modules/sso/widgets/injection-table.ts +12 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const enterprisePackage = {
|
|
2
2
|
id: "enterprise",
|
|
3
3
|
description: "Optional enterprise overlays and modules for Open Mercato.",
|
|
4
|
-
modules: ["security", "record_locks"]
|
|
4
|
+
modules: ["security", "sso", "record_locks"]
|
|
5
5
|
};
|
|
6
6
|
var index_default = enterprisePackage;
|
|
7
7
|
export {
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export const enterprisePackage = {\n id: 'enterprise',\n description: 'Optional enterprise overlays and modules for Open Mercato.',\n modules: ['security', 'record_locks'],\n} as const\n\nexport default enterprisePackage\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,oBAAoB;AAAA,EAC/B,IAAI;AAAA,EACJ,aAAa;AAAA,EACb,SAAS,CAAC,YAAY,cAAc;
|
|
4
|
+
"sourcesContent": ["export const enterprisePackage = {\n id: 'enterprise',\n description: 'Optional enterprise overlays and modules for Open Mercato.',\n modules: ['security', 'sso','record_locks'],\n} as const\n\nexport default enterprisePackage\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,oBAAoB;AAAA,EAC/B,IAAI;AAAA,EACJ,aAAa;AAAA,EACb,SAAS,CAAC,YAAY,OAAM,cAAc;AAC5C;AAEA,IAAO,gBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const features = [
|
|
2
|
+
{ id: "sso.config.view", title: "View SSO configuration", module: "sso" },
|
|
3
|
+
{ id: "sso.config.manage", title: "Manage SSO configuration", module: "sso" },
|
|
4
|
+
{ id: "sso.scim.manage", title: "Manage SCIM provisioning tokens", module: "sso" }
|
|
5
|
+
];
|
|
6
|
+
var acl_default = features;
|
|
7
|
+
export {
|
|
8
|
+
acl_default as default,
|
|
9
|
+
features
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=acl.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/sso/acl.ts"],
|
|
4
|
+
"sourcesContent": ["export const features = [\n { id: 'sso.config.view', title: 'View SSO configuration', module: 'sso' },\n { id: 'sso.config.manage', title: 'Manage SSO configuration', module: 'sso' },\n { id: 'sso.scim.manage', title: 'Manage SCIM provisioning tokens', module: 'sso' },\n]\n\nexport default features\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,EAAE,IAAI,mBAAmB,OAAO,0BAA0B,QAAQ,MAAM;AAAA,EACxE,EAAE,IAAI,qBAAqB,OAAO,4BAA4B,QAAQ,MAAM;AAAA,EAC5E,EAAE,IAAI,mBAAmB,OAAO,mCAAmC,QAAQ,MAAM;AACnF;AAEA,IAAO,cAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
2
|
+
async function resolveSsoAdminContext(req) {
|
|
3
|
+
const auth = await getAuthFromRequest(req);
|
|
4
|
+
if (!auth?.sub) throw new SsoAdminAuthError("Unauthorized", 401);
|
|
5
|
+
const isSuperAdmin = !!auth.isSuperAdmin;
|
|
6
|
+
const url = new URL(req.url);
|
|
7
|
+
return {
|
|
8
|
+
auth,
|
|
9
|
+
scope: {
|
|
10
|
+
isSuperAdmin,
|
|
11
|
+
organizationId: isSuperAdmin ? url.searchParams.get("organizationId") ?? null : auth.orgId ?? null,
|
|
12
|
+
tenantId: isSuperAdmin ? url.searchParams.get("tenantId") ?? null : auth.tenantId ?? null
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
class SsoAdminAuthError extends Error {
|
|
17
|
+
constructor(message, statusCode) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.statusCode = statusCode;
|
|
20
|
+
this.name = "SsoAdminAuthError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
SsoAdminAuthError,
|
|
25
|
+
resolveSsoAdminContext
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=admin-context.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/sso/api/admin-context.ts"],
|
|
4
|
+
"sourcesContent": ["import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport type { SsoAdminScope } from '../services/ssoConfigService'\n\nexport async function resolveSsoAdminContext(req: Request): Promise<{\n auth: Awaited<ReturnType<typeof getAuthFromRequest>>\n scope: SsoAdminScope\n}> {\n const auth = await getAuthFromRequest(req)\n if (!auth?.sub) throw new SsoAdminAuthError('Unauthorized', 401)\n\n const isSuperAdmin = !!(auth as Record<string, unknown>).isSuperAdmin\n const url = new URL(req.url)\n\n return {\n auth,\n scope: {\n isSuperAdmin,\n organizationId: isSuperAdmin\n ? url.searchParams.get('organizationId') ?? null\n : auth.orgId ?? null,\n tenantId: isSuperAdmin\n ? url.searchParams.get('tenantId') ?? null\n : auth.tenantId ?? null,\n },\n }\n}\n\nexport class SsoAdminAuthError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number,\n ) {\n super(message)\n this.name = 'SsoAdminAuthError'\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,0BAA0B;AAGnC,eAAsB,uBAAuB,KAG1C;AACD,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,IAAK,OAAM,IAAI,kBAAkB,gBAAgB,GAAG;AAE/D,QAAM,eAAe,CAAC,CAAE,KAAiC;AACzD,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAE3B,SAAO;AAAA,IACL;AAAA,IACA,OAAO;AAAA,MACL;AAAA,MACA,gBAAgB,eACZ,IAAI,aAAa,IAAI,gBAAgB,KAAK,OAC1C,KAAK,SAAS;AAAA,MAClB,UAAU,eACN,IAAI,aAAa,IAAI,UAAU,KAAK,OACpC,KAAK,YAAY;AAAA,IACvB;AAAA,EACF;AACF;AAEO,MAAM,0BAA0B,MAAM;AAAA,EAC3C,YACE,SACgB,YAChB;AACA,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { toAbsoluteUrl } from "@open-mercato/shared/lib/url";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { emitSsoEvent } from "../../../events.js";
|
|
5
|
+
function parseCookie(req, name) {
|
|
6
|
+
const cookie = req.headers.get("cookie") || "";
|
|
7
|
+
const m = cookie.match(new RegExp("(?:^|;\\s*)" + name + "=([^;]+)"));
|
|
8
|
+
return m ? decodeURIComponent(m[1]) : null;
|
|
9
|
+
}
|
|
10
|
+
async function handleCallback(req) {
|
|
11
|
+
try {
|
|
12
|
+
const url = new URL(req.url);
|
|
13
|
+
const callbackParams = {};
|
|
14
|
+
url.searchParams.forEach((value, key) => {
|
|
15
|
+
callbackParams[key] = value;
|
|
16
|
+
});
|
|
17
|
+
if (req.method === "POST") {
|
|
18
|
+
const contentType = req.headers.get("content-type") || "";
|
|
19
|
+
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
20
|
+
const form = await req.formData();
|
|
21
|
+
form.forEach((value, key) => {
|
|
22
|
+
callbackParams[key] = String(value);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const stateCookie = parseCookie(req, "sso_state");
|
|
27
|
+
if (!stateCookie) {
|
|
28
|
+
return NextResponse.redirect(toAbsoluteUrl(req, "/login?error=sso_state_missing"));
|
|
29
|
+
}
|
|
30
|
+
if (callbackParams.error) {
|
|
31
|
+
void emitSsoEvent("sso.login.failed", {
|
|
32
|
+
reason: callbackParams.error
|
|
33
|
+
}).catch((e) => console.error("[SSO Event]", e));
|
|
34
|
+
return NextResponse.redirect(toAbsoluteUrl(req, "/login?error=sso_idp_error"));
|
|
35
|
+
}
|
|
36
|
+
if (!callbackParams.code || !callbackParams.state) {
|
|
37
|
+
return NextResponse.redirect(toAbsoluteUrl(req, "/login?error=sso_missing_params"));
|
|
38
|
+
}
|
|
39
|
+
const redirectUri = toAbsoluteUrl(req, "/api/sso/callback/oidc");
|
|
40
|
+
const container = await createRequestContainer();
|
|
41
|
+
const ssoService = container.resolve("ssoService");
|
|
42
|
+
const result = await ssoService.handleOidcCallback(callbackParams, stateCookie, redirectUri);
|
|
43
|
+
const res = NextResponse.redirect(toAbsoluteUrl(req, result.redirectUrl));
|
|
44
|
+
res.cookies.set("auth_token", result.token, {
|
|
45
|
+
httpOnly: true,
|
|
46
|
+
path: "/",
|
|
47
|
+
sameSite: "lax",
|
|
48
|
+
secure: process.env.NODE_ENV !== "development",
|
|
49
|
+
maxAge: 60 * 60 * 8
|
|
50
|
+
});
|
|
51
|
+
res.cookies.set("session_token", result.sessionToken, {
|
|
52
|
+
httpOnly: true,
|
|
53
|
+
path: "/",
|
|
54
|
+
sameSite: "lax",
|
|
55
|
+
secure: process.env.NODE_ENV !== "development",
|
|
56
|
+
expires: result.sessionExpiresAt
|
|
57
|
+
});
|
|
58
|
+
res.cookies.set("sso_state", "", { path: "/", maxAge: 0 });
|
|
59
|
+
return res;
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error("[SSO Callback] Error:", err);
|
|
62
|
+
void emitSsoEvent("sso.login.failed", {
|
|
63
|
+
reason: err instanceof Error ? err.message : "callback_failed"
|
|
64
|
+
}).catch((e) => console.error("[SSO Event]", e));
|
|
65
|
+
const message = err instanceof Error ? err.message : "";
|
|
66
|
+
const errorCode = message.includes("email is not verified") ? "sso_email_not_verified" : "sso_failed";
|
|
67
|
+
return NextResponse.redirect(toAbsoluteUrl(req, `/login?error=${errorCode}`));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function GET(req) {
|
|
71
|
+
return handleCallback(req);
|
|
72
|
+
}
|
|
73
|
+
async function POST(req) {
|
|
74
|
+
return handleCallback(req);
|
|
75
|
+
}
|
|
76
|
+
const openApi = {
|
|
77
|
+
tag: "SSO",
|
|
78
|
+
summary: "OIDC callback",
|
|
79
|
+
methods: {
|
|
80
|
+
GET: {
|
|
81
|
+
summary: "Handle OIDC callback (GET)",
|
|
82
|
+
description: "Receives the authorization code from the IdP, exchanges it for tokens, resolves the user, and issues auth cookies.",
|
|
83
|
+
tags: ["SSO"],
|
|
84
|
+
responses: [
|
|
85
|
+
{ status: 302, description: "Redirect to application with auth cookies set", mediaType: "text/html" }
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
POST: {
|
|
89
|
+
summary: "Handle OIDC callback (POST)",
|
|
90
|
+
description: "Some IdPs send the callback as a POST (form_post response mode). Handles the same flow as the GET variant.",
|
|
91
|
+
tags: ["SSO"],
|
|
92
|
+
responses: [
|
|
93
|
+
{ status: 302, description: "Redirect to application with auth cookies set", mediaType: "text/html" }
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
export {
|
|
99
|
+
GET,
|
|
100
|
+
POST,
|
|
101
|
+
openApi
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/sso/api/callback/oidc/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { toAbsoluteUrl } from '@open-mercato/shared/lib/url'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoService } from '../../../services/ssoService'\nimport { emitSsoEvent } from '../../../events'\n\nfunction parseCookie(req: Request, name: string): string | null {\n const cookie = req.headers.get('cookie') || ''\n const m = cookie.match(new RegExp('(?:^|;\\\\s*)' + name + '=([^;]+)'))\n return m ? decodeURIComponent(m[1]) : null\n}\n\nasync function handleCallback(req: Request): Promise<NextResponse> {\n try {\n const url = new URL(req.url)\n const callbackParams: Record<string, string> = {}\n url.searchParams.forEach((value, key) => {\n callbackParams[key] = value\n })\n\n if (req.method === 'POST') {\n const contentType = req.headers.get('content-type') || ''\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const form = await req.formData()\n form.forEach((value, key) => {\n callbackParams[key] = String(value)\n })\n }\n }\n\n const stateCookie = parseCookie(req, 'sso_state')\n if (!stateCookie) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_state_missing'))\n }\n\n if (callbackParams.error) {\n void emitSsoEvent('sso.login.failed', {\n reason: callbackParams.error,\n }).catch((e) => console.error('[SSO Event]', e))\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_idp_error'))\n }\n\n if (!callbackParams.code || !callbackParams.state) {\n return NextResponse.redirect(toAbsoluteUrl(req, '/login?error=sso_missing_params'))\n }\n\n const redirectUri = toAbsoluteUrl(req, '/api/sso/callback/oidc')\n const container = await createRequestContainer()\n const ssoService = container.resolve<SsoService>('ssoService')\n\n const result = await ssoService.handleOidcCallback(callbackParams, stateCookie, redirectUri)\n\n const res = NextResponse.redirect(toAbsoluteUrl(req, result.redirectUrl))\n\n res.cookies.set('auth_token', result.token, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n maxAge: 60 * 60 * 8,\n })\n\n res.cookies.set('session_token', result.sessionToken, {\n httpOnly: true,\n path: '/',\n sameSite: 'lax',\n secure: process.env.NODE_ENV !== 'development',\n expires: result.sessionExpiresAt,\n })\n\n res.cookies.set('sso_state', '', { path: '/', maxAge: 0 })\n\n return res\n } catch (err) {\n console.error('[SSO Callback] Error:', err)\n void emitSsoEvent('sso.login.failed', {\n reason: err instanceof Error ? err.message : 'callback_failed',\n }).catch((e) => console.error('[SSO Event]', e))\n const message = err instanceof Error ? err.message : ''\n const errorCode = message.includes('email is not verified') ? 'sso_email_not_verified' : 'sso_failed'\n return NextResponse.redirect(toAbsoluteUrl(req, `/login?error=${errorCode}`))\n }\n}\n\nexport async function GET(req: Request) {\n return handleCallback(req)\n}\n\nexport async function POST(req: Request) {\n return handleCallback(req)\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'OIDC callback',\n methods: {\n GET: {\n summary: 'Handle OIDC callback (GET)',\n description: 'Receives the authorization code from the IdP, exchanges it for tokens, resolves the user, and issues auth cookies.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to application with auth cookies set', mediaType: 'text/html' },\n ],\n },\n POST: {\n summary: 'Handle OIDC callback (POST)',\n description: 'Some IdPs send the callback as a POST (form_post response mode). Handles the same flow as the GET variant.',\n tags: ['SSO'],\n responses: [\n { status: 302, description: 'Redirect to application with auth cookies set', mediaType: 'text/html' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
|
+
import { ssoActivateSchema } from "../../../../data/validators.js";
|
|
4
|
+
import { resolveSsoAdminContext } from "../../../admin-context.js";
|
|
5
|
+
import { handleSsoAdminApiError } from "../../../error-handler.js";
|
|
6
|
+
const metadata = {
|
|
7
|
+
POST: { requireAuth: true, requireFeatures: ["sso.config.manage"] }
|
|
8
|
+
};
|
|
9
|
+
async function POST(req, ctx) {
|
|
10
|
+
try {
|
|
11
|
+
const { id } = await ctx.params;
|
|
12
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
13
|
+
const body = await req.json();
|
|
14
|
+
const parsed = ssoActivateSchema.safeParse(body);
|
|
15
|
+
if (!parsed.success) {
|
|
16
|
+
return NextResponse.json({ error: "Invalid request" }, { status: 400 });
|
|
17
|
+
}
|
|
18
|
+
const container = await createRequestContainer();
|
|
19
|
+
const service = container.resolve("ssoConfigService");
|
|
20
|
+
const config = await service.activate(scope, id, parsed.data.active);
|
|
21
|
+
return NextResponse.json(config);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const openApi = {
|
|
27
|
+
tag: "SSO",
|
|
28
|
+
summary: "Activate/Deactivate SSO Configuration",
|
|
29
|
+
methods: {
|
|
30
|
+
POST: {
|
|
31
|
+
summary: "Activate or deactivate SSO configuration",
|
|
32
|
+
description: "Activation requires at least one domain and a successful OIDC discovery test.",
|
|
33
|
+
tags: ["SSO"],
|
|
34
|
+
requestBody: { contentType: "application/json", schema: ssoActivateSchema },
|
|
35
|
+
responses: [{ status: 200, description: "Config activation status updated" }],
|
|
36
|
+
errors: [
|
|
37
|
+
{ status: 400, description: "Activation failed \u2014 no domains or discovery failed" },
|
|
38
|
+
{ status: 401, description: "Unauthorized" },
|
|
39
|
+
{ status: 404, description: "Config not found" }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
export {
|
|
45
|
+
POST,
|
|
46
|
+
metadata,
|
|
47
|
+
openApi
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../src/modules/sso/api/config/%5Bid%5D/activate/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoConfigService } from '../../../../services/ssoConfigService'\nimport { ssoActivateSchema } from '../../../../data/validators'\nimport { resolveSsoAdminContext } from '../../../admin-context'\nimport { handleSsoAdminApiError } from '../../../error-handler'\n\ntype RouteContext = { params: Promise<{ id: string }> }\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['sso.config.manage'] },\n}\n\nexport async function POST(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const body = await req.json()\n const parsed = ssoActivateSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid request' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n const config = await service.activate(scope, id, parsed.data.active)\n\n return NextResponse.json(config)\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'Activate/Deactivate SSO Configuration',\n methods: {\n POST: {\n summary: 'Activate or deactivate SSO configuration',\n description: 'Activation requires at least one domain and a successful OIDC discovery test.',\n tags: ['SSO'],\n requestBody: { contentType: 'application/json', schema: ssoActivateSchema },\n responses: [{ status: 200, description: 'Config activation status updated' }],\n errors: [\n { status: 400, description: 'Activation failed \u2014 no domains or discovery failed' },\n { status: 401, description: 'Unauthorized' },\n { status: 404, description: 'Config not found' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AAEvC,SAAS,yBAAyB;AAClC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AAIhC,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,mBAAmB,EAAE;AACpE;AAEA,eAAsB,KAAK,KAAc,KAAmB;AAC1D,MAAI;AACF,UAAM,EAAE,GAAG,IAAI,MAAM,IAAI;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,uBAAuB,GAAG;AAElD,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,SAAS,kBAAkB,UAAU,IAAI;AAC/C,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,aAAa,KAAK,EAAE,OAAO,kBAAkB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACxE;AAEA,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,UAAU,UAAU,QAA0B,kBAAkB;AACtE,UAAM,SAAS,MAAM,QAAQ,SAAS,OAAO,IAAI,OAAO,KAAK,MAAM;AAEnE,WAAO,aAAa,KAAK,MAAM;AAAA,EACjC,SAAS,KAAK;AACZ,WAAO,uBAAuB,KAAK,gBAAgB;AAAA,EACrD;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,MACb,MAAM,CAAC,KAAK;AAAA,MACZ,aAAa,EAAE,aAAa,oBAAoB,QAAQ,kBAAkB;AAAA,MAC1E,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,mCAAmC,CAAC;AAAA,MAC5E,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,0DAAqD;AAAA,QACjF,EAAE,QAAQ,KAAK,aAAa,eAAe;AAAA,QAC3C,EAAE,QAAQ,KAAK,aAAa,mBAAmB;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
|
+
import { ssoDomainAddSchema } from "../../../../data/validators.js";
|
|
4
|
+
import { resolveSsoAdminContext } from "../../../admin-context.js";
|
|
5
|
+
import { handleSsoAdminApiError } from "../../../error-handler.js";
|
|
6
|
+
const metadata = {
|
|
7
|
+
GET: { requireAuth: true, requireFeatures: ["sso.config.view"] },
|
|
8
|
+
POST: { requireAuth: true, requireFeatures: ["sso.config.manage"] },
|
|
9
|
+
DELETE: { requireAuth: true, requireFeatures: ["sso.config.manage"] }
|
|
10
|
+
};
|
|
11
|
+
async function GET(req, ctx) {
|
|
12
|
+
try {
|
|
13
|
+
const { id } = await ctx.params;
|
|
14
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
15
|
+
const container = await createRequestContainer();
|
|
16
|
+
const service = container.resolve("ssoConfigService");
|
|
17
|
+
const config = await service.getById(scope, id);
|
|
18
|
+
if (!config) {
|
|
19
|
+
return NextResponse.json({ error: "SSO configuration not found" }, { status: 404 });
|
|
20
|
+
}
|
|
21
|
+
return NextResponse.json({ domains: config.allowedDomains });
|
|
22
|
+
} catch (err) {
|
|
23
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function POST(req, ctx) {
|
|
27
|
+
try {
|
|
28
|
+
const { id } = await ctx.params;
|
|
29
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
30
|
+
const body = await req.json();
|
|
31
|
+
const parsed = ssoDomainAddSchema.safeParse(body);
|
|
32
|
+
if (!parsed.success) {
|
|
33
|
+
return NextResponse.json({ error: "Invalid request", details: parsed.error.flatten() }, { status: 400 });
|
|
34
|
+
}
|
|
35
|
+
const container = await createRequestContainer();
|
|
36
|
+
const service = container.resolve("ssoConfigService");
|
|
37
|
+
const config = await service.addDomain(scope, id, parsed.data.domain);
|
|
38
|
+
return NextResponse.json({ domains: config.allowedDomains });
|
|
39
|
+
} catch (err) {
|
|
40
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function DELETE(req, ctx) {
|
|
44
|
+
try {
|
|
45
|
+
const { id } = await ctx.params;
|
|
46
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
47
|
+
const url = new URL(req.url);
|
|
48
|
+
const domain = url.searchParams.get("domain");
|
|
49
|
+
if (!domain) {
|
|
50
|
+
return NextResponse.json({ error: "Missing domain query parameter" }, { status: 400 });
|
|
51
|
+
}
|
|
52
|
+
const container = await createRequestContainer();
|
|
53
|
+
const service = container.resolve("ssoConfigService");
|
|
54
|
+
const config = await service.removeDomain(scope, id, domain);
|
|
55
|
+
return NextResponse.json({ domains: config.allowedDomains });
|
|
56
|
+
} catch (err) {
|
|
57
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const openApi = {
|
|
61
|
+
tag: "SSO",
|
|
62
|
+
summary: "SSO Domain Management",
|
|
63
|
+
methods: {
|
|
64
|
+
GET: {
|
|
65
|
+
summary: "List allowed domains",
|
|
66
|
+
tags: ["SSO"],
|
|
67
|
+
responses: [{ status: 200, description: "List of allowed domains" }],
|
|
68
|
+
errors: [{ status: 404, description: "Config not found" }]
|
|
69
|
+
},
|
|
70
|
+
POST: {
|
|
71
|
+
summary: "Add an allowed domain",
|
|
72
|
+
tags: ["SSO"],
|
|
73
|
+
requestBody: { contentType: "application/json", schema: ssoDomainAddSchema },
|
|
74
|
+
responses: [{ status: 200, description: "Domain added" }],
|
|
75
|
+
errors: [
|
|
76
|
+
{ status: 400, description: "Invalid domain or limit reached" },
|
|
77
|
+
{ status: 404, description: "Config not found" }
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
DELETE: {
|
|
81
|
+
summary: "Remove an allowed domain",
|
|
82
|
+
description: "Pass domain as query parameter: ?domain=example.com",
|
|
83
|
+
tags: ["SSO"],
|
|
84
|
+
responses: [{ status: 200, description: "Domain removed" }],
|
|
85
|
+
errors: [{ status: 404, description: "Config not found" }]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
export {
|
|
90
|
+
DELETE,
|
|
91
|
+
GET,
|
|
92
|
+
POST,
|
|
93
|
+
metadata,
|
|
94
|
+
openApi
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../src/modules/sso/api/config/%5Bid%5D/domains/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoConfigService } from '../../../../services/ssoConfigService'\nimport { ssoDomainAddSchema } from '../../../../data/validators'\nimport { resolveSsoAdminContext } from '../../../admin-context'\nimport { handleSsoAdminApiError } from '../../../error-handler'\n\ntype RouteContext = { params: Promise<{ id: string }> }\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['sso.config.view'] },\n POST: { requireAuth: true, requireFeatures: ['sso.config.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['sso.config.manage'] },\n}\n\nexport async function GET(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n const config = await service.getById(scope, id)\n\n if (!config) {\n return NextResponse.json({ error: 'SSO configuration not found' }, { status: 404 })\n }\n\n return NextResponse.json({ domains: config.allowedDomains })\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\nexport async function POST(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const body = await req.json()\n const parsed = ssoDomainAddSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid request', details: parsed.error.flatten() }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n const config = await service.addDomain(scope, id, parsed.data.domain)\n\n return NextResponse.json({ domains: config.allowedDomains })\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\nexport async function DELETE(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const url = new URL(req.url)\n const domain = url.searchParams.get('domain')\n if (!domain) {\n return NextResponse.json({ error: 'Missing domain query parameter' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n const config = await service.removeDomain(scope, id, domain)\n\n return NextResponse.json({ domains: config.allowedDomains })\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'SSO Domain Management',\n methods: {\n GET: {\n summary: 'List allowed domains',\n tags: ['SSO'],\n responses: [{ status: 200, description: 'List of allowed domains' }],\n errors: [{ status: 404, description: 'Config not found' }],\n },\n POST: {\n summary: 'Add an allowed domain',\n tags: ['SSO'],\n requestBody: { contentType: 'application/json', schema: ssoDomainAddSchema },\n responses: [{ status: 200, description: 'Domain added' }],\n errors: [\n { status: 400, description: 'Invalid domain or limit reached' },\n { status: 404, description: 'Config not found' },\n ],\n },\n DELETE: {\n summary: 'Remove an allowed domain',\n description: 'Pass domain as query parameter: ?domain=example.com',\n tags: ['SSO'],\n responses: [{ status: 200, description: 'Domain removed' }],\n errors: [{ status: 404, description: 'Config not found' }],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AAEvC,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AAIhC,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,iBAAiB,EAAE;AAAA,EAC/D,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,mBAAmB,EAAE;AAAA,EAClE,QAAQ,EAAE,aAAa,MAAM,iBAAiB,CAAC,mBAAmB,EAAE;AACtE;AAEA,eAAsB,IAAI,KAAc,KAAmB;AACzD,MAAI;AACF,UAAM,EAAE,GAAG,IAAI,MAAM,IAAI;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,uBAAuB,GAAG;AAElD,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,UAAU,UAAU,QAA0B,kBAAkB;AACtE,UAAM,SAAS,MAAM,QAAQ,QAAQ,OAAO,EAAE;AAE9C,QAAI,CAAC,QAAQ;AACX,aAAO,aAAa,KAAK,EAAE,OAAO,8BAA8B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACpF;AAEA,WAAO,aAAa,KAAK,EAAE,SAAS,OAAO,eAAe,CAAC;AAAA,EAC7D,SAAS,KAAK;AACZ,WAAO,uBAAuB,KAAK,gBAAgB;AAAA,EACrD;AACF;AAEA,eAAsB,KAAK,KAAc,KAAmB;AAC1D,MAAI;AACF,UAAM,EAAE,GAAG,IAAI,MAAM,IAAI;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,uBAAuB,GAAG;AAElD,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,SAAS,mBAAmB,UAAU,IAAI;AAChD,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO,aAAa,KAAK,EAAE,OAAO,mBAAmB,SAAS,OAAO,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACzG;AAEA,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,UAAU,UAAU,QAA0B,kBAAkB;AACtE,UAAM,SAAS,MAAM,QAAQ,UAAU,OAAO,IAAI,OAAO,KAAK,MAAM;AAEpE,WAAO,aAAa,KAAK,EAAE,SAAS,OAAO,eAAe,CAAC;AAAA,EAC7D,SAAS,KAAK;AACZ,WAAO,uBAAuB,KAAK,gBAAgB;AAAA,EACrD;AACF;AAEA,eAAsB,OAAO,KAAc,KAAmB;AAC5D,MAAI;AACF,UAAM,EAAE,GAAG,IAAI,MAAM,IAAI;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,uBAAuB,GAAG;AAElD,UAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,UAAM,SAAS,IAAI,aAAa,IAAI,QAAQ;AAC5C,QAAI,CAAC,QAAQ;AACX,aAAO,aAAa,KAAK,EAAE,OAAO,iCAAiC,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACvF;AAEA,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,UAAU,UAAU,QAA0B,kBAAkB;AACtE,UAAM,SAAS,MAAM,QAAQ,aAAa,OAAO,IAAI,MAAM;AAE3D,WAAO,aAAa,KAAK,EAAE,SAAS,OAAO,eAAe,CAAC;AAAA,EAC7D,SAAS,KAAK;AACZ,WAAO,uBAAuB,KAAK,gBAAgB;AAAA,EACrD;AACF;AAGO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,MAAM,CAAC,KAAK;AAAA,MACZ,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,0BAA0B,CAAC;AAAA,MACnE,QAAQ,CAAC,EAAE,QAAQ,KAAK,aAAa,mBAAmB,CAAC;AAAA,IAC3D;AAAA,IACA,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,MAAM,CAAC,KAAK;AAAA,MACZ,aAAa,EAAE,aAAa,oBAAoB,QAAQ,mBAAmB;AAAA,MAC3E,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,eAAe,CAAC;AAAA,MACxD,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,kCAAkC;AAAA,QAC9D,EAAE,QAAQ,KAAK,aAAa,mBAAmB;AAAA,MACjD;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA,MACT,aAAa;AAAA,MACb,MAAM,CAAC,KAAK;AAAA,MACZ,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,iBAAiB,CAAC;AAAA,MAC1D,QAAQ,CAAC,EAAE,QAAQ,KAAK,aAAa,mBAAmB,CAAC;AAAA,IAC3D;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
|
+
import { ssoConfigAdminUpdateSchema } from "../../../data/validators.js";
|
|
4
|
+
import { resolveSsoAdminContext } from "../../admin-context.js";
|
|
5
|
+
import { handleSsoAdminApiError } from "../../error-handler.js";
|
|
6
|
+
import { ScimToken } from "../../../data/entities.js";
|
|
7
|
+
const metadata = {
|
|
8
|
+
GET: { requireAuth: true, requireFeatures: ["sso.config.view"] },
|
|
9
|
+
PUT: { requireAuth: true, requireFeatures: ["sso.config.manage"] },
|
|
10
|
+
DELETE: { requireAuth: true, requireFeatures: ["sso.config.manage"] }
|
|
11
|
+
};
|
|
12
|
+
async function GET(req, ctx) {
|
|
13
|
+
try {
|
|
14
|
+
const { id } = await ctx.params;
|
|
15
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
16
|
+
const container = await createRequestContainer();
|
|
17
|
+
const service = container.resolve("ssoConfigService");
|
|
18
|
+
const config = await service.getById(scope, id);
|
|
19
|
+
if (!config) {
|
|
20
|
+
return NextResponse.json({ error: "SSO configuration not found" }, { status: 404 });
|
|
21
|
+
}
|
|
22
|
+
const em = container.resolve("em");
|
|
23
|
+
const activeScimCount = await em.count(ScimToken, { ssoConfigId: id, isActive: true });
|
|
24
|
+
return NextResponse.json({ ...config, hasActiveScimTokens: activeScimCount > 0 });
|
|
25
|
+
} catch (err) {
|
|
26
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function PUT(req, ctx) {
|
|
30
|
+
try {
|
|
31
|
+
const { id } = await ctx.params;
|
|
32
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
33
|
+
const body = await req.json();
|
|
34
|
+
const parsed = ssoConfigAdminUpdateSchema.safeParse(body);
|
|
35
|
+
if (!parsed.success) {
|
|
36
|
+
return NextResponse.json({ error: "Invalid request", details: parsed.error.flatten() }, { status: 400 });
|
|
37
|
+
}
|
|
38
|
+
const container = await createRequestContainer();
|
|
39
|
+
const service = container.resolve("ssoConfigService");
|
|
40
|
+
const config = await service.update(scope, id, parsed.data);
|
|
41
|
+
return NextResponse.json(config);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function DELETE(req, ctx) {
|
|
47
|
+
try {
|
|
48
|
+
const { id } = await ctx.params;
|
|
49
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
50
|
+
const container = await createRequestContainer();
|
|
51
|
+
const service = container.resolve("ssoConfigService");
|
|
52
|
+
await service.delete(scope, id);
|
|
53
|
+
return NextResponse.json({ ok: true });
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const openApi = {
|
|
59
|
+
tag: "SSO",
|
|
60
|
+
summary: "SSO Configuration Detail",
|
|
61
|
+
methods: {
|
|
62
|
+
GET: {
|
|
63
|
+
summary: "Get SSO configuration by ID",
|
|
64
|
+
tags: ["SSO"],
|
|
65
|
+
responses: [{ status: 200, description: "SSO config detail" }],
|
|
66
|
+
errors: [
|
|
67
|
+
{ status: 401, description: "Unauthorized" },
|
|
68
|
+
{ status: 404, description: "Config not found" }
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
PUT: {
|
|
72
|
+
summary: "Update SSO configuration",
|
|
73
|
+
tags: ["SSO"],
|
|
74
|
+
requestBody: { contentType: "application/json", schema: ssoConfigAdminUpdateSchema },
|
|
75
|
+
responses: [{ status: 200, description: "SSO config updated" }],
|
|
76
|
+
errors: [
|
|
77
|
+
{ status: 400, description: "Invalid input" },
|
|
78
|
+
{ status: 401, description: "Unauthorized" },
|
|
79
|
+
{ status: 404, description: "Config not found" },
|
|
80
|
+
{ status: 409, description: "Conflict \u2014 JIT and SCIM are mutually exclusive" }
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
DELETE: {
|
|
84
|
+
summary: "Delete SSO configuration",
|
|
85
|
+
description: "Soft-deletes the config. Must be deactivated first.",
|
|
86
|
+
tags: ["SSO"],
|
|
87
|
+
responses: [{ status: 200, description: "Config deleted" }],
|
|
88
|
+
errors: [
|
|
89
|
+
{ status: 400, description: "Cannot delete active config" },
|
|
90
|
+
{ status: 401, description: "Unauthorized" },
|
|
91
|
+
{ status: 404, description: "Config not found" }
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
export {
|
|
97
|
+
DELETE,
|
|
98
|
+
GET,
|
|
99
|
+
PUT,
|
|
100
|
+
metadata,
|
|
101
|
+
openApi
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/sso/api/config/%5Bid%5D/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoConfigService } from '../../../services/ssoConfigService'\nimport { ssoConfigAdminUpdateSchema } from '../../../data/validators'\nimport { resolveSsoAdminContext } from '../../admin-context'\nimport { handleSsoAdminApiError } from '../../error-handler'\nimport { ScimToken } from '../../../data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\n\ntype RouteContext = { params: Promise<{ id: string }> }\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['sso.config.view'] },\n PUT: { requireAuth: true, requireFeatures: ['sso.config.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['sso.config.manage'] },\n}\n\nexport async function GET(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n const config = await service.getById(scope, id)\n\n if (!config) {\n return NextResponse.json({ error: 'SSO configuration not found' }, { status: 404 })\n }\n\n const em = container.resolve<EntityManager>('em')\n const activeScimCount = await em.count(ScimToken, { ssoConfigId: id, isActive: true })\n\n return NextResponse.json({ ...config, hasActiveScimTokens: activeScimCount > 0 })\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\nexport async function PUT(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const body = await req.json()\n const parsed = ssoConfigAdminUpdateSchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid request', details: parsed.error.flatten() }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n const config = await service.update(scope, id, parsed.data)\n\n return NextResponse.json(config)\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\nexport async function DELETE(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n await service.delete(scope, id)\n\n return NextResponse.json({ ok: true })\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'SSO Configuration Detail',\n methods: {\n GET: {\n summary: 'Get SSO configuration by ID',\n tags: ['SSO'],\n responses: [{ status: 200, description: 'SSO config detail' }],\n errors: [\n { status: 401, description: 'Unauthorized' },\n { status: 404, description: 'Config not found' },\n ],\n },\n PUT: {\n summary: 'Update SSO configuration',\n tags: ['SSO'],\n requestBody: { contentType: 'application/json', schema: ssoConfigAdminUpdateSchema },\n responses: [{ status: 200, description: 'SSO config updated' }],\n errors: [\n { status: 400, description: 'Invalid input' },\n { status: 401, description: 'Unauthorized' },\n { status: 404, description: 'Config not found' },\n { status: 409, description: 'Conflict \u2014 JIT and SCIM are mutually exclusive' },\n ],\n },\n DELETE: {\n summary: 'Delete SSO configuration',\n description: 'Soft-deletes the config. Must be deactivated first.',\n tags: ['SSO'],\n responses: [{ status: 200, description: 'Config deleted' }],\n errors: [\n { status: 400, description: 'Cannot delete active config' },\n { status: 401, description: 'Unauthorized' },\n { status: 404, description: 'Config not found' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
|
+
import { resolveSsoAdminContext } from "../../../admin-context.js";
|
|
4
|
+
import { handleSsoAdminApiError } from "../../../error-handler.js";
|
|
5
|
+
const metadata = {
|
|
6
|
+
POST: { requireAuth: true, requireFeatures: ["sso.config.manage"] }
|
|
7
|
+
};
|
|
8
|
+
async function POST(req, ctx) {
|
|
9
|
+
try {
|
|
10
|
+
const { id } = await ctx.params;
|
|
11
|
+
const { scope } = await resolveSsoAdminContext(req);
|
|
12
|
+
const container = await createRequestContainer();
|
|
13
|
+
const service = container.resolve("ssoConfigService");
|
|
14
|
+
const result = await service.testConnection(scope, id);
|
|
15
|
+
return NextResponse.json(result);
|
|
16
|
+
} catch (err) {
|
|
17
|
+
return handleSsoAdminApiError(err, "SSO Config API");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const openApi = {
|
|
21
|
+
tag: "SSO",
|
|
22
|
+
summary: "Test SSO Connection",
|
|
23
|
+
methods: {
|
|
24
|
+
POST: {
|
|
25
|
+
summary: "Test OIDC discovery",
|
|
26
|
+
description: "Verifies that the issuer URL is reachable and returns a valid OIDC discovery document. Does not verify client credentials.",
|
|
27
|
+
tags: ["SSO"],
|
|
28
|
+
responses: [{ status: 200, description: "Test result with ok/error" }],
|
|
29
|
+
errors: [
|
|
30
|
+
{ status: 401, description: "Unauthorized" },
|
|
31
|
+
{ status: 404, description: "Config not found" }
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export {
|
|
37
|
+
POST,
|
|
38
|
+
metadata,
|
|
39
|
+
openApi
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../../src/modules/sso/api/config/%5Bid%5D/test/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { SsoConfigService } from '../../../../services/ssoConfigService'\nimport { resolveSsoAdminContext } from '../../../admin-context'\nimport { handleSsoAdminApiError } from '../../../error-handler'\n\ntype RouteContext = { params: Promise<{ id: string }> }\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['sso.config.manage'] },\n}\n\nexport async function POST(req: Request, ctx: RouteContext) {\n try {\n const { id } = await ctx.params\n const { scope } = await resolveSsoAdminContext(req)\n\n const container = await createRequestContainer()\n const service = container.resolve<SsoConfigService>('ssoConfigService')\n const result = await service.testConnection(scope, id)\n\n return NextResponse.json(result)\n } catch (err) {\n return handleSsoAdminApiError(err, 'SSO Config API')\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'SSO',\n summary: 'Test SSO Connection',\n methods: {\n POST: {\n summary: 'Test OIDC discovery',\n description: 'Verifies that the issuer URL is reachable and returns a valid OIDC discovery document. Does not verify client credentials.',\n tags: ['SSO'],\n responses: [{ status: 200, description: 'Test result with ok/error' }],\n errors: [\n { status: 401, description: 'Unauthorized' },\n { status: 404, description: 'Config not found' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,8BAA8B;AAEvC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AAIhC,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,mBAAmB,EAAE;AACpE;AAEA,eAAsB,KAAK,KAAc,KAAmB;AAC1D,MAAI;AACF,UAAM,EAAE,GAAG,IAAI,MAAM,IAAI;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,uBAAuB,GAAG;AAElD,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,UAAU,UAAU,QAA0B,kBAAkB;AACtE,UAAM,SAAS,MAAM,QAAQ,eAAe,OAAO,EAAE;AAErD,WAAO,aAAa,KAAK,MAAM;AAAA,EACjC,SAAS,KAAK;AACZ,WAAO,uBAAuB,KAAK,gBAAgB;AAAA,EACrD;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,MACb,MAAM,CAAC,KAAK;AAAA,MACZ,WAAW,CAAC,EAAE,QAAQ,KAAK,aAAa,4BAA4B,CAAC;AAAA,MACrE,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,eAAe;AAAA,QAC3C,EAAE,QAAQ,KAAK,aAAa,mBAAmB;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|