2021-07-08 12:12:34 +02:00
|
|
|
const env = require("../../environment")
|
|
|
|
const jwt = require("jsonwebtoken")
|
2021-08-02 19:34:43 +02:00
|
|
|
const { generateGlobalUserID } = require("../../db/utils")
|
2021-07-08 12:12:34 +02:00
|
|
|
const { authError } = require("./utils")
|
2021-07-08 21:03:51 +02:00
|
|
|
const { newid } = require("../../hashing")
|
|
|
|
const { createASession } = require("../../security/sessions")
|
2021-08-02 19:34:43 +02:00
|
|
|
const { getGlobalUserByEmail } = require("../../utils")
|
|
|
|
const { getGlobalDB, getTenantId } = require("../../tenancy")
|
2021-07-08 12:12:34 +02:00
|
|
|
|
|
|
|
/**
|
2021-07-08 14:12:25 +02:00
|
|
|
* Common authentication logic for third parties. e.g. OAuth, OIDC.
|
2021-07-08 12:12:34 +02:00
|
|
|
*/
|
|
|
|
exports.authenticateThirdParty = async function (
|
2021-07-08 14:12:25 +02:00
|
|
|
thirdPartyUser,
|
|
|
|
requireLocalAccount = true,
|
|
|
|
done
|
|
|
|
) {
|
2021-07-20 16:56:12 +02:00
|
|
|
if (!thirdPartyUser.provider) {
|
2021-07-08 14:12:25 +02:00
|
|
|
return authError(done, "third party user provider required")
|
2021-07-20 16:56:12 +02:00
|
|
|
}
|
|
|
|
if (!thirdPartyUser.userId) {
|
2021-07-08 14:12:25 +02:00
|
|
|
return authError(done, "third party user id required")
|
2021-07-20 16:56:12 +02:00
|
|
|
}
|
|
|
|
if (!thirdPartyUser.email) {
|
2021-07-08 14:12:25 +02:00
|
|
|
return authError(done, "third party user email required")
|
2021-07-20 16:56:12 +02:00
|
|
|
}
|
2021-07-08 14:12:25 +02:00
|
|
|
|
|
|
|
// use the third party id
|
|
|
|
const userId = generateGlobalUserID(thirdPartyUser.userId)
|
2021-08-02 19:34:43 +02:00
|
|
|
const db = getGlobalDB()
|
2021-07-20 16:56:12 +02:00
|
|
|
|
|
|
|
let dbUser
|
2021-07-08 14:12:25 +02:00
|
|
|
|
2021-07-08 17:11:48 +02:00
|
|
|
// try to load by id
|
2021-07-08 14:12:25 +02:00
|
|
|
try {
|
|
|
|
dbUser = await db.get(userId)
|
|
|
|
} catch (err) {
|
|
|
|
// abort when not 404 error
|
|
|
|
if (!err.status || err.status !== 404) {
|
|
|
|
return authError(
|
|
|
|
done,
|
|
|
|
"Unexpected error when retrieving existing user",
|
|
|
|
err
|
|
|
|
)
|
2021-07-08 12:12:34 +02:00
|
|
|
}
|
2021-07-08 17:11:48 +02:00
|
|
|
}
|
2021-07-08 14:12:25 +02:00
|
|
|
|
2021-07-08 17:11:48 +02:00
|
|
|
// fallback to loading by email
|
|
|
|
if (!dbUser) {
|
2021-08-02 19:34:43 +02:00
|
|
|
dbUser = await getGlobalUserByEmail(thirdPartyUser.email)
|
2021-07-08 17:11:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// exit early if there is still no user and auto creation is disabled
|
2021-07-08 21:03:51 +02:00
|
|
|
if (!dbUser && requireLocalAccount) {
|
2021-07-13 11:45:13 +02:00
|
|
|
return authError(
|
|
|
|
done,
|
|
|
|
"Email does not yet exist. You must set up your local budibase account first."
|
|
|
|
)
|
2021-07-08 17:11:48 +02:00
|
|
|
}
|
2021-07-08 14:12:25 +02:00
|
|
|
|
2021-07-08 17:11:48 +02:00
|
|
|
// first time creation
|
|
|
|
if (!dbUser) {
|
2021-07-08 17:49:07 +02:00
|
|
|
// setup a blank user using the third party id
|
|
|
|
dbUser = {
|
|
|
|
_id: userId,
|
|
|
|
roles: {},
|
|
|
|
}
|
2021-07-08 14:12:25 +02:00
|
|
|
}
|
|
|
|
|
2021-07-08 17:49:07 +02:00
|
|
|
dbUser = syncUser(dbUser, thirdPartyUser)
|
|
|
|
|
2021-07-08 17:11:48 +02:00
|
|
|
// create or sync the user
|
2021-07-08 17:49:07 +02:00
|
|
|
const response = await db.post(dbUser)
|
2021-07-08 17:11:48 +02:00
|
|
|
dbUser._rev = response.rev
|
|
|
|
|
2021-07-08 14:12:25 +02:00
|
|
|
// authenticate
|
2021-07-08 21:03:51 +02:00
|
|
|
const sessionId = newid()
|
2021-08-02 19:34:43 +02:00
|
|
|
const tenantId = getTenantId()
|
2021-07-20 16:56:12 +02:00
|
|
|
await createASession(dbUser._id, { sessionId, tenantId })
|
2021-07-08 14:12:25 +02:00
|
|
|
|
2021-07-08 21:03:51 +02:00
|
|
|
dbUser.token = jwt.sign(
|
|
|
|
{
|
|
|
|
userId: dbUser._id,
|
|
|
|
sessionId,
|
|
|
|
},
|
|
|
|
env.JWT_SECRET
|
|
|
|
)
|
2021-07-08 14:12:25 +02:00
|
|
|
|
|
|
|
return done(null, dbUser)
|
2021-07-08 12:12:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-07-08 17:49:07 +02:00
|
|
|
* @returns a user that has been sync'd with third party information
|
2021-07-08 12:12:34 +02:00
|
|
|
*/
|
2021-07-08 17:49:07 +02:00
|
|
|
function syncUser(user, thirdPartyUser) {
|
|
|
|
// provider
|
|
|
|
user.provider = thirdPartyUser.provider
|
|
|
|
user.providerType = thirdPartyUser.providerType
|
2021-07-08 12:12:34 +02:00
|
|
|
|
2021-07-08 17:49:07 +02:00
|
|
|
// email
|
|
|
|
user.email = thirdPartyUser.email
|
2021-07-08 12:12:34 +02:00
|
|
|
|
|
|
|
if (thirdPartyUser.profile) {
|
2021-07-08 17:11:48 +02:00
|
|
|
const profile = thirdPartyUser.profile
|
|
|
|
|
|
|
|
if (profile.name) {
|
|
|
|
const name = profile.name
|
|
|
|
// first name
|
|
|
|
if (name.givenName) {
|
|
|
|
user.firstName = name.givenName
|
|
|
|
}
|
|
|
|
// last name
|
|
|
|
if (name.familyName) {
|
|
|
|
user.lastName = name.familyName
|
|
|
|
}
|
|
|
|
}
|
2021-07-08 21:03:51 +02:00
|
|
|
|
2021-07-08 17:11:48 +02:00
|
|
|
// profile
|
2021-07-08 12:12:34 +02:00
|
|
|
user.thirdPartyProfile = {
|
2021-07-08 17:11:48 +02:00
|
|
|
...profile._json,
|
2021-07-08 12:12:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 17:49:07 +02:00
|
|
|
// oauth tokens for future use
|
2021-07-08 12:12:34 +02:00
|
|
|
if (thirdPartyUser.oauth2) {
|
|
|
|
user.oauth2 = {
|
2021-07-08 14:12:25 +02:00
|
|
|
...thirdPartyUser.oauth2,
|
2021-07-08 12:12:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return user
|
|
|
|
}
|