From 58aa32f1b00ce6aad3b9814122f834168c8dac61 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 9 Sep 2021 13:27:18 +0100 Subject: [PATCH] Fixing issue with multi-tenancy and public apps, when the tenant isn't necessarily known, it can be found in the app ID, building a middleware to manage this. --- packages/auth/src/db/utils.js | 17 +++++++++++++++ packages/auth/src/index.js | 2 ++ packages/auth/src/middleware/appTenancy.js | 25 ++++++++++++++++++++++ packages/auth/src/middleware/index.js | 2 ++ packages/auth/src/middleware/tenancy.js | 6 +++++- packages/auth/src/tenancy/context.js | 4 +--- packages/server/src/api/index.js | 10 +++++++-- packages/server/src/db/utils.js | 1 + 8 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 packages/auth/src/middleware/appTenancy.js diff --git a/packages/auth/src/db/utils.js b/packages/auth/src/db/utils.js index 4cd29c9bc8..99aef0287d 100644 --- a/packages/auth/src/db/utils.js +++ b/packages/auth/src/db/utils.js @@ -62,6 +62,23 @@ function getDocParams(docType, docId = null, otherProps = {}) { } } +/** + * Given an app ID this will attempt to retrieve the tenant ID from it. + * @return {null|string} The tenant ID found within the app ID. + */ +exports.getTenantIDFromAppID = appId => { + const split = appId.split(SEPARATOR) + const hasDev = split[1] === DocumentTypes.DEV + if ((hasDev && split.length === 3) || (!hasDev && split.length === 2)) { + return null + } + if (hasDev) { + return split[2] + } else { + return split[1] + } +} + /** * Generates a new workspace ID. * @returns {string} The new workspace ID which the workspace doc can be stored under. diff --git a/packages/auth/src/index.js b/packages/auth/src/index.js index 5421dea214..569456ea10 100644 --- a/packages/auth/src/index.js +++ b/packages/auth/src/index.js @@ -11,6 +11,7 @@ const { oidc, auditLog, tenancy, + appTenancy, } = require("./middleware") const { setDB } = require("./db") const userCache = require("./cache/user") @@ -57,6 +58,7 @@ module.exports = { oidc, jwt: require("jsonwebtoken"), buildTenancyMiddleware: tenancy, + buildAppTenancyMiddleware: appTenancy, auditLog, }, cache: { diff --git a/packages/auth/src/middleware/appTenancy.js b/packages/auth/src/middleware/appTenancy.js new file mode 100644 index 0000000000..30fc4f7453 --- /dev/null +++ b/packages/auth/src/middleware/appTenancy.js @@ -0,0 +1,25 @@ +const { + isMultiTenant, + updateTenantId, + isTenantIdSet, + DEFAULT_TENANT_ID, +} = require("../tenancy") +const ContextFactory = require("../tenancy/FunctionContext") +const { getTenantIDFromAppID } = require("../db/utils") + +module.exports = () => { + return ContextFactory.getMiddleware(ctx => { + // if not in multi-tenancy mode make sure its default and exit + if (!isMultiTenant()) { + updateTenantId(DEFAULT_TENANT_ID) + return + } + // if tenant ID already set no need to continue + if (isTenantIdSet()) { + return + } + const appId = ctx.appId ? ctx.appId : ctx.user ? ctx.user.appId : null + const tenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID + updateTenantId(tenantId) + }) +} diff --git a/packages/auth/src/middleware/index.js b/packages/auth/src/middleware/index.js index 689859a139..059f20af8b 100644 --- a/packages/auth/src/middleware/index.js +++ b/packages/auth/src/middleware/index.js @@ -5,6 +5,7 @@ const oidc = require("./passport/oidc") const authenticated = require("./authenticated") const auditLog = require("./auditLog") const tenancy = require("./tenancy") +const appTenancy = require("./appTenancy") module.exports = { google, @@ -14,4 +15,5 @@ module.exports = { authenticated, auditLog, tenancy, + appTenancy, } diff --git a/packages/auth/src/middleware/tenancy.js b/packages/auth/src/middleware/tenancy.js index 19cce82273..adfd36a503 100644 --- a/packages/auth/src/middleware/tenancy.js +++ b/packages/auth/src/middleware/tenancy.js @@ -2,7 +2,11 @@ const { setTenantId } = require("../tenancy") const ContextFactory = require("../tenancy/FunctionContext") const { buildMatcherRegex, matches } = require("./matchers") -module.exports = (allowQueryStringPatterns, noTenancyPatterns, opts = {}) => { +module.exports = ( + allowQueryStringPatterns, + noTenancyPatterns, + opts = { noTenancyRequired: false } +) => { const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns) const noTenancyOptions = buildMatcherRegex(noTenancyPatterns) diff --git a/packages/auth/src/tenancy/context.js b/packages/auth/src/tenancy/context.js index f3f1f541e9..b1ef5a5807 100644 --- a/packages/auth/src/tenancy/context.js +++ b/packages/auth/src/tenancy/context.js @@ -21,9 +21,7 @@ exports.doInTenant = (tenantId, task) => { cls.setOnContext(TENANT_ID, tenantId) // invoke the task - const result = task() - - return result + return task() }) } diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 24567b54a6..dfe1f83fb4 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -1,6 +1,10 @@ const Router = require("@koa/router") -const { buildAuthMiddleware, auditLog, buildTenancyMiddleware } = - require("@budibase/auth").auth +const { + buildAuthMiddleware, + auditLog, + buildTenancyMiddleware, + buildAppTenancyMiddleware, +} = require("@budibase/auth").auth const currentApp = require("../middleware/currentapp") const compress = require("koa-compress") const zlib = require("zlib") @@ -48,6 +52,8 @@ router }) ) .use(currentApp) + // this middleware will try to use the app ID to determine the tenancy + .use(buildAppTenancyMiddleware()) .use(auditLog) // error handling middleware diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 92734c5e7b..706d5ed207 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -19,6 +19,7 @@ const AppStatus = { const DocumentTypes = { APP: CoreDocTypes.APP, + DEV: CoreDocTypes.DEV, APP_DEV: CoreDocTypes.APP_DEV, APP_METADATA: CoreDocTypes.APP_METADATA, ROLE: CoreDocTypes.ROLE,