Add database test configuration to auth package

This commit is contained in:
Rory Powell 2021-07-15 12:55:35 +01:00
parent 121a8e5e9a
commit 9e24bc14e7
11 changed files with 4077 additions and 40 deletions

View File

@ -27,9 +27,17 @@
"uuid": "^8.3.2", "uuid": "^8.3.2",
"zlib": "^1.0.5" "zlib": "^1.0.5"
}, },
"jest": {
"setupFiles": [
"./scripts/jestSetup.js"
]
},
"devDependencies": { "devDependencies": {
"ioredis-mock": "^5.5.5", "ioredis-mock": "^5.5.5",
"jest": "^26.6.3" "jest": "^26.6.3",
"pouchdb-adapter-memory": "^7.2.2",
"pouchdb": "^7.2.1",
"pouchdb-all-dbs": "^1.0.2"
}, },
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc" "gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc"
} }

View File

@ -0,0 +1,5 @@
const env = require("../src/environment")
env._set("NODE_ENV", "jest")
env._set("JWT_SECRET", "test-jwtsecret")
env._set("LOG_LEVEL", "silent")

View File

@ -17,4 +17,8 @@ module.exports = {
MINIO_URL: process.env.MINIO_URL, MINIO_URL: process.env.MINIO_URL,
INTERNAL_API_KEY: process.env.INTERNAL_API_KEY, INTERNAL_API_KEY: process.env.INTERNAL_API_KEY,
isTest, isTest,
_set(key, value) {
process.env[key] = value
module.exports[key] = value
},
} }

View File

@ -1,6 +1,6 @@
// Mock data // Mock data
const { data } = require("./utilities") const { data } = require("./utilities/mock-data")
const googleConfig = { const googleConfig = {
callbackURL: "http://somecallbackurl", callbackURL: "http://somecallbackurl",

View File

@ -1,6 +1,6 @@
// Mock data // Mock data
const { data } = require("./utilities") const { data } = require("./utilities/mock-data")
const issuer = "mockIssuer" const issuer = "mockIssuer"
const sub = "mockSub" const sub = "mockSub"

View File

@ -1,18 +1,151 @@
// Mock data // Mock data
require("./utilities/test-config")
const database = require("../../../db")
const { authenticateThirdParty } = require("../third-party-common") const { authenticateThirdParty } = require("../third-party-common")
const { data } = require("./utilities/mock-data")
const {
StaticDatabases,
generateGlobalUserID
} = require("../../../db/utils")
const { newid } = require("../../../hashing")
let db
const done = jest.fn()
const getErrorMessage = () => {
return done.mock.calls[0][2].message
}
describe("third party common", () => { describe("third party common", () => {
describe("authenticateThirdParty", () => { describe("authenticateThirdParty", () => {
it("", () => { let thirdPartyUser
beforeEach(() => {
db = database.getDB(StaticDatabases.GLOBAL.name)
thirdPartyUser = data.buildThirdPartyUser()
})
afterEach(async () => {
jest.clearAllMocks()
await db.destroy()
})
describe("validation", () => {
const testValidation = async (message) => {
await authenticateThirdParty(thirdPartyUser, false, done)
expect(done.mock.calls.length).toBe(1)
expect(getErrorMessage()).toContain(message)
}
it("provider fails", async () => {
delete thirdPartyUser.provider
testValidation("third party user provider required")
})
it("user id fails", async () => {
delete thirdPartyUser.userId
testValidation("third party user id required")
})
it("email fails", async () => {
delete thirdPartyUser.email
testValidation("third party user email required")
}) })
}) })
describe("syncUser", () => { const expectUserIsAuthenticated = () => {
it("", () => { const user = done.mock.calls[0][1]
expect(user).toBeDefined()
expect(user._id).toBeDefined()
expect(user._rev).toBeDefined()
expect(user.token).toBeDefined()
return user
}
const expectUserIsSynced = (user, thirdPartyUser) => {
expect(user.provider).toBe(thirdPartyUser.provider)
expect(user.email).toBe(thirdPartyUser.email)
expect(user.firstName).toBe(thirdPartyUser.profile.name.givenName)
expect(user.lastName).toBe(thirdPartyUser.profile.name.familyName)
expect(user.thirdPartyProfile).toStrictEqual(thirdPartyUser.profile._json)
expect(user.oauth2).toStrictEqual(thirdPartyUser.oauth2)
}
describe("when the user doesn't exist", () => {
describe("when a local account is required", () => {
it("returns an error message", async () => {
await authenticateThirdParty(thirdPartyUser, true, done)
expect(done.mock.calls.length).toBe(1)
expect(getErrorMessage()).toContain("Email does not yet exist. You must set up your local budibase account first.")
})
})
describe("when a local account isn't required", () => {
it("creates and authenticates the user", async () => {
await authenticateThirdParty(thirdPartyUser, false, done)
const user = expectUserIsAuthenticated()
expectUserIsSynced(user, thirdPartyUser)
expect(user.roles).toStrictEqual({})
})
})
})
describe("when the user exists", () => {
let dbUser
let id
let email
const createUser = async () => {
dbUser = {
_id: id,
email: email,
}
const response = await db.post(dbUser)
dbUser._rev = response.rev
}
const expectUserIsUpdated = (user) => {
// id is unchanged
expect(user._id).toBe(id)
// user is updated
expect(user._rev).not.toBe(dbUser._rev)
}
describe("exists by email", () => {
beforeEach(async () => {
id = generateGlobalUserID(newid()) // random id
email = thirdPartyUser.email // matching email
await createUser()
})
it("syncs and authenticates the user", async () => {
await authenticateThirdParty(thirdPartyUser, true, done)
const user = expectUserIsAuthenticated()
expectUserIsSynced(user, thirdPartyUser)
expectUserIsUpdated(user)
})
})
describe("exists by id", () => {
beforeEach(async () => {
id = generateGlobalUserID(thirdPartyUser.userId) // matching id
email = "test@test.com" // random email
await createUser()
})
it("syncs and authenticates the user", async () => {
await authenticateThirdParty(thirdPartyUser, true, done)
const user = expectUserIsAuthenticated()
expectUserIsSynced(user, thirdPartyUser)
expectUserIsUpdated(user)
})
})
}) })
}) })
}) })

View File

@ -0,0 +1,20 @@
const PouchDB = require("pouchdb")
const allDbs = require("pouchdb-all-dbs")
const env = require("../../../../environment")
let POUCH_DB_DEFAULTS
// should always be test but good to do the sanity check
if (env.isTest()) {
PouchDB.plugin(require("pouchdb-adapter-memory"))
POUCH_DB_DEFAULTS = {
prefix: undefined,
adapter: "memory",
}
}
const Pouch = PouchDB.defaults(POUCH_DB_DEFAULTS)
allDbs(Pouch)
module.exports = Pouch

View File

@ -7,6 +7,20 @@ const mockEmail = "mock@budibase.com"
const mockAccessToken = "mockAccessToken" const mockAccessToken = "mockAccessToken"
const mockRefreshToken = "mockRefreshToken" const mockRefreshToken = "mockRefreshToken"
const mockProvider = "mockProvider"
const mockProviderType = "mockProviderType"
const mockProfile = {
id: "mockId",
name: {
givenName: "mockGivenName",
familyName: "mockFamilyName",
},
_json: {
email: mockEmail,
},
}
const buildOauth2 = ( const buildOauth2 = (
accessToken = mockAccessToken, accessToken = mockAccessToken,
refreshToken = mockRefreshToken refreshToken = mockRefreshToken
@ -16,9 +30,9 @@ const buildOauth2 = (
}) })
const buildThirdPartyUser = ( const buildThirdPartyUser = (
provider, provider = mockProvider,
providerType, providerType = mockProviderType,
profile, profile = mockProfile,
email = mockEmail, email = mockEmail,
oauth2 = buildOauth2() oauth2 = buildOauth2()
) => ({ ) => ({

View File

@ -0,0 +1,3 @@
const packageConfiguration = require("../../../../index")
const CouchDB = require("./db")
packageConfiguration.init(CouchDB)

View File

@ -1,14 +1,11 @@
const env = require("../../environment") const env = require("../../environment")
const jwt = require("jsonwebtoken") const jwt = require("jsonwebtoken")
const database = require("../../db") const database = require("../../db")
const { const { StaticDatabases, generateGlobalUserID } = require("../../db/utils")
StaticDatabases,
generateGlobalUserID,
ViewNames,
} = require("../../db/utils")
const { authError } = require("./utils") const { authError } = require("./utils")
const { newid } = require("../../hashing") const { newid } = require("../../hashing")
const { createASession } = require("../../security/sessions") const { createASession } = require("../../security/sessions")
const { getGlobalUserByEmail } = require("../../utils")
/** /**
* Common authentication logic for third parties. e.g. OAuth, OIDC. * Common authentication logic for third parties. e.g. OAuth, OIDC.
@ -48,14 +45,7 @@ exports.authenticateThirdParty = async function (
// fallback to loading by email // fallback to loading by email
if (!dbUser) { if (!dbUser) {
const users = await db.query(`database/${ViewNames.USER_BY_EMAIL}`, { dbUser = await getGlobalUserByEmail(thirdPartyUser.email)
key: thirdPartyUser.email,
include_docs: true,
})
if (users.rows.length > 0) {
dbUser = users.rows[0].doc
}
} }
// exit early if there is still no user and auto creation is disabled // exit early if there is still no user and auto creation is disabled

File diff suppressed because it is too large Load Diff