Merge pull request #2691 from Budibase/feature/onboarding-backend

SSO flow and account deletion
This commit is contained in:
Rory Powell 2021-09-22 09:47:06 +01:00 committed by GitHub
commit e4fb901e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 12 deletions

View File

@ -12,6 +12,7 @@ const {
auditLog, auditLog,
tenancy, tenancy,
appTenancy, appTenancy,
authError,
} = require("./middleware") } = require("./middleware")
const { setDB } = require("./db") const { setDB } = require("./db")
const userCache = require("./cache/user") const userCache = require("./cache/user")
@ -60,6 +61,7 @@ module.exports = {
buildTenancyMiddleware: tenancy, buildTenancyMiddleware: tenancy,
buildAppTenancyMiddleware: appTenancy, buildAppTenancyMiddleware: appTenancy,
auditLog, auditLog,
authError,
}, },
cache: { cache: {
user: userCache, user: userCache,

View File

@ -2,6 +2,7 @@ const jwt = require("./passport/jwt")
const local = require("./passport/local") const local = require("./passport/local")
const google = require("./passport/google") const google = require("./passport/google")
const oidc = require("./passport/oidc") const oidc = require("./passport/oidc")
const { authError } = require("./passport/utils")
const authenticated = require("./authenticated") const authenticated = require("./authenticated")
const auditLog = require("./auditLog") const auditLog = require("./auditLog")
const tenancy = require("./tenancy") const tenancy = require("./tenancy")
@ -16,4 +17,5 @@ module.exports = {
auditLog, auditLog,
tenancy, tenancy,
appTenancy, appTenancy,
authError,
} }

View File

@ -27,7 +27,11 @@ async function authenticate(accessToken, refreshToken, profile, done) {
* from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport. * from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport.
* @returns Dynamically configured Passport Google Strategy * @returns Dynamically configured Passport Google Strategy
*/ */
exports.strategyFactory = async function (config, callbackUrl) { exports.strategyFactory = async function (
config,
callbackUrl,
verify = authenticate
) {
try { try {
const { clientID, clientSecret } = config const { clientID, clientSecret } = config
@ -43,7 +47,7 @@ exports.strategyFactory = async function (config, callbackUrl) {
clientSecret: config.clientSecret, clientSecret: config.clientSecret,
callbackURL: callbackUrl, callbackURL: callbackUrl,
}, },
authenticate verify
) )
} catch (err) { } catch (err) {
console.error(err) console.error(err)

View File

@ -30,6 +30,10 @@ exports.invalidateSessions = async (userId, sessionId = null) => {
sessions.push({ key: makeSessionID(userId, sessionId) }) sessions.push({ key: makeSessionID(userId, sessionId) })
} else { } else {
sessions = await getSessionsForUser(userId) sessions = await getSessionsForUser(userId)
sessions.forEach(
session =>
(session.key = makeSessionID(session.userId, session.sessionId))
)
} }
const client = await redis.getSessionClient() const client = await redis.getSessionClient()
const promises = [] const promises = []

View File

@ -31,7 +31,12 @@ async function allUsers() {
return response.rows.map(row => row.doc) return response.rows.map(row => row.doc)
} }
async function saveUser(user, tenantId, hashPassword = true) { async function saveUser(
user,
tenantId,
hashPassword = true,
requirePassword = true
) {
if (!tenantId) { if (!tenantId) {
throw "No tenancy specified." throw "No tenancy specified."
} }
@ -57,7 +62,7 @@ async function saveUser(user, tenantId, hashPassword = true) {
hashedPassword = hashPassword ? await hash(password) : password hashedPassword = hashPassword ? await hash(password) : password
} else if (dbUser) { } else if (dbUser) {
hashedPassword = dbUser.password hashedPassword = dbUser.password
} else { } else if (requirePassword) {
throw "Password must be specified." throw "Password must be specified."
} }
@ -106,16 +111,21 @@ exports.save = async ctx => {
} }
} }
const parseBooleanParam = param => {
if (param && param == "false") {
return false
} else {
return true
}
}
exports.adminUser = async ctx => { exports.adminUser = async ctx => {
const { email, password, tenantId } = ctx.request.body const { email, password, tenantId } = ctx.request.body
// account portal sends a pre-hashed password - honour param to prevent double hashing // account portal sends a pre-hashed password - honour param to prevent double hashing
let hashPassword = ctx.request.query.hashPassword const hashPassword = parseBooleanParam(ctx.request.query.hashPassword)
if (hashPassword && hashPassword == "false") { // account portal sends no password for SSO users
hashPassword = false const requirePassword = parseBooleanParam(ctx.request.query.requirePassword)
} else {
hashPassword = true
}
if (await doesTenantExist(tenantId)) { if (await doesTenantExist(tenantId)) {
ctx.throw(403, "Organisation already exists.") ctx.throw(403, "Organisation already exists.")
@ -148,7 +158,7 @@ exports.adminUser = async ctx => {
tenantId, tenantId,
} }
try { try {
ctx.body = await saveUser(user, tenantId, hashPassword) ctx.body = await saveUser(user, tenantId, hashPassword, requirePassword)
} catch (err) { } catch (err) {
ctx.throw(err.status || 400, err) ctx.throw(err.status || 400, err)
} }

View File

@ -10,7 +10,7 @@ function buildAdminInitValidation() {
return joiValidator.body( return joiValidator.body(
Joi.object({ Joi.object({
email: Joi.string().required(), email: Joi.string().required(),
password: Joi.string().required(), password: Joi.string(),
tenantId: Joi.string().required(), tenantId: Joi.string().required(),
}) })
.required() .required()