1
0
Fork 0
mirror of synced 2024-07-04 22:11:23 +12:00

Remove loop for get account during user bulk import (#10203)

This commit is contained in:
Rory Powell 2023-04-04 10:14:20 +01:00 committed by GitHub
parent fbbb36b809
commit 5eecb6e686
3 changed files with 52 additions and 29 deletions

View file

@ -126,9 +126,8 @@ describe("/api/global/auth", () => {
it("should prevent user from logging in", async () => { it("should prevent user from logging in", async () => {
user = await config.createUser() user = await config.createUser()
const account = structures.accounts.ssoAccount() as CloudAccount const account = structures.accounts.ssoAccount() as CloudAccount
mocks.accounts.getAccount.mockReturnValueOnce( account.email = user.email
Promise.resolve(account) mocks.accounts.getAccountByTenantId.mockResolvedValueOnce(account)
)
await testSSOUser() await testSSOUser()
}) })
@ -186,9 +185,8 @@ describe("/api/global/auth", () => {
it("should prevent user from generating password reset email", async () => { it("should prevent user from generating password reset email", async () => {
user = await config.createUser(structures.users.user()) user = await config.createUser(structures.users.user())
const account = structures.accounts.ssoAccount() as CloudAccount const account = structures.accounts.ssoAccount() as CloudAccount
mocks.accounts.getAccount.mockReturnValueOnce( account.email = user.email
Promise.resolve(account) mocks.accounts.getAccountByTenantId.mockResolvedValueOnce(account)
)
await testSSOUser() await testSSOUser()
}) })

View file

@ -1,6 +1,6 @@
import { structures } from "../../../tests" import { structures } from "../../../tests"
import { mocks } from "@budibase/backend-core/tests" import { mocks } from "@budibase/backend-core/tests"
import { env } from "@budibase/backend-core" import { env, context } from "@budibase/backend-core"
import * as users from "../users" import * as users from "../users"
import { CloudAccount } from "@budibase/types" import { CloudAccount } from "@budibase/types"
import { isPreventPasswordActions } from "../users" import { isPreventPasswordActions } from "../users"
@ -16,32 +16,50 @@ describe("users", () => {
describe("isPreventPasswordActions", () => { describe("isPreventPasswordActions", () => {
it("returns false for non sso user", async () => { it("returns false for non sso user", async () => {
const user = structures.users.user() await context.doInTenant(structures.tenant.id(), async () => {
const result = await users.isPreventPasswordActions(user) const user = structures.users.user()
expect(result).toBe(false) const result = await users.isPreventPasswordActions(user)
expect(result).toBe(false)
})
}) })
it("returns true for sso account user", async () => { it("returns true for sso account user", async () => {
const user = structures.users.user() await context.doInTenant(structures.tenant.id(), async () => {
mocks.accounts.getAccount.mockReturnValue( const user = structures.users.user()
Promise.resolve(structures.accounts.ssoAccount() as CloudAccount) const account = structures.accounts.ssoAccount() as CloudAccount
) account.email = user.email
const result = await users.isPreventPasswordActions(user) mocks.accounts.getAccountByTenantId.mockResolvedValueOnce(account)
expect(result).toBe(true) const result = await users.isPreventPasswordActions(user)
expect(result).toBe(true)
})
})
it("returns false when account doesn't match user email", async () => {
await context.doInTenant(structures.tenant.id(), async () => {
const user = structures.users.user()
const account = structures.accounts.ssoAccount() as CloudAccount
mocks.accounts.getAccountByTenantId.mockResolvedValueOnce(account)
const result = await users.isPreventPasswordActions(user)
expect(result).toBe(false)
})
}) })
it("returns true for sso user", async () => { it("returns true for sso user", async () => {
const user = structures.users.ssoUser() await context.doInTenant(structures.tenant.id(), async () => {
const result = await users.isPreventPasswordActions(user) const user = structures.users.ssoUser()
expect(result).toBe(true) const result = await users.isPreventPasswordActions(user)
expect(result).toBe(true)
})
}) })
describe("enforced sso", () => { describe("enforced sso", () => {
it("returns true for all users when sso is enforced", async () => { it("returns true for all users when sso is enforced", async () => {
const user = structures.users.user() await context.doInTenant(structures.tenant.id(), async () => {
pro.features.isSSOEnforced.mockReturnValue(Promise.resolve(true)) const user = structures.users.user()
const result = await users.isPreventPasswordActions(user) pro.features.isSSOEnforced.mockResolvedValueOnce(true)
expect(result).toBe(true) const result = await users.isPreventPasswordActions(user)
expect(result).toBe(true)
})
}) })
}) })

View file

@ -31,6 +31,7 @@ import {
SearchUsersRequest, SearchUsersRequest,
User, User,
SaveUserOpts, SaveUserOpts,
Account,
} from "@budibase/types" } from "@budibase/types"
import { sendEmail } from "../../utilities/email" import { sendEmail } from "../../utilities/email"
import { EmailTemplatePurpose } from "../../constants" import { EmailTemplatePurpose } from "../../constants"
@ -127,7 +128,8 @@ const buildUser = async (
requirePassword: true, requirePassword: true,
}, },
tenantId: string, tenantId: string,
dbUser?: any dbUser?: any,
account?: Account
): Promise<User> => { ): Promise<User> => {
let { password, _id } = user let { password, _id } = user
@ -138,7 +140,7 @@ const buildUser = async (
let hashedPassword let hashedPassword
if (password) { if (password) {
if (await isPreventPasswordActions(user)) { if (await isPreventPasswordActions(user, account)) {
throw new HTTPError("Password change is disabled for this user", 400) throw new HTTPError("Password change is disabled for this user", 400)
} }
hashedPassword = opts.hashPassword ? await utils.hash(password) : password hashedPassword = opts.hashPassword ? await utils.hash(password) : password
@ -209,7 +211,7 @@ const validateUniqueUser = async (email: string, tenantId: string) => {
} }
} }
export async function isPreventPasswordActions(user: User) { export async function isPreventPasswordActions(user: User, account?: Account) {
// when in maintenance mode we allow sso users with the admin role // when in maintenance mode we allow sso users with the admin role
// to perform any password action - this prevents lockout // to perform any password action - this prevents lockout
if (coreEnv.ENABLE_SSO_MAINTENANCE_MODE && user.admin?.global) { if (coreEnv.ENABLE_SSO_MAINTENANCE_MODE && user.admin?.global) {
@ -227,8 +229,10 @@ export async function isPreventPasswordActions(user: User) {
} }
// Check account sso // Check account sso
const account = await accountSdk.api.getAccount(user.email) if (!account) {
return !!(account && isSSOAccount(account)) account = await accountSdk.api.getAccountByTenantId(tenancy.getTenantId())
}
return !!(account && account.email === user.email && isSSOAccount(account))
} }
export const save = async ( export const save = async (
@ -439,6 +443,7 @@ export const bulkCreate = async (
newUsers.push(newUser) newUsers.push(newUser)
} }
const account = await accountSdk.api.getAccountByTenantId(tenantId)
// create the promises array that will be called by bulkDocs // create the promises array that will be called by bulkDocs
newUsers.forEach((user: any) => { newUsers.forEach((user: any) => {
usersToSave.push( usersToSave.push(
@ -448,7 +453,9 @@ export const bulkCreate = async (
hashPassword: true, hashPassword: true,
requirePassword: user.requirePassword, requirePassword: user.requirePassword,
}, },
tenantId tenantId,
undefined, // no dbUser
account
) )
) )
}) })