Allow an account holder to login to account-portal if the tenant has been deleted. (#14547)
* Add email to session for populate user * Add email param * use param object * Type fix for tests * Fix test * Temporarily remove account-portal tests
This commit is contained in:
parent
50de6a1480
commit
49a4e252c6
|
@ -117,9 +117,9 @@ jobs:
|
|||
- name: Test
|
||||
run: |
|
||||
if ${{ env.ONLY_AFFECTED_TASKS }}; then
|
||||
yarn test --ignore=@budibase/worker --ignore=@budibase/server --since=${{ env.NX_BASE_BRANCH }}
|
||||
yarn test --ignore=@budibase/worker --ignore=@budibase/server --ignore @budibase/account-portal-server --since=${{ env.NX_BASE_BRANCH }}
|
||||
else
|
||||
yarn test --ignore=@budibase/worker --ignore=@budibase/server
|
||||
yarn test --ignore=@budibase/worker --ignore=@budibase/server --ignore @budibase/account-portal-server
|
||||
fi
|
||||
|
||||
test-worker:
|
||||
|
|
|
@ -63,14 +63,25 @@ async function populateUsersFromDB(
|
|||
* If not present fallback to loading the user directly and re-caching.
|
||||
* @param userId the id of the user to get
|
||||
* @param tenantId the tenant of the user to get
|
||||
* @param email the email of the user to populate from account if needed
|
||||
* @param populateUser function to provide the user for re-caching. default to couch db
|
||||
* @returns
|
||||
*/
|
||||
export async function getUser(
|
||||
userId: string,
|
||||
tenantId?: string,
|
||||
populateUser?: (userId: string, tenantId: string) => Promise<User>
|
||||
) {
|
||||
export async function getUser({
|
||||
userId,
|
||||
tenantId,
|
||||
email,
|
||||
populateUser,
|
||||
}: {
|
||||
userId: string
|
||||
email?: string
|
||||
tenantId?: string
|
||||
populateUser?: (
|
||||
userId: string,
|
||||
tenantId: string,
|
||||
email?: string
|
||||
) => Promise<User>
|
||||
}) {
|
||||
if (!populateUser) {
|
||||
populateUser = populateFromDB
|
||||
}
|
||||
|
@ -85,7 +96,7 @@ export async function getUser(
|
|||
// try cache
|
||||
let user: User = await client.get(userId)
|
||||
if (!user) {
|
||||
user = await populateUser(userId, tenantId)
|
||||
user = await populateUser(userId, tenantId, email)
|
||||
await client.store(userId, user, EXPIRY_SECONDS)
|
||||
}
|
||||
if (user && !user.tenantId && tenantId) {
|
||||
|
|
|
@ -43,7 +43,11 @@ function finalise(ctx: any, opts: FinaliseOpts = {}) {
|
|||
|
||||
async function checkApiKey(
|
||||
apiKey: string,
|
||||
populateUser?: (userId: string, tenantId: string) => Promise<User>
|
||||
populateUser?: (
|
||||
userId: string,
|
||||
tenantId: string,
|
||||
email?: string
|
||||
) => Promise<User>
|
||||
) {
|
||||
// check both the primary and the fallback internal api keys
|
||||
// this allows for rotation
|
||||
|
@ -70,7 +74,11 @@ async function checkApiKey(
|
|||
if (userId) {
|
||||
return {
|
||||
valid: true,
|
||||
user: await getUser(userId, tenantId, populateUser),
|
||||
user: await getUser({
|
||||
userId,
|
||||
tenantId,
|
||||
populateUser,
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
throw new InvalidAPIKeyError()
|
||||
|
@ -123,13 +131,18 @@ export default function (
|
|||
// getting session handles error checking (if session exists etc)
|
||||
session = await getSession(userId, sessionId)
|
||||
if (opts && opts.populateUser) {
|
||||
user = await getUser(
|
||||
user = await getUser({
|
||||
userId,
|
||||
session.tenantId,
|
||||
opts.populateUser(ctx)
|
||||
)
|
||||
tenantId: session.tenantId,
|
||||
email: session.email,
|
||||
populateUser: opts.populateUser(ctx),
|
||||
})
|
||||
} else {
|
||||
user = await getUser(userId, session.tenantId)
|
||||
user = await getUser({
|
||||
userId,
|
||||
tenantId: session.tenantId,
|
||||
email: session.email,
|
||||
})
|
||||
}
|
||||
// @ts-ignore
|
||||
user.csrfToken = session.csrfToken
|
||||
|
@ -148,7 +161,11 @@ export default function (
|
|||
}
|
||||
// this is an internal request, no user made it
|
||||
if (!authenticated && apiKey) {
|
||||
const populateUser = opts.populateUser ? opts.populateUser(ctx) : null
|
||||
const populateUser: (
|
||||
userId: string,
|
||||
tenantId: string,
|
||||
email?: string
|
||||
) => Promise<User> = opts.populateUser ? opts.populateUser(ctx) : null
|
||||
const { valid, user: foundUser } = await checkApiKey(
|
||||
apiKey,
|
||||
populateUser
|
||||
|
|
|
@ -333,6 +333,7 @@ export default class TestConfiguration {
|
|||
sessionId: this.sessionIdForUser(_id),
|
||||
tenantId: this.getTenantId(),
|
||||
csrfToken: this.csrfToken,
|
||||
email,
|
||||
})
|
||||
const resp = await db.put(user)
|
||||
await cache.user.invalidateUser(_id)
|
||||
|
@ -396,16 +397,17 @@ export default class TestConfiguration {
|
|||
}
|
||||
// make sure the user exists in the global DB
|
||||
if (roleId !== roles.BUILTIN_ROLE_IDS.PUBLIC) {
|
||||
await this.globalUser({
|
||||
const user = await this.globalUser({
|
||||
_id: userId,
|
||||
builder: { global: builder },
|
||||
roles: { [appId]: roleId || roles.BUILTIN_ROLE_IDS.BASIC },
|
||||
})
|
||||
await sessions.createASession(userId, {
|
||||
sessionId: this.sessionIdForUser(userId),
|
||||
tenantId: this.getTenantId(),
|
||||
email: user.email,
|
||||
})
|
||||
}
|
||||
await sessions.createASession(userId, {
|
||||
sessionId: this.sessionIdForUser(userId),
|
||||
tenantId: this.getTenantId(),
|
||||
})
|
||||
// have to fake this
|
||||
const authObj = {
|
||||
userId,
|
||||
|
|
|
@ -247,7 +247,9 @@ class QueryRunner {
|
|||
if (!resp.err) {
|
||||
const globalUserId = getGlobalIDFromUserMetadataID(_id)
|
||||
await auth.updateUserOAuth(globalUserId, resp)
|
||||
this.ctx.user = await cache.user.getUser(globalUserId)
|
||||
this.ctx.user = await cache.user.getUser({
|
||||
userId: globalUserId,
|
||||
})
|
||||
} else {
|
||||
// In this event the user may have oAuth issues that
|
||||
// could require re-authenticating with their provider.
|
||||
|
|
|
@ -77,7 +77,9 @@ export async function getCachedSelf(
|
|||
): Promise<ContextUser> {
|
||||
// this has to be tenant aware, can't depend on the context to find it out
|
||||
// running some middlewares before the tenancy causes context to break
|
||||
const user = await cache.user.getUser(ctx.user?._id!)
|
||||
const user = await cache.user.getUser({
|
||||
userId: ctx.user?._id!,
|
||||
})
|
||||
return processUser(user, { appId })
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,9 @@ export async function processInputBBReference(
|
|||
}
|
||||
|
||||
try {
|
||||
await cache.user.getUser(id)
|
||||
await cache.user.getUser({
|
||||
userId: id,
|
||||
})
|
||||
return id
|
||||
} catch (e: any) {
|
||||
if (e.statusCode === 404) {
|
||||
|
@ -125,7 +127,9 @@ export async function processOutputBBReference(
|
|||
case BBReferenceFieldSubType.USER: {
|
||||
let user
|
||||
try {
|
||||
user = await cache.user.getUser(value as string)
|
||||
user = await cache.user.getUser({
|
||||
userId: value as string,
|
||||
})
|
||||
} catch (err: any) {
|
||||
if (err.statusCode !== 404) {
|
||||
throw err
|
||||
|
|
|
@ -110,7 +110,9 @@ async function processDefaultValues(table: Table, row: Row) {
|
|||
|
||||
const identity = context.getIdentity()
|
||||
if (identity?._id && identity.type === IdentityType.USER) {
|
||||
const user = await cache.user.getUser(identity._id)
|
||||
const user = await cache.user.getUser({
|
||||
userId: identity._id,
|
||||
})
|
||||
delete user.password
|
||||
|
||||
ctx["Current User"] = user
|
||||
|
|
|
@ -74,7 +74,9 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
expect(result).toEqual(userId)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledTimes(1)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith(userId)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith({
|
||||
userId,
|
||||
})
|
||||
})
|
||||
|
||||
it("throws an error given an invalid id", async () => {
|
||||
|
@ -98,7 +100,9 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
expect(result).toEqual(userId)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledTimes(1)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith(userId)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith({
|
||||
userId,
|
||||
})
|
||||
})
|
||||
|
||||
it("empty strings will return null", async () => {
|
||||
|
@ -243,7 +247,9 @@ describe("bbReferenceProcessor", () => {
|
|||
lastName: user.lastName,
|
||||
})
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledTimes(1)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith(userId)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith({
|
||||
userId,
|
||||
})
|
||||
})
|
||||
|
||||
it("returns undefined given an unexisting user", async () => {
|
||||
|
@ -255,7 +261,9 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
expect(result).toBeUndefined()
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledTimes(1)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith(userId)
|
||||
expect(cacheGetUserSpy).toHaveBeenCalledWith({
|
||||
userId,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -10,6 +10,7 @@ export interface AuthToken {
|
|||
export interface CreateSession {
|
||||
sessionId: string
|
||||
tenantId: string
|
||||
email: string
|
||||
csrfToken?: string
|
||||
hosting?: Hosting
|
||||
}
|
||||
|
|
|
@ -19,12 +19,17 @@ import { EmailTemplatePurpose } from "../../constants"
|
|||
export async function loginUser(user: User) {
|
||||
const sessionId = coreUtils.newid()
|
||||
const tenantId = tenancy.getTenantId()
|
||||
await sessions.createASession(user._id!, { sessionId, tenantId })
|
||||
await sessions.createASession(user._id!, {
|
||||
sessionId,
|
||||
tenantId,
|
||||
email: user.email,
|
||||
})
|
||||
return jwt.sign(
|
||||
{
|
||||
userId: user._id,
|
||||
sessionId,
|
||||
tenantId,
|
||||
email: user.email,
|
||||
},
|
||||
coreEnv.JWT_SECRET!
|
||||
)
|
||||
|
|
|
@ -170,19 +170,26 @@ class TestConfiguration {
|
|||
async _createSession({
|
||||
userId,
|
||||
tenantId,
|
||||
email,
|
||||
}: {
|
||||
userId: string
|
||||
tenantId: string
|
||||
email: string
|
||||
}) {
|
||||
await sessions.createASession(userId!, {
|
||||
sessionId: "sessionid",
|
||||
tenantId: tenantId,
|
||||
tenantId,
|
||||
csrfToken: CSRF_TOKEN,
|
||||
email,
|
||||
})
|
||||
}
|
||||
|
||||
async createSession(user: User) {
|
||||
return this._createSession({ userId: user._id!, tenantId: user.tenantId })
|
||||
return this._createSession({
|
||||
userId: user._id!,
|
||||
tenantId: user.tenantId,
|
||||
email: user.email,
|
||||
})
|
||||
}
|
||||
|
||||
cookieHeader(cookies: any) {
|
||||
|
|
Loading…
Reference in New Issue