From 654a53fc0ae8077d1eb85aed551202677b10fab1 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 13 Apr 2021 11:56:57 +0100 Subject: [PATCH 1/2] Authentication working on builder homepage, integration with currentapp middleware --- packages/auth/src/middleware/authenticated.js | 2 +- packages/auth/src/middleware/passport/jwt.js | 5 +++++ packages/auth/src/middleware/passport/local.js | 2 +- .../builder/src/components/login/LoginForm.svelte | 6 +++++- packages/builder/src/stores/backend/auth.js | 4 ++-- packages/server/src/api/controllers/application.js | 4 ++-- packages/server/src/api/controllers/auth.js | 13 +++++++++++-- packages/server/src/api/controllers/static/index.js | 7 +++---- packages/server/src/api/routes/auth.js | 1 - packages/server/src/middleware/currentapp.js | 2 +- packages/server/src/utilities/users.js | 4 ++-- 11 files changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/auth/src/middleware/authenticated.js b/packages/auth/src/middleware/authenticated.js index 5966da483e..2fdf4baf6c 100644 --- a/packages/auth/src/middleware/authenticated.js +++ b/packages/auth/src/middleware/authenticated.js @@ -11,7 +11,7 @@ module.exports = async (ctx, next) => { ctx.isAuthenticated = true ctx.user = authCookie // make sure email is correct from ID - ctx.user.email = getEmailFromUserID(authCookie._id) + ctx.user.email = getEmailFromUserID(authCookie.userId) } await next() diff --git a/packages/auth/src/middleware/passport/jwt.js b/packages/auth/src/middleware/passport/jwt.js index 1d6a4e04e0..06071f77e8 100644 --- a/packages/auth/src/middleware/passport/jwt.js +++ b/packages/auth/src/middleware/passport/jwt.js @@ -1,5 +1,10 @@ +const { Cookies } = require("../../constants") + exports.options = { secretOrKey: process.env.JWT_SECRET, + jwtFromRequest: function(ctx) { + return ctx.cookies.get(Cookies.Auth) + }, } exports.authenticate = async function(jwt, done) { diff --git a/packages/auth/src/middleware/passport/local.js b/packages/auth/src/middleware/passport/local.js index 379ec58dbb..5a2221499a 100644 --- a/packages/auth/src/middleware/passport/local.js +++ b/packages/auth/src/middleware/passport/local.js @@ -38,7 +38,7 @@ exports.authenticate = async function(username, password, done) { // authenticate if (await compare(password, dbUser.password)) { const payload = { - _id: dbUser._id, + userId: dbUser._id, } const token = jwt.sign(payload, process.env.JWT_SECRET, { diff --git a/packages/builder/src/components/login/LoginForm.svelte b/packages/builder/src/components/login/LoginForm.svelte index 5265d2e6d6..57ba75934c 100644 --- a/packages/builder/src/components/login/LoginForm.svelte +++ b/packages/builder/src/components/login/LoginForm.svelte @@ -12,7 +12,11 @@ username, password, }) - notifier.success("Logged in successfully.") + if (json.success) { + notifier.success("Logged in successfully.") + } else { + notifier.danger("Invalid credentials") + } } catch (err) { console.error(err) notifier.danger(`Error logging in: ${err}`) diff --git a/packages/builder/src/stores/backend/auth.js b/packages/builder/src/stores/backend/auth.js index e0a9496b94..b6a39dc0af 100644 --- a/packages/builder/src/stores/backend/auth.js +++ b/packages/builder/src/stores/backend/auth.js @@ -3,8 +3,7 @@ import api from "../../builderStore/api" async function checkAuth() { const response = await api.get("/api/self") - const user = await response.json() - if (json) return json + return await response.json() } export function createAuthStore() { @@ -21,6 +20,7 @@ export function createAuthStore() { localStorage.setItem("auth:user", JSON.stringify(json.user)) set({ user: json.user }) } + return json }, logout: async () => { const response = await api.post(`/api/auth/logout`) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 042474c5b6..fd1d7a6688 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -145,7 +145,7 @@ exports.fetchAppPackage = async function(ctx) { layouts, clientLibPath: clientLibraryPath(ctx.params.appId), } - await setBuilderToken(ctx, ctx.params.appId, application.version) + // await setBuilderToken(ctx, ctx.params.appId, application.version) } exports.create = async function(ctx) { @@ -184,7 +184,7 @@ exports.create = async function(ctx) { await createApp(appId) } - await setBuilderToken(ctx, appId, version) + // await setBuilderToken(ctx, appId, version) ctx.status = 200 ctx.body = newApplication ctx.message = `Application ${ctx.request.body.name} created successfully` diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js index 0cc8668687..f62afdf185 100644 --- a/packages/server/src/api/controllers/auth.js +++ b/packages/server/src/api/controllers/auth.js @@ -7,7 +7,7 @@ const { generateUserMetadataID } = require("../../db/utils") const { setCookie } = require("../../utilities") const { outputProcessing } = require("../../utilities/rowProcessor") const { InternalTables } = require("../../db/utils") -const { UserStatus } = require("@budibase/auth") +const { UserStatus, StaticDatabases } = require("@budibase/auth") const { getFullUser } = require("../../utilities/users") const INVALID_ERR = "Invalid Credentials" @@ -73,10 +73,19 @@ exports.authenticate = async ctx => { exports.fetchSelf = async ctx => { const { userId, appId } = ctx.user /* istanbul ignore next */ - if (!userId || !appId) { + if (!userId) { ctx.body = {} return } + + if (!appId) { + const db = new CouchDB(StaticDatabases.USER.name) + const user = await db.get(userId) + delete user.password + ctx.body = { user } + return + } + const db = new CouchDB(appId) const user = await getFullUser({ ctx, userId: userId }) const userTable = await db.get(InternalTables.USER_METADATA) diff --git a/packages/server/src/api/controllers/static/index.js b/packages/server/src/api/controllers/static/index.js index a1edd4643a..dd60ee5985 100644 --- a/packages/server/src/api/controllers/static/index.js +++ b/packages/server/src/api/controllers/static/index.js @@ -9,7 +9,6 @@ const { processString } = require("@budibase/string-templates") const { budibaseTempDir } = require("../../../utilities/budibaseDir") const { getDeployedApps } = require("../../../utilities/builder/hosting") const CouchDB = require("../../../db") -const setBuilderToken = require("../../../utilities/builder/setBuilderToken") const { loadHandlebarsFile, NODE_MODULES_PATH, @@ -35,9 +34,9 @@ const COMP_LIB_BASE_APP_VERSION = "0.2.5" exports.serveBuilder = async function(ctx) { let builderPath = resolve(TOP_LEVEL_PATH, "builder") - if (ctx.file === "index.html") { - // await setBuilderToken(ctx) - } + // if (ctx.file === "index.html") { + // // await setBuilderToken(ctx) + // } await send(ctx, ctx.file, { root: builderPath }) } diff --git a/packages/server/src/api/routes/auth.js b/packages/server/src/api/routes/auth.js index 954130370b..b07627c29e 100644 --- a/packages/server/src/api/routes/auth.js +++ b/packages/server/src/api/routes/auth.js @@ -4,7 +4,6 @@ const controller = require("../controllers/auth") const router = Router() // TODO: needs removed -router.post("/api/authenticate", controller.authenticate) router.get("/api/self", controller.fetchSelf) module.exports = router diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index a591874e6f..80522d6ac0 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -15,7 +15,7 @@ function finish(ctx, next, { appId, roleId, cookie = false }) { ctx.roleId = roleId } if (cookie && appId) { - setCookie(ctx, new CurrentAppCookie(appId, roleId)) + setCookie(ctx, new CurrentAppCookie(appId, roleId), Cookies.CurrentApp) } return next() } diff --git a/packages/server/src/utilities/users.js b/packages/server/src/utilities/users.js index b41a0da9c7..f8246e4e91 100644 --- a/packages/server/src/utilities/users.js +++ b/packages/server/src/utilities/users.js @@ -1,9 +1,9 @@ -const CouchDB = require("../../db") +const CouchDB = require("../db") const { generateUserMetadataID, getEmailFromUserMetadataID, } = require("../db/utils") -const { getGlobalUsers } = require("../../utilities/workerRequests") +const { getGlobalUsers } = require("../utilities/workerRequests") exports.getFullUser = async ({ ctx, email, userId }) => { if (!email) { From b728fc1a3c2283036af8e87b311b24b4f779674c Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 13 Apr 2021 13:26:13 +0100 Subject: [PATCH 2/2] currentapp being set correctly for user --- packages/auth/src/db/utils.js | 3 + packages/auth/src/middleware/authenticated.js | 2 +- packages/builder/src/stores/backend/auth.js | 9 ++- .../server/src/middleware/authenticated.js | 73 ------------------- packages/server/src/middleware/currentapp.js | 12 +-- .../middleware/tests/authenticated.spec.js | 2 +- .../src/utilities/builder/setBuilderToken.js | 2 +- .../server/src/utilities/workerRequests.js | 2 +- 8 files changed, 16 insertions(+), 89 deletions(-) delete mode 100644 packages/server/src/middleware/authenticated.js diff --git a/packages/auth/src/db/utils.js b/packages/auth/src/db/utils.js index b928d809f9..043987fcc4 100644 --- a/packages/auth/src/db/utils.js +++ b/packages/auth/src/db/utils.js @@ -6,6 +6,7 @@ exports.StaticDatabases = { const DocumentTypes = { USER: "us", + APP: "app", } exports.DocumentTypes = DocumentTypes @@ -13,6 +14,8 @@ exports.DocumentTypes = DocumentTypes const UNICODE_MAX = "\ufff0" const SEPARATOR = "_" +exports.SEPARATOR = SEPARATOR + /** * Generates a new user ID based on the passed in email. * @param {string} email The email which the ID is going to be built up of. diff --git a/packages/auth/src/middleware/authenticated.js b/packages/auth/src/middleware/authenticated.js index 2fdf4baf6c..af2c7d5575 100644 --- a/packages/auth/src/middleware/authenticated.js +++ b/packages/auth/src/middleware/authenticated.js @@ -16,6 +16,6 @@ module.exports = async (ctx, next) => { await next() } catch (err) { - ctx.throw(err.status || 403, err.text) + ctx.throw(err.status || 403, err) } } diff --git a/packages/builder/src/stores/backend/auth.js b/packages/builder/src/stores/backend/auth.js index b6a39dc0af..d0a92237b7 100644 --- a/packages/builder/src/stores/backend/auth.js +++ b/packages/builder/src/stores/backend/auth.js @@ -3,13 +3,18 @@ import api from "../../builderStore/api" async function checkAuth() { const response = await api.get("/api/self") - return await response.json() + const user = await response.json() + if (response.status === 200) return user + + return null } export function createAuthStore() { const { subscribe, set } = writable({}) - checkAuth().then(user => set({ user })) + checkAuth() + .then(user => set({ user })) + .catch(err => set({ user: null })) return { subscribe, diff --git a/packages/server/src/middleware/authenticated.js b/packages/server/src/middleware/authenticated.js deleted file mode 100644 index 848670d67a..0000000000 --- a/packages/server/src/middleware/authenticated.js +++ /dev/null @@ -1,73 +0,0 @@ -// const jwt = require("jsonwebtoken") -// const STATUS_CODES = require("../utilities/statusCodes") -// const { getRole, getBuiltinRoles } = require("../utilities/security/roles") -// const { AuthTypes } = require("../constants") -// const { -// getAppId, -// getCookieName, -// clearCookie, -// setCookie, -// isClient, -// } = require("../utilities") - -// module.exports = async (ctx, next) => { -// if (ctx.path === "/builder") { -// await next() -// return -// } - -// // do everything we can to make sure the appId is held correctly -// // we hold it in state as a -// let appId = getAppId(ctx) -// const cookieAppId = ctx.cookies.get(getCookieName("currentapp")) -// const builtinRoles = getBuiltinRoles() -// if (appId && cookieAppId !== appId) { -// setCookie(ctx, appId, "currentapp") -// } else if (cookieAppId) { -// appId = cookieAppId -// } -// let token, authType -// if (!isClient(ctx)) { -// token = ctx.cookies.get(getCookieName()) -// authType = AuthTypes.BUILDER -// } - -// if (!token && appId) { -// token = ctx.cookies.get(getCookieName(appId)) -// authType = AuthTypes.APP -// } - -// if (!token) { -// ctx.auth.authenticated = false -// ctx.appId = appId -// ctx.user = { -// role: builtinRoles.PUBLIC, -// } -// await next() -// return -// } - -// try { -// ctx.auth.authenticated = authType -// const jwtPayload = jwt.verify(token, ctx.config.jwtSecret) -// ctx.appId = appId -// ctx.auth.apiKey = jwtPayload.apiKey -// ctx.user = { -// ...jwtPayload, -// role: await getRole(appId, jwtPayload.roleId), -// } -// // appId no longer carried in user, make sure -// delete ctx.user.appId -// } catch (err) { -// console.log(err) -// if (authType === AuthTypes.BUILDER) { -// clearCookie(ctx) -// ctx.status = 200 -// return -// } else { -// ctx.throw(err.status || STATUS_CODES.FORBIDDEN, err.text) -// } -// } - -// await next() -// } diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index 80522d6ac0..ec330b75ab 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -2,11 +2,6 @@ const { getAppId, setCookie, getCookie, Cookies } = require("@budibase/auth") const { getGlobalUsers } = require("../utilities/workerRequests") const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles") -function CurrentAppCookie(appId, roleId) { - this.appId = appId - this.roleId = roleId -} - function finish(ctx, next, { appId, roleId, cookie = false }) { if (appId) { ctx.appId = appId @@ -15,7 +10,7 @@ function finish(ctx, next, { appId, roleId, cookie = false }) { ctx.roleId = roleId } if (cookie && appId) { - setCookie(ctx, new CurrentAppCookie(appId, roleId), Cookies.CurrentApp) + setCookie(ctx, { appId, roleId }, Cookies.CurrentApp) } return next() } @@ -37,10 +32,7 @@ module.exports = async (ctx, next) => { updateCookie = true appId = requestAppId roleId = BUILTIN_ROLE_IDS.PUBLIC - } else if ( - requestAppId != null && - (appCookie == null || requestAppId === appCookie.appId) - ) { + } else if (requestAppId != null) { const globalUser = await getGlobalUsers(ctx, requestAppId, ctx.user.email) updateCookie = true appId = requestAppId diff --git a/packages/server/src/middleware/tests/authenticated.spec.js b/packages/server/src/middleware/tests/authenticated.spec.js index 94441b7a5e..1e532bd0e7 100644 --- a/packages/server/src/middleware/tests/authenticated.spec.js +++ b/packages/server/src/middleware/tests/authenticated.spec.js @@ -66,7 +66,7 @@ describe("Authenticated middleware", () => { await config.executeMiddleware() expect(config.ctx.cookies.set).toHaveBeenCalledWith( - "budibase:currentapp:local", + "budibase:currentapp", appId, expect.any(Object) ) diff --git a/packages/server/src/utilities/builder/setBuilderToken.js b/packages/server/src/utilities/builder/setBuilderToken.js index c8fc54cd12..663a962582 100644 --- a/packages/server/src/utilities/builder/setBuilderToken.js +++ b/packages/server/src/utilities/builder/setBuilderToken.js @@ -22,7 +22,7 @@ module.exports = async (ctx, appId, version) => { // set the builder token // setCookie(ctx, token, "builder") - setCookie(ctx, appId, "currentapp") + // setCookie(ctx, appId, "currentapp") // need to clear all app tokens or else unable to use the app in the builder // let allDbNames = await CouchDB.allDbs() // allDbNames.map(dbName => { diff --git a/packages/server/src/utilities/workerRequests.js b/packages/server/src/utilities/workerRequests.js index b081762e13..65d013c935 100644 --- a/packages/server/src/utilities/workerRequests.js +++ b/packages/server/src/utilities/workerRequests.js @@ -11,7 +11,7 @@ function getAppRole(appId, user) { if (!user.roleId) { user.roleId = BUILTIN_ROLE_IDS.PUBLIC } - delete user.roles + // delete user.roles return user }