more flexible datasource auth config

This commit is contained in:
Martin McKeaveney 2022-01-17 15:52:10 +01:00
parent 857d1f7c0b
commit 20cb3d8f2c
7 changed files with 106 additions and 69 deletions

View File

@ -7,6 +7,7 @@ exports.Cookies = {
CurrentApp: "budibase:currentapp", CurrentApp: "budibase:currentapp",
Auth: "budibase:auth", Auth: "budibase:auth",
Init: "budibase:init", Init: "budibase:init",
DatasourceAuth: "budibase:datasourceauth",
OIDC_CONFIG: "budibase:oidc:config", OIDC_CONFIG: "budibase:oidc:config",
} }

View File

@ -7,6 +7,7 @@ const authenticated = require("./authenticated")
const auditLog = require("./auditLog") const auditLog = require("./auditLog")
const tenancy = require("./tenancy") const tenancy = require("./tenancy")
const appTenancy = require("./appTenancy") const appTenancy = require("./appTenancy")
const datasourceGoogle = require("./passport/datasource/google")
module.exports = { module.exports = {
google, google,
@ -18,4 +19,7 @@ module.exports = {
tenancy, tenancy,
appTenancy, appTenancy,
authError, authError,
datasource: {
google: datasourceGoogle,
},
} }

View File

@ -0,0 +1,77 @@
const { getScopedConfig } = require("../../../db/utils")
const { getGlobalDB } = require("../../../tenancy")
const google = require("../google")
const { Configs, Cookies } = require("../../../constants")
const { clearCookie, getCookie } = require("../../../utils")
const { getDB } = require("../../../db")
async function preAuth(passport, ctx, next) {
const db = getGlobalDB()
// get the relevant config
const config = await getScopedConfig(db, {
type: Configs.GOOGLE,
workspace: ctx.query.workspace,
})
const publicConfig = await getScopedConfig(db, {
type: Configs.SETTINGS,
})
let callbackUrl = `${publicConfig.platformUrl}/api/global/auth/datasource/google/callback`
const strategy = await google.strategyFactory(config, callbackUrl)
if (!ctx.query.appId || !ctx.query.datasourceId) {
ctx.throw(400, "appId and datasourceId query params not present.")
}
// TODO: prob update - shouldn't include the google sheets scopes here
return passport.authenticate(strategy, {
scope: ["profile", "email", "https://www.googleapis.com/auth/spreadsheets"],
})(ctx, next)
}
async function postAuth(passport, ctx, next) {
const db = getGlobalDB()
const config = await getScopedConfig(db, {
type: Configs.GOOGLE,
workspace: ctx.query.workspace,
})
const publicConfig = await getScopedConfig(db, {
type: Configs.SETTINGS,
})
let callbackUrl = `${publicConfig.platformUrl}/api/global/auth/datasource/google/callback`
const strategy = await google.strategyFactory(
config,
callbackUrl,
(accessToken, refreshToken, profile, done) => {
clearCookie(ctx, Cookies.DatasourceAuth)
done(null, { accessToken, refreshToken })
}
)
const authStateCookie = getCookie(ctx, Cookies.DatasourceAuth)
return passport.authenticate(
strategy,
{ successRedirect: "/", failureRedirect: "/error" },
async (err, tokens) => {
// update the DB for the datasource with all the user info
const db = getDB(authStateCookie.appId)
const datasource = await db.get(authStateCookie.datasourceId)
datasource.config = {
auth: {
type: "google",
...tokens,
},
}
await db.put(datasource)
ctx.redirect(
`/builder/app/${authStateCookie.appId}/data/datasource/${authStateCookie.datasourceId}`
)
}
)(ctx, next)
}
exports.preAuth = preAuth
exports.postAuth = postAuth

View File

@ -12,9 +12,8 @@
<ActionButton <ActionButton
on:click={async () => { on:click={async () => {
const datasource = await preAuthStep() const datasource = await preAuthStep()
console.log(datasource)
window.open( window.open(
`/api/global/auth/${tenantId}/google2?datasourceId=${datasource._id}&appId=${$store.appId}`, `/api/global/auth/${tenantId}/datasource/google?datasourceId=${datasource._id}&appId=${$store.appId}`,
"_blank" "_blank"
) )
}} }}

View File

@ -9,8 +9,11 @@ const { Thread, ThreadType } = require("../../../threads")
const { save: saveDatasource } = require("../datasource") const { save: saveDatasource } = require("../datasource")
const { RestImporter } = require("./import") const { RestImporter } = require("./import")
const { invalidateDynamicVariables } = require("../../../threads/utils") const { invalidateDynamicVariables } = require("../../../threads/utils")
const environment = require("../../../environment")
const Runner = new Thread(ThreadType.QUERY, { timeoutMs: 10000 }) const Runner = new Thread(ThreadType.QUERY, {
timeoutMs: 10000 || environment.QUERY_THREAD_TIMEOUT,
})
// simple function to append "readable" to all read queries // simple function to append "readable" to all read queries
function enrichQueries(input) { function enrichQueries(input) {

View File

@ -21,7 +21,6 @@ const {
isMultiTenant, isMultiTenant,
} = require("@budibase/backend-core/tenancy") } = require("@budibase/backend-core/tenancy")
const env = require("../../../environment") const env = require("../../../environment")
const CouchDB = require("../../../db")
const ssoCallbackUrl = async (config, type) => { const ssoCallbackUrl = async (config, type) => {
// incase there is a callback URL from before // incase there is a callback URL from before
@ -146,78 +145,30 @@ exports.logout = async ctx => {
ctx.body = { message: "User logged out." } ctx.body = { message: "User logged out." }
} }
/** exports.datasourcePreAuth = async (ctx, next) => {
* The initial call that google authentication makes to take you to the google login screen. const provider = ctx.params.provider
* On a successful login, you will be redirected to the googleAuth callback route. const middleware = require(`@budibase/backend-core/middleware`)
*/ const handler = middleware.datasource[provider]
exports.googlePreAuth2 = async (ctx, next) => {
const db = getGlobalDB()
const config = await core.db.getScopedConfig(db, {
type: Configs.GOOGLE,
workspace: ctx.query.workspace,
})
// let callbackUrl = await exports.googleCallbackUrl(config)
// TODO: Hardcoded - fix
let callbackUrl = "http://localhost:10000/api/global/auth/google2/callback"
const strategy = await google.strategyFactory(config, callbackUrl)
// TODO: fix
setCookie( setCookie(
ctx, ctx,
{ {
provider,
appId: ctx.query.appId, appId: ctx.query.appId,
datasourceId: ctx.query.datasourceId, datasourceId: ctx.query.datasourceId,
}, },
"AuthCallback" Cookies.DatasourceAuth
) )
// TODO: prob update - shouldn't include the google sheets scopes here return handler.preAuth(passport, ctx, next)
return passport.authenticate(strategy, {
scope: ["profile", "email", "https://www.googleapis.com/auth/spreadsheets"],
})(ctx, next)
} }
exports.googleAuth2 = async (ctx, next) => { exports.datasourceAuth = async (ctx, next) => {
const db = getGlobalDB() const authStateCookie = getCookie(ctx, Cookies.DatasourceAuth)
const provider = authStateCookie.provider
const config = await core.db.getScopedConfig(db, { const middleware = require(`@budibase/backend-core/middleware`)
type: Configs.GOOGLE, const handler = middleware.datasource[provider]
workspace: ctx.query.workspace, return handler.postAuth(passport, ctx, next)
})
// const callbackUrl = await exports.googleCallbackUrl(config)
const authStateCookie = getCookie(ctx, "AuthCallback")
// TODO: correct callback URL
let callbackUrl = "http://localhost:10000/api/global/auth/google2/callback"
const strategy = await google.strategyFactory(
config,
callbackUrl,
(accessToken, refreshToken, profile, done) => {
clearCookie(ctx, "AuthCallback")
done(null, { accessToken, refreshToken })
}
)
return passport.authenticate(
strategy,
{ successRedirect: "/", failureRedirect: "/error" },
async (err, tokens) => {
// update the DB for the datasource with all the user info
const db = new CouchDB(authStateCookie.appId)
const datasource = await db.get(authStateCookie.datasourceId)
datasource.config = {
auth: {
type: "google",
...tokens,
},
}
await db.put(datasource)
ctx.redirect(
`/builder/app/${authStateCookie.appId}/data/datasource/${authStateCookie.datasourceId}`
)
}
)(ctx, next)
} }
/** /**

View File

@ -64,14 +64,16 @@ router
authController.googlePreAuth authController.googlePreAuth
) )
.get( .get(
"/api/global/auth/:tenantId/google2", "/api/global/auth/:tenantId/datasource/:provider",
updateTenant, updateTenant,
authController.googlePreAuth2 authController.datasourcePreAuth
) )
// single tenancy endpoint // single tenancy endpoint
.get("/api/global/auth/google/callback", authController.googleAuth) .get("/api/global/auth/google/callback", authController.googleAuth)
// TODO: Remove .get(
.get("/api/global/auth/google2/callback", authController.googleAuth2) "/api/global/auth/datasource/:provider/callback",
authController.datasourceAuth
)
// multi-tenancy endpoint // multi-tenancy endpoint
.get( .get(
"/api/global/auth/:tenantId/google/callback", "/api/global/auth/:tenantId/google/callback",