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",
Auth: "budibase:auth",
Init: "budibase:init",
DatasourceAuth: "budibase:datasourceauth",
OIDC_CONFIG: "budibase:oidc:config",
}

View File

@ -7,6 +7,7 @@ const authenticated = require("./authenticated")
const auditLog = require("./auditLog")
const tenancy = require("./tenancy")
const appTenancy = require("./appTenancy")
const datasourceGoogle = require("./passport/datasource/google")
module.exports = {
google,
@ -18,4 +19,7 @@ module.exports = {
tenancy,
appTenancy,
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
on:click={async () => {
const datasource = await preAuthStep()
console.log(datasource)
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"
)
}}

View File

@ -9,8 +9,11 @@ const { Thread, ThreadType } = require("../../../threads")
const { save: saveDatasource } = require("../datasource")
const { RestImporter } = require("./import")
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
function enrichQueries(input) {

View File

@ -21,7 +21,6 @@ const {
isMultiTenant,
} = require("@budibase/backend-core/tenancy")
const env = require("../../../environment")
const CouchDB = require("../../../db")
const ssoCallbackUrl = async (config, type) => {
// incase there is a callback URL from before
@ -146,78 +145,30 @@ exports.logout = async ctx => {
ctx.body = { message: "User logged out." }
}
/**
* The initial call that google authentication makes to take you to the google login screen.
* On a successful login, you will be redirected to the googleAuth callback route.
*/
exports.googlePreAuth2 = async (ctx, next) => {
const db = getGlobalDB()
exports.datasourcePreAuth = async (ctx, next) => {
const provider = ctx.params.provider
const middleware = require(`@budibase/backend-core/middleware`)
const handler = middleware.datasource[provider]
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(
ctx,
{
provider,
appId: ctx.query.appId,
datasourceId: ctx.query.datasourceId,
},
"AuthCallback"
Cookies.DatasourceAuth
)
// 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)
return handler.preAuth(passport, ctx, next)
}
exports.googleAuth2 = async (ctx, next) => {
const db = getGlobalDB()
const config = await core.db.getScopedConfig(db, {
type: Configs.GOOGLE,
workspace: ctx.query.workspace,
})
// 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)
exports.datasourceAuth = async (ctx, next) => {
const authStateCookie = getCookie(ctx, Cookies.DatasourceAuth)
const provider = authStateCookie.provider
const middleware = require(`@budibase/backend-core/middleware`)
const handler = middleware.datasource[provider]
return handler.postAuth(passport, ctx, next)
}
/**

View File

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