@authhero/multi-tenancy 14.20.0 → 14.20.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/multi-tenancy.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var ce=Object.defineProperty;var le=(e,t,n)=>t in e?ce(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var k=(e,t,n)=>le(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ue=require("hono"),_=require("authhero"),T=require("@hono/zod-openapi");function J(e){const{controlPlaneTenantId:t,requireOrganizationMatch:n=!0}=e;return{async onTenantAccessValidation(r,a){if(a===t)return!0;if(n){const s=r.var.org_name,c=r.var.organization_id,i=s||c;return i?i.toLowerCase()===a.toLowerCase():!1}return!0}}}function X(e,t,n,r){if(t===n)return!0;const a=r||e;return a?a.toLowerCase()===t.toLowerCase():!1}function Y(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(n){console.error(`Failed to resolve data adapters for tenant ${t}:`,n);return}}}}function de(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function N(e){return{async beforeCreate(t,n){return!n.audience&&n.id?{...n,audience:de(n.id)}:n},async afterCreate(t,n){const{accessControl:r,databaseIsolation:a}=e;r&&t.ctx&&await fe(t,n,r),a!=null&&a.onProvision&&await a.onProvision(n.id)},async beforeDelete(t,n){const{accessControl:r,databaseIsolation:a}=e;if(r)try{const c=(await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find(i=>i.name===n);c&&await t.adapters.organizations.remove(r.controlPlaneTenantId,c.id)}catch(s){console.warn(`Failed to remove organization for tenant ${n}:`,s)}if(a!=null&&a.onDeprovision)try{await a.onDeprovision(n)}catch(s){console.warn(`Failed to deprovision database for tenant ${n}:`,s)}}}}async function fe(e,t,n){const{controlPlaneTenantId:r,defaultPermissions:a,defaultRoles:s,issuer:c,adminRoleName:i="Tenant Admin",adminRoleDescription:u="Full access to all tenant management operations",addCreatorToOrganization:o=!0}=n,l=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id});let g;if(c&&(g=await ge(e,r,i,u)),o&&e.ctx){const d=e.ctx.var.user;if(d!=null&&d.sub&&!await me(e,r,d.sub))try{await e.adapters.userOrganizations.create(r,{user_id:d.sub,organization_id:l.id}),g&&await e.adapters.userRoles.create(r,d.sub,g,l.id)}catch(m){console.warn(`Failed to add creator ${d.sub} to organization ${l.id}:`,m)}}s&&s.length>0&&console.log(`Would assign roles ${s.join(", ")} to organization ${l.id}`),a&&a.length>0&&console.log(`Would grant permissions ${a.join(", ")} to organization ${l.id}`)}async function me(e,t,n){const r=await e.adapters.userRoles.list(t,n,void 0,"");for(const a of r)if((await e.adapters.rolePermissions.list(t,a.id,{per_page:1e3})).some(i=>i.permission_name==="admin:organizations"))return!0;return!1}async function ge(e,t,n,r){const s=(await e.adapters.roles.list(t,{})).roles.find(o=>o.name===n);if(s)return s.id;const c=await e.adapters.roles.create(t,{name:n,description:r}),i=_.MANAGEMENT_API_AUDIENCE,u=_.MANAGEMENT_API_SCOPES.map(o=>({role_id:c.id,resource_server_identifier:i,permission_name:o.value}));return await e.adapters.rolePermissions.assign(t,c.id,u),c.id}function U(e,t,n=()=>!0){const{controlPlaneTenantId:r,getChildTenantIds:a,getAdapters:s}=e,c=new Map;async function i(l,g,d){return(await t(l).list(g,{q:`name:${d}`,per_page:1}))[0]??null}async function u(l){const g=await a(),d=t(await s(r));await Promise.all(g.map(async f=>{try{const m=await s(f),w=t(m),y={...d.transform(l),is_system:!0},C=await i(m,f,l.name),P=C?w.getId(C):void 0;if(C&&P){const S=w.preserveOnUpdate?w.preserveOnUpdate(C,y):y;await w.update(f,P,S)}else await w.create(f,y)}catch(m){console.error(`Failed to sync ${d.listKey} "${l.name}" to tenant "${f}":`,m)}}))}async function o(l){const g=await a();await Promise.all(g.map(async d=>{try{const f=await s(d),m=t(f),w=await i(f,d,l),b=w?m.getId(w):void 0;w&&b&&await m.remove(d,b)}catch(f){console.error(`Failed to delete entity "${l}" from tenant "${d}":`,f)}}))}return{afterCreate:async(l,g)=>{l.tenantId===r&&n(g)&&await u(g)},afterUpdate:async(l,g,d)=>{l.tenantId===r&&n(d)&&await u(d)},beforeDelete:async(l,g)=>{if(l.tenantId!==r)return;const f=await t(l.adapters).get(l.tenantId,g);f&&n(f)&&c.set(g,f)},afterDelete:async(l,g)=>{if(l.tenantId!==r)return;const d=c.get(g);d&&(c.delete(g),await o(d.name))}}}function G(e,t,n=()=>!0){const{controlPlaneTenantId:r,getControlPlaneAdapters:a,getAdapters:s}=e;return{async afterCreate(c,i){if(i.id!==r)try{const u=await a(),o=await s(i.id),l=t(u),g=t(o),d=await _.fetchAll(f=>l.listPaginated(r,f),l.listKey,{cursorField:"id",pageSize:100});await Promise.all(d.filter(f=>n(f)).map(async f=>{try{const m=l.transform(f);await g.create(i.id,{...m,is_system:!0})}catch(m){console.error(`Failed to sync entity to new tenant "${i.id}":`,m)}}))}catch(u){console.error(`Failed to sync entities to new tenant "${i.id}":`,u)}}}}const L=e=>({list:async(t,n)=>(await e.resourceServers.list(t,n)).resource_servers,listPaginated:(t,n)=>e.resourceServers.list(t,n),get:(t,n)=>e.resourceServers.get(t,n),create:(t,n)=>e.resourceServers.create(t,n),update:(t,n,r)=>e.resourceServers.update(t,n,r),remove:(t,n)=>e.resourceServers.remove(t,n),listKey:"resource_servers",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,identifier:t.identifier,scopes:t.scopes,signing_alg:t.signing_alg,token_lifetime:t.token_lifetime,token_lifetime_for_web:t.token_lifetime_for_web})}),W=e=>({list:async(t,n)=>(await e.roles.list(t,n)).roles,listPaginated:(t,n)=>e.roles.list(t,n),get:(t,n)=>e.roles.get(t,n),create:(t,n)=>e.roles.create(t,n),update:(t,n,r)=>e.roles.update(t,n,r),remove:(t,n)=>e.roles.remove(t,n),listKey:"roles",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,description:t.description})});function K(e){var t;return((t=e.metadata)==null?void 0:t.sync)!==!1}function Z(e){const{sync:t={},filters:n={}}=e,r=t.resourceServers??!0,a=t.roles??!0,s=m=>K(m)?n.resourceServers?n.resourceServers(m):!0:!1,c=m=>K(m)?n.roles?n.roles(m):!0:!1,i=r?U(e,L,s):void 0,u=a?U(e,W,c):void 0,o=r?G(e,L,s):void 0,l=a?G(e,W,c):void 0,g=a?{async afterCreate(m,w){var b;if(w.id!==e.controlPlaneTenantId){await((b=l==null?void 0:l.afterCreate)==null?void 0:b.call(l,m,w));try{const y=await e.getControlPlaneAdapters(),C=await e.getAdapters(w.id),P=await _.fetchAll(p=>y.roles.list(e.controlPlaneTenantId,p),"roles",{cursorField:"id",pageSize:100}),S=new Map;for(const p of P.filter(A=>{var h;return((h=n.roles)==null?void 0:h.call(n,A))??!0})){const A=await d(C,w.id,p.name);A&&S.set(p.name,A.id)}for(const p of P.filter(A=>{var h;return((h=n.roles)==null?void 0:h.call(n,A))??!0})){const A=S.get(p.name);if(A)try{const h=await y.rolePermissions.list(e.controlPlaneTenantId,p.id,{});h.length>0&&await C.rolePermissions.assign(w.id,A,h.map(R=>({role_id:A,resource_server_identifier:R.resource_server_identifier,permission_name:R.permission_name})))}catch(h){console.error(`Failed to sync permissions for role "${p.name}" to tenant "${w.id}":`,h)}}}catch(y){console.error(`Failed to sync role permissions to tenant "${w.id}":`,y)}}}}:void 0;async function d(m,w,b){return(await m.roles.list(w,{q:`name:${b}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:i,roles:u},tenantHooks:{async afterCreate(m,w){const b=[o==null?void 0:o.afterCreate,(g==null?void 0:g.afterCreate)??(l==null?void 0:l.afterCreate)],y=[];for(const C of b)if(C)try{await C(m,w)}catch(P){y.push(P instanceof Error?P:new Error(String(P)))}if(y.length===1)throw y[0];if(y.length>1)throw new AggregateError(y,y.map(C=>C.message).join("; "))}}}}var I=class extends Error{constructor(t=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});k(this,"res");k(this,"status");this.res=n==null?void 0:n.res,this.status=t}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function q(e,t){const n=new T.OpenAPIHono;return n.openapi(T.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:_.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:T.z.object({tenants:T.z.array(_.tenantSchema),start:T.z.number().optional(),limit:T.z.number().optional(),length:T.z.number().optional()})}},description:"List of tenants"}}}),async r=>{var m,w,b,y,C,P;const a=r.req.valid("query"),{page:s,per_page:c,include_totals:i,q:u}=a,o=r.var.user,l=(o==null?void 0:o.permissions)||[];if(l.includes("auth:read")||l.includes("admin:organizations")){const S=await r.env.data.tenants.list({page:s,per_page:c,include_totals:i,q:u});return i?r.json({tenants:S.tenants,start:((m=S.totals)==null?void 0:m.start)??0,limit:((w=S.totals)==null?void 0:w.limit)??c,length:S.tenants.length}):r.json({tenants:S.tenants})}const d=((b=e.accessControl)==null?void 0:b.controlPlaneTenantId)??((y=r.env.data.multiTenancyConfig)==null?void 0:y.controlPlaneTenantId);if(d&&(o!=null&&o.sub)){const p=(await _.fetchAll(M=>r.env.data.userOrganizations.listUserOrganizations(d,o.sub,M),"organizations")).map(M=>M.name);if(p.length===0)return i?r.json({tenants:[],start:0,limit:c??50,length:0}):r.json({tenants:[]});const A=p.length,h=s??0,R=c??50,F=h*R,D=p.slice(F,F+R);if(D.length===0)return i?r.json({tenants:[],start:F,limit:R,length:A}):r.json({tenants:[]});const z=D.map(M=>`id:${M}`).join(" OR "),v=u?`(${z}) AND (${u})`:z,$=await r.env.data.tenants.list({q:v,per_page:R,include_totals:!1});return i?r.json({tenants:$.tenants,start:F,limit:R,length:A}):r.json({tenants:$.tenants})}const f=await r.env.data.tenants.list({page:s,per_page:c,include_totals:i,q:u});return i?r.json({tenants:f.tenants,start:((C=f.totals)==null?void 0:C.start)??0,limit:((P=f.totals)==null?void 0:P.limit)??c,length:f.tenants.length}):r.json({tenants:f.tenants})}),n.openapi(T.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:_.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:_.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async r=>{var u,o;const a=r.var.user;if(!(a!=null&&a.sub))throw new I(401,{message:"Authentication required to create tenants"});let s=r.req.valid("json");const c={adapters:r.env.data,ctx:r};(u=t.tenants)!=null&&u.beforeCreate&&(s=await t.tenants.beforeCreate(c,s));const i=await r.env.data.tenants.create(s);return(o=t.tenants)!=null&&o.afterCreate&&await t.tenants.afterCreate(c,i),r.json(i,201)}),n.openapi(T.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:T.z.object({id:T.z.string()})},security:[{Bearer:["delete:tenants"]}],responses:{204:{description:"Tenant deleted"},403:{description:"Access denied or cannot delete the control plane"},404:{description:"Tenant not found"}}}),async r=>{var u,o,l,g;const{id:a}=r.req.valid("param"),s=((u=e.accessControl)==null?void 0:u.controlPlaneTenantId)??((o=r.env.data.multiTenancyConfig)==null?void 0:o.controlPlaneTenantId);if(s){const d=r.var.user;if(!(d!=null&&d.sub))throw new I(401,{message:"Authentication required"});if(a===s)throw new I(403,{message:"Cannot delete the control plane"});if(!(await _.fetchAll(w=>r.env.data.userOrganizations.listUserOrganizations(s,d.sub,w),"organizations")).some(w=>w.name===a))throw new I(403,{message:"Access denied to this tenant"})}if(!await r.env.data.tenants.get(a))throw new I(404,{message:"Tenant not found"});const i={adapters:r.env.data,ctx:r};return(l=t.tenants)!=null&&l.beforeDelete&&await t.tenants.beforeDelete(i,a),await r.env.data.tenants.remove(a),(g=t.tenants)!=null&&g.afterDelete&&await t.tenants.afterDelete(i,a),r.body(null,204)}),n.openapi(T.createRoute({tags:["tenants","settings"],method:"get",path:"/settings",request:{headers:T.z.object({"tenant-id":T.z.string().optional()})},security:[{Bearer:["read:tenants","auth:read"]}],responses:{200:{content:{"application/json":{schema:_.tenantSchema}},description:"Current tenant settings"}}}),async r=>{const a=await r.env.data.tenants.get(r.var.tenant_id);if(!a)throw new I(404,{message:"Tenant not found"});return r.json(a)}),n.openapi(T.createRoute({tags:["tenants","settings"],method:"patch",path:"/settings",request:{headers:T.z.object({"tenant-id":T.z.string().optional()}),body:{content:{"application/json":{schema:T.z.object(_.tenantInsertSchema.shape).partial()}}}},security:[{Bearer:["update:tenants","auth:write"]}],responses:{200:{content:{"application/json":{schema:_.tenantSchema}},description:"Updated tenant settings"}}}),async r=>{const a=r.req.valid("json"),{id:s,...c}=a,i=await r.env.data.tenants.get(r.var.tenant_id);if(!i)throw new I(404,{message:"Tenant not found"});const u=_.deepMergePatch(i,c);await r.env.data.tenants.update(r.var.tenant_id,u);const o=await r.env.data.tenants.get(r.var.tenant_id);if(!o)throw new I(500,{message:"Failed to retrieve updated tenant"});return r.json(o)}),n}function we(e){const t=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:n,type:r}of t){const a=e.match(n);if(a&&a[1])return{type:r,id:a[1]}}return null}async function pe(e,t,n){try{switch(n.type){case"resource_server":{const r=await e.resourceServers.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"role":{const r=await e.roles.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"connection":{const r=await e.connections.get(t,n.id);return(r==null?void 0:r.is_system)===!0}default:return!1}}catch{return!1}}function he(e){return{resource_server:"resource server",role:"role",connection:"connection"}[e]}function x(){return async(e,t)=>{if(!["PATCH","PUT","DELETE"].includes(e.req.method))return t();const n=we(e.req.path);if(!n)return t();const r=e.var.tenant_id||e.req.header("x-tenant-id")||e.req.header("tenant-id");if(!r)return t();if(await pe(e.env.data,r,n))throw new I(403,{message:`This ${he(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function E(e,t){const n=t.find(a=>a.strategy===e.strategy);if(!(n!=null&&n.options))return e;const r=_.connectionSchema.passthrough().parse({...n,...e});return r.options=_.connectionOptionsSchema.passthrough().parse({...n.options||{},...e.options}),r}function j(e,t){const n=[...t||[],...e||[]];return[...new Set(n)]}function ye(e,t){if(!(t!=null&&t.length))return e||[];if(!(e!=null&&e.length))return t;const n=new Map;for(const r of t)n.set(r.value,r);for(const r of e)n.set(r.value,r);return Array.from(n.values())}function Q(e,t){return t?{...e,scopes:ye(e.scopes,t.scopes)}:e}function V(e,t){return t?{...e,callbacks:j(e.callbacks,t.callbacks),web_origins:j(e.web_origins,t.web_origins),allowed_logout_urls:j(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:j(e.allowed_origins,t.allowed_origins)}:e}function ee(e,t){return{...e.resourceServers,get:async(n,r)=>{const a=await e.resourceServers.get(n,r);if(!a||!t||n===t||!a.is_system)return a;const s=await e.resourceServers.get(t,r);return Q(a,s)},list:async(n,r)=>{const a=await e.resourceServers.list(n,r);if(!t||n===t)return a;const s=t,c=a.resource_servers.filter(o=>!!(o.is_system&&o.id)).map(o=>o.id);if(c.length===0)return a;const i=new Map;await Promise.all(c.map(async o=>{const l=await e.resourceServers.get(s,o);l&&i.set(o,l)}));const u=a.resource_servers.map(o=>o.is_system&&o.id?Q(o,i.get(o.id)??null):o);return{...a,resource_servers:u}}}}function te(e,t){return{...e,resourceServers:ee(e,t.controlPlaneTenantId)}}function ne(e,t){const{controlPlaneTenantId:n,controlPlaneClientId:r}=t;return{...e,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r},connections:{...e.connections,get:async(a,s)=>{const c=await e.connections.get(a,s);if(!c||!n||a===n)return c;const i=await e.connections.list(n);return E(c,i.connections||[])},list:async(a,s)=>{const c=await e.connections.list(a,s);if(!n||a===n)return c;const i=await e.connections.list(n),u=c.connections.map(o=>E(o,i.connections||[]));return{...c,connections:u}}},clientConnections:{...e.clientConnections,listByClient:async(a,s)=>{let c=await e.clientConnections.listByClient(a,s);if(c.length===0&&(c=(await e.connections.list(a)).connections||[]),!n||a===n)return c;const i=await e.connections.list(n);return c.map(u=>E(u,i.connections||[]))}},clients:{...e.clients,get:async(a,s)=>{const c=await e.clients.get(a,s);if(!c)return null;if(!n||!r||a===n&&s===r)return c;const i=await e.clients.get(n,r);return V(c,i)},getByClientId:async a=>{const s=await e.clients.getByClientId(a);if(!s)return null;if(!n||!r||s.tenant_id===n&&s.client_id===r)return s;const c=await e.clients.get(n,r);return{...V(s,c),tenant_id:s.tenant_id}}},emailProviders:{...e.emailProviders,get:async a=>{const s=await e.emailProviders.get(a);return s||(!n||a===n?null:e.emailProviders.get(n))}},resourceServers:ee(e,n)}}function B(e,t){return ne(e,t)}function re(e){return async(t,n)=>{const r=t.var.user;return(r==null?void 0:r.tenant_id)===e&&r.org_name&&t.set("tenant_id",r.org_name),n()}}function ae(e){return async(t,n)=>{if(!e.accessControl)return n();const{controlPlaneTenantId:r}=e.accessControl,a=t.var.org_name,s=t.var.organization_id,c=a||s;let i=t.var.tenant_id;const u=t.var.user,l=(u!=null&&u.aud?Array.isArray(u.aud)?u.aud:[u.aud]:[]).includes(_.MANAGEMENT_API_AUDIENCE);if(!i&&c&&l&&(t.set("tenant_id",c),i=c),!i)throw new I(400,{message:"Tenant ID not found in request"});if(!X(s,i,r,a))throw new I(403,{message:`Access denied to tenant ${i}`});return n()}}function se(e){return async(t,n)=>{if(!e.subdomainRouting)return n();const{baseDomain:r,reservedSubdomains:a=[],resolveSubdomain:s}=e.subdomainRouting,c=t.req.header("x-forwarded-host")||t.req.header("host")||"";let i=null;if(c.endsWith(r)){const o=c.slice(0,-(r.length+1));o&&!o.includes(".")&&(i=o)}if(i&&a.includes(i)&&(i=null),!i)return e.accessControl&&t.set("tenant_id",e.accessControl.controlPlaneTenantId),n();let u=null;if(s)u=await s(i);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{const o=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,i);o&&(u=o.id)}catch{}if(!u)throw new I(404,{message:`Tenant not found for subdomain: ${i}`});return t.set("tenant_id",u),n()}}function oe(e){return async(t,n)=>{if(!e.databaseIsolation)return n();const r=t.var.tenant_id;if(!r)throw new I(400,{message:"Tenant ID not found in request"});try{const a=await e.databaseIsolation.getAdapters(r);t.env.data=a}catch(a){throw console.error(`Failed to resolve database for tenant ${r}:`,a),new I(500,{message:"Failed to resolve tenant database"})}return n()}}function H(e){const t=se(e),n=ae(e),r=oe(e);return async(a,s)=>(await t(a,async()=>{}),await n(a,async()=>{}),await r(a,async()=>{}),s())}function ve(e){const{dataAdapter:t,controlPlane:n,controlPlane:{tenantId:r="control_plane",clientId:a}={},sync:s={resourceServers:!0,roles:!0},defaultPermissions:c=["tenant:admin"],requireOrganizationMatch:i=!1,managementApiExtensions:u=[],entityHooks:o,getChildTenantIds:l,getAdapters:g,...d}=e;let f=t,m=t;n&&(f=B(t,{controlPlaneTenantId:r,controlPlaneClientId:a}),m={...te(t,{controlPlaneTenantId:r}),multiTenancyConfig:{controlPlaneTenantId:r,controlPlaneClientId:a}});const w=s!==!1,b=w?{resourceServers:s.resourceServers??!0,roles:s.roles??!0}:{resourceServers:!1,roles:!1},P={controlPlaneTenantId:r,getChildTenantIds:l??(async()=>(await _.fetchAll(v=>f.tenants.list(v),"tenants",{cursorField:"id",pageSize:100})).filter(v=>v.id!==r).map(v=>v.id)),getAdapters:g??(async()=>f),getControlPlaneAdapters:async()=>f,sync:b},{entityHooks:S,tenantHooks:p}=Z(P),A={resourceServers:[S.resourceServers,...(o==null?void 0:o.resourceServers)??[]],roles:[S.roles,...(o==null?void 0:o.roles)??[]],connections:(o==null?void 0:o.connections)??[],tenants:(o==null?void 0:o.tenants)??[],rolePermissions:(o==null?void 0:o.rolePermissions)??[]},h=N({accessControl:{controlPlaneTenantId:r,requireOrganizationMatch:i,defaultPermissions:c}}),F=q({accessControl:{controlPlaneTenantId:r,requireOrganizationMatch:i,defaultPermissions:c}},{tenants:{async beforeCreate(z,v){return h.beforeCreate&&(v=await h.beforeCreate(z,v)),p.beforeCreate&&(v=await p.beforeCreate(z,v)),v},async afterCreate(z,v){var $,M;await(($=h.afterCreate)==null?void 0:$.call(h,z,v)),await((M=p.afterCreate)==null?void 0:M.call(p,z,v))},async beforeDelete(z,v){var $,M;await(($=h.beforeDelete)==null?void 0:$.call(h,z,v)),await((M=p.beforeDelete)==null?void 0:M.call(p,z,v))}}}),{app:D}=_.init({dataAdapter:f,managementDataAdapter:m,...d,entityHooks:A,managementApiExtensions:[...u,{path:"/tenants",router:F}]});return D.use("/api/v2/*",re(r)),w&&D.use("/api/v2/*",x()),{app:D,controlPlaneTenantId:r}}function _e(e){const t=O(e);return{name:"multi-tenancy",middleware:H(e),hooks:t,routes:[{path:"/management",handler:q(e,t)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),e.accessControl&&console.log(` - Access control enabled (control plane: ${e.accessControl.controlPlaneTenantId})`),e.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${e.subdomainRouting.baseDomain})`),e.databaseIsolation&&console.log(" - Database isolation enabled")}}}function O(e){const t=e.accessControl?J(e.accessControl):{},n=e.databaseIsolation?Y(e.databaseIsolation):{},r=N(e);return{...t,...n,tenants:r}}function ie(e){const t=new ue.Hono,n=O(e);return t.route("/tenants",q(e,n)),t}function Te(e){return{hooks:O(e),middleware:H(e),app:ie(e),config:e,wrapAdapters:(t,n)=>{var r;return B(t,{controlPlaneTenantId:(r=e.accessControl)==null?void 0:r.controlPlaneTenantId,controlPlaneClientId:n==null?void 0:n.controlPlaneClientId})}}}exports.createAccessControlHooks=J;exports.createAccessControlMiddleware=ae;exports.createControlPlaneTenantMiddleware=re;exports.createDatabaseHooks=Y;exports.createDatabaseMiddleware=oe;exports.createMultiTenancy=ie;exports.createMultiTenancyHooks=O;exports.createMultiTenancyMiddleware=H;exports.createMultiTenancyPlugin=_e;exports.createProtectSyncedMiddleware=x;exports.createProvisioningHooks=N;exports.createRuntimeFallbackAdapter=ne;exports.createSubdomainMiddleware=se;exports.createSyncHooks=Z;exports.createTenantsOpenAPIRouter=q;exports.initMultiTenant=ve;exports.setupMultiTenancy=Te;exports.validateTenantAccess=X;exports.withRuntimeFallback=B;exports.withSystemResourceServerInheritance=te;
|
|
1
|
+
"use strict";var le=Object.defineProperty;var ue=(e,t,n)=>t in e?le(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var O=(e,t,n)=>ue(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const de=require("hono"),_=require("authhero"),C=require("@hono/zod-openapi");function X(e){const{controlPlaneTenantId:t,requireOrganizationMatch:n=!0}=e;return{async onTenantAccessValidation(r,a){if(a===t)return!0;if(n){const s=r.var.org_name,i=r.var.organization_id,c=s||i;return c?c.toLowerCase()===a.toLowerCase():!1}return!0}}}function Y(e,t,n,r){if(t===n)return!0;const a=r||e;return a?a.toLowerCase()===t.toLowerCase():!1}function Z(e){return{async resolveDataAdapters(t){try{return await e.getAdapters(t)}catch(n){console.error(`Failed to resolve data adapters for tenant ${t}:`,n);return}}}}function fe(e){return`urn:authhero:tenant:${e.toLowerCase()}`}function N(e){return{async beforeCreate(t,n){return!n.audience&&n.id?{...n,audience:fe(n.id)}:n},async afterCreate(t,n){const{accessControl:r,databaseIsolation:a}=e;r&&t.ctx&&await me(t,n,r),a!=null&&a.onProvision&&await a.onProvision(n.id)},async beforeDelete(t,n){const{accessControl:r,databaseIsolation:a}=e;if(r)try{const i=(await t.adapters.organizations.list(r.controlPlaneTenantId)).organizations.find(c=>c.name===n);i&&await t.adapters.organizations.remove(r.controlPlaneTenantId,i.id)}catch(s){console.warn(`Failed to remove organization for tenant ${n}:`,s)}if(a!=null&&a.onDeprovision)try{await a.onDeprovision(n)}catch(s){console.warn(`Failed to deprovision database for tenant ${n}:`,s)}}}}async function me(e,t,n){const{controlPlaneTenantId:r,defaultPermissions:a,defaultRoles:s,issuer:i,adminRoleName:c="Tenant Admin",adminRoleDescription:u="Full access to all tenant management operations",addCreatorToOrganization:o=!0}=n,l=await e.adapters.organizations.create(r,{name:t.id,display_name:t.friendly_name||t.id});let g;if(i&&(g=await we(e,r,c,u)),o&&e.ctx){const d=e.ctx.var.user;if(d!=null&&d.sub&&!await ge(e,r,d.sub))try{await e.adapters.userOrganizations.create(r,{user_id:d.sub,organization_id:l.id}),g&&await e.adapters.userRoles.create(r,d.sub,g,l.id)}catch(m){console.warn(`Failed to add creator ${d.sub} to organization ${l.id}:`,m)}}s&&s.length>0&&console.log(`Would assign roles ${s.join(", ")} to organization ${l.id}`),a&&a.length>0&&console.log(`Would grant permissions ${a.join(", ")} to organization ${l.id}`)}async function ge(e,t,n){const r=await e.adapters.userRoles.list(t,n,void 0,"");for(const a of r)if((await e.adapters.rolePermissions.list(t,a.id,{per_page:1e3})).some(c=>c.permission_name==="admin:organizations"))return!0;return!1}async function we(e,t,n,r){const s=(await e.adapters.roles.list(t,{})).roles.find(o=>o.name===n);if(s)return s.id;const i=await e.adapters.roles.create(t,{name:n,description:r}),c=_.MANAGEMENT_API_AUDIENCE,u=_.MANAGEMENT_API_SCOPES.map(o=>({role_id:i.id,resource_server_identifier:c,permission_name:o.value}));return await e.adapters.rolePermissions.assign(t,i.id,u),i.id}function U(e,t,n=()=>!0){const{controlPlaneTenantId:r,getChildTenantIds:a,getAdapters:s}=e,i=new Map;async function c(l,g,d){return(await t(l).list(g,{q:`name:${d}`,per_page:1}))[0]??null}async function u(l){const g=await a(),d=t(await s(r));await Promise.all(g.map(async f=>{try{const m=await s(f),w=t(m),y={...d.transform(l),is_system:!0},T=await c(m,f,l.name),A=T?w.getId(T):void 0;if(T&&A){const S=w.preserveOnUpdate?w.preserveOnUpdate(T,y):y;await w.update(f,A,S)}else await w.create(f,y)}catch(m){console.error(`Failed to sync ${d.listKey} "${l.name}" to tenant "${f}":`,m)}}))}async function o(l){const g=await a();await Promise.all(g.map(async d=>{try{const f=await s(d),m=t(f),w=await c(f,d,l),b=w?m.getId(w):void 0;w&&b&&await m.remove(d,b)}catch(f){console.error(`Failed to delete entity "${l}" from tenant "${d}":`,f)}}))}return{afterCreate:async(l,g)=>{l.tenantId===r&&n(g)&&await u(g)},afterUpdate:async(l,g,d)=>{l.tenantId===r&&n(d)&&await u(d)},beforeDelete:async(l,g)=>{if(l.tenantId!==r)return;const f=await t(l.adapters).get(l.tenantId,g);f&&n(f)&&i.set(g,f)},afterDelete:async(l,g)=>{if(l.tenantId!==r)return;const d=i.get(g);d&&(i.delete(g),await o(d.name))}}}function G(e,t,n=()=>!0){const{controlPlaneTenantId:r,getControlPlaneAdapters:a,getAdapters:s}=e;return{async afterCreate(i,c){if(c.id!==r)try{const u=await a(),o=await s(c.id),l=t(u),g=t(o),d=await _.fetchAll(f=>l.listPaginated(r,f),l.listKey,{cursorField:"id",pageSize:100});await Promise.all(d.filter(f=>n(f)).map(async f=>{try{const m=l.transform(f);await g.create(c.id,{...m,is_system:!0})}catch(m){console.error(`Failed to sync entity to new tenant "${c.id}":`,m)}}))}catch(u){console.error(`Failed to sync entities to new tenant "${c.id}":`,u)}}}}const W=e=>({list:async(t,n)=>(await e.resourceServers.list(t,n)).resource_servers,listPaginated:(t,n)=>e.resourceServers.list(t,n),get:(t,n)=>e.resourceServers.get(t,n),create:(t,n)=>e.resourceServers.create(t,n),update:(t,n,r)=>e.resourceServers.update(t,n,r),remove:(t,n)=>e.resourceServers.remove(t,n),listKey:"resource_servers",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,identifier:t.identifier,scopes:t.scopes,signing_alg:t.signing_alg,token_lifetime:t.token_lifetime,token_lifetime_for_web:t.token_lifetime_for_web})}),L=e=>({list:async(t,n)=>(await e.roles.list(t,n)).roles,listPaginated:(t,n)=>e.roles.list(t,n),get:(t,n)=>e.roles.get(t,n),create:(t,n)=>e.roles.create(t,n),update:(t,n,r)=>e.roles.update(t,n,r),remove:(t,n)=>e.roles.remove(t,n),listKey:"roles",getId:t=>t.id,transform:t=>({id:t.id,name:t.name,description:t.description})});function K(e){var t;return((t=e.metadata)==null?void 0:t.sync)!==!1}function x(e){const{sync:t={},filters:n={}}=e,r=t.resourceServers??!0,a=t.roles??!0,s=m=>K(m)?n.resourceServers?n.resourceServers(m):!0:!1,i=m=>K(m)?n.roles?n.roles(m):!0:!1,c=r?U(e,W,s):void 0,u=a?U(e,L,i):void 0,o=r?G(e,W,s):void 0,l=a?G(e,L,i):void 0,g=a?{async afterCreate(m,w){var b;if(w.id!==e.controlPlaneTenantId){await((b=l==null?void 0:l.afterCreate)==null?void 0:b.call(l,m,w));try{const y=await e.getControlPlaneAdapters(),T=await e.getAdapters(w.id),A=await _.fetchAll(h=>y.roles.list(e.controlPlaneTenantId,h),"roles",{cursorField:"id",pageSize:100}),S=new Map;for(const h of A.filter(P=>{var p;return((p=n.roles)==null?void 0:p.call(n,P))??!0})){const P=await d(T,w.id,h.name);P&&S.set(h.name,P.id)}for(const h of A.filter(P=>{var p;return((p=n.roles)==null?void 0:p.call(n,P))??!0})){const P=S.get(h.name);if(P)try{const p=await y.rolePermissions.list(e.controlPlaneTenantId,h.id,{});p.length>0&&await T.rolePermissions.assign(w.id,P,p.map(R=>({role_id:P,resource_server_identifier:R.resource_server_identifier,permission_name:R.permission_name})))}catch(p){console.error(`Failed to sync permissions for role "${h.name}" to tenant "${w.id}":`,p)}}}catch(y){console.error(`Failed to sync role permissions to tenant "${w.id}":`,y)}}}}:void 0;async function d(m,w,b){return(await m.roles.list(w,{q:`name:${b}`,per_page:1})).roles[0]??null}return{entityHooks:{resourceServers:c,roles:u},tenantHooks:{async afterCreate(m,w){const b=[o==null?void 0:o.afterCreate,(g==null?void 0:g.afterCreate)??(l==null?void 0:l.afterCreate)],y=[];for(const T of b)if(T)try{await T(m,w)}catch(A){y.push(A instanceof Error?A:new Error(String(A)))}if(y.length===1)throw y[0];if(y.length>1)throw new AggregateError(y,y.map(T=>T.message).join("; "))}}}}var I=class extends Error{constructor(t=500,n){super(n==null?void 0:n.message,{cause:n==null?void 0:n.cause});O(this,"res");O(this,"status");this.res=n==null?void 0:n.res,this.status=t}getResponse(){return this.res?new Response(this.res.body,{status:this.status,headers:this.res.headers}):new Response(this.message,{status:this.status})}};function D(e,t){const n=new C.OpenAPIHono;return n.openapi(C.createRoute({tags:["tenants"],method:"get",path:"/",request:{query:_.auth0QuerySchema},security:[{Bearer:[]}],responses:{200:{content:{"application/json":{schema:C.z.object({tenants:C.z.array(_.tenantSchema),start:C.z.number().optional(),limit:C.z.number().optional(),length:C.z.number().optional()})}},description:"List of tenants"}}}),async r=>{var m,w,b,y,T,A;const a=r.req.valid("query"),{page:s,per_page:i,include_totals:c,q:u}=a,o=r.var.user,l=(o==null?void 0:o.permissions)||[];if(l.includes("auth:read")||l.includes("admin:organizations")){const S=await r.env.data.tenants.list({page:s,per_page:i,include_totals:c,q:u});return c?r.json({tenants:S.tenants,start:((m=S.totals)==null?void 0:m.start)??0,limit:((w=S.totals)==null?void 0:w.limit)??i,length:S.tenants.length}):r.json({tenants:S.tenants})}const d=((b=e.accessControl)==null?void 0:b.controlPlaneTenantId)??((y=r.env.data.multiTenancyConfig)==null?void 0:y.controlPlaneTenantId);if(d&&(o!=null&&o.sub)){const h=(await _.fetchAll(M=>r.env.data.userOrganizations.listUserOrganizations(d,o.sub,M),"organizations")).map(M=>M.name);if(h.length===0)return c?r.json({tenants:[],start:0,limit:i??50,length:0}):r.json({tenants:[]});const P=h.length,p=s??0,R=i??50,$=p*R,j=h.slice($,$+R);if(j.length===0)return c?r.json({tenants:[],start:$,limit:R,length:P}):r.json({tenants:[]});const z=j.map(M=>`id:${M}`).join(" OR "),v=u?`(${z}) AND (${u})`:z,k=await r.env.data.tenants.list({q:v,per_page:R,include_totals:!1});return c?r.json({tenants:k.tenants,start:$,limit:R,length:P}):r.json({tenants:k.tenants})}const f=await r.env.data.tenants.list({page:s,per_page:i,include_totals:c,q:u});return c?r.json({tenants:f.tenants,start:((T=f.totals)==null?void 0:T.start)??0,limit:((A=f.totals)==null?void 0:A.limit)??i,length:f.tenants.length}):r.json({tenants:f.tenants})}),n.openapi(C.createRoute({tags:["tenants"],method:"post",path:"/",request:{body:{content:{"application/json":{schema:_.tenantInsertSchema}}}},security:[{Bearer:[]}],responses:{201:{content:{"application/json":{schema:_.tenantSchema}},description:"Tenant created"},400:{description:"Validation error"},409:{description:"Tenant with this ID already exists"}}}),async r=>{var u,o;const a=r.var.user;if(!(a!=null&&a.sub))throw new I(401,{message:"Authentication required to create tenants"});let s=r.req.valid("json");const i={adapters:r.env.data,ctx:r};(u=t.tenants)!=null&&u.beforeCreate&&(s=await t.tenants.beforeCreate(i,s));const c=await r.env.data.tenants.create(s);return(o=t.tenants)!=null&&o.afterCreate&&await t.tenants.afterCreate(i,c),r.json(c,201)}),n.openapi(C.createRoute({tags:["tenants"],method:"delete",path:"/{id}",request:{params:C.z.object({id:C.z.string()})},security:[{Bearer:["delete:tenants"]}],responses:{204:{description:"Tenant deleted"},403:{description:"Access denied or cannot delete the control plane"},404:{description:"Tenant not found"}}}),async r=>{var u,o,l,g;const{id:a}=r.req.valid("param"),s=((u=e.accessControl)==null?void 0:u.controlPlaneTenantId)??((o=r.env.data.multiTenancyConfig)==null?void 0:o.controlPlaneTenantId);if(s){const d=r.var.user;if(!(d!=null&&d.sub))throw new I(401,{message:"Authentication required"});if(a===s)throw new I(403,{message:"Cannot delete the control plane"});if(!(await _.fetchAll(w=>r.env.data.userOrganizations.listUserOrganizations(s,d.sub,w),"organizations")).some(w=>w.name===a))throw new I(403,{message:"Access denied to this tenant"})}if(!await r.env.data.tenants.get(a))throw new I(404,{message:"Tenant not found"});const c={adapters:r.env.data,ctx:r};return(l=t.tenants)!=null&&l.beforeDelete&&await t.tenants.beforeDelete(c,a),await r.env.data.tenants.remove(a),(g=t.tenants)!=null&&g.afterDelete&&await t.tenants.afterDelete(c,a),r.body(null,204)}),n.openapi(C.createRoute({tags:["tenants","settings"],method:"get",path:"/settings",request:{headers:C.z.object({"tenant-id":C.z.string().optional()})},security:[{Bearer:["read:tenants","auth:read"]}],responses:{200:{content:{"application/json":{schema:_.tenantSchema}},description:"Current tenant settings"}}}),async r=>{const a=await r.env.data.tenants.get(r.var.tenant_id);if(!a)throw new I(404,{message:"Tenant not found"});return r.json(a)}),n.openapi(C.createRoute({tags:["tenants","settings"],method:"patch",path:"/settings",request:{headers:C.z.object({"tenant-id":C.z.string().optional()}),body:{content:{"application/json":{schema:C.z.object(_.tenantInsertSchema.shape).partial()}}}},security:[{Bearer:["update:tenants","auth:write"]}],responses:{200:{content:{"application/json":{schema:_.tenantSchema}},description:"Updated tenant settings"}}}),async r=>{const a=r.req.valid("json"),{id:s,...i}=a,c=await r.env.data.tenants.get(r.var.tenant_id);if(!c)throw new I(404,{message:"Tenant not found"});const u=_.deepMergePatch(c,i);await r.env.data.tenants.update(r.var.tenant_id,u);const o=await r.env.data.tenants.get(r.var.tenant_id);if(!o)throw new I(500,{message:"Failed to retrieve updated tenant"});return r.json(o)}),n}function he(e){const t=[{pattern:/\/api\/v2\/resource-servers\/([^/]+)$/,type:"resource_server"},{pattern:/\/api\/v2\/roles\/([^/]+)$/,type:"role"},{pattern:/\/api\/v2\/connections\/([^/]+)$/,type:"connection"}];for(const{pattern:n,type:r}of t){const a=e.match(n);if(a&&a[1])return{type:r,id:a[1]}}return null}async function pe(e,t,n){try{switch(n.type){case"resource_server":{const r=await e.resourceServers.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"role":{const r=await e.roles.get(t,n.id);return(r==null?void 0:r.is_system)===!0}case"connection":{const r=await e.connections.get(t,n.id);return(r==null?void 0:r.is_system)===!0}default:return!1}}catch{return!1}}function ye(e){return{resource_server:"resource server",role:"role",connection:"connection"}[e]}function ee(){return async(e,t)=>{if(!["PATCH","PUT","DELETE"].includes(e.req.method))return t();const n=he(e.req.path);if(!n)return t();const r=e.var.tenant_id||e.req.header("x-tenant-id")||e.req.header("tenant-id");if(!r)return t();if(await pe(e.env.data,r,n))throw new I(403,{message:`This ${ye(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`});return t()}}function E(e,t){const n=t.find(a=>a.strategy===e.strategy);if(!(n!=null&&n.options))return e;const r=_.connectionSchema.passthrough().parse({...n,...e});return r.options=_.connectionOptionsSchema.passthrough().parse({...n.options||{},...e.options}),r}function F(e,t){const n=[...t||[],...e||[]];return[...new Set(n)]}function ve(e,t){if(!(t!=null&&t.length))return e||[];if(!(e!=null&&e.length))return t;const n=new Map;for(const r of t)n.set(r.value,r);for(const r of e)n.set(r.value,r);return Array.from(n.values())}function Q(e,t){return t?{...e,scopes:ve(e.scopes,t.scopes)}:e}function V(e,t){return t?{...e,callbacks:F(e.callbacks,t.callbacks),web_origins:F(e.web_origins,t.web_origins),allowed_logout_urls:F(e.allowed_logout_urls,t.allowed_logout_urls),allowed_origins:F(e.allowed_origins,t.allowed_origins)}:e}function te(e,t){return{...e.resourceServers,get:async(n,r)=>{const a=await e.resourceServers.get(n,r);if(!a||!t||n===t||!a.is_system)return a;const s=await e.resourceServers.get(t,r);return Q(a,s)},list:async(n,r)=>{const a=await e.resourceServers.list(n,r);if(!t||n===t)return a;const s=t,i=a.resource_servers.filter(o=>!!(o.is_system&&o.id)).map(o=>o.id);if(i.length===0)return a;const c=new Map;await Promise.all(i.map(async o=>{const l=await e.resourceServers.get(s,o);l&&c.set(o,l)}));const u=a.resource_servers.map(o=>o.is_system&&o.id?Q(o,c.get(o.id)??null):o);return{...a,resource_servers:u}}}}function ne(e,t){return{...e,resourceServers:te(e,t.controlPlaneTenantId)}}function re(e,t){const{controlPlaneTenantId:n,controlPlaneClientId:r}=t;return{...e,multiTenancyConfig:{controlPlaneTenantId:n,controlPlaneClientId:r},connections:{...e.connections,get:async(a,s)=>{const i=await e.connections.get(a,s);if(!i||!n||a===n)return i;const c=await e.connections.list(n);return E(i,c.connections||[])},list:async(a,s)=>{const i=await e.connections.list(a,s);if(!n||a===n)return i;const c=await e.connections.list(n),u=i.connections.map(o=>E(o,c.connections||[]));return{...i,connections:u}}},clientConnections:{...e.clientConnections,listByClient:async(a,s)=>{let i=await e.clientConnections.listByClient(a,s);if(i.length===0&&(i=(await e.connections.list(a)).connections||[]),!n||a===n)return i;const c=await e.connections.list(n);return i.map(u=>E(u,c.connections||[]))}},clients:{...e.clients,get:async(a,s)=>{const i=await e.clients.get(a,s);if(!i)return null;if(!n||!r||a===n&&s===r)return i;const c=await e.clients.get(n,r);return V(i,c)},getByClientId:async a=>{const s=await e.clients.getByClientId(a);if(!s)return null;if(!n||!r||s.tenant_id===n&&s.client_id===r)return s;const i=await e.clients.get(n,r);return{...V(s,i),tenant_id:s.tenant_id}}},emailProviders:{...e.emailProviders,get:async a=>{const s=await e.emailProviders.get(a);return s||(!n||a===n?null:e.emailProviders.get(n))}},resourceServers:te(e,n),hooks:_e(e,n)}}function J(e){if(!e||typeof e!="object")return!1;const t=e.metadata;return!t||typeof t!="object"?!1:t.inheritable===!0}function _e(e,t){return{...e.hooks,list:async(n,r)=>{const a=await e.hooks.list(n,r);if(!t||n===t)return a;const i=((await e.hooks.list(t,r)).hooks||[]).filter(J);if(i.length===0)return a;const c=new Set((a.hooks||[]).map(o=>o.hook_id)),u=i.filter(o=>!c.has(o.hook_id));return{...a,hooks:[...a.hooks||[],...u],length:typeof a.length=="number"?a.length+u.length:a.length}},get:async(n,r)=>{const a=await e.hooks.get(n,r);if(a||!t||n===t)return a;const s=await e.hooks.get(t,r);return s&&J(s)?s:null}}}function H(e,t){return re(e,t)}function ae(e){return async(t,n)=>{const r=t.var.user;return(r==null?void 0:r.tenant_id)===e&&r.org_name&&t.set("tenant_id",r.org_name),n()}}function se(e){return async(t,n)=>{if(!e.accessControl)return n();const{controlPlaneTenantId:r}=e.accessControl,a=t.var.org_name,s=t.var.organization_id,i=a||s;let c=t.var.tenant_id;const u=t.var.user,l=(u!=null&&u.aud?Array.isArray(u.aud)?u.aud:[u.aud]:[]).includes(_.MANAGEMENT_API_AUDIENCE);if(!c&&i&&l&&(t.set("tenant_id",i),c=i),!c)throw new I(400,{message:"Tenant ID not found in request"});if(!Y(s,c,r,a))throw new I(403,{message:`Access denied to tenant ${c}`});return n()}}function oe(e){return async(t,n)=>{if(!e.subdomainRouting)return n();const{baseDomain:r,reservedSubdomains:a=[],resolveSubdomain:s}=e.subdomainRouting,i=t.req.header("x-forwarded-host")||t.req.header("host")||"";let c=null;if(i.endsWith(r)){const o=i.slice(0,-(r.length+1));o&&!o.includes(".")&&(c=o)}if(c&&a.includes(c)&&(c=null),!c)return e.accessControl&&t.set("tenant_id",e.accessControl.controlPlaneTenantId),n();let u=null;if(s)u=await s(c);else if(e.subdomainRouting.useOrganizations!==!1&&e.accessControl)try{const o=await t.env.data.organizations.get(e.accessControl.controlPlaneTenantId,c);o&&(u=o.id)}catch{}if(!u)throw new I(404,{message:`Tenant not found for subdomain: ${c}`});return t.set("tenant_id",u),n()}}function ie(e){return async(t,n)=>{if(!e.databaseIsolation)return n();const r=t.var.tenant_id;if(!r)throw new I(400,{message:"Tenant ID not found in request"});try{const a=await e.databaseIsolation.getAdapters(r);t.env.data=a}catch(a){throw console.error(`Failed to resolve database for tenant ${r}:`,a),new I(500,{message:"Failed to resolve tenant database"})}return n()}}function B(e){const t=oe(e),n=se(e),r=ie(e);return async(a,s)=>(await t(a,async()=>{}),await n(a,async()=>{}),await r(a,async()=>{}),s())}function Ce(e){const{dataAdapter:t,controlPlane:n,controlPlane:{tenantId:r="control_plane",clientId:a}={},sync:s={resourceServers:!0,roles:!0},defaultPermissions:i=["tenant:admin"],requireOrganizationMatch:c=!1,managementApiExtensions:u=[],entityHooks:o,getChildTenantIds:l,getAdapters:g,...d}=e;let f=t,m=t;n&&(f=H(t,{controlPlaneTenantId:r,controlPlaneClientId:a}),m={...ne(t,{controlPlaneTenantId:r}),multiTenancyConfig:{controlPlaneTenantId:r,controlPlaneClientId:a}});const w=s!==!1,b=w?{resourceServers:s.resourceServers??!0,roles:s.roles??!0}:{resourceServers:!1,roles:!1},A={controlPlaneTenantId:r,getChildTenantIds:l??(async()=>(await _.fetchAll(v=>f.tenants.list(v),"tenants",{cursorField:"id",pageSize:100})).filter(v=>v.id!==r).map(v=>v.id)),getAdapters:g??(async()=>f),getControlPlaneAdapters:async()=>f,sync:b},{entityHooks:S,tenantHooks:h}=x(A),P={resourceServers:[S.resourceServers,...(o==null?void 0:o.resourceServers)??[]],roles:[S.roles,...(o==null?void 0:o.roles)??[]],connections:(o==null?void 0:o.connections)??[],tenants:(o==null?void 0:o.tenants)??[],rolePermissions:(o==null?void 0:o.rolePermissions)??[]},p=N({accessControl:{controlPlaneTenantId:r,requireOrganizationMatch:c,defaultPermissions:i}}),$=D({accessControl:{controlPlaneTenantId:r,requireOrganizationMatch:c,defaultPermissions:i}},{tenants:{async beforeCreate(z,v){return p.beforeCreate&&(v=await p.beforeCreate(z,v)),h.beforeCreate&&(v=await h.beforeCreate(z,v)),v},async afterCreate(z,v){var k,M;await((k=p.afterCreate)==null?void 0:k.call(p,z,v)),await((M=h.afterCreate)==null?void 0:M.call(h,z,v))},async beforeDelete(z,v){var k,M;await((k=p.beforeDelete)==null?void 0:k.call(p,z,v)),await((M=h.beforeDelete)==null?void 0:M.call(h,z,v))}}}),{app:j}=_.init({dataAdapter:f,managementDataAdapter:m,...d,entityHooks:P,managementApiExtensions:[...u,{path:"/tenants",router:$}]});return j.use("/api/v2/*",ae(r)),w&&j.use("/api/v2/*",ee()),{app:j,controlPlaneTenantId:r}}function Te(e){const t=q(e);return{name:"multi-tenancy",middleware:B(e),hooks:t,routes:[{path:"/management",handler:D(e,t)}],onRegister:async()=>{console.log("Multi-tenancy plugin registered"),e.accessControl&&console.log(` - Access control enabled (control plane: ${e.accessControl.controlPlaneTenantId})`),e.subdomainRouting&&console.log(` - Subdomain routing enabled (base domain: ${e.subdomainRouting.baseDomain})`),e.databaseIsolation&&console.log(" - Database isolation enabled")}}}function q(e){const t=e.accessControl?X(e.accessControl):{},n=e.databaseIsolation?Z(e.databaseIsolation):{},r=N(e);return{...t,...n,tenants:r}}function ce(e){const t=new de.Hono,n=q(e);return t.route("/tenants",D(e,n)),t}function be(e){return{hooks:q(e),middleware:B(e),app:ce(e),config:e,wrapAdapters:(t,n)=>{var r;return H(t,{controlPlaneTenantId:(r=e.accessControl)==null?void 0:r.controlPlaneTenantId,controlPlaneClientId:n==null?void 0:n.controlPlaneClientId})}}}exports.createAccessControlHooks=X;exports.createAccessControlMiddleware=se;exports.createControlPlaneTenantMiddleware=ae;exports.createDatabaseHooks=Z;exports.createDatabaseMiddleware=ie;exports.createMultiTenancy=ce;exports.createMultiTenancyHooks=q;exports.createMultiTenancyMiddleware=B;exports.createMultiTenancyPlugin=Te;exports.createProtectSyncedMiddleware=ee;exports.createProvisioningHooks=N;exports.createRuntimeFallbackAdapter=re;exports.createSubdomainMiddleware=oe;exports.createSyncHooks=x;exports.createTenantsOpenAPIRouter=D;exports.initMultiTenant=Ce;exports.setupMultiTenancy=be;exports.validateTenantAccess=Y;exports.withRuntimeFallback=H;exports.withSystemResourceServerInheritance=ne;
|
package/dist/multi-tenancy.mjs
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { Hono as
|
|
5
|
-
import { MANAGEMENT_API_SCOPES as
|
|
6
|
-
import { OpenAPIHono as
|
|
7
|
-
function
|
|
1
|
+
var te = Object.defineProperty;
|
|
2
|
+
var ne = (e, t, n) => t in e ? te(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
|
|
3
|
+
var O = (e, t, n) => ne(e, typeof t != "symbol" ? t + "" : t, n);
|
|
4
|
+
import { Hono as re } from "hono";
|
|
5
|
+
import { MANAGEMENT_API_SCOPES as ae, MANAGEMENT_API_AUDIENCE as X, fetchAll as D, auth0QuerySchema as se, tenantSchema as q, tenantInsertSchema as U, deepMergePatch as oe, connectionSchema as ie, connectionOptionsSchema as ce, init as le } from "authhero";
|
|
6
|
+
import { OpenAPIHono as ue, createRoute as M, z as I } from "@hono/zod-openapi";
|
|
7
|
+
function de(e) {
|
|
8
8
|
const { controlPlaneTenantId: t, requireOrganizationMatch: n = !0 } = e;
|
|
9
9
|
return {
|
|
10
10
|
async onTenantAccessValidation(r, a) {
|
|
11
11
|
if (a === t)
|
|
12
12
|
return !0;
|
|
13
13
|
if (n) {
|
|
14
|
-
const s = r.var.org_name,
|
|
15
|
-
return
|
|
14
|
+
const s = r.var.org_name, i = r.var.organization_id, c = s || i;
|
|
15
|
+
return c ? c.toLowerCase() === a.toLowerCase() : !1;
|
|
16
16
|
}
|
|
17
17
|
return !0;
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
function
|
|
21
|
+
function fe(e, t, n, r) {
|
|
22
22
|
if (t === n)
|
|
23
23
|
return !0;
|
|
24
24
|
const a = r || e;
|
|
25
25
|
return a ? a.toLowerCase() === t.toLowerCase() : !1;
|
|
26
26
|
}
|
|
27
|
-
function
|
|
27
|
+
function me(e) {
|
|
28
28
|
return {
|
|
29
29
|
async resolveDataAdapters(t) {
|
|
30
30
|
try {
|
|
@@ -39,31 +39,31 @@ function fe(e) {
|
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
-
function
|
|
42
|
+
function ge(e) {
|
|
43
43
|
return `urn:authhero:tenant:${e.toLowerCase()}`;
|
|
44
44
|
}
|
|
45
|
-
function
|
|
45
|
+
function Y(e) {
|
|
46
46
|
return {
|
|
47
47
|
async beforeCreate(t, n) {
|
|
48
48
|
return !n.audience && n.id ? {
|
|
49
49
|
...n,
|
|
50
|
-
audience:
|
|
50
|
+
audience: ge(n.id)
|
|
51
51
|
} : n;
|
|
52
52
|
},
|
|
53
53
|
async afterCreate(t, n) {
|
|
54
54
|
const { accessControl: r, databaseIsolation: a } = e;
|
|
55
|
-
r && t.ctx && await
|
|
55
|
+
r && t.ctx && await we(t, n, r), a != null && a.onProvision && await a.onProvision(n.id);
|
|
56
56
|
},
|
|
57
57
|
async beforeDelete(t, n) {
|
|
58
58
|
const { accessControl: r, databaseIsolation: a } = e;
|
|
59
59
|
if (r)
|
|
60
60
|
try {
|
|
61
|
-
const
|
|
61
|
+
const i = (await t.adapters.organizations.list(
|
|
62
62
|
r.controlPlaneTenantId
|
|
63
|
-
)).organizations.find((
|
|
64
|
-
|
|
63
|
+
)).organizations.find((c) => c.name === n);
|
|
64
|
+
i && await t.adapters.organizations.remove(
|
|
65
65
|
r.controlPlaneTenantId,
|
|
66
|
-
|
|
66
|
+
i.id
|
|
67
67
|
);
|
|
68
68
|
} catch (s) {
|
|
69
69
|
console.warn(
|
|
@@ -83,13 +83,13 @@ function X(e) {
|
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
-
async function
|
|
86
|
+
async function we(e, t, n) {
|
|
87
87
|
const {
|
|
88
88
|
controlPlaneTenantId: r,
|
|
89
89
|
defaultPermissions: a,
|
|
90
90
|
defaultRoles: s,
|
|
91
|
-
issuer:
|
|
92
|
-
adminRoleName:
|
|
91
|
+
issuer: i,
|
|
92
|
+
adminRoleName: c = "Tenant Admin",
|
|
93
93
|
adminRoleDescription: u = "Full access to all tenant management operations",
|
|
94
94
|
addCreatorToOrganization: o = !0
|
|
95
95
|
} = n, l = await e.adapters.organizations.create(
|
|
@@ -100,14 +100,14 @@ async function ge(e, t, n) {
|
|
|
100
100
|
}
|
|
101
101
|
);
|
|
102
102
|
let g;
|
|
103
|
-
if (
|
|
103
|
+
if (i && (g = await pe(
|
|
104
104
|
e,
|
|
105
105
|
r,
|
|
106
|
-
|
|
106
|
+
c,
|
|
107
107
|
u
|
|
108
108
|
)), o && e.ctx) {
|
|
109
109
|
const d = e.ctx.var.user;
|
|
110
|
-
if (d != null && d.sub && !await
|
|
110
|
+
if (d != null && d.sub && !await he(
|
|
111
111
|
e,
|
|
112
112
|
r,
|
|
113
113
|
d.sub
|
|
@@ -136,7 +136,7 @@ async function ge(e, t, n) {
|
|
|
136
136
|
`Would grant permissions ${a.join(", ")} to organization ${l.id}`
|
|
137
137
|
);
|
|
138
138
|
}
|
|
139
|
-
async function
|
|
139
|
+
async function he(e, t, n) {
|
|
140
140
|
const r = await e.adapters.userRoles.list(
|
|
141
141
|
t,
|
|
142
142
|
n,
|
|
@@ -150,7 +150,7 @@ async function we(e, t, n) {
|
|
|
150
150
|
a.id,
|
|
151
151
|
{ per_page: 1e3 }
|
|
152
152
|
)).some(
|
|
153
|
-
(
|
|
153
|
+
(c) => c.permission_name === "admin:organizations"
|
|
154
154
|
))
|
|
155
155
|
return !0;
|
|
156
156
|
return !1;
|
|
@@ -159,23 +159,23 @@ async function pe(e, t, n, r) {
|
|
|
159
159
|
const s = (await e.adapters.roles.list(t, {})).roles.find((o) => o.name === n);
|
|
160
160
|
if (s)
|
|
161
161
|
return s.id;
|
|
162
|
-
const
|
|
162
|
+
const i = await e.adapters.roles.create(t, {
|
|
163
163
|
name: n,
|
|
164
164
|
description: r
|
|
165
|
-
}),
|
|
166
|
-
role_id:
|
|
167
|
-
resource_server_identifier:
|
|
165
|
+
}), c = X, u = ae.map((o) => ({
|
|
166
|
+
role_id: i.id,
|
|
167
|
+
resource_server_identifier: c,
|
|
168
168
|
permission_name: o.value
|
|
169
169
|
}));
|
|
170
170
|
return await e.adapters.rolePermissions.assign(
|
|
171
171
|
t,
|
|
172
|
-
|
|
172
|
+
i.id,
|
|
173
173
|
u
|
|
174
|
-
),
|
|
174
|
+
), i.id;
|
|
175
175
|
}
|
|
176
176
|
function G(e, t, n = () => !0) {
|
|
177
|
-
const { controlPlaneTenantId: r, getChildTenantIds: a, getAdapters: s } = e,
|
|
178
|
-
async function
|
|
177
|
+
const { controlPlaneTenantId: r, getChildTenantIds: a, getAdapters: s } = e, i = /* @__PURE__ */ new Map();
|
|
178
|
+
async function c(l, g, d) {
|
|
179
179
|
return (await t(l).list(g, {
|
|
180
180
|
q: `name:${d}`,
|
|
181
181
|
per_page: 1
|
|
@@ -189,7 +189,7 @@ function G(e, t, n = () => !0) {
|
|
|
189
189
|
const m = await s(f), w = t(m), y = {
|
|
190
190
|
...d.transform(l),
|
|
191
191
|
is_system: !0
|
|
192
|
-
}, _ = await
|
|
192
|
+
}, _ = await c(m, f, l.name), b = _ ? w.getId(_) : void 0;
|
|
193
193
|
if (_ && b) {
|
|
194
194
|
const P = w.preserveOnUpdate ? w.preserveOnUpdate(_, y) : y;
|
|
195
195
|
await w.update(f, b, P);
|
|
@@ -209,7 +209,7 @@ function G(e, t, n = () => !0) {
|
|
|
209
209
|
await Promise.all(
|
|
210
210
|
g.map(async (d) => {
|
|
211
211
|
try {
|
|
212
|
-
const f = await s(d), m = t(f), w = await
|
|
212
|
+
const f = await s(d), m = t(f), w = await c(f, d, l), C = w ? m.getId(w) : void 0;
|
|
213
213
|
w && C && await m.remove(d, C);
|
|
214
214
|
} catch (f) {
|
|
215
215
|
console.error(
|
|
@@ -230,22 +230,22 @@ function G(e, t, n = () => !0) {
|
|
|
230
230
|
beforeDelete: async (l, g) => {
|
|
231
231
|
if (l.tenantId !== r) return;
|
|
232
232
|
const f = await t(l.adapters).get(l.tenantId, g);
|
|
233
|
-
f && n(f) &&
|
|
233
|
+
f && n(f) && i.set(g, f);
|
|
234
234
|
},
|
|
235
235
|
afterDelete: async (l, g) => {
|
|
236
236
|
if (l.tenantId !== r) return;
|
|
237
|
-
const d =
|
|
238
|
-
d && (
|
|
237
|
+
const d = i.get(g);
|
|
238
|
+
d && (i.delete(g), await o(d.name));
|
|
239
239
|
}
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
|
-
function
|
|
242
|
+
function H(e, t, n = () => !0) {
|
|
243
243
|
const { controlPlaneTenantId: r, getControlPlaneAdapters: a, getAdapters: s } = e;
|
|
244
244
|
return {
|
|
245
|
-
async afterCreate(
|
|
246
|
-
if (
|
|
245
|
+
async afterCreate(i, c) {
|
|
246
|
+
if (c.id !== r)
|
|
247
247
|
try {
|
|
248
|
-
const u = await a(), o = await s(
|
|
248
|
+
const u = await a(), o = await s(c.id), l = t(u), g = t(o), d = await D(
|
|
249
249
|
(f) => l.listPaginated(r, f),
|
|
250
250
|
l.listKey,
|
|
251
251
|
{ cursorField: "id", pageSize: 100 }
|
|
@@ -254,13 +254,13 @@ function L(e, t, n = () => !0) {
|
|
|
254
254
|
d.filter((f) => n(f)).map(async (f) => {
|
|
255
255
|
try {
|
|
256
256
|
const m = l.transform(f);
|
|
257
|
-
await g.create(
|
|
257
|
+
await g.create(c.id, {
|
|
258
258
|
...m,
|
|
259
259
|
is_system: !0
|
|
260
260
|
});
|
|
261
261
|
} catch (m) {
|
|
262
262
|
console.error(
|
|
263
|
-
`Failed to sync entity to new tenant "${
|
|
263
|
+
`Failed to sync entity to new tenant "${c.id}":`,
|
|
264
264
|
m
|
|
265
265
|
);
|
|
266
266
|
}
|
|
@@ -268,7 +268,7 @@ function L(e, t, n = () => !0) {
|
|
|
268
268
|
);
|
|
269
269
|
} catch (u) {
|
|
270
270
|
console.error(
|
|
271
|
-
`Failed to sync entities to new tenant "${
|
|
271
|
+
`Failed to sync entities to new tenant "${c.id}":`,
|
|
272
272
|
u
|
|
273
273
|
);
|
|
274
274
|
}
|
|
@@ -293,7 +293,7 @@ const W = (e) => ({
|
|
|
293
293
|
token_lifetime: t.token_lifetime,
|
|
294
294
|
token_lifetime_for_web: t.token_lifetime_for_web
|
|
295
295
|
})
|
|
296
|
-
}),
|
|
296
|
+
}), L = (e) => ({
|
|
297
297
|
list: async (t, n) => (await e.roles.list(t, n)).roles,
|
|
298
298
|
listPaginated: (t, n) => e.roles.list(t, n),
|
|
299
299
|
get: (t, n) => e.roles.get(t, n),
|
|
@@ -312,19 +312,19 @@ function K(e) {
|
|
|
312
312
|
var t;
|
|
313
313
|
return ((t = e.metadata) == null ? void 0 : t.sync) !== !1;
|
|
314
314
|
}
|
|
315
|
-
function
|
|
316
|
-
const { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, a = t.roles ?? !0, s = (m) => K(m) ? n.resourceServers ? n.resourceServers(m) : !0 : !1,
|
|
315
|
+
function ye(e) {
|
|
316
|
+
const { sync: t = {}, filters: n = {} } = e, r = t.resourceServers ?? !0, a = t.roles ?? !0, s = (m) => K(m) ? n.resourceServers ? n.resourceServers(m) : !0 : !1, i = (m) => K(m) ? n.roles ? n.roles(m) : !0 : !1, c = r ? G(
|
|
317
317
|
e,
|
|
318
318
|
W,
|
|
319
319
|
s
|
|
320
|
-
) : void 0, u = a ? G(e,
|
|
320
|
+
) : void 0, u = a ? G(e, L, i) : void 0, o = r ? H(
|
|
321
321
|
e,
|
|
322
322
|
W,
|
|
323
323
|
s
|
|
324
|
-
) : void 0, l = a ?
|
|
324
|
+
) : void 0, l = a ? H(
|
|
325
325
|
e,
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
L,
|
|
327
|
+
i
|
|
328
328
|
) : void 0, g = a ? {
|
|
329
329
|
async afterCreate(m, w) {
|
|
330
330
|
var C;
|
|
@@ -332,53 +332,53 @@ function he(e) {
|
|
|
332
332
|
await ((C = l == null ? void 0 : l.afterCreate) == null ? void 0 : C.call(l, m, w));
|
|
333
333
|
try {
|
|
334
334
|
const y = await e.getControlPlaneAdapters(), _ = await e.getAdapters(w.id), b = await D(
|
|
335
|
-
(
|
|
335
|
+
(h) => y.roles.list(
|
|
336
336
|
e.controlPlaneTenantId,
|
|
337
|
-
|
|
337
|
+
h
|
|
338
338
|
),
|
|
339
339
|
"roles",
|
|
340
340
|
{ cursorField: "id", pageSize: 100 }
|
|
341
341
|
), P = /* @__PURE__ */ new Map();
|
|
342
|
-
for (const
|
|
342
|
+
for (const h of b.filter(
|
|
343
343
|
(T) => {
|
|
344
|
-
var
|
|
345
|
-
return ((
|
|
344
|
+
var p;
|
|
345
|
+
return ((p = n.roles) == null ? void 0 : p.call(n, T)) ?? !0;
|
|
346
346
|
}
|
|
347
347
|
)) {
|
|
348
348
|
const T = await d(
|
|
349
349
|
_,
|
|
350
350
|
w.id,
|
|
351
|
-
|
|
351
|
+
h.name
|
|
352
352
|
);
|
|
353
|
-
T && P.set(
|
|
353
|
+
T && P.set(h.name, T.id);
|
|
354
354
|
}
|
|
355
|
-
for (const
|
|
355
|
+
for (const h of b.filter(
|
|
356
356
|
(T) => {
|
|
357
|
-
var
|
|
358
|
-
return ((
|
|
357
|
+
var p;
|
|
358
|
+
return ((p = n.roles) == null ? void 0 : p.call(n, T)) ?? !0;
|
|
359
359
|
}
|
|
360
360
|
)) {
|
|
361
|
-
const T = P.get(
|
|
361
|
+
const T = P.get(h.name);
|
|
362
362
|
if (T)
|
|
363
363
|
try {
|
|
364
|
-
const
|
|
364
|
+
const p = await y.rolePermissions.list(
|
|
365
365
|
e.controlPlaneTenantId,
|
|
366
|
-
|
|
366
|
+
h.id,
|
|
367
367
|
{}
|
|
368
368
|
);
|
|
369
|
-
|
|
369
|
+
p.length > 0 && await _.rolePermissions.assign(
|
|
370
370
|
w.id,
|
|
371
371
|
T,
|
|
372
|
-
|
|
372
|
+
p.map((z) => ({
|
|
373
373
|
role_id: T,
|
|
374
374
|
resource_server_identifier: z.resource_server_identifier,
|
|
375
375
|
permission_name: z.permission_name
|
|
376
376
|
}))
|
|
377
377
|
);
|
|
378
|
-
} catch (
|
|
378
|
+
} catch (p) {
|
|
379
379
|
console.error(
|
|
380
|
-
`Failed to sync permissions for role "${
|
|
381
|
-
|
|
380
|
+
`Failed to sync permissions for role "${h.name}" to tenant "${w.id}":`,
|
|
381
|
+
p
|
|
382
382
|
);
|
|
383
383
|
}
|
|
384
384
|
}
|
|
@@ -399,7 +399,7 @@ function he(e) {
|
|
|
399
399
|
}
|
|
400
400
|
return {
|
|
401
401
|
entityHooks: {
|
|
402
|
-
resourceServers:
|
|
402
|
+
resourceServers: c,
|
|
403
403
|
roles: u
|
|
404
404
|
},
|
|
405
405
|
tenantHooks: {
|
|
@@ -433,8 +433,8 @@ var A = class extends Error {
|
|
|
433
433
|
*/
|
|
434
434
|
constructor(t = 500, n) {
|
|
435
435
|
super(n == null ? void 0 : n.message, { cause: n == null ? void 0 : n.cause });
|
|
436
|
-
|
|
437
|
-
|
|
436
|
+
O(this, "res");
|
|
437
|
+
O(this, "status");
|
|
438
438
|
this.res = n == null ? void 0 : n.res, this.status = t;
|
|
439
439
|
}
|
|
440
440
|
/**
|
|
@@ -452,14 +452,14 @@ var A = class extends Error {
|
|
|
452
452
|
}
|
|
453
453
|
};
|
|
454
454
|
function N(e, t) {
|
|
455
|
-
const n = new
|
|
455
|
+
const n = new ue();
|
|
456
456
|
return n.openapi(
|
|
457
457
|
M({
|
|
458
458
|
tags: ["tenants"],
|
|
459
459
|
method: "get",
|
|
460
460
|
path: "/",
|
|
461
461
|
request: {
|
|
462
|
-
query:
|
|
462
|
+
query: se
|
|
463
463
|
},
|
|
464
464
|
security: [
|
|
465
465
|
{
|
|
@@ -484,24 +484,24 @@ function N(e, t) {
|
|
|
484
484
|
}),
|
|
485
485
|
async (r) => {
|
|
486
486
|
var m, w, C, y, _, b;
|
|
487
|
-
const a = r.req.valid("query"), { page: s, per_page:
|
|
487
|
+
const a = r.req.valid("query"), { page: s, per_page: i, include_totals: c, q: u } = a, o = r.var.user, l = (o == null ? void 0 : o.permissions) || [];
|
|
488
488
|
if (l.includes("auth:read") || l.includes("admin:organizations")) {
|
|
489
489
|
const P = await r.env.data.tenants.list({
|
|
490
490
|
page: s,
|
|
491
|
-
per_page:
|
|
492
|
-
include_totals:
|
|
491
|
+
per_page: i,
|
|
492
|
+
include_totals: c,
|
|
493
493
|
q: u
|
|
494
494
|
});
|
|
495
|
-
return
|
|
495
|
+
return c ? r.json({
|
|
496
496
|
tenants: P.tenants,
|
|
497
497
|
start: ((m = P.totals) == null ? void 0 : m.start) ?? 0,
|
|
498
|
-
limit: ((w = P.totals) == null ? void 0 : w.limit) ??
|
|
498
|
+
limit: ((w = P.totals) == null ? void 0 : w.limit) ?? i,
|
|
499
499
|
length: P.tenants.length
|
|
500
500
|
}) : r.json({ tenants: P.tenants });
|
|
501
501
|
}
|
|
502
502
|
const d = ((C = e.accessControl) == null ? void 0 : C.controlPlaneTenantId) ?? ((y = r.env.data.multiTenancyConfig) == null ? void 0 : y.controlPlaneTenantId);
|
|
503
503
|
if (d && (o != null && o.sub)) {
|
|
504
|
-
const
|
|
504
|
+
const h = (await D(
|
|
505
505
|
(R) => r.env.data.userOrganizations.listUserOrganizations(
|
|
506
506
|
d,
|
|
507
507
|
o.sub,
|
|
@@ -509,44 +509,44 @@ function N(e, t) {
|
|
|
509
509
|
),
|
|
510
510
|
"organizations"
|
|
511
511
|
)).map((R) => R.name);
|
|
512
|
-
if (
|
|
513
|
-
return
|
|
512
|
+
if (h.length === 0)
|
|
513
|
+
return c ? r.json({
|
|
514
514
|
tenants: [],
|
|
515
515
|
start: 0,
|
|
516
|
-
limit:
|
|
516
|
+
limit: i ?? 50,
|
|
517
517
|
length: 0
|
|
518
518
|
}) : r.json({ tenants: [] });
|
|
519
|
-
const T =
|
|
520
|
-
if (
|
|
521
|
-
return
|
|
519
|
+
const T = h.length, p = s ?? 0, z = i ?? 50, j = p * z, F = h.slice(j, j + z);
|
|
520
|
+
if (F.length === 0)
|
|
521
|
+
return c ? r.json({
|
|
522
522
|
tenants: [],
|
|
523
|
-
start:
|
|
523
|
+
start: j,
|
|
524
524
|
limit: z,
|
|
525
525
|
length: T
|
|
526
526
|
}) : r.json({ tenants: [] });
|
|
527
|
-
const S =
|
|
527
|
+
const S = F.map((R) => `id:${R}`).join(" OR "), v = u ? `(${S}) AND (${u})` : S, $ = await r.env.data.tenants.list({
|
|
528
528
|
q: v,
|
|
529
529
|
per_page: z,
|
|
530
530
|
include_totals: !1
|
|
531
531
|
// We calculate totals from accessibleTenantIds
|
|
532
532
|
});
|
|
533
|
-
return
|
|
533
|
+
return c ? r.json({
|
|
534
534
|
tenants: $.tenants,
|
|
535
|
-
start:
|
|
535
|
+
start: j,
|
|
536
536
|
limit: z,
|
|
537
537
|
length: T
|
|
538
538
|
}) : r.json({ tenants: $.tenants });
|
|
539
539
|
}
|
|
540
540
|
const f = await r.env.data.tenants.list({
|
|
541
541
|
page: s,
|
|
542
|
-
per_page:
|
|
543
|
-
include_totals:
|
|
542
|
+
per_page: i,
|
|
543
|
+
include_totals: c,
|
|
544
544
|
q: u
|
|
545
545
|
});
|
|
546
|
-
return
|
|
546
|
+
return c ? r.json({
|
|
547
547
|
tenants: f.tenants,
|
|
548
548
|
start: ((_ = f.totals) == null ? void 0 : _.start) ?? 0,
|
|
549
|
-
limit: ((b = f.totals) == null ? void 0 : b.limit) ??
|
|
549
|
+
limit: ((b = f.totals) == null ? void 0 : b.limit) ?? i,
|
|
550
550
|
length: f.tenants.length
|
|
551
551
|
}) : r.json({ tenants: f.tenants });
|
|
552
552
|
}
|
|
@@ -594,13 +594,13 @@ function N(e, t) {
|
|
|
594
594
|
message: "Authentication required to create tenants"
|
|
595
595
|
});
|
|
596
596
|
let s = r.req.valid("json");
|
|
597
|
-
const
|
|
597
|
+
const i = {
|
|
598
598
|
adapters: r.env.data,
|
|
599
599
|
ctx: r
|
|
600
600
|
};
|
|
601
|
-
(u = t.tenants) != null && u.beforeCreate && (s = await t.tenants.beforeCreate(
|
|
602
|
-
const
|
|
603
|
-
return (o = t.tenants) != null && o.afterCreate && await t.tenants.afterCreate(
|
|
601
|
+
(u = t.tenants) != null && u.beforeCreate && (s = await t.tenants.beforeCreate(i, s));
|
|
602
|
+
const c = await r.env.data.tenants.create(s);
|
|
603
|
+
return (o = t.tenants) != null && o.afterCreate && await t.tenants.afterCreate(i, c), r.json(c, 201);
|
|
604
604
|
}
|
|
605
605
|
), n.openapi(
|
|
606
606
|
M({
|
|
@@ -658,11 +658,11 @@ function N(e, t) {
|
|
|
658
658
|
throw new A(404, {
|
|
659
659
|
message: "Tenant not found"
|
|
660
660
|
});
|
|
661
|
-
const
|
|
661
|
+
const c = {
|
|
662
662
|
adapters: r.env.data,
|
|
663
663
|
ctx: r
|
|
664
664
|
};
|
|
665
|
-
return (l = t.tenants) != null && l.beforeDelete && await t.tenants.beforeDelete(
|
|
665
|
+
return (l = t.tenants) != null && l.beforeDelete && await t.tenants.beforeDelete(c, a), await r.env.data.tenants.remove(a), (g = t.tenants) != null && g.afterDelete && await t.tenants.afterDelete(c, a), r.body(null, 204);
|
|
666
666
|
}
|
|
667
667
|
), n.openapi(
|
|
668
668
|
M({
|
|
@@ -732,12 +732,12 @@ function N(e, t) {
|
|
|
732
732
|
}
|
|
733
733
|
}),
|
|
734
734
|
async (r) => {
|
|
735
|
-
const a = r.req.valid("json"), { id: s, ...
|
|
736
|
-
if (!
|
|
735
|
+
const a = r.req.valid("json"), { id: s, ...i } = a, c = await r.env.data.tenants.get(r.var.tenant_id);
|
|
736
|
+
if (!c)
|
|
737
737
|
throw new A(404, {
|
|
738
738
|
message: "Tenant not found"
|
|
739
739
|
});
|
|
740
|
-
const u =
|
|
740
|
+
const u = oe(c, i);
|
|
741
741
|
await r.env.data.tenants.update(r.var.tenant_id, u);
|
|
742
742
|
const o = await r.env.data.tenants.get(r.var.tenant_id);
|
|
743
743
|
if (!o)
|
|
@@ -748,7 +748,7 @@ function N(e, t) {
|
|
|
748
748
|
}
|
|
749
749
|
), n;
|
|
750
750
|
}
|
|
751
|
-
function
|
|
751
|
+
function ve(e) {
|
|
752
752
|
const t = [
|
|
753
753
|
{
|
|
754
754
|
pattern: /\/api\/v2\/resource-servers\/([^/]+)$/,
|
|
@@ -764,7 +764,7 @@ function ye(e) {
|
|
|
764
764
|
}
|
|
765
765
|
return null;
|
|
766
766
|
}
|
|
767
|
-
async function
|
|
767
|
+
async function _e(e, t, n) {
|
|
768
768
|
try {
|
|
769
769
|
switch (n.type) {
|
|
770
770
|
case "resource_server": {
|
|
@@ -786,50 +786,50 @@ async function ve(e, t, n) {
|
|
|
786
786
|
return !1;
|
|
787
787
|
}
|
|
788
788
|
}
|
|
789
|
-
function
|
|
789
|
+
function Ce(e) {
|
|
790
790
|
return {
|
|
791
791
|
resource_server: "resource server",
|
|
792
792
|
role: "role",
|
|
793
793
|
connection: "connection"
|
|
794
794
|
}[e];
|
|
795
795
|
}
|
|
796
|
-
function
|
|
796
|
+
function Te() {
|
|
797
797
|
return async (e, t) => {
|
|
798
798
|
if (!["PATCH", "PUT", "DELETE"].includes(e.req.method))
|
|
799
799
|
return t();
|
|
800
|
-
const n =
|
|
800
|
+
const n = ve(e.req.path);
|
|
801
801
|
if (!n)
|
|
802
802
|
return t();
|
|
803
803
|
const r = e.var.tenant_id || e.req.header("x-tenant-id") || e.req.header("tenant-id");
|
|
804
804
|
if (!r)
|
|
805
805
|
return t();
|
|
806
|
-
if (await
|
|
806
|
+
if (await _e(e.env.data, r, n))
|
|
807
807
|
throw new A(403, {
|
|
808
|
-
message: `This ${
|
|
808
|
+
message: `This ${Ce(n.type)} is a system resource and cannot be modified. Make changes in the control plane instead.`
|
|
809
809
|
});
|
|
810
810
|
return t();
|
|
811
811
|
};
|
|
812
812
|
}
|
|
813
|
-
function
|
|
813
|
+
function E(e, t) {
|
|
814
814
|
const n = t.find(
|
|
815
815
|
(a) => a.strategy === e.strategy
|
|
816
816
|
);
|
|
817
817
|
if (!(n != null && n.options))
|
|
818
818
|
return e;
|
|
819
|
-
const r =
|
|
819
|
+
const r = ie.passthrough().parse({
|
|
820
820
|
...n,
|
|
821
821
|
...e
|
|
822
822
|
});
|
|
823
|
-
return r.options =
|
|
823
|
+
return r.options = ce.passthrough().parse({
|
|
824
824
|
...n.options || {},
|
|
825
825
|
...e.options
|
|
826
826
|
}), r;
|
|
827
827
|
}
|
|
828
|
-
function
|
|
828
|
+
function k(e, t) {
|
|
829
829
|
const n = [...t || [], ...e || []];
|
|
830
830
|
return [...new Set(n)];
|
|
831
831
|
}
|
|
832
|
-
function
|
|
832
|
+
function be(e, t) {
|
|
833
833
|
if (!(t != null && t.length))
|
|
834
834
|
return e || [];
|
|
835
835
|
if (!(e != null && e.length))
|
|
@@ -844,7 +844,7 @@ function Te(e, t) {
|
|
|
844
844
|
function Q(e, t) {
|
|
845
845
|
return t ? {
|
|
846
846
|
...e,
|
|
847
|
-
scopes:
|
|
847
|
+
scopes: be(
|
|
848
848
|
e.scopes,
|
|
849
849
|
t.scopes
|
|
850
850
|
)
|
|
@@ -853,22 +853,22 @@ function Q(e, t) {
|
|
|
853
853
|
function V(e, t) {
|
|
854
854
|
return t ? {
|
|
855
855
|
...e,
|
|
856
|
-
callbacks:
|
|
857
|
-
web_origins:
|
|
856
|
+
callbacks: k(e.callbacks, t.callbacks),
|
|
857
|
+
web_origins: k(
|
|
858
858
|
e.web_origins,
|
|
859
859
|
t.web_origins
|
|
860
860
|
),
|
|
861
|
-
allowed_logout_urls:
|
|
861
|
+
allowed_logout_urls: k(
|
|
862
862
|
e.allowed_logout_urls,
|
|
863
863
|
t.allowed_logout_urls
|
|
864
864
|
),
|
|
865
|
-
allowed_origins:
|
|
865
|
+
allowed_origins: k(
|
|
866
866
|
e.allowed_origins,
|
|
867
867
|
t.allowed_origins
|
|
868
868
|
)
|
|
869
869
|
} : e;
|
|
870
870
|
}
|
|
871
|
-
function
|
|
871
|
+
function Z(e, t) {
|
|
872
872
|
return {
|
|
873
873
|
...e.resourceServers,
|
|
874
874
|
get: async (n, r) => {
|
|
@@ -891,22 +891,22 @@ function Y(e, t) {
|
|
|
891
891
|
const a = await e.resourceServers.list(n, r);
|
|
892
892
|
if (!t || n === t)
|
|
893
893
|
return a;
|
|
894
|
-
const s = t,
|
|
894
|
+
const s = t, i = a.resource_servers.filter(
|
|
895
895
|
(o) => !!(o.is_system && o.id)
|
|
896
896
|
).map((o) => o.id);
|
|
897
|
-
if (
|
|
897
|
+
if (i.length === 0)
|
|
898
898
|
return a;
|
|
899
|
-
const
|
|
899
|
+
const c = /* @__PURE__ */ new Map();
|
|
900
900
|
await Promise.all(
|
|
901
|
-
|
|
901
|
+
i.map(async (o) => {
|
|
902
902
|
const l = await e.resourceServers.get(s, o);
|
|
903
|
-
l &&
|
|
903
|
+
l && c.set(o, l);
|
|
904
904
|
})
|
|
905
905
|
);
|
|
906
906
|
const u = a.resource_servers.map(
|
|
907
907
|
(o) => o.is_system && o.id ? Q(
|
|
908
908
|
o,
|
|
909
|
-
|
|
909
|
+
c.get(o.id) ?? null
|
|
910
910
|
) : o
|
|
911
911
|
);
|
|
912
912
|
return {
|
|
@@ -916,16 +916,16 @@ function Y(e, t) {
|
|
|
916
916
|
}
|
|
917
917
|
};
|
|
918
918
|
}
|
|
919
|
-
function
|
|
919
|
+
function Pe(e, t) {
|
|
920
920
|
return {
|
|
921
921
|
...e,
|
|
922
|
-
resourceServers:
|
|
922
|
+
resourceServers: Z(
|
|
923
923
|
e,
|
|
924
924
|
t.controlPlaneTenantId
|
|
925
925
|
)
|
|
926
926
|
};
|
|
927
927
|
}
|
|
928
|
-
function
|
|
928
|
+
function Ae(e, t) {
|
|
929
929
|
const { controlPlaneTenantId: n, controlPlaneClientId: r } = t;
|
|
930
930
|
return {
|
|
931
931
|
...e,
|
|
@@ -937,30 +937,30 @@ function Pe(e, t) {
|
|
|
937
937
|
connections: {
|
|
938
938
|
...e.connections,
|
|
939
939
|
get: async (a, s) => {
|
|
940
|
-
const
|
|
940
|
+
const i = await e.connections.get(
|
|
941
941
|
a,
|
|
942
942
|
s
|
|
943
943
|
);
|
|
944
|
-
if (!
|
|
945
|
-
return
|
|
946
|
-
const
|
|
947
|
-
return
|
|
948
|
-
|
|
949
|
-
|
|
944
|
+
if (!i || !n || a === n)
|
|
945
|
+
return i;
|
|
946
|
+
const c = await e.connections.list(n);
|
|
947
|
+
return E(
|
|
948
|
+
i,
|
|
949
|
+
c.connections || []
|
|
950
950
|
);
|
|
951
951
|
},
|
|
952
952
|
list: async (a, s) => {
|
|
953
|
-
const
|
|
953
|
+
const i = await e.connections.list(a, s);
|
|
954
954
|
if (!n || a === n)
|
|
955
|
-
return
|
|
956
|
-
const
|
|
957
|
-
(o) =>
|
|
955
|
+
return i;
|
|
956
|
+
const c = await e.connections.list(n), u = i.connections.map(
|
|
957
|
+
(o) => E(
|
|
958
958
|
o,
|
|
959
|
-
|
|
959
|
+
c.connections || []
|
|
960
960
|
)
|
|
961
961
|
);
|
|
962
962
|
return {
|
|
963
|
-
...
|
|
963
|
+
...i,
|
|
964
964
|
connections: u
|
|
965
965
|
};
|
|
966
966
|
}
|
|
@@ -968,17 +968,17 @@ function Pe(e, t) {
|
|
|
968
968
|
clientConnections: {
|
|
969
969
|
...e.clientConnections,
|
|
970
970
|
listByClient: async (a, s) => {
|
|
971
|
-
let
|
|
971
|
+
let i = await e.clientConnections.listByClient(
|
|
972
972
|
a,
|
|
973
973
|
s
|
|
974
974
|
);
|
|
975
|
-
if (
|
|
976
|
-
return
|
|
977
|
-
const
|
|
978
|
-
return
|
|
979
|
-
(u) =>
|
|
975
|
+
if (i.length === 0 && (i = (await e.connections.list(a)).connections || []), !n || a === n)
|
|
976
|
+
return i;
|
|
977
|
+
const c = await e.connections.list(n);
|
|
978
|
+
return i.map(
|
|
979
|
+
(u) => E(
|
|
980
980
|
u,
|
|
981
|
-
|
|
981
|
+
c.connections || []
|
|
982
982
|
)
|
|
983
983
|
);
|
|
984
984
|
}
|
|
@@ -986,16 +986,16 @@ function Pe(e, t) {
|
|
|
986
986
|
clients: {
|
|
987
987
|
...e.clients,
|
|
988
988
|
get: async (a, s) => {
|
|
989
|
-
const
|
|
990
|
-
if (!
|
|
989
|
+
const i = await e.clients.get(a, s);
|
|
990
|
+
if (!i)
|
|
991
991
|
return null;
|
|
992
992
|
if (!n || !r || a === n && s === r)
|
|
993
|
-
return
|
|
994
|
-
const
|
|
993
|
+
return i;
|
|
994
|
+
const c = await e.clients.get(
|
|
995
995
|
n,
|
|
996
996
|
r
|
|
997
997
|
);
|
|
998
|
-
return V(
|
|
998
|
+
return V(i, c);
|
|
999
999
|
},
|
|
1000
1000
|
getByClientId: async (a) => {
|
|
1001
1001
|
const s = await e.clients.getByClientId(a);
|
|
@@ -1003,12 +1003,12 @@ function Pe(e, t) {
|
|
|
1003
1003
|
return null;
|
|
1004
1004
|
if (!n || !r || s.tenant_id === n && s.client_id === r)
|
|
1005
1005
|
return s;
|
|
1006
|
-
const
|
|
1006
|
+
const i = await e.clients.get(
|
|
1007
1007
|
n,
|
|
1008
1008
|
r
|
|
1009
1009
|
);
|
|
1010
1010
|
return {
|
|
1011
|
-
...V(s,
|
|
1011
|
+
...V(s, i),
|
|
1012
1012
|
tenant_id: s.tenant_id
|
|
1013
1013
|
};
|
|
1014
1014
|
}
|
|
@@ -1020,48 +1020,90 @@ function Pe(e, t) {
|
|
|
1020
1020
|
return s || (!n || a === n ? null : e.emailProviders.get(n));
|
|
1021
1021
|
}
|
|
1022
1022
|
},
|
|
1023
|
-
resourceServers:
|
|
1023
|
+
resourceServers: Z(
|
|
1024
1024
|
e,
|
|
1025
1025
|
n
|
|
1026
|
-
)
|
|
1026
|
+
),
|
|
1027
|
+
hooks: Se(e, n)
|
|
1027
1028
|
// Note: Additional adapters can be extended here for runtime fallback:
|
|
1028
1029
|
// - promptSettings: Fall back to control plane prompts
|
|
1029
1030
|
// - branding: Fall back to control plane branding/themes
|
|
1030
1031
|
};
|
|
1031
1032
|
}
|
|
1032
|
-
function
|
|
1033
|
-
|
|
1033
|
+
function J(e) {
|
|
1034
|
+
if (!e || typeof e != "object") return !1;
|
|
1035
|
+
const t = e.metadata;
|
|
1036
|
+
return !t || typeof t != "object" ? !1 : t.inheritable === !0;
|
|
1034
1037
|
}
|
|
1035
|
-
function
|
|
1038
|
+
function Se(e, t) {
|
|
1039
|
+
return {
|
|
1040
|
+
...e.hooks,
|
|
1041
|
+
list: async (n, r) => {
|
|
1042
|
+
const a = await e.hooks.list(n, r);
|
|
1043
|
+
if (!t || n === t)
|
|
1044
|
+
return a;
|
|
1045
|
+
const i = ((await e.hooks.list(
|
|
1046
|
+
t,
|
|
1047
|
+
r
|
|
1048
|
+
)).hooks || []).filter(
|
|
1049
|
+
J
|
|
1050
|
+
);
|
|
1051
|
+
if (i.length === 0)
|
|
1052
|
+
return a;
|
|
1053
|
+
const c = new Set(
|
|
1054
|
+
(a.hooks || []).map((o) => o.hook_id)
|
|
1055
|
+
), u = i.filter((o) => !c.has(o.hook_id));
|
|
1056
|
+
return {
|
|
1057
|
+
...a,
|
|
1058
|
+
hooks: [...a.hooks || [], ...u],
|
|
1059
|
+
length: typeof a.length == "number" ? a.length + u.length : a.length
|
|
1060
|
+
};
|
|
1061
|
+
},
|
|
1062
|
+
get: async (n, r) => {
|
|
1063
|
+
const a = await e.hooks.get(n, r);
|
|
1064
|
+
if (a || !t || n === t)
|
|
1065
|
+
return a;
|
|
1066
|
+
const s = await e.hooks.get(
|
|
1067
|
+
t,
|
|
1068
|
+
r
|
|
1069
|
+
);
|
|
1070
|
+
return s && J(s) ? s : null;
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
function x(e, t) {
|
|
1075
|
+
return Ae(e, t);
|
|
1076
|
+
}
|
|
1077
|
+
function Ie(e) {
|
|
1036
1078
|
return async (t, n) => {
|
|
1037
1079
|
const r = t.var.user;
|
|
1038
1080
|
return (r == null ? void 0 : r.tenant_id) === e && r.org_name && t.set("tenant_id", r.org_name), n();
|
|
1039
1081
|
};
|
|
1040
1082
|
}
|
|
1041
|
-
function
|
|
1083
|
+
function Re(e) {
|
|
1042
1084
|
return async (t, n) => {
|
|
1043
1085
|
if (!e.accessControl)
|
|
1044
1086
|
return n();
|
|
1045
|
-
const { controlPlaneTenantId: r } = e.accessControl, a = t.var.org_name, s = t.var.organization_id,
|
|
1046
|
-
let
|
|
1047
|
-
const u = t.var.user, l = (u != null && u.aud ? Array.isArray(u.aud) ? u.aud : [u.aud] : []).includes(
|
|
1048
|
-
if (!
|
|
1087
|
+
const { controlPlaneTenantId: r } = e.accessControl, a = t.var.org_name, s = t.var.organization_id, i = a || s;
|
|
1088
|
+
let c = t.var.tenant_id;
|
|
1089
|
+
const u = t.var.user, l = (u != null && u.aud ? Array.isArray(u.aud) ? u.aud : [u.aud] : []).includes(X);
|
|
1090
|
+
if (!c && i && l && (t.set("tenant_id", i), c = i), !c)
|
|
1049
1091
|
throw new A(400, {
|
|
1050
1092
|
message: "Tenant ID not found in request"
|
|
1051
1093
|
});
|
|
1052
|
-
if (!
|
|
1094
|
+
if (!fe(
|
|
1053
1095
|
s,
|
|
1054
|
-
|
|
1096
|
+
c,
|
|
1055
1097
|
r,
|
|
1056
1098
|
a
|
|
1057
1099
|
))
|
|
1058
1100
|
throw new A(403, {
|
|
1059
|
-
message: `Access denied to tenant ${
|
|
1101
|
+
message: `Access denied to tenant ${c}`
|
|
1060
1102
|
});
|
|
1061
1103
|
return n();
|
|
1062
1104
|
};
|
|
1063
1105
|
}
|
|
1064
|
-
function
|
|
1106
|
+
function ze(e) {
|
|
1065
1107
|
return async (t, n) => {
|
|
1066
1108
|
if (!e.subdomainRouting)
|
|
1067
1109
|
return n();
|
|
@@ -1069,34 +1111,34 @@ function Ie(e) {
|
|
|
1069
1111
|
baseDomain: r,
|
|
1070
1112
|
reservedSubdomains: a = [],
|
|
1071
1113
|
resolveSubdomain: s
|
|
1072
|
-
} = e.subdomainRouting,
|
|
1073
|
-
let
|
|
1074
|
-
if (
|
|
1075
|
-
const o =
|
|
1076
|
-
o && !o.includes(".") && (
|
|
1114
|
+
} = e.subdomainRouting, i = t.req.header("x-forwarded-host") || t.req.header("host") || "";
|
|
1115
|
+
let c = null;
|
|
1116
|
+
if (i.endsWith(r)) {
|
|
1117
|
+
const o = i.slice(0, -(r.length + 1));
|
|
1118
|
+
o && !o.includes(".") && (c = o);
|
|
1077
1119
|
}
|
|
1078
|
-
if (
|
|
1120
|
+
if (c && a.includes(c) && (c = null), !c)
|
|
1079
1121
|
return e.accessControl && t.set("tenant_id", e.accessControl.controlPlaneTenantId), n();
|
|
1080
1122
|
let u = null;
|
|
1081
1123
|
if (s)
|
|
1082
|
-
u = await s(
|
|
1124
|
+
u = await s(c);
|
|
1083
1125
|
else if (e.subdomainRouting.useOrganizations !== !1 && e.accessControl)
|
|
1084
1126
|
try {
|
|
1085
1127
|
const o = await t.env.data.organizations.get(
|
|
1086
1128
|
e.accessControl.controlPlaneTenantId,
|
|
1087
|
-
|
|
1129
|
+
c
|
|
1088
1130
|
);
|
|
1089
1131
|
o && (u = o.id);
|
|
1090
1132
|
} catch {
|
|
1091
1133
|
}
|
|
1092
1134
|
if (!u)
|
|
1093
1135
|
throw new A(404, {
|
|
1094
|
-
message: `Tenant not found for subdomain: ${
|
|
1136
|
+
message: `Tenant not found for subdomain: ${c}`
|
|
1095
1137
|
});
|
|
1096
1138
|
return t.set("tenant_id", u), n();
|
|
1097
1139
|
};
|
|
1098
1140
|
}
|
|
1099
|
-
function
|
|
1141
|
+
function $e(e) {
|
|
1100
1142
|
return async (t, n) => {
|
|
1101
1143
|
if (!e.databaseIsolation)
|
|
1102
1144
|
return n();
|
|
@@ -1119,14 +1161,14 @@ function Re(e) {
|
|
|
1119
1161
|
return n();
|
|
1120
1162
|
};
|
|
1121
1163
|
}
|
|
1122
|
-
function
|
|
1123
|
-
const t =
|
|
1164
|
+
function ee(e) {
|
|
1165
|
+
const t = ze(e), n = Re(e), r = $e(e);
|
|
1124
1166
|
return async (a, s) => (await t(a, async () => {
|
|
1125
1167
|
}), await n(a, async () => {
|
|
1126
1168
|
}), await r(a, async () => {
|
|
1127
1169
|
}), s());
|
|
1128
1170
|
}
|
|
1129
|
-
function
|
|
1171
|
+
function ke(e) {
|
|
1130
1172
|
const {
|
|
1131
1173
|
dataAdapter: t,
|
|
1132
1174
|
controlPlane: n,
|
|
@@ -1135,8 +1177,8 @@ function De(e) {
|
|
|
1135
1177
|
clientId: a
|
|
1136
1178
|
} = {},
|
|
1137
1179
|
sync: s = { resourceServers: !0, roles: !0 },
|
|
1138
|
-
defaultPermissions:
|
|
1139
|
-
requireOrganizationMatch:
|
|
1180
|
+
defaultPermissions: i = ["tenant:admin"],
|
|
1181
|
+
requireOrganizationMatch: c = !1,
|
|
1140
1182
|
managementApiExtensions: u = [],
|
|
1141
1183
|
entityHooks: o,
|
|
1142
1184
|
getChildTenantIds: l,
|
|
@@ -1144,11 +1186,11 @@ function De(e) {
|
|
|
1144
1186
|
...d
|
|
1145
1187
|
} = e;
|
|
1146
1188
|
let f = t, m = t;
|
|
1147
|
-
n && (f =
|
|
1189
|
+
n && (f = x(t, {
|
|
1148
1190
|
controlPlaneTenantId: r,
|
|
1149
1191
|
controlPlaneClientId: a
|
|
1150
1192
|
}), m = {
|
|
1151
|
-
...
|
|
1193
|
+
...Pe(t, {
|
|
1152
1194
|
controlPlaneTenantId: r
|
|
1153
1195
|
}),
|
|
1154
1196
|
multiTenancyConfig: {
|
|
@@ -1169,7 +1211,7 @@ function De(e) {
|
|
|
1169
1211
|
getAdapters: g ?? (async () => f),
|
|
1170
1212
|
getControlPlaneAdapters: async () => f,
|
|
1171
1213
|
sync: C
|
|
1172
|
-
}, { entityHooks: P, tenantHooks:
|
|
1214
|
+
}, { entityHooks: P, tenantHooks: h } = ye(b), T = {
|
|
1173
1215
|
resourceServers: [
|
|
1174
1216
|
P.resourceServers,
|
|
1175
1217
|
...(o == null ? void 0 : o.resourceServers) ?? []
|
|
@@ -1178,54 +1220,54 @@ function De(e) {
|
|
|
1178
1220
|
connections: (o == null ? void 0 : o.connections) ?? [],
|
|
1179
1221
|
tenants: (o == null ? void 0 : o.tenants) ?? [],
|
|
1180
1222
|
rolePermissions: (o == null ? void 0 : o.rolePermissions) ?? []
|
|
1181
|
-
},
|
|
1223
|
+
}, p = Y({
|
|
1182
1224
|
accessControl: {
|
|
1183
1225
|
controlPlaneTenantId: r,
|
|
1184
|
-
requireOrganizationMatch:
|
|
1185
|
-
defaultPermissions:
|
|
1226
|
+
requireOrganizationMatch: c,
|
|
1227
|
+
defaultPermissions: i
|
|
1186
1228
|
}
|
|
1187
|
-
}),
|
|
1229
|
+
}), j = N(
|
|
1188
1230
|
{
|
|
1189
1231
|
accessControl: {
|
|
1190
1232
|
controlPlaneTenantId: r,
|
|
1191
|
-
requireOrganizationMatch:
|
|
1192
|
-
defaultPermissions:
|
|
1233
|
+
requireOrganizationMatch: c,
|
|
1234
|
+
defaultPermissions: i
|
|
1193
1235
|
}
|
|
1194
1236
|
},
|
|
1195
1237
|
{ tenants: {
|
|
1196
1238
|
async beforeCreate(S, v) {
|
|
1197
|
-
return
|
|
1239
|
+
return p.beforeCreate && (v = await p.beforeCreate(S, v)), h.beforeCreate && (v = await h.beforeCreate(S, v)), v;
|
|
1198
1240
|
},
|
|
1199
1241
|
async afterCreate(S, v) {
|
|
1200
1242
|
var $, R;
|
|
1201
|
-
await (($ =
|
|
1243
|
+
await (($ = p.afterCreate) == null ? void 0 : $.call(p, S, v)), await ((R = h.afterCreate) == null ? void 0 : R.call(h, S, v));
|
|
1202
1244
|
},
|
|
1203
1245
|
async beforeDelete(S, v) {
|
|
1204
1246
|
var $, R;
|
|
1205
|
-
await (($ =
|
|
1247
|
+
await (($ = p.beforeDelete) == null ? void 0 : $.call(p, S, v)), await ((R = h.beforeDelete) == null ? void 0 : R.call(h, S, v));
|
|
1206
1248
|
}
|
|
1207
1249
|
} }
|
|
1208
|
-
), { app:
|
|
1250
|
+
), { app: F } = le({
|
|
1209
1251
|
dataAdapter: f,
|
|
1210
1252
|
managementDataAdapter: m,
|
|
1211
1253
|
...d,
|
|
1212
1254
|
entityHooks: T,
|
|
1213
1255
|
managementApiExtensions: [
|
|
1214
1256
|
...u,
|
|
1215
|
-
{ path: "/tenants", router:
|
|
1257
|
+
{ path: "/tenants", router: j }
|
|
1216
1258
|
]
|
|
1217
1259
|
});
|
|
1218
|
-
return
|
|
1260
|
+
return F.use(
|
|
1219
1261
|
"/api/v2/*",
|
|
1220
|
-
|
|
1221
|
-
), w &&
|
|
1262
|
+
Ie(r)
|
|
1263
|
+
), w && F.use("/api/v2/*", Te()), { app: F, controlPlaneTenantId: r };
|
|
1222
1264
|
}
|
|
1223
|
-
function
|
|
1265
|
+
function Oe(e) {
|
|
1224
1266
|
const t = B(e);
|
|
1225
1267
|
return {
|
|
1226
1268
|
name: "multi-tenancy",
|
|
1227
1269
|
// Apply multi-tenancy middleware for subdomain routing, database resolution, etc.
|
|
1228
|
-
middleware:
|
|
1270
|
+
middleware: ee(e),
|
|
1229
1271
|
// Provide lifecycle hooks
|
|
1230
1272
|
hooks: t,
|
|
1231
1273
|
// Mount tenant management routes
|
|
@@ -1246,22 +1288,22 @@ function qe(e) {
|
|
|
1246
1288
|
};
|
|
1247
1289
|
}
|
|
1248
1290
|
function B(e) {
|
|
1249
|
-
const t = e.accessControl ?
|
|
1291
|
+
const t = e.accessControl ? de(e.accessControl) : {}, n = e.databaseIsolation ? me(e.databaseIsolation) : {}, r = Y(e);
|
|
1250
1292
|
return {
|
|
1251
1293
|
...t,
|
|
1252
1294
|
...n,
|
|
1253
1295
|
tenants: r
|
|
1254
1296
|
};
|
|
1255
1297
|
}
|
|
1256
|
-
function
|
|
1257
|
-
const t = new
|
|
1298
|
+
function je(e) {
|
|
1299
|
+
const t = new re(), n = B(e);
|
|
1258
1300
|
return t.route("/tenants", N(e, n)), t;
|
|
1259
1301
|
}
|
|
1260
|
-
function
|
|
1302
|
+
function Ee(e) {
|
|
1261
1303
|
return {
|
|
1262
1304
|
hooks: B(e),
|
|
1263
|
-
middleware:
|
|
1264
|
-
app:
|
|
1305
|
+
middleware: ee(e),
|
|
1306
|
+
app: je(e),
|
|
1265
1307
|
config: e,
|
|
1266
1308
|
/**
|
|
1267
1309
|
* Wraps data adapters with runtime fallback from the control plane.
|
|
@@ -1273,7 +1315,7 @@ function Oe(e) {
|
|
|
1273
1315
|
*/
|
|
1274
1316
|
wrapAdapters: (t, n) => {
|
|
1275
1317
|
var r;
|
|
1276
|
-
return
|
|
1318
|
+
return x(t, {
|
|
1277
1319
|
controlPlaneTenantId: (r = e.accessControl) == null ? void 0 : r.controlPlaneTenantId,
|
|
1278
1320
|
controlPlaneClientId: n == null ? void 0 : n.controlPlaneClientId
|
|
1279
1321
|
});
|
|
@@ -1281,24 +1323,24 @@ function Oe(e) {
|
|
|
1281
1323
|
};
|
|
1282
1324
|
}
|
|
1283
1325
|
export {
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1326
|
+
de as createAccessControlHooks,
|
|
1327
|
+
Re as createAccessControlMiddleware,
|
|
1328
|
+
Ie as createControlPlaneTenantMiddleware,
|
|
1329
|
+
me as createDatabaseHooks,
|
|
1330
|
+
$e as createDatabaseMiddleware,
|
|
1331
|
+
je as createMultiTenancy,
|
|
1290
1332
|
B as createMultiTenancyHooks,
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1333
|
+
ee as createMultiTenancyMiddleware,
|
|
1334
|
+
Oe as createMultiTenancyPlugin,
|
|
1335
|
+
Te as createProtectSyncedMiddleware,
|
|
1336
|
+
Y as createProvisioningHooks,
|
|
1337
|
+
Ae as createRuntimeFallbackAdapter,
|
|
1338
|
+
ze as createSubdomainMiddleware,
|
|
1339
|
+
ye as createSyncHooks,
|
|
1298
1340
|
N as createTenantsOpenAPIRouter,
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1341
|
+
ke as initMultiTenant,
|
|
1342
|
+
Ee as setupMultiTenancy,
|
|
1343
|
+
fe as validateTenantAccess,
|
|
1344
|
+
x as withRuntimeFallback,
|
|
1345
|
+
Pe as withSystemResourceServerInheritance
|
|
1304
1346
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-inheritance.d.ts","sourceRoot":"","sources":["../../../src/middleware/settings-inheritance.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAOb,MAAM,UAAU,CAAC;AAmNlB;;;;;;;;GAQG;AACH,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,YAAY,CAQd;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,
|
|
1
|
+
{"version":3,"file":"settings-inheritance.d.ts","sourceRoot":"","sources":["../../../src/middleware/settings-inheritance.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAOb,MAAM,UAAU,CAAC;AAmNlB;;;;;;;;GAQG;AACH,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,YAAY,CAQd;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CA2Md;AA2FD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,qBAAqB,GAC5B,YAAY,CAEd"}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "https://github.com/markusahlstrand/authhero"
|
|
13
13
|
},
|
|
14
|
-
"version": "14.20.
|
|
14
|
+
"version": "14.20.1",
|
|
15
15
|
"description": "Multi-tenancy support for AuthHero with organization-based access control and per-tenant database isolation",
|
|
16
16
|
"files": [
|
|
17
17
|
"dist"
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"typescript": "^5.6.0",
|
|
37
37
|
"vite": "^6.0.0",
|
|
38
38
|
"vitest": "^2.1.0",
|
|
39
|
-
"@authhero/kysely-adapter": "10.
|
|
40
|
-
"authhero": "4.
|
|
41
|
-
"@authhero/adapter-interfaces": "1.
|
|
39
|
+
"@authhero/kysely-adapter": "10.131.4",
|
|
40
|
+
"authhero": "4.107.0",
|
|
41
|
+
"@authhero/adapter-interfaces": "1.10.2"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"zod": "^3.24.0"
|