Some re-work of the auth package, making it a bit easier to use/less likely to make a mistake.

This commit is contained in:
mike12345567 2021-04-21 16:42:44 +01:00
parent ebaf8c3a2f
commit bb5dbf27aa
21 changed files with 164 additions and 106 deletions

View File

@ -14,6 +14,7 @@ const DocumentTypes = {
USER: "us",
APP: "app",
GROUP: "group",
TEMPLATE: "template",
}
exports.DocumentTypes = DocumentTypes
@ -53,7 +54,7 @@ exports.generateGlobalUserID = () => {
/**
* Gets parameters for retrieving users.
*/
exports.getGlobalUserParams = (globalId = "", otherProps = {}) => {
exports.getGlobalUserParams = (globalId, otherProps = {}) => {
if (!globalId) {
globalId = ""
}
@ -63,3 +64,27 @@ exports.getGlobalUserParams = (globalId = "", otherProps = {}) => {
endkey: `${DocumentTypes.USER}${SEPARATOR}${globalId}${UNICODE_MAX}`,
}
}
/**
* Generates a template ID.
* @param ownerId The owner/user of the template, this could be global or a group level.
*/
exports.generateTemplateID = ownerId => {
return `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${newid()}`
}
/**
* Gets parameters for retrieving templates. Owner ID must be specified, either global or a group level.
*/
exports.getTemplateParams = (ownerId, templateId, otherProps = {}) => {
if (!templateId) {
templateId = ""
}
const base = `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}`
const final = templateId ? `${base}${SEPARATOR}${templateId}` : base
return {
...otherProps,
startkey: final,
endkey: `${final}${UNICODE_MAX}`,
}
}

View File

@ -5,23 +5,6 @@ const JwtStrategy = require("passport-jwt").Strategy
const { setDB, getDB } = require("./db")
const { StaticDatabases } = require("./db/utils")
const { jwt, local, authenticated } = require("./middleware")
const { Cookies, UserStatus } = require("./constants")
const { hash, compare } = require("./hashing")
const {
getAppId,
setCookie,
getCookie,
clearCookie,
isClient,
getGlobalUserByEmail,
} = require("./utils")
const {
generateGlobalUserID,
getGlobalUserParams,
generateGroupID,
getGroupParams,
} = require("./db/utils")
// Strategies
passport.use(new LocalStrategy(local.options, local.authenticate))
passport.use(new JwtStrategy(jwt.options, jwt.authenticate))
@ -45,21 +28,14 @@ module.exports = {
init(pouch) {
setDB(pouch)
},
passport,
Cookies,
UserStatus,
StaticDatabases,
generateGlobalUserID,
getGlobalUserParams,
generateGroupID,
getGroupParams,
hash,
compare,
getAppId,
setCookie,
getCookie,
clearCookie,
authenticated,
isClient,
getGlobalUserByEmail,
db: require("./db/utils"),
utils: {
...require("./utils"),
...require("./hashing")
},
auth: {
buildAuthMiddleware: authenticated,
passport,
},
constants: require("./constants"),
}

View File

@ -1,18 +1,25 @@
const { Cookies } = require("../constants")
const { getCookie } = require("../utils")
module.exports = async (ctx, next) => {
try {
// check the actual user is authenticated first
const authCookie = getCookie(ctx, Cookies.Auth)
if (authCookie) {
ctx.isAuthenticated = true
ctx.user = authCookie
module.exports = (noAuthPatterns = []) => {
const regex = new RegExp(noAuthPatterns.join("|"))
return async (ctx, next) => {
// the path is not authenticated
if (regex.test(ctx.request.url)) {
return next()
}
try {
// check the actual user is authenticated first
const authCookie = getCookie(ctx, Cookies.Auth)
await next()
} catch (err) {
ctx.throw(err.status || 403, err)
if (authCookie) {
ctx.isAuthenticated = true
ctx.user = authCookie
}
return next()
} catch (err) {
ctx.throw(err.status || 403, err)
}
}
}

View File

@ -1,14 +1,21 @@
const Router = require("@koa/router")
const { authenticated } = require("@budibase/auth")
const { buildAuthMiddleware } = require("@budibase/auth").auth
const currentApp = require("../middleware/currentapp")
const compress = require("koa-compress")
const zlib = require("zlib")
const { mainRoutes, authRoutes, staticRoutes } = require("./routes")
const { mainRoutes, staticRoutes } = require("./routes")
const pkg = require("../../package.json")
const router = new Router()
const env = require("../environment")
const NO_AUTH_ENDPOINTS = [
"/health",
"/version",
"webhooks/trigger",
"webhooks/schema",
]
router
.use(
compress({
@ -31,7 +38,7 @@ router
})
.use("/health", ctx => (ctx.status = 200))
.use("/version", ctx => (ctx.body = pkg.version))
.use(authenticated)
.use(buildAuthMiddleware(NO_AUTH_ENDPOINTS))
.use(currentApp)
// error handling middleware
@ -53,9 +60,6 @@ router.use(async (ctx, next) => {
router.get("/health", ctx => (ctx.status = 200))
router.use(authRoutes.routes())
router.use(authRoutes.allowedMethods())
// authenticated routes
for (let route of mainRoutes) {
router.use(route.routes())

View File

@ -25,6 +25,7 @@ const backupRoutes = require("./backup")
const devRoutes = require("./dev")
exports.mainRoutes = [
authRoutes,
deployRoutes,
layoutRoutes,
screenRoutes,
@ -52,5 +53,4 @@ exports.mainRoutes = [
rowRoutes,
]
exports.authRoutes = authRoutes
exports.staticRoutes = staticRoutes

View File

@ -1,5 +1,5 @@
const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles")
const { UserStatus } = require("@budibase/auth")
const { UserStatus } = require("@budibase/auth").constants
exports.LOGO_URL =
"https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"

View File

@ -1,4 +1,5 @@
const { getAppId, setCookie, getCookie, Cookies } = require("@budibase/auth")
const { getAppId, setCookie, getCookie } = require("@budibase/auth").utils
const { Cookies } = require("@budibase/auth").constants
const { getRole } = require("../utilities/security/roles")
const { getGlobalUsers } = require("../utilities/workerRequests")
const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles")

View File

@ -23,10 +23,14 @@ function mockAuthWithNoCookie() {
jest.resetModules()
mockWorker()
jest.mock("@budibase/auth", () => ({
getAppId: jest.fn(),
setCookie: jest.fn(),
getCookie: jest.fn(),
Cookies: {},
utils: {
getAppId: jest.fn(),
setCookie: jest.fn(),
getCookie: jest.fn(),
},
constants: {
Cookies: {},
},
}))
}
@ -34,15 +38,19 @@ function mockAuthWithCookie() {
jest.resetModules()
mockWorker()
jest.mock("@budibase/auth", () => ({
getAppId: () => {
return "app_test"
utils: {
getAppId: () => {
return "app_test"
},
setCookie: jest.fn(),
getCookie: () => ({appId: "app_different", roleId: "PUBLIC"}),
},
constants: {
Cookies: {
Auth: "auth",
CurrentApp: "currentapp",
},
},
setCookie: jest.fn(),
getCookie: () => ({ appId: "app_different", roleId: "PUBLIC" }),
Cookies: {
Auth: "auth",
CurrentApp: "currentapp",
}
}))
}
@ -102,7 +110,7 @@ describe("Current app middleware", () => {
async function checkExpected(setCookie) {
config.setUser()
await config.executeMiddleware()
const cookieFn = require("@budibase/auth").setCookie
const cookieFn = require("@budibase/auth").utils.setCookie
if (setCookie) {
expect(cookieFn).toHaveBeenCalled()
} else {
@ -122,12 +130,16 @@ describe("Current app middleware", () => {
it("should perform correct when no cookie exists", async () => {
mockReset()
jest.mock("@budibase/auth", () => ({
getAppId: () => {
return "app_test"
utils: {
getAppId: () => {
return "app_test"
},
setCookie: jest.fn(),
getCookie: jest.fn(),
},
constants: {
Cookies: {},
},
setCookie: jest.fn(),
getCookie: jest.fn(),
Cookies: {},
}))
await checkExpected(true)
})
@ -135,12 +147,14 @@ describe("Current app middleware", () => {
it("lastly check what occurs when cookie doesn't need updated", async () => {
mockReset()
jest.mock("@budibase/auth", () => ({
getAppId: () => {
return "app_test"
utils: {
getAppId: () => {
return "app_test"
},
setCookie: jest.fn(),
getCookie: () => ({appId: "app_test", roleId: "BASIC"}),
},
setCookie: jest.fn(),
getCookie: () => ({ appId: "app_test", roleId: "BASIC" }),
Cookies: {},
constants: { Cookies: {} },
}))
await checkExpected(false)
})

View File

@ -15,7 +15,7 @@ const {
const controllers = require("./controllers")
const supertest = require("supertest")
const { cleanup } = require("../../utilities/fileSystem")
const { Cookies } = require("@budibase/auth")
const { Cookies } = require("@budibase/auth").constants
const EMAIL = "babs@babs.com"
const PASSWORD = "babs_password"

View File

@ -1,6 +1,5 @@
const CouchDB = require("../../../db")
const { getGroupParams, StaticDatabases } = require("@budibase/auth")
const { generateGroupID } = require("@budibase/auth")
const { getGroupParams, generateGroupID, StaticDatabases } = require("@budibase/auth").db
const GLOBAL_DB = StaticDatabases.GLOBAL.name

View File

@ -1,7 +0,0 @@
const users = require("./users")
const groups = require("./groups")
module.exports = {
users,
groups,
}

View File

@ -0,0 +1,18 @@
const { generateTemplateID, getTemplateParams } = require("@budibase/auth").db
const { CouchDB } = require("../../../db")
exports.save = async ctx => {
}
exports.fetch = async ctx => {
}
exports.find = async ctx => {
}
exports.destroy = async ctx => {
}

View File

@ -1,11 +1,10 @@
const CouchDB = require("../../../db")
const {
hash,
generateGlobalUserID,
getGlobalUserParams,
StaticDatabases,
getGlobalUserByEmail,
} = require("@budibase/auth")
} = require("@budibase/auth").db
const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils
const { UserStatus } = require("../../../constants")
const FIRST_USER_EMAIL = "test@test.com"

View File

@ -1,4 +1,7 @@
const { passport, Cookies, clearCookie } = require("@budibase/auth")
const authPkg = require("@budibase/auth")
const { clearCookie } = authPkg.utils
const { Cookies } = authPkg.constants
const { passport } = authPkg.auth
exports.authenticate = async (ctx, next) => {
return passport.authenticate("local", async (err, user) => {

View File

@ -2,6 +2,9 @@ const Router = require("@koa/router")
const compress = require("koa-compress")
const zlib = require("zlib")
const { routes } = require("./routes")
const { buildAuthMiddleware } = require("@budibase/auth").auth
const NO_AUTH_ENDPOINTS = ["/api/admin/users/first"]
const router = new Router()
@ -19,6 +22,7 @@ router
})
)
.use("/health", ctx => (ctx.status = 200))
.use(buildAuthMiddleware(NO_AUTH_ENDPOINTS))
// error handling middleware
router.use(async (ctx, next) => {

View File

@ -1,7 +1,6 @@
const Router = require("@koa/router")
const controller = require("../../controllers/admin/groups")
const joiValidator = require("../../../middleware/joi-validator")
const { authenticated } = require("@budibase/auth")
const Joi = require("joi")
const router = Router()
@ -28,11 +27,10 @@ router
.post(
"/api/admin/groups",
buildGroupSaveValidation(),
authenticated,
controller.save
)
.delete("/api/admin/groups/:id", authenticated, controller.destroy)
.get("/api/admin/groups", authenticated, controller.fetch)
.get("/api/admin/groups/:id", authenticated, controller.find)
.get("/api/admin/groups", controller.fetch)
.delete("/api/admin/groups/:id", controller.destroy)
.get("/api/admin/groups/:id", controller.find)
module.exports = router

View File

@ -0,0 +1,20 @@
const Router = require("@koa/router")
const controller = require("../../controllers/admin/templates")
const joiValidator = require("../../../middleware/joi-validator")
const Joi = require("joi")
const router = Router()
function buildTemplateSaveValidation() {
}
router
.post(
"/api/admin/template/:type",
buildTemplateSaveValidation(),
controller.save
)
.get("/api/admin/template/:type", controller.fetch)
.delete("/api/admin/template/:type/:id", controller.destroy)
.get("/api/admin/template/:type/:id", controller.find)

View File

@ -1,7 +1,6 @@
const Router = require("@koa/router")
const controller = require("../../controllers/admin/users")
const joiValidator = require("../../../middleware/joi-validator")
const { authenticated } = require("@budibase/auth")
const Joi = require("joi")
const router = Router()
@ -29,12 +28,11 @@ router
.post(
"/api/admin/users",
buildUserSaveValidation(),
authenticated,
controller.userSave
)
.get("/api/admin/users", controller.userFetch)
.post("/api/admin/users/first", controller.firstUser)
.delete("/api/admin/users/:id", authenticated, controller.userDelete)
.get("/api/admin/users", authenticated, controller.userFetch)
.get("/api/admin/users/:id", authenticated, controller.userFind)
.delete("/api/admin/users/:id", controller.userDelete)
.get("/api/admin/users/:id", controller.userFind)
module.exports = router

View File

@ -1,9 +1,8 @@
const Router = require("@koa/router")
const controller = require("../controllers/app")
const { authenticated } = require("@budibase/auth")
const router = Router()
router.get("/api/apps", authenticated, controller.getApps)
router.get("/api/apps", controller.getApps)
module.exports = router

View File

@ -1,5 +1,5 @@
const Router = require("@koa/router")
const { passport } = require("@budibase/auth")
const { passport } = require("@budibase/auth").auth
const authController = require("../controllers/auth")
const router = Router()

View File

@ -5,7 +5,7 @@ require("@budibase/auth").init(CouchDB)
const Koa = require("koa")
const destroyable = require("server-destroy")
const koaBody = require("koa-body")
const { passport } = require("@budibase/auth")
const { passport } = require("@budibase/auth").auth
const logger = require("koa-pino-logger")
const http = require("http")
const api = require("./api")