budibase/packages/backend-core/src/auth.js

173 lines
4.0 KiB
JavaScript
Raw Normal View History

const passport = require("koa-passport")
const LocalStrategy = require("passport-local").Strategy
const JwtStrategy = require("passport-jwt").Strategy
const { getGlobalDB } = require("./tenancy")
2022-06-23 15:29:19 +02:00
const refresh = require("passport-oauth2-refresh")
const { Configs } = require("./constants")
const { getScopedConfig } = require("./db/utils")
const {
jwt,
local,
authenticated,
google,
oidc,
auditLog,
tenancy,
appTenancy,
authError,
2022-07-04 13:54:26 +02:00
ssoCallbackUrl,
2022-01-25 23:54:50 +01:00
csrf,
2022-01-24 11:48:59 +01:00
internalApi,
} = require("./middleware")
// Strategies
passport.use(new LocalStrategy(local.options, local.authenticate))
passport.use(new JwtStrategy(jwt.options, jwt.authenticate))
passport.serializeUser((user, done) => done(null, user))
passport.deserializeUser(async (user, done) => {
const db = getGlobalDB()
try {
const user = await db.get(user._id)
return done(null, user)
} catch (err) {
console.error(`User not found`, err)
return done(null, false, { message: "User not found" })
}
})
async function refreshOIDCAccessToken(db, chosenConfig, refreshToken) {
const callbackUrl = await oidc.getCallbackUrl(db, chosenConfig)
let enrichedConfig
let strategy
2022-06-23 15:29:19 +02:00
try {
enrichedConfig = await oidc.fetchStrategyConfig(chosenConfig, callbackUrl)
if (!enrichedConfig) {
throw new Error("OIDC Config contents invalid")
}
strategy = await oidc.strategyFactory(enrichedConfig)
} catch (err) {
console.error(err)
throw new Error("Could not refresh OAuth Token")
}
2022-06-23 15:29:19 +02:00
refresh.use(strategy, {
setRefreshOAuth2() {
return strategy._getOAuth2Client(enrichedConfig)
},
})
2022-06-23 15:29:19 +02:00
return new Promise(resolve => {
refresh.requestNewAccessToken(
Configs.OIDC,
refreshToken,
(err, accessToken, refreshToken, params) => {
resolve({ err, accessToken, refreshToken, params })
}
)
2022-06-23 15:29:19 +02:00
})
}
2022-06-23 15:29:19 +02:00
async function refreshGoogleAccessToken(db, config, refreshToken) {
let callbackUrl = await google.getCallbackUrl(db, config)
let strategy
2022-06-23 15:29:19 +02:00
try {
2022-07-04 13:54:26 +02:00
strategy = await google.strategyFactory(config, callbackUrl)
2022-06-23 15:29:19 +02:00
} catch (err) {
console.error(err)
throw new Error("Error constructing OIDC refresh strategy", err)
}
refresh.use(strategy)
return new Promise(resolve => {
refresh.requestNewAccessToken(
Configs.GOOGLE,
refreshToken,
(err, accessToken, refreshToken, params) => {
resolve({ err, accessToken, refreshToken, params })
}
)
})
}
async function refreshOAuthToken(refreshToken, configType, configId) {
const db = getGlobalDB()
const config = await getScopedConfig(db, {
type: configType,
group: {},
})
let chosenConfig = {}
let refreshResponse
if (configType === Configs.OIDC) {
// configId - retrieved from cookie.
chosenConfig = config.configs.filter(c => c.uuid === configId)[0]
if (!chosenConfig) {
throw new Error("Invalid OIDC configuration")
}
refreshResponse = await refreshOIDCAccessToken(
db,
chosenConfig,
refreshToken
)
} else {
chosenConfig = config
refreshResponse = await refreshGoogleAccessToken(
db,
chosenConfig,
refreshToken
)
}
return refreshResponse
}
async function updateUserOAuth(userId, oAuthConfig) {
2022-07-03 23:14:18 +02:00
const details = {
accessToken: oAuthConfig.accessToken,
refreshToken: oAuthConfig.refreshToken,
}
try {
const db = getGlobalDB()
2022-07-03 23:14:18 +02:00
const dbUser = await db.get(userId)
//Do not overwrite the refresh token if a valid one is not provided.
if (typeof details.refreshToken !== "string") {
delete details.refreshToken
}
2022-07-03 23:14:18 +02:00
dbUser.oauth2 = {
...dbUser.oauth2,
...details,
}
await db.put(dbUser)
} catch (e) {
console.error("Could not update OAuth details for current user", e)
}
2022-06-23 15:29:19 +02:00
}
module.exports = {
buildAuthMiddleware: authenticated,
passport,
google,
oidc,
jwt: require("jsonwebtoken"),
buildTenancyMiddleware: tenancy,
buildAppTenancyMiddleware: appTenancy,
auditLog,
authError,
2022-01-25 23:54:50 +01:00
buildCsrfMiddleware: csrf,
2022-01-24 11:48:59 +01:00
internalApi,
refreshOAuthToken,
updateUserOAuth,
2022-07-04 13:54:26 +02:00
ssoCallbackUrl,
}