@de-otio/trellis 0.6.1 → 0.7.1
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/env.d.ts +21 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +12 -0
- package/dist/env.js.map +1 -1
- package/dist/lambda/nightly-cron.d.ts.map +1 -1
- package/dist/lambda/nightly-cron.js +5 -2
- package/dist/lambda/nightly-cron.js.map +1 -1
- package/dist/lambda/post-confirmation.d.ts +30 -0
- package/dist/lambda/post-confirmation.d.ts.map +1 -1
- package/dist/lambda/post-confirmation.js +333 -29
- package/dist/lambda/post-confirmation.js.map +1 -1
- package/dist/lambda/pre-token-generation.d.ts +20 -0
- package/dist/lambda/pre-token-generation.d.ts.map +1 -1
- package/dist/lambda/pre-token-generation.js +233 -48
- package/dist/lambda/pre-token-generation.js.map +1 -1
- package/dist/lib/activitypub/activity-processor.d.ts.map +1 -1
- package/dist/lib/activitypub/activity-processor.js +2 -1
- package/dist/lib/activitypub/activity-processor.js.map +1 -1
- package/dist/lib/activitypub/group-service.d.ts +2 -2
- package/dist/lib/activitypub/group-service.d.ts.map +1 -1
- package/dist/lib/activitypub/group-service.js +5 -2
- package/dist/lib/activitypub/group-service.js.map +1 -1
- package/dist/lib/age-tier-transition.d.ts.map +1 -1
- package/dist/lib/age-tier-transition.js +19 -10
- package/dist/lib/age-tier-transition.js.map +1 -1
- package/dist/lib/audit/csv-export.d.ts +25 -0
- package/dist/lib/audit/csv-export.d.ts.map +1 -0
- package/dist/lib/audit/csv-export.js +54 -0
- package/dist/lib/audit/csv-export.js.map +1 -0
- package/dist/lib/audit/emit.d.ts +56 -0
- package/dist/lib/audit/emit.d.ts.map +1 -0
- package/dist/lib/audit/emit.js +124 -0
- package/dist/lib/audit/emit.js.map +1 -0
- package/dist/lib/audit/event-types.d.ts +36 -0
- package/dist/lib/audit/event-types.d.ts.map +1 -0
- package/dist/lib/audit/event-types.js +69 -0
- package/dist/lib/audit/event-types.js.map +1 -0
- package/dist/lib/audit/pii-filter.d.ts +22 -0
- package/dist/lib/audit/pii-filter.d.ts.map +1 -0
- package/dist/lib/audit/pii-filter.js +51 -0
- package/dist/lib/audit/pii-filter.js.map +1 -0
- package/dist/lib/audit-logger.js +1 -1
- package/dist/lib/audit-logger.js.map +1 -1
- package/dist/lib/auth/auth-context.d.ts +34 -0
- package/dist/lib/auth/auth-context.d.ts.map +1 -0
- package/dist/lib/auth/auth-context.js +10 -0
- package/dist/lib/auth/auth-context.js.map +1 -0
- package/dist/lib/auth/auth-middleware.d.ts +50 -0
- package/dist/lib/auth/auth-middleware.d.ts.map +1 -0
- package/dist/lib/auth/auth-middleware.js +153 -0
- package/dist/lib/auth/auth-middleware.js.map +1 -0
- package/dist/lib/auth/capabilities.d.ts +40 -0
- package/dist/lib/auth/capabilities.d.ts.map +1 -0
- package/dist/lib/auth/capabilities.js +44 -0
- package/dist/lib/auth/capabilities.js.map +1 -0
- package/dist/lib/auth/claims-cache.d.ts +70 -0
- package/dist/lib/auth/claims-cache.d.ts.map +1 -0
- package/dist/lib/auth/claims-cache.js +139 -0
- package/dist/lib/auth/claims-cache.js.map +1 -0
- package/dist/lib/auth/cognito-jwt.d.ts +6 -0
- package/dist/lib/auth/cognito-jwt.d.ts.map +1 -1
- package/dist/lib/auth/cognito-jwt.js.map +1 -1
- package/dist/lib/auth/idp-redirect-builder.d.ts +43 -0
- package/dist/lib/auth/idp-redirect-builder.d.ts.map +1 -0
- package/dist/lib/auth/idp-redirect-builder.js +48 -0
- package/dist/lib/auth/idp-redirect-builder.js.map +1 -0
- package/dist/lib/auth/require.d.ts +51 -0
- package/dist/lib/auth/require.d.ts.map +1 -0
- package/dist/lib/auth/require.js +99 -0
- package/dist/lib/auth/require.js.map +1 -0
- package/dist/lib/auth/role-grants.d.ts +18 -0
- package/dist/lib/auth/role-grants.d.ts.map +1 -0
- package/dist/lib/auth/role-grants.js +62 -0
- package/dist/lib/auth/role-grants.js.map +1 -0
- package/dist/lib/cognito/idp-sdk.d.ts +80 -0
- package/dist/lib/cognito/idp-sdk.d.ts.map +1 -0
- package/dist/lib/cognito/idp-sdk.js +186 -0
- package/dist/lib/cognito/idp-sdk.js.map +1 -0
- package/dist/lib/cognito/issuer-probe.d.ts +47 -0
- package/dist/lib/cognito/issuer-probe.d.ts.map +1 -0
- package/dist/lib/cognito/issuer-probe.js +319 -0
- package/dist/lib/cognito/issuer-probe.js.map +1 -0
- package/dist/lib/comment-handler.d.ts +7 -7
- package/dist/lib/comment-handler.d.ts.map +1 -1
- package/dist/lib/comment-handler.js +23 -20
- package/dist/lib/comment-handler.js.map +1 -1
- package/dist/lib/compliance/baseline.d.ts +15 -0
- package/dist/lib/compliance/baseline.d.ts.map +1 -0
- package/dist/lib/compliance/baseline.js +205 -0
- package/dist/lib/compliance/baseline.js.map +1 -0
- package/dist/lib/compliance/tenant-merge.d.ts +35 -0
- package/dist/lib/compliance/tenant-merge.d.ts.map +1 -0
- package/dist/lib/compliance/tenant-merge.js +80 -0
- package/dist/lib/compliance/tenant-merge.js.map +1 -0
- package/dist/lib/compliance/types.d.ts +135 -0
- package/dist/lib/compliance/types.d.ts.map +1 -0
- package/dist/lib/compliance/types.js +9 -0
- package/dist/lib/compliance/types.js.map +1 -0
- package/dist/lib/connection-code-handler.d.ts +4 -4
- package/dist/lib/connection-code-handler.d.ts.map +1 -1
- package/dist/lib/connection-code-handler.js +21 -11
- package/dist/lib/connection-code-handler.js.map +1 -1
- package/dist/lib/feed-handler.d.ts +2 -2
- package/dist/lib/feed-handler.d.ts.map +1 -1
- package/dist/lib/feed-handler.js +5 -9
- package/dist/lib/feed-handler.js.map +1 -1
- package/dist/lib/middleware/idempotency-store.d.ts +86 -0
- package/dist/lib/middleware/idempotency-store.d.ts.map +1 -0
- package/dist/lib/middleware/idempotency-store.js +109 -0
- package/dist/lib/middleware/idempotency-store.js.map +1 -0
- package/dist/lib/middleware/idempotency.d.ts +37 -0
- package/dist/lib/middleware/idempotency.d.ts.map +1 -0
- package/dist/lib/middleware/idempotency.js +358 -0
- package/dist/lib/middleware/idempotency.js.map +1 -0
- package/dist/lib/net/trusted-client-ip.d.ts +39 -0
- package/dist/lib/net/trusted-client-ip.d.ts.map +1 -0
- package/dist/lib/net/trusted-client-ip.js +100 -0
- package/dist/lib/net/trusted-client-ip.js.map +1 -0
- package/dist/lib/notification-handler.d.ts +5 -5
- package/dist/lib/notification-handler.d.ts.map +1 -1
- package/dist/lib/notification-handler.js +11 -9
- package/dist/lib/notification-handler.js.map +1 -1
- package/dist/lib/oauth/cognito-issuer.d.ts +34 -0
- package/dist/lib/oauth/cognito-issuer.d.ts.map +1 -0
- package/dist/lib/oauth/cognito-issuer.js +53 -0
- package/dist/lib/oauth/cognito-issuer.js.map +1 -0
- package/dist/lib/oauth/device-authorization.d.ts +145 -0
- package/dist/lib/oauth/device-authorization.d.ts.map +1 -0
- package/dist/lib/oauth/device-authorization.js +312 -0
- package/dist/lib/oauth/device-authorization.js.map +1 -0
- package/dist/lib/oauth/envelope-crypto.d.ts +101 -0
- package/dist/lib/oauth/envelope-crypto.d.ts.map +1 -0
- package/dist/lib/oauth/envelope-crypto.js +223 -0
- package/dist/lib/oauth/envelope-crypto.js.map +1 -0
- package/dist/lib/oauth/refresh-detection.d.ts +126 -0
- package/dist/lib/oauth/refresh-detection.d.ts.map +1 -0
- package/dist/lib/oauth/refresh-detection.js +248 -0
- package/dist/lib/oauth/refresh-detection.js.map +1 -0
- package/dist/lib/openapi/generator.d.ts +78 -0
- package/dist/lib/openapi/generator.d.ts.map +1 -0
- package/dist/lib/openapi/generator.js +201 -0
- package/dist/lib/openapi/generator.js.map +1 -0
- package/dist/lib/post-handler.d.ts +1 -1
- package/dist/lib/post-handler.d.ts.map +1 -1
- package/dist/lib/post-handler.js +4 -15
- package/dist/lib/post-handler.js.map +1 -1
- package/dist/lib/rate-limit.d.ts.map +1 -1
- package/dist/lib/rate-limit.js +11 -3
- package/dist/lib/rate-limit.js.map +1 -1
- package/dist/lib/routes/agent-authorize.d.ts +32 -0
- package/dist/lib/routes/agent-authorize.d.ts.map +1 -0
- package/dist/lib/routes/agent-authorize.js +479 -0
- package/dist/lib/routes/agent-authorize.js.map +1 -0
- package/dist/lib/routes/agent-sessions.d.ts +20 -0
- package/dist/lib/routes/agent-sessions.d.ts.map +1 -0
- package/dist/lib/routes/agent-sessions.js +124 -0
- package/dist/lib/routes/agent-sessions.js.map +1 -0
- package/dist/lib/routes/agent-surface.d.ts +37 -0
- package/dist/lib/routes/agent-surface.d.ts.map +1 -0
- package/dist/lib/routes/agent-surface.js +208 -0
- package/dist/lib/routes/agent-surface.js.map +1 -0
- package/dist/lib/routes/auth-discover.d.ts +18 -0
- package/dist/lib/routes/auth-discover.d.ts.map +1 -0
- package/dist/lib/routes/auth-discover.js +177 -0
- package/dist/lib/routes/auth-discover.js.map +1 -0
- package/dist/lib/routes/comments.d.ts.map +1 -1
- package/dist/lib/routes/comments.js +36 -7
- package/dist/lib/routes/comments.js.map +1 -1
- package/dist/lib/routes/connection-codes.d.ts.map +1 -1
- package/dist/lib/routes/connection-codes.js +21 -4
- package/dist/lib/routes/connection-codes.js.map +1 -1
- package/dist/lib/routes/content-discovery.d.ts.map +1 -1
- package/dist/lib/routes/content-discovery.js +18 -13
- package/dist/lib/routes/content-discovery.js.map +1 -1
- package/dist/lib/routes/dashboard.js +1 -1
- package/dist/lib/routes/dashboard.js.map +1 -1
- package/dist/lib/routes/employees.d.ts.map +1 -1
- package/dist/lib/routes/employees.js +57 -15
- package/dist/lib/routes/employees.js.map +1 -1
- package/dist/lib/routes/entities.d.ts.map +1 -1
- package/dist/lib/routes/entities.js +35 -19
- package/dist/lib/routes/entities.js.map +1 -1
- package/dist/lib/routes/errors.d.ts +34 -0
- package/dist/lib/routes/errors.d.ts.map +1 -0
- package/dist/lib/routes/errors.js +57 -0
- package/dist/lib/routes/errors.js.map +1 -0
- package/dist/lib/routes/feeds.d.ts.map +1 -1
- package/dist/lib/routes/feeds.js +12 -2
- package/dist/lib/routes/feeds.js.map +1 -1
- package/dist/lib/routes/index.d.ts.map +1 -1
- package/dist/lib/routes/index.js +50 -0
- package/dist/lib/routes/index.js.map +1 -1
- package/dist/lib/routes/mfa.d.ts.map +1 -1
- package/dist/lib/routes/mfa.js +1 -0
- package/dist/lib/routes/mfa.js.map +1 -1
- package/dist/lib/routes/notifications.d.ts.map +1 -1
- package/dist/lib/routes/notifications.js +21 -4
- package/dist/lib/routes/notifications.js.map +1 -1
- package/dist/lib/routes/oauth.d.ts +15 -0
- package/dist/lib/routes/oauth.d.ts.map +1 -0
- package/dist/lib/routes/oauth.js +139 -0
- package/dist/lib/routes/oauth.js.map +1 -0
- package/dist/lib/routes/posts.d.ts.map +1 -1
- package/dist/lib/routes/posts.js +30 -19
- package/dist/lib/routes/posts.js.map +1 -1
- package/dist/lib/routes/products.d.ts.map +1 -1
- package/dist/lib/routes/products.js +19 -22
- package/dist/lib/routes/products.js.map +1 -1
- package/dist/lib/routes/setup-status.d.ts +34 -0
- package/dist/lib/routes/setup-status.d.ts.map +1 -0
- package/dist/lib/routes/setup-status.js +87 -0
- package/dist/lib/routes/setup-status.js.map +1 -0
- package/dist/lib/routes/taxonomy-analytics.d.ts.map +1 -1
- package/dist/lib/routes/taxonomy-analytics.js +15 -14
- package/dist/lib/routes/taxonomy-analytics.js.map +1 -1
- package/dist/lib/routes/taxonomy.d.ts.map +1 -1
- package/dist/lib/routes/taxonomy.js +19 -16
- package/dist/lib/routes/taxonomy.js.map +1 -1
- package/dist/lib/routes/tenant-audit.d.ts +19 -0
- package/dist/lib/routes/tenant-audit.d.ts.map +1 -0
- package/dist/lib/routes/tenant-audit.js +244 -0
- package/dist/lib/routes/tenant-audit.js.map +1 -0
- package/dist/lib/routes/tenant-compliance.d.ts +21 -0
- package/dist/lib/routes/tenant-compliance.d.ts.map +1 -0
- package/dist/lib/routes/tenant-compliance.js +122 -0
- package/dist/lib/routes/tenant-compliance.js.map +1 -0
- package/dist/lib/routes/tenant-domains.d.ts +11 -0
- package/dist/lib/routes/tenant-domains.d.ts.map +1 -0
- package/dist/lib/routes/tenant-domains.js +95 -0
- package/dist/lib/routes/tenant-domains.js.map +1 -0
- package/dist/lib/routes/tenant-idp.d.ts +3 -0
- package/dist/lib/routes/tenant-idp.d.ts.map +1 -0
- package/dist/lib/routes/tenant-idp.js +89 -0
- package/dist/lib/routes/tenant-idp.js.map +1 -0
- package/dist/lib/routes/tenant-members.d.ts +13 -0
- package/dist/lib/routes/tenant-members.d.ts.map +1 -0
- package/dist/lib/routes/tenant-members.js +75 -0
- package/dist/lib/routes/tenant-members.js.map +1 -0
- package/dist/lib/routes/tenant-role-mappings.d.ts +11 -0
- package/dist/lib/routes/tenant-role-mappings.d.ts.map +1 -0
- package/dist/lib/routes/tenant-role-mappings.js +90 -0
- package/dist/lib/routes/tenant-role-mappings.js.map +1 -0
- package/dist/lib/routes/tenants.d.ts +13 -0
- package/dist/lib/routes/tenants.d.ts.map +1 -0
- package/dist/lib/routes/tenants.js +121 -0
- package/dist/lib/routes/tenants.js.map +1 -0
- package/dist/lib/routes/types.d.ts +9 -0
- package/dist/lib/routes/types.d.ts.map +1 -1
- package/dist/lib/schemas.d.ts +2 -2
- package/dist/lib/secrets/idp-secrets.d.ts +51 -0
- package/dist/lib/secrets/idp-secrets.d.ts.map +1 -0
- package/dist/lib/secrets/idp-secrets.js +111 -0
- package/dist/lib/secrets/idp-secrets.js.map +1 -0
- package/dist/lib/security-monitor.d.ts.map +1 -1
- package/dist/lib/security-monitor.js +6 -1
- package/dist/lib/security-monitor.js.map +1 -1
- package/dist/lib/session-manager.d.ts +1 -0
- package/dist/lib/session-manager.d.ts.map +1 -1
- package/dist/lib/session-manager.js.map +1 -1
- package/dist/lib/taxonomy-handler-factory.d.ts +4 -2
- package/dist/lib/taxonomy-handler-factory.d.ts.map +1 -1
- package/dist/lib/taxonomy-handler-factory.js +8 -7
- package/dist/lib/taxonomy-handler-factory.js.map +1 -1
- package/dist/lib/tenant/audit-emit.d.ts +18 -0
- package/dist/lib/tenant/audit-emit.d.ts.map +1 -0
- package/dist/lib/tenant/audit-emit.js +16 -0
- package/dist/lib/tenant/audit-emit.js.map +1 -0
- package/dist/lib/tenant/derive-domain.d.ts +19 -0
- package/dist/lib/tenant/derive-domain.d.ts.map +1 -0
- package/dist/lib/tenant/derive-domain.js +38 -0
- package/dist/lib/tenant/derive-domain.js.map +1 -0
- package/dist/lib/tenant/domain-handler.d.ts +42 -0
- package/dist/lib/tenant/domain-handler.d.ts.map +1 -0
- package/dist/lib/tenant/domain-handler.js +344 -0
- package/dist/lib/tenant/domain-handler.js.map +1 -0
- package/dist/lib/tenant/domain-validator.d.ts +28 -0
- package/dist/lib/tenant/domain-validator.d.ts.map +1 -0
- package/dist/lib/tenant/domain-validator.js +145 -0
- package/dist/lib/tenant/domain-validator.js.map +1 -0
- package/dist/lib/tenant/domain-verifier.d.ts +30 -0
- package/dist/lib/tenant/domain-verifier.d.ts.map +1 -0
- package/dist/lib/tenant/domain-verifier.js +53 -0
- package/dist/lib/tenant/domain-verifier.js.map +1 -0
- package/dist/lib/tenant/idp-handler.d.ts +29 -0
- package/dist/lib/tenant/idp-handler.d.ts.map +1 -0
- package/dist/lib/tenant/idp-handler.js +693 -0
- package/dist/lib/tenant/idp-handler.js.map +1 -0
- package/dist/lib/tenant/idp-name.d.ts +2 -0
- package/dist/lib/tenant/idp-name.d.ts.map +1 -0
- package/dist/lib/tenant/idp-name.js +20 -0
- package/dist/lib/tenant/idp-name.js.map +1 -0
- package/dist/lib/tenant/member-handler.d.ts +31 -0
- package/dist/lib/tenant/member-handler.d.ts.map +1 -0
- package/dist/lib/tenant/member-handler.js +343 -0
- package/dist/lib/tenant/member-handler.js.map +1 -0
- package/dist/lib/tenant/reserved-slugs.d.ts +37 -0
- package/dist/lib/tenant/reserved-slugs.d.ts.map +1 -0
- package/dist/lib/tenant/reserved-slugs.js +116 -0
- package/dist/lib/tenant/reserved-slugs.js.map +1 -0
- package/dist/lib/tenant/resolve-role.d.ts +39 -0
- package/dist/lib/tenant/resolve-role.d.ts.map +1 -0
- package/dist/lib/tenant/resolve-role.js +60 -0
- package/dist/lib/tenant/resolve-role.js.map +1 -0
- package/dist/lib/tenant/role-mapping-handler.d.ts +26 -0
- package/dist/lib/tenant/role-mapping-handler.d.ts.map +1 -0
- package/dist/lib/tenant/role-mapping-handler.js +260 -0
- package/dist/lib/tenant/role-mapping-handler.js.map +1 -0
- package/dist/lib/tenant/setup-status.d.ts +83 -0
- package/dist/lib/tenant/setup-status.d.ts.map +1 -0
- package/dist/lib/tenant/setup-status.js +201 -0
- package/dist/lib/tenant/setup-status.js.map +1 -0
- package/dist/lib/tenant/slug-validator.d.ts +31 -0
- package/dist/lib/tenant/slug-validator.d.ts.map +1 -0
- package/dist/lib/tenant/slug-validator.js +42 -0
- package/dist/lib/tenant/slug-validator.js.map +1 -0
- package/dist/lib/tenant/tenant-handler.d.ts +49 -0
- package/dist/lib/tenant/tenant-handler.d.ts.map +1 -0
- package/dist/lib/tenant/tenant-handler.js +377 -0
- package/dist/lib/tenant/tenant-handler.js.map +1 -0
- package/dist/lib/tenant/transfer-ownership.d.ts +39 -0
- package/dist/lib/tenant/transfer-ownership.d.ts.map +1 -0
- package/dist/lib/tenant/transfer-ownership.js +66 -0
- package/dist/lib/tenant/transfer-ownership.js.map +1 -0
- package/dist/lib/user/derive-handle.d.ts +29 -0
- package/dist/lib/user/derive-handle.d.ts.map +1 -0
- package/dist/lib/user/derive-handle.js +65 -0
- package/dist/lib/user/derive-handle.js.map +1 -0
- package/dist/lib/user-deprovisioning.d.ts +11 -1
- package/dist/lib/user-deprovisioning.d.ts.map +1 -1
- package/dist/lib/user-deprovisioning.js +46 -2
- package/dist/lib/user-deprovisioning.js.map +1 -1
- package/dist/lib/validation/feature-toggle-schemas.d.ts +10 -10
- package/package.json +7 -5
- package/prisma/migrations/20260502094501_add_tenancy_model/migration.sql +334 -0
- package/prisma/migrations/20260503000000_add_tenant_region/migration.sql +4 -0
- package/prisma/schema.prisma +324 -74
- package/src/lambda/nightly-cron.ts +4 -1
- package/src/lambda/post-confirmation.ts +405 -29
- package/src/lambda/pre-token-generation.ts +300 -59
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.IdpHandler = void 0;
|
|
37
|
+
const client_cognito_identity_provider_1 = require("@aws-sdk/client-cognito-identity-provider");
|
|
38
|
+
const auth_middleware_1 = require("../auth/auth-middleware");
|
|
39
|
+
const require_1 = require("../auth/require");
|
|
40
|
+
const claims_cache_1 = require("../auth/claims-cache");
|
|
41
|
+
const emit_1 = require("../audit/emit");
|
|
42
|
+
const event_types_1 = require("../audit/event-types");
|
|
43
|
+
const idp_name_1 = require("./idp-name");
|
|
44
|
+
const idp_sdk_1 = require("../cognito/idp-sdk");
|
|
45
|
+
const issuer_probe_1 = require("../cognito/issuer-probe");
|
|
46
|
+
const idp_secrets_1 = require("../secrets/idp-secrets");
|
|
47
|
+
const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
|
|
48
|
+
const JSON_HEADERS = { "content-type": "application/json" };
|
|
49
|
+
function jsonResponse(status, body) {
|
|
50
|
+
return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS });
|
|
51
|
+
}
|
|
52
|
+
function badRequest(message, code = "VALIDATION_ERROR") {
|
|
53
|
+
return jsonResponse(400, { error: code, message });
|
|
54
|
+
}
|
|
55
|
+
function unprocessable(message, remediation) {
|
|
56
|
+
return jsonResponse(422, {
|
|
57
|
+
error: "UNPROCESSABLE",
|
|
58
|
+
message,
|
|
59
|
+
...(remediation ? { remediation } : {}),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function badGateway() {
|
|
63
|
+
return jsonResponse(502, {
|
|
64
|
+
error: "COGNITO_ERROR",
|
|
65
|
+
message: "Identity-provider service is unavailable. Try again in a few minutes.",
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function notFound() {
|
|
69
|
+
return jsonResponse(404, { error: "NOT_FOUND", message: "Identity provider not found" });
|
|
70
|
+
}
|
|
71
|
+
const auditEmitter = new emit_1.AuditEventEmitter();
|
|
72
|
+
class IdpHandler {
|
|
73
|
+
deps;
|
|
74
|
+
constructor(deps = {}) {
|
|
75
|
+
this.deps = deps;
|
|
76
|
+
}
|
|
77
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
78
|
+
getIdp(env) {
|
|
79
|
+
if (this.deps.idp)
|
|
80
|
+
return this.deps.idp;
|
|
81
|
+
return new idp_sdk_1.CognitoIdpSdk(new client_cognito_identity_provider_1.CognitoIdentityProviderClient({
|
|
82
|
+
region: env.COGNITO_REGION ?? process.env.AWS_REGION,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
getSecrets(env) {
|
|
86
|
+
if (this.deps.secrets)
|
|
87
|
+
return this.deps.secrets;
|
|
88
|
+
return new idp_secrets_1.IdpSecretsClient(new client_secrets_manager_1.SecretsManagerClient({
|
|
89
|
+
region: env.COGNITO_REGION ?? process.env.AWS_REGION,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
async invalidateAllMemberClaims(tenantId, env) {
|
|
93
|
+
const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
|
|
94
|
+
const db = createPrisma(env);
|
|
95
|
+
const members = await db.tenantMember.findMany({
|
|
96
|
+
where: { tenantId },
|
|
97
|
+
select: { user: { select: { cognitoSub: true } } },
|
|
98
|
+
});
|
|
99
|
+
const subs = members.map((m) => m.user.cognitoSub).filter((s) => !!s);
|
|
100
|
+
if (this.deps.invalidateClaimsForSubs) {
|
|
101
|
+
await this.deps.invalidateClaimsForSubs(subs);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (subs.length === 0)
|
|
105
|
+
return;
|
|
106
|
+
try {
|
|
107
|
+
const cache = (0, claims_cache_1.createClaimsCacheFromEnv)();
|
|
108
|
+
await Promise.all(subs.map((s) => cache.invalidate(s).catch(() => undefined)));
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
console.warn(JSON.stringify({
|
|
112
|
+
level: "warn",
|
|
113
|
+
msg: "claims-cache invalidate-all failed",
|
|
114
|
+
tenantId,
|
|
115
|
+
error: String(err),
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// ── POST ───────────────────────────────────────────────────────────────────
|
|
120
|
+
async handleCreate(tenantId, request, auth, env) {
|
|
121
|
+
const denied = (0, auth_middleware_1.requireActiveTenant)(auth, tenantId) ??
|
|
122
|
+
(0, require_1.requireCapability)(auth, require_1.Capability.IdpConfigure);
|
|
123
|
+
if (denied)
|
|
124
|
+
return denied;
|
|
125
|
+
const { z } = await Promise.resolve().then(() => __importStar(require("zod")));
|
|
126
|
+
let raw;
|
|
127
|
+
try {
|
|
128
|
+
raw = await request.json();
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return badRequest("Body must be valid JSON", "INVALID_JSON");
|
|
132
|
+
}
|
|
133
|
+
const kind = raw?.kind;
|
|
134
|
+
if (kind === "SAML") {
|
|
135
|
+
return jsonResponse(501, {
|
|
136
|
+
error: "SAML_NOT_AVAILABLE_IN_MVP",
|
|
137
|
+
message: "SAML identity providers are not available in MVP. Use OIDC.",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (kind !== "OIDC") {
|
|
141
|
+
return badRequest("kind must be 'OIDC'");
|
|
142
|
+
}
|
|
143
|
+
const schema = z.object({
|
|
144
|
+
kind: z.literal("OIDC"),
|
|
145
|
+
issuerUrl: z.string().url().max(2048),
|
|
146
|
+
clientId: z.string().min(1).max(512),
|
|
147
|
+
clientSecret: z.string().min(1).max(2048),
|
|
148
|
+
defaultRole: z.enum(["ADMIN", "MEMBER", "GUEST"]).optional(),
|
|
149
|
+
scopes: z.string().max(1024).optional(),
|
|
150
|
+
attributeMapping: z.record(z.string(), z.string()).optional(),
|
|
151
|
+
});
|
|
152
|
+
const parsed = schema.safeParse(raw);
|
|
153
|
+
if (!parsed.success) {
|
|
154
|
+
return badRequest(parsed.error.issues[0]?.message ?? "Invalid input");
|
|
155
|
+
}
|
|
156
|
+
const body = parsed.data;
|
|
157
|
+
const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
|
|
158
|
+
const db = createPrisma(env);
|
|
159
|
+
const tenant = await db.tenant.findUnique({
|
|
160
|
+
where: { id: tenantId },
|
|
161
|
+
select: { id: true },
|
|
162
|
+
});
|
|
163
|
+
if (!tenant)
|
|
164
|
+
return notFound();
|
|
165
|
+
const verifiedDomains = await db.tenantDomain.findMany({
|
|
166
|
+
where: { tenantId, verifiedAt: { not: null } },
|
|
167
|
+
select: { domain: true },
|
|
168
|
+
orderBy: { domain: "asc" },
|
|
169
|
+
});
|
|
170
|
+
if (verifiedDomains.length === 0) {
|
|
171
|
+
return unprocessable("Tenant must have at least one verified domain before connecting an IdP", `POST /api/tenants/${tenantId}/domains`);
|
|
172
|
+
}
|
|
173
|
+
const existing = await db.tenantIdentityProvider.findUnique({
|
|
174
|
+
where: { tenantId },
|
|
175
|
+
select: { id: true },
|
|
176
|
+
});
|
|
177
|
+
if (existing) {
|
|
178
|
+
return jsonResponse(409, {
|
|
179
|
+
error: "IDP_EXISTS",
|
|
180
|
+
message: "Tenant already has an identity provider",
|
|
181
|
+
remediation: `PATCH or DELETE /api/tenants/${tenantId}/identity-provider`,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const probe = await (0, issuer_probe_1.probeOidcIssuer)(body.issuerUrl);
|
|
185
|
+
if (!probe.ok) {
|
|
186
|
+
return jsonResponse(422, {
|
|
187
|
+
error: "ISSUER_UNREACHABLE",
|
|
188
|
+
message: probe.message,
|
|
189
|
+
reason: probe.reason,
|
|
190
|
+
remediation: "Confirm the issuer URL hosts a valid OIDC discovery document at /.well-known/openid-configuration",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const userPoolId = env.COGNITO_USER_POOL_ID;
|
|
194
|
+
const userPoolClientId = env.COGNITO_APP_CLIENT_ID;
|
|
195
|
+
if (!userPoolId || !userPoolClientId) {
|
|
196
|
+
return badGateway();
|
|
197
|
+
}
|
|
198
|
+
const providerName = (0, idp_name_1.cognitoIdpName)(tenantId);
|
|
199
|
+
const attributeMapping = {
|
|
200
|
+
...(0, idp_sdk_1.defaultOidcAttributeMapping)(),
|
|
201
|
+
...(body.attributeMapping ?? {}),
|
|
202
|
+
};
|
|
203
|
+
const idpIdentifiers = verifiedDomains.map((d) => d.domain);
|
|
204
|
+
const secrets = this.getSecrets(env);
|
|
205
|
+
const idp = this.getIdp(env);
|
|
206
|
+
let secretArn;
|
|
207
|
+
try {
|
|
208
|
+
const secret = await secrets.create(tenantId, body.clientSecret);
|
|
209
|
+
secretArn = secret.arn;
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
const errName = err.name;
|
|
213
|
+
if (errName === "ResourceExistsException") {
|
|
214
|
+
return jsonResponse(409, {
|
|
215
|
+
error: "IDP_EXISTS",
|
|
216
|
+
message: "An IdP secret already exists for this tenant",
|
|
217
|
+
remediation: `PATCH or DELETE /api/tenants/${tenantId}/identity-provider`,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
console.warn(JSON.stringify({
|
|
221
|
+
level: "warn",
|
|
222
|
+
msg: "idp-secret create failed",
|
|
223
|
+
tenantId,
|
|
224
|
+
errName,
|
|
225
|
+
}));
|
|
226
|
+
return badGateway();
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
await idp.createOidcProvider({
|
|
230
|
+
userPoolId,
|
|
231
|
+
providerName,
|
|
232
|
+
details: {
|
|
233
|
+
clientId: body.clientId,
|
|
234
|
+
clientSecret: body.clientSecret,
|
|
235
|
+
issuerUrl: body.issuerUrl,
|
|
236
|
+
...(body.scopes ? { scopes: body.scopes } : {}),
|
|
237
|
+
},
|
|
238
|
+
attributeMapping,
|
|
239
|
+
idpIdentifiers,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
await secrets.delete(tenantId).catch(() => undefined);
|
|
244
|
+
console.warn(JSON.stringify({
|
|
245
|
+
level: "warn",
|
|
246
|
+
msg: "Cognito CreateIdentityProvider failed; rolled back secret",
|
|
247
|
+
tenantId,
|
|
248
|
+
errName: err.name,
|
|
249
|
+
}));
|
|
250
|
+
return badGateway();
|
|
251
|
+
}
|
|
252
|
+
let row;
|
|
253
|
+
try {
|
|
254
|
+
// 15s — must outlast the Cognito Describe+Update round-trip held under
|
|
255
|
+
// the advisory lock; default 5s is too short and would release the
|
|
256
|
+
// lock while the Cognito mutation is still in-flight.
|
|
257
|
+
row = await db.$transaction(async (tx) => {
|
|
258
|
+
await (0, idp_sdk_1.withUserPoolClientLock)(tx, userPoolId, async () => {
|
|
259
|
+
await idp.setSupportedIdentityProvider(userPoolId, userPoolClientId, providerName, "add");
|
|
260
|
+
});
|
|
261
|
+
return tx.tenantIdentityProvider.create({
|
|
262
|
+
data: {
|
|
263
|
+
tenantId,
|
|
264
|
+
kind: "OIDC",
|
|
265
|
+
cognitoIdpName: providerName,
|
|
266
|
+
issuerUrl: body.issuerUrl,
|
|
267
|
+
clientId: body.clientId,
|
|
268
|
+
clientSecretArn: secretArn,
|
|
269
|
+
scopes: body.scopes ?? "openid email profile groups",
|
|
270
|
+
attributeMapping: attributeMapping,
|
|
271
|
+
defaultRole: body.defaultRole ?? null,
|
|
272
|
+
status: "ACTIVE",
|
|
273
|
+
enabledAt: new Date(),
|
|
274
|
+
},
|
|
275
|
+
select: {
|
|
276
|
+
id: true,
|
|
277
|
+
tenantId: true,
|
|
278
|
+
kind: true,
|
|
279
|
+
status: true,
|
|
280
|
+
cognitoIdpName: true,
|
|
281
|
+
issuerUrl: true,
|
|
282
|
+
clientId: true,
|
|
283
|
+
defaultRole: true,
|
|
284
|
+
attributeMapping: true,
|
|
285
|
+
scopes: true,
|
|
286
|
+
enabledAt: true,
|
|
287
|
+
createdAt: true,
|
|
288
|
+
updatedAt: true,
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
}, { timeout: 15000 });
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
await idp.deleteProvider(userPoolId, providerName).catch(() => undefined);
|
|
295
|
+
await secrets.delete(tenantId).catch(() => undefined);
|
|
296
|
+
console.warn(JSON.stringify({
|
|
297
|
+
level: "warn",
|
|
298
|
+
msg: "RDS commit failed; rolled back Cognito + secret",
|
|
299
|
+
tenantId,
|
|
300
|
+
errName: err.name,
|
|
301
|
+
}));
|
|
302
|
+
return badGateway();
|
|
303
|
+
}
|
|
304
|
+
void auditEmitter
|
|
305
|
+
.emit({
|
|
306
|
+
type: event_types_1.AuditEventType.TENANT_IDP_CONNECTED,
|
|
307
|
+
tenantId,
|
|
308
|
+
actorUserId: auth.userId,
|
|
309
|
+
payload: {
|
|
310
|
+
idpKind: "OIDC",
|
|
311
|
+
issuer: body.issuerUrl,
|
|
312
|
+
idpStatus: "ACTIVE",
|
|
313
|
+
},
|
|
314
|
+
}, db)
|
|
315
|
+
.catch((err) => console.warn(JSON.stringify({
|
|
316
|
+
event: "audit.emit_failed",
|
|
317
|
+
error: err?.message ?? "unknown",
|
|
318
|
+
})));
|
|
319
|
+
return jsonResponse(201, formatIdpRecord(row));
|
|
320
|
+
}
|
|
321
|
+
// ── GET ────────────────────────────────────────────────────────────────────
|
|
322
|
+
async handleGet(tenantId, auth, env) {
|
|
323
|
+
const denied = (0, auth_middleware_1.requireOwnTenant)(auth, tenantId) ??
|
|
324
|
+
(0, require_1.requireCapability)(auth, require_1.Capability.IdpView);
|
|
325
|
+
if (denied)
|
|
326
|
+
return denied;
|
|
327
|
+
const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
|
|
328
|
+
const db = createPrisma(env);
|
|
329
|
+
const row = await db.tenantIdentityProvider.findUnique({
|
|
330
|
+
where: { tenantId },
|
|
331
|
+
select: {
|
|
332
|
+
id: true,
|
|
333
|
+
tenantId: true,
|
|
334
|
+
kind: true,
|
|
335
|
+
status: true,
|
|
336
|
+
cognitoIdpName: true,
|
|
337
|
+
issuerUrl: true,
|
|
338
|
+
clientId: true,
|
|
339
|
+
defaultRole: true,
|
|
340
|
+
attributeMapping: true,
|
|
341
|
+
scopes: true,
|
|
342
|
+
enabledAt: true,
|
|
343
|
+
createdAt: true,
|
|
344
|
+
updatedAt: true,
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
if (!row)
|
|
348
|
+
return notFound();
|
|
349
|
+
return jsonResponse(200, formatIdpRecord(row));
|
|
350
|
+
}
|
|
351
|
+
// ── PATCH ──────────────────────────────────────────────────────────────────
|
|
352
|
+
async handlePatch(tenantId, request, auth, env) {
|
|
353
|
+
const denied = (0, auth_middleware_1.requireActiveTenant)(auth, tenantId) ??
|
|
354
|
+
(0, require_1.requireCapability)(auth, require_1.Capability.IdpConfigure);
|
|
355
|
+
if (denied)
|
|
356
|
+
return denied;
|
|
357
|
+
const { z } = await Promise.resolve().then(() => __importStar(require("zod")));
|
|
358
|
+
let raw;
|
|
359
|
+
try {
|
|
360
|
+
raw = await request.json();
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
return badRequest("Body must be valid JSON", "INVALID_JSON");
|
|
364
|
+
}
|
|
365
|
+
const isStatus = typeof raw?.status === "string";
|
|
366
|
+
if (isStatus) {
|
|
367
|
+
const schema = z.object({ status: z.enum(["ACTIVE", "DISABLED"]) });
|
|
368
|
+
const parsed = schema.safeParse(raw);
|
|
369
|
+
if (!parsed.success) {
|
|
370
|
+
return badRequest("status must be ACTIVE or DISABLED");
|
|
371
|
+
}
|
|
372
|
+
return this.applyStatus(tenantId, parsed.data, auth, env);
|
|
373
|
+
}
|
|
374
|
+
const schema = z.object({
|
|
375
|
+
clientSecret: z.string().min(1).max(2048).optional(),
|
|
376
|
+
attributeMapping: z.record(z.string(), z.string()).optional(),
|
|
377
|
+
defaultRole: z
|
|
378
|
+
.enum(["ADMIN", "MEMBER", "GUEST"])
|
|
379
|
+
.nullable()
|
|
380
|
+
.optional(),
|
|
381
|
+
scopes: z.string().max(1024).optional(),
|
|
382
|
+
});
|
|
383
|
+
const parsed = schema.safeParse(raw);
|
|
384
|
+
if (!parsed.success) {
|
|
385
|
+
return badRequest(parsed.error.issues[0]?.message ?? "Invalid input");
|
|
386
|
+
}
|
|
387
|
+
const body = parsed.data;
|
|
388
|
+
if (body.clientSecret === undefined &&
|
|
389
|
+
body.attributeMapping === undefined &&
|
|
390
|
+
body.defaultRole === undefined &&
|
|
391
|
+
body.scopes === undefined) {
|
|
392
|
+
return badRequest("At least one of clientSecret, attributeMapping, defaultRole or scopes is required");
|
|
393
|
+
}
|
|
394
|
+
return this.applyConfig(tenantId, body, auth, env);
|
|
395
|
+
}
|
|
396
|
+
async applyStatus(tenantId, body, auth, env) {
|
|
397
|
+
const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
|
|
398
|
+
const db = createPrisma(env);
|
|
399
|
+
const row = await db.tenantIdentityProvider.findUnique({
|
|
400
|
+
where: { tenantId },
|
|
401
|
+
select: { id: true, status: true, cognitoIdpName: true },
|
|
402
|
+
});
|
|
403
|
+
if (!row)
|
|
404
|
+
return notFound();
|
|
405
|
+
if (row.status === body.status) {
|
|
406
|
+
return jsonResponse(200, { id: row.id, status: row.status, unchanged: true });
|
|
407
|
+
}
|
|
408
|
+
const userPoolId = env.COGNITO_USER_POOL_ID;
|
|
409
|
+
const userPoolClientId = env.COGNITO_APP_CLIENT_ID;
|
|
410
|
+
if (!userPoolId || !userPoolClientId)
|
|
411
|
+
return badGateway();
|
|
412
|
+
const idp = this.getIdp(env);
|
|
413
|
+
const op = body.status === "ACTIVE" ? "add" : "remove";
|
|
414
|
+
try {
|
|
415
|
+
// 15s — see handleCreate; the Cognito Describe+Update under the
|
|
416
|
+
// advisory lock can exceed Prisma's default 5s.
|
|
417
|
+
await db.$transaction(async (tx) => {
|
|
418
|
+
await (0, idp_sdk_1.withUserPoolClientLock)(tx, userPoolId, async () => {
|
|
419
|
+
await idp.setSupportedIdentityProvider(userPoolId, userPoolClientId, row.cognitoIdpName, op);
|
|
420
|
+
});
|
|
421
|
+
await tx.tenantIdentityProvider.update({
|
|
422
|
+
where: { id: row.id },
|
|
423
|
+
data: {
|
|
424
|
+
status: body.status,
|
|
425
|
+
...(body.status === "ACTIVE" ? { enabledAt: new Date() } : {}),
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
}, { timeout: 15000 });
|
|
429
|
+
}
|
|
430
|
+
catch (err) {
|
|
431
|
+
console.warn(JSON.stringify({
|
|
432
|
+
level: "warn",
|
|
433
|
+
msg: "IdP status toggle failed",
|
|
434
|
+
tenantId,
|
|
435
|
+
errName: err.name,
|
|
436
|
+
}));
|
|
437
|
+
return badGateway();
|
|
438
|
+
}
|
|
439
|
+
if (body.status === "DISABLED") {
|
|
440
|
+
await this.invalidateAllMemberClaims(tenantId, env);
|
|
441
|
+
}
|
|
442
|
+
void auditEmitter
|
|
443
|
+
.emit({
|
|
444
|
+
type: body.status === "DISABLED"
|
|
445
|
+
? event_types_1.AuditEventType.TENANT_IDP_DISABLED
|
|
446
|
+
: event_types_1.AuditEventType.TENANT_IDP_MODIFIED,
|
|
447
|
+
tenantId,
|
|
448
|
+
actorUserId: auth.userId,
|
|
449
|
+
payload: { idpStatus: body.status },
|
|
450
|
+
}, db)
|
|
451
|
+
.catch((err) => console.warn(JSON.stringify({
|
|
452
|
+
event: "audit.emit_failed",
|
|
453
|
+
error: err?.message ?? "unknown",
|
|
454
|
+
})));
|
|
455
|
+
return jsonResponse(200, { id: row.id, status: body.status });
|
|
456
|
+
}
|
|
457
|
+
async applyConfig(tenantId, body, auth, env) {
|
|
458
|
+
const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
|
|
459
|
+
const db = createPrisma(env);
|
|
460
|
+
const row = await db.tenantIdentityProvider.findUnique({
|
|
461
|
+
where: { tenantId },
|
|
462
|
+
select: {
|
|
463
|
+
id: true,
|
|
464
|
+
kind: true,
|
|
465
|
+
cognitoIdpName: true,
|
|
466
|
+
attributeMapping: true,
|
|
467
|
+
scopes: true,
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
if (!row)
|
|
471
|
+
return notFound();
|
|
472
|
+
if (row.kind !== "OIDC") {
|
|
473
|
+
return jsonResponse(501, {
|
|
474
|
+
error: "SAML_NOT_AVAILABLE_IN_MVP",
|
|
475
|
+
message: "SAML providers cannot be modified in MVP",
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
const userPoolId = env.COGNITO_USER_POOL_ID;
|
|
479
|
+
if (!userPoolId)
|
|
480
|
+
return badGateway();
|
|
481
|
+
const idp = this.getIdp(env);
|
|
482
|
+
const secrets = this.getSecrets(env);
|
|
483
|
+
const newAttributeMapping = body.attributeMapping
|
|
484
|
+
? mergeAttributeMapping(row.attributeMapping, body.attributeMapping)
|
|
485
|
+
: undefined;
|
|
486
|
+
// Cognito UpdateIdentityProvider goes first. If it fails, Secrets Manager
|
|
487
|
+
// is untouched and the old client secret remains the source of truth. The
|
|
488
|
+
// create flow is structured the other way (secret first) because the
|
|
489
|
+
// secret must exist before Cognito can reference it; rotation has no such
|
|
490
|
+
// ordering constraint.
|
|
491
|
+
try {
|
|
492
|
+
await idp.updateOidcProvider({
|
|
493
|
+
userPoolId,
|
|
494
|
+
providerName: row.cognitoIdpName,
|
|
495
|
+
...(body.clientSecret !== undefined
|
|
496
|
+
? { details: { clientSecret: body.clientSecret, ...(body.scopes ? { scopes: body.scopes } : {}) } }
|
|
497
|
+
: body.scopes
|
|
498
|
+
? { details: { scopes: body.scopes } }
|
|
499
|
+
: {}),
|
|
500
|
+
...(newAttributeMapping ? { attributeMapping: newAttributeMapping } : {}),
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
catch (err) {
|
|
504
|
+
console.warn(JSON.stringify({
|
|
505
|
+
level: "warn",
|
|
506
|
+
msg: "Cognito UpdateIdentityProvider failed",
|
|
507
|
+
tenantId,
|
|
508
|
+
errName: err.name,
|
|
509
|
+
}));
|
|
510
|
+
return badGateway();
|
|
511
|
+
}
|
|
512
|
+
if (body.clientSecret !== undefined) {
|
|
513
|
+
try {
|
|
514
|
+
await secrets.rotate(tenantId, body.clientSecret);
|
|
515
|
+
}
|
|
516
|
+
catch (err) {
|
|
517
|
+
console.warn(JSON.stringify({
|
|
518
|
+
level: "warn",
|
|
519
|
+
msg: "idp-secret rotate failed",
|
|
520
|
+
tenantId,
|
|
521
|
+
errName: err.name,
|
|
522
|
+
}));
|
|
523
|
+
return badGateway();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const data = {};
|
|
527
|
+
if (newAttributeMapping)
|
|
528
|
+
data.attributeMapping = newAttributeMapping;
|
|
529
|
+
if (body.defaultRole !== undefined)
|
|
530
|
+
data.defaultRole = body.defaultRole;
|
|
531
|
+
if (body.scopes !== undefined)
|
|
532
|
+
data.scopes = body.scopes;
|
|
533
|
+
const updated = await db.tenantIdentityProvider.update({
|
|
534
|
+
where: { id: row.id },
|
|
535
|
+
data,
|
|
536
|
+
select: {
|
|
537
|
+
id: true,
|
|
538
|
+
tenantId: true,
|
|
539
|
+
kind: true,
|
|
540
|
+
status: true,
|
|
541
|
+
cognitoIdpName: true,
|
|
542
|
+
issuerUrl: true,
|
|
543
|
+
clientId: true,
|
|
544
|
+
defaultRole: true,
|
|
545
|
+
attributeMapping: true,
|
|
546
|
+
scopes: true,
|
|
547
|
+
enabledAt: true,
|
|
548
|
+
createdAt: true,
|
|
549
|
+
updatedAt: true,
|
|
550
|
+
},
|
|
551
|
+
});
|
|
552
|
+
void auditEmitter
|
|
553
|
+
.emit({
|
|
554
|
+
type: event_types_1.AuditEventType.TENANT_IDP_MODIFIED,
|
|
555
|
+
tenantId,
|
|
556
|
+
actorUserId: auth.userId,
|
|
557
|
+
payload: {
|
|
558
|
+
idpKind: row.kind,
|
|
559
|
+
changedAttributes: Object.keys(data),
|
|
560
|
+
},
|
|
561
|
+
}, db)
|
|
562
|
+
.catch((err) => console.warn(JSON.stringify({
|
|
563
|
+
event: "audit.emit_failed",
|
|
564
|
+
error: err?.message ?? "unknown",
|
|
565
|
+
})));
|
|
566
|
+
return jsonResponse(200, formatIdpRecord(updated));
|
|
567
|
+
}
|
|
568
|
+
// ── DELETE ─────────────────────────────────────────────────────────────────
|
|
569
|
+
async handleDelete(tenantId, url, auth, env) {
|
|
570
|
+
const denied = (0, auth_middleware_1.requireActiveTenant)(auth, tenantId) ??
|
|
571
|
+
(0, require_1.requireCapability)(auth, require_1.Capability.IdpConfigure);
|
|
572
|
+
if (denied)
|
|
573
|
+
return denied;
|
|
574
|
+
if (url.searchParams.get("confirm") !== "true") {
|
|
575
|
+
return jsonResponse(400, {
|
|
576
|
+
error: "CONFIRM_REQUIRED",
|
|
577
|
+
message: "Disconnecting an IdP requires confirm=true",
|
|
578
|
+
remediation: `DELETE /api/tenants/${tenantId}/identity-provider?confirm=true`,
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
const { createPrisma } = await Promise.resolve().then(() => __importStar(require("../../db")));
|
|
582
|
+
const db = createPrisma(env);
|
|
583
|
+
const row = await db.tenantIdentityProvider.findUnique({
|
|
584
|
+
where: { tenantId },
|
|
585
|
+
select: { id: true, cognitoIdpName: true, kind: true },
|
|
586
|
+
});
|
|
587
|
+
if (!row)
|
|
588
|
+
return notFound();
|
|
589
|
+
const userPoolId = env.COGNITO_USER_POOL_ID;
|
|
590
|
+
const userPoolClientId = env.COGNITO_APP_CLIENT_ID;
|
|
591
|
+
if (!userPoolId || !userPoolClientId)
|
|
592
|
+
return badGateway();
|
|
593
|
+
const idp = this.getIdp(env);
|
|
594
|
+
const secrets = this.getSecrets(env);
|
|
595
|
+
try {
|
|
596
|
+
// 15s — see handleCreate; both Cognito calls happen under the advisory
|
|
597
|
+
// lock and can exceed Prisma's default 5s.
|
|
598
|
+
await db.$transaction(async (tx) => {
|
|
599
|
+
await (0, idp_sdk_1.withUserPoolClientLock)(tx, userPoolId, async () => {
|
|
600
|
+
await idp.setSupportedIdentityProvider(userPoolId, userPoolClientId, row.cognitoIdpName, "remove");
|
|
601
|
+
});
|
|
602
|
+
await idp.deleteProvider(userPoolId, row.cognitoIdpName);
|
|
603
|
+
await tx.tenantIdentityProvider.delete({ where: { id: row.id } });
|
|
604
|
+
}, { timeout: 15000 });
|
|
605
|
+
}
|
|
606
|
+
catch (err) {
|
|
607
|
+
console.warn(JSON.stringify({
|
|
608
|
+
level: "warn",
|
|
609
|
+
msg: "IdP delete failed",
|
|
610
|
+
tenantId,
|
|
611
|
+
errName: err.name,
|
|
612
|
+
}));
|
|
613
|
+
return badGateway();
|
|
614
|
+
}
|
|
615
|
+
await secrets.delete(tenantId).catch(() => undefined);
|
|
616
|
+
await this.invalidateAllMemberClaims(tenantId, env);
|
|
617
|
+
await bestEffortGlobalSignOutAllMembers(env, tenantId, db);
|
|
618
|
+
void auditEmitter
|
|
619
|
+
.emit({
|
|
620
|
+
type: event_types_1.AuditEventType.TENANT_IDP_DELETED,
|
|
621
|
+
tenantId,
|
|
622
|
+
actorUserId: auth.userId,
|
|
623
|
+
payload: { idpKind: row.kind },
|
|
624
|
+
}, db)
|
|
625
|
+
.catch((err) => console.warn(JSON.stringify({
|
|
626
|
+
event: "audit.emit_failed",
|
|
627
|
+
error: err?.message ?? "unknown",
|
|
628
|
+
})));
|
|
629
|
+
return jsonResponse(200, { ok: true });
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
exports.IdpHandler = IdpHandler;
|
|
633
|
+
function mergeAttributeMapping(existing, incoming) {
|
|
634
|
+
const base = existing && typeof existing === "object" && !Array.isArray(existing)
|
|
635
|
+
? existing
|
|
636
|
+
: (0, idp_sdk_1.defaultOidcAttributeMapping)();
|
|
637
|
+
return { ...base, ...incoming };
|
|
638
|
+
}
|
|
639
|
+
function formatIdpRecord(row) {
|
|
640
|
+
return {
|
|
641
|
+
id: row.id,
|
|
642
|
+
tenantId: row.tenantId,
|
|
643
|
+
kind: row.kind,
|
|
644
|
+
status: row.status,
|
|
645
|
+
cognitoIdpName: row.cognitoIdpName,
|
|
646
|
+
issuerUrl: row.issuerUrl,
|
|
647
|
+
clientId: row.clientId,
|
|
648
|
+
defaultRole: row.defaultRole,
|
|
649
|
+
attributeMapping: row.attributeMapping,
|
|
650
|
+
scopes: row.scopes,
|
|
651
|
+
enabledAt: row.enabledAt,
|
|
652
|
+
createdAt: row.createdAt,
|
|
653
|
+
updatedAt: row.updatedAt,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
async function bestEffortGlobalSignOutAllMembers(env, tenantId, db) {
|
|
657
|
+
const userPoolId = env.COGNITO_USER_POOL_ID;
|
|
658
|
+
if (!userPoolId)
|
|
659
|
+
return;
|
|
660
|
+
let usernames = [];
|
|
661
|
+
try {
|
|
662
|
+
const members = await db.tenantMember.findMany({
|
|
663
|
+
where: { tenantId },
|
|
664
|
+
select: { user: { select: { email: true } } },
|
|
665
|
+
});
|
|
666
|
+
usernames = members.map((m) => m.user.email).filter((e) => !!e);
|
|
667
|
+
}
|
|
668
|
+
catch {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
if (usernames.length === 0)
|
|
672
|
+
return;
|
|
673
|
+
try {
|
|
674
|
+
const { CognitoIdentityProviderClient: CIP, AdminUserGlobalSignOutCommand } = await Promise.resolve().then(() => __importStar(require("@aws-sdk/client-cognito-identity-provider")));
|
|
675
|
+
const client = new CIP({
|
|
676
|
+
region: env.COGNITO_REGION ?? process.env.AWS_REGION,
|
|
677
|
+
});
|
|
678
|
+
await Promise.all(usernames.map((u) => client
|
|
679
|
+
.send(new AdminUserGlobalSignOutCommand({ UserPoolId: userPoolId, Username: u }))
|
|
680
|
+
.catch((err) => {
|
|
681
|
+
console.warn(JSON.stringify({
|
|
682
|
+
level: "warn",
|
|
683
|
+
msg: "AdminUserGlobalSignOut failed (best effort)",
|
|
684
|
+
tenantId,
|
|
685
|
+
errName: err.name,
|
|
686
|
+
}));
|
|
687
|
+
})));
|
|
688
|
+
}
|
|
689
|
+
catch {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
//# sourceMappingURL=idp-handler.js.map
|