google auth E2E
This commit is contained in:
parent
301f681c88
commit
ffe167bbd3
|
@ -70,12 +70,11 @@ exports.getUserParams = (email = "", otherProps = {}) => {
|
||||||
* Generates a new configuration ID.
|
* Generates a new configuration ID.
|
||||||
* @returns {string} The new configuration ID which the config doc can be stored under.
|
* @returns {string} The new configuration ID which the config doc can be stored under.
|
||||||
*/
|
*/
|
||||||
exports.generateConfigID = (type = "", group = "") => {
|
exports.generateConfigID = (type = "", group = "", user = "") => {
|
||||||
group += SEPARATOR
|
// group += SEPARATOR
|
||||||
|
const scope = [type, group, user].join(SEPARATOR)
|
||||||
|
|
||||||
return `${
|
return `${DocumentTypes.CONFIG}${SEPARATOR}${scope}${newid()}`
|
||||||
DocumentTypes.CONFIG
|
|
||||||
}${SEPARATOR}${type}${SEPARATOR}${group}${newid()}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
const passport = require("koa-passport")
|
const passport = require("koa-passport")
|
||||||
const LocalStrategy = require("passport-local").Strategy
|
const LocalStrategy = require("passport-local").Strategy
|
||||||
const JwtStrategy = require("passport-jwt").Strategy
|
const JwtStrategy = require("passport-jwt").Strategy
|
||||||
// const GoogleStrategy = require("passport-google-oauth").Strategy
|
const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy
|
||||||
const database = require("./db")
|
const database = require("./db")
|
||||||
const { StaticDatabases } = require("./db/utils")
|
const { StaticDatabases, DocumentTypes } = require("./db/utils")
|
||||||
const { jwt, local, authenticated } = require("./middleware")
|
const { jwt, local, google, authenticated } = require("./middleware")
|
||||||
const { Cookies, UserStatus } = require("./constants")
|
const { Cookies, UserStatus } = require("./constants")
|
||||||
const { hash, compare } = require("./hashing")
|
const { hash, compare } = require("./hashing")
|
||||||
const {
|
const {
|
||||||
|
@ -27,7 +27,7 @@ const {
|
||||||
// Strategies
|
// Strategies
|
||||||
passport.use(new LocalStrategy(local.options, local.authenticate))
|
passport.use(new LocalStrategy(local.options, local.authenticate))
|
||||||
passport.use(new JwtStrategy(jwt.options, jwt.authenticate))
|
passport.use(new JwtStrategy(jwt.options, jwt.authenticate))
|
||||||
// passport.use(new GoogleStrategy(google.options, google.authenticate))
|
passport.use(new GoogleStrategy(google.options, google.authenticate))
|
||||||
|
|
||||||
passport.serializeUser((user, done) => done(null, user))
|
passport.serializeUser((user, done) => done(null, user))
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ module.exports = {
|
||||||
passport,
|
passport,
|
||||||
Cookies,
|
Cookies,
|
||||||
UserStatus,
|
UserStatus,
|
||||||
|
DocumentTypes,
|
||||||
StaticDatabases,
|
StaticDatabases,
|
||||||
generateUserID,
|
generateUserID,
|
||||||
getUserParams,
|
getUserParams,
|
||||||
|
|
|
@ -1,18 +1,54 @@
|
||||||
const env = require("../../environment")
|
const env = require("../../environment")
|
||||||
|
const jwt = require("jsonwebtoken")
|
||||||
|
const database = require("../../db")
|
||||||
|
const { StaticDatabases, generateUserID } = require("../../db/utils")
|
||||||
|
|
||||||
exports.options = {
|
exports.options = {
|
||||||
clientId: env.GOOGLE_CLIENT_ID,
|
clientID: env.GOOGLE_CLIENT_ID,
|
||||||
clientSecret: env.GOOGLE_CLIENT_SECRET,
|
clientSecret: env.GOOGLE_CLIENT_SECRET,
|
||||||
callbackURL: env.GOOGLE_AUTH_CALLBACK_URL,
|
callbackURL: env.GOOGLE_AUTH_CALLBACK_URL,
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.authenticate = async function(token, tokenSecret, profile, done) {
|
exports.authenticate = async function(token, tokenSecret, profile, done) {
|
||||||
console.log({
|
if (!profile._json.email) return done(null, false, "Email Required.")
|
||||||
token,
|
|
||||||
tokenSecret,
|
// Check the user exists in the instance DB by email
|
||||||
profile,
|
const db = new database.CouchDB(StaticDatabases.GLOBAL.name)
|
||||||
done,
|
|
||||||
|
let dbUser
|
||||||
|
const userId = generateUserID(profile._json.email)
|
||||||
|
|
||||||
|
try {
|
||||||
|
// use the google profile id
|
||||||
|
dbUser = await db.get(userId)
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Google user not found. Creating..")
|
||||||
|
// create the user
|
||||||
|
const user = {
|
||||||
|
_id: userId,
|
||||||
|
provider: profile.provider,
|
||||||
|
roles: {},
|
||||||
|
builder: {
|
||||||
|
global: true,
|
||||||
|
},
|
||||||
|
...profile._json,
|
||||||
|
}
|
||||||
|
const response = await db.post(user)
|
||||||
|
|
||||||
|
dbUser = user
|
||||||
|
dbUser._rev = response.rev
|
||||||
|
}
|
||||||
|
|
||||||
|
// authenticate
|
||||||
|
const payload = {
|
||||||
|
userId: dbUser._id,
|
||||||
|
builder: dbUser.builder,
|
||||||
|
email: dbUser.email,
|
||||||
|
}
|
||||||
|
|
||||||
|
dbUser.token = jwt.sign(payload, env.JWT_SECRET, {
|
||||||
|
expiresIn: "1 day",
|
||||||
})
|
})
|
||||||
// retrieve user ...
|
|
||||||
// fetchUser().then(user => done(null, user))
|
return done(null, dbUser)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
<Input outline type="password" on:change bind:value={password} />
|
<Input outline type="password" on:change bind:value={password} />
|
||||||
<Spacer large />
|
<Spacer large />
|
||||||
<Button primary on:click={login}>Login</Button>
|
<Button primary on:click={login}>Login</Button>
|
||||||
|
<a target="_blank" href="/api/admin/auth/google">Sign In with Google</a>
|
||||||
<Button secondary on:click={createTestUser}>Create Test User</Button>
|
<Button secondary on:click={createTestUser}>Create Test User</Button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,47 @@
|
||||||
const CouchDB = require("../../../db")
|
const CouchDB = require("../../../db")
|
||||||
const { StaticDatabases } = require("@budibase/auth")
|
const { StaticDatabases, DocumentTypes } = require("@budibase/auth")
|
||||||
const { generateConfigID } = require("@budibase/auth")
|
const { generateConfigID, getConfigParams } = require("@budibase/auth")
|
||||||
const { getConfigParams } = require("@budibase/auth/src/db/utils")
|
const { SEPARATOR } = require("@budibase/auth/src/db/utils")
|
||||||
|
const { Configs } = require("../../../constants")
|
||||||
|
|
||||||
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||||
|
|
||||||
|
exports.configStatus = async function(ctx) {
|
||||||
|
const db = new CouchDB(GLOBAL_DB)
|
||||||
|
let configured = {}
|
||||||
|
|
||||||
|
// check for super admin user
|
||||||
|
try {
|
||||||
|
configured.user = true
|
||||||
|
} catch (err) {
|
||||||
|
configured.user = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for SMTP config
|
||||||
|
try {
|
||||||
|
const response = await db.allDocs(
|
||||||
|
getConfigParams(`${DocumentTypes.CONFIG}${SEPARATOR}${Configs.SMTP}`)
|
||||||
|
)
|
||||||
|
console.log(response)
|
||||||
|
configured.smtp = true
|
||||||
|
} catch (err) {
|
||||||
|
configured.smtp = false
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = configured
|
||||||
|
}
|
||||||
|
|
||||||
exports.save = async function(ctx) {
|
exports.save = async function(ctx) {
|
||||||
const db = new CouchDB(GLOBAL_DB)
|
const db = new CouchDB(GLOBAL_DB)
|
||||||
const configDoc = ctx.request.body
|
const configDoc = ctx.request.body
|
||||||
|
|
||||||
// Config does not exist yet
|
// Config does not exist yet
|
||||||
if (!configDoc._id) {
|
if (!configDoc._id) {
|
||||||
configDoc._id = generateConfigID(configDoc.type, configDoc.group)
|
configDoc._id = generateConfigID(
|
||||||
|
configDoc.type,
|
||||||
|
configDoc.group,
|
||||||
|
configDoc.user
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,4 +1,38 @@
|
||||||
const { passport, Cookies, clearCookie } = require("@budibase/auth")
|
const {
|
||||||
|
passport,
|
||||||
|
Cookies,
|
||||||
|
StaticDatabases,
|
||||||
|
clearCookie,
|
||||||
|
} = require("@budibase/auth")
|
||||||
|
const CouchDB = require("../../db")
|
||||||
|
|
||||||
|
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||||
|
|
||||||
|
async function setToken(ctx) {
|
||||||
|
return async function(err, user) {
|
||||||
|
if (err) {
|
||||||
|
return ctx.throw(403, "Unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
const expires = new Date()
|
||||||
|
expires.setDate(expires.getDate() + 1)
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return ctx.throw(403, "Unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.cookies.set(Cookies.Auth, user.token, {
|
||||||
|
expires,
|
||||||
|
path: "/",
|
||||||
|
httpOnly: false,
|
||||||
|
overwrite: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
delete user.token
|
||||||
|
|
||||||
|
ctx.body = { user }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exports.authenticate = async (ctx, next) => {
|
exports.authenticate = async (ctx, next) => {
|
||||||
return passport.authenticate("local", async (err, user) => {
|
return passport.authenticate("local", async (err, user) => {
|
||||||
|
@ -31,10 +65,30 @@ exports.logout = async ctx => {
|
||||||
ctx.body = { message: "User logged out" }
|
ctx.body = { message: "User logged out" }
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.googleAuth = async () => {
|
exports.googleAuth = async (ctx, next) => {
|
||||||
// return passport.authenticate("google")
|
return passport.authenticate(
|
||||||
}
|
"google",
|
||||||
|
{ successRedirect: "/", failureRedirect: "/" },
|
||||||
|
async (err, user) => {
|
||||||
|
if (err) {
|
||||||
|
return ctx.throw(403, "Unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
exports.googleAuth = async () => {
|
const expires = new Date()
|
||||||
// return passport.authenticate("google")
|
expires.setDate(expires.getDate() + 1)
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return ctx.throw(403, "Unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.cookies.set(Cookies.Auth, user.token, {
|
||||||
|
expires,
|
||||||
|
path: "/",
|
||||||
|
httpOnly: false,
|
||||||
|
overwrite: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.redirect("/")
|
||||||
|
}
|
||||||
|
)(ctx, next)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ const router = Router()
|
||||||
function buildConfigSaveValidation() {
|
function buildConfigSaveValidation() {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return joiValidator.body(Joi.object({
|
return joiValidator.body(Joi.object({
|
||||||
type: Joi.string().valid(...Object.values(Configs)).required()
|
type: Joi.string().valid(...Object.values(Configs)).required(),
|
||||||
}).required().unknown(true))
|
}).required().unknown(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ router
|
||||||
authenticated,
|
authenticated,
|
||||||
controller.save
|
controller.save
|
||||||
)
|
)
|
||||||
|
.post("/api/admin/config/status", controller.configStatus)
|
||||||
.delete("/api/admin/configs/:id", authenticated, controller.destroy)
|
.delete("/api/admin/configs/:id", authenticated, controller.destroy)
|
||||||
.get("/api/admin/configs", authenticated, controller.fetch)
|
.get("/api/admin/configs", authenticated, controller.fetch)
|
||||||
.get("/api/admin/configs/:id", authenticated, controller.find)
|
.get("/api/admin/configs/:id", authenticated, controller.find)
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
const Router = require("@koa/router")
|
const Router = require("@koa/router")
|
||||||
const { passport } = require("@budibase/auth")
|
const { passport } = require("@budibase/auth")
|
||||||
const authController = require("../controllers/auth")
|
const authController = require("../controllers/auth")
|
||||||
|
const context = require("koa/lib/context")
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
router
|
router
|
||||||
.post("/api/admin/auth", authController.authenticate)
|
.post("/api/admin/auth", authController.authenticate)
|
||||||
.post("/api/admin/auth/logout", authController.logout)
|
|
||||||
.get("/api/auth/google", passport.authenticate("google"))
|
|
||||||
.get(
|
.get(
|
||||||
"/api/auth/google/callback",
|
"/api/admin/auth/google",
|
||||||
passport.authenticate("google", {
|
passport.authenticate("google", { scope: ["profile", "email"] })
|
||||||
successRedirect: "/app",
|
|
||||||
failureRedirect: "/",
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
|
.get("/api/admin/auth/google/callback", authController.googleAuth)
|
||||||
|
.post("/api/admin/auth/logout", authController.logout)
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
Loading…
Reference in New Issue