Skip to content

Commit 9c25e7b

Browse files
fix(plugin-multi-tenant): scope access constraint to admin collection (#11430)
### What? The idea of this plugin is to only add constraints when a user is present on a request. This change makes it so access control only applies to admin panel users as they are the ones assigned to tenants. This change allows you to more freely write access functions on tenant enabled collections. Say you have 2 auth enabled collections, the plugin would incorrectly assume since there is a user on the req that it needs to apply tenant constraints. When really, you should be able to just add in your own access check for `req.user.collection` and return true/false if you want to prevent/allow other auth enabled collections for certain operations. ```ts import { Access } from 'payload' const readByTenant: Access = ({ req }) => { const { user } = req if (!user || user.collection === 'auth2') return false return true } ``` When you have a function like this that returns `true` and the collection is multi-tenant enabled - the plugin injects constraints ensuring the user on the request is assigned to the tenant on the doc being accessed. Before this change, you would need to opt out of access control with `useTenantAccess` and then wire up your own access function: ```ts import type { Access } from 'payload' import { getTenantAccess } from '@payloadcms/plugin-multi-tenant/utilities' export const tenantAccess: Access = async ({ req: { user } }) => { if (user) { if (user.collection === 'auth2') { return true } // Before, you would need to re-implement // internal multi-tenant access constraints if (user.roles?.includes('super-admin')) return true return getTenantAccess({ fieldName: 'tenant', user, }) } return false } ``` After this change you would not need to opt out of `useTenantAccess` and can just write: ```ts import type { Access } from 'payload' import { getTenantAccess } from '@payloadcms/plugin-multi-tenant/utilities' export const tenantAccess: Access = async ({ req: { user } }) => { return Boolean(user) } ``` This is because internally the plugin will only add the tenant constraint when the access function returns true/Where _AND_ the user belongs to the admin panel users collection.
1 parent 1d252cb commit 9c25e7b

File tree

5 files changed

+17
-5
lines changed

5 files changed

+17
-5
lines changed

packages/plugin-multi-tenant/src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,11 @@ export const multiTenantPlugin =
8080
if (!incomingConfig.i18n.translations) {
8181
incomingConfig.i18n.translations = {}
8282
}
83-
if (!incomingConfig.i18n.translations[locale]) {
83+
if (!(locale in incomingConfig.i18n.translations)) {
8484
incomingConfig.i18n.translations[locale] = {}
8585
}
86+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
87+
// @ts-expect-error
8688
if (!('multiTenant' in incomingConfig.i18n.translations[locale])) {
8789
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
8890
// @ts-expect-error
@@ -125,6 +127,7 @@ export const multiTenantPlugin =
125127
}
126128

127129
addCollectionAccess({
130+
adminUsersSlug: adminUsersCollection.slug,
128131
collection: adminUsersCollection,
129132
fieldName: `${tenantsArrayFieldName}.${tenantsArrayTenantFieldName}`,
130133
tenantsArrayFieldName,
@@ -182,6 +185,7 @@ export const multiTenantPlugin =
182185
* - constrains access a users assigned tenants
183186
*/
184187
addCollectionAccess({
188+
adminUsersSlug: adminUsersCollection.slug,
185189
collection,
186190
fieldName: 'id',
187191
tenantsArrayFieldName,
@@ -284,6 +288,7 @@ export const multiTenantPlugin =
284288
* Add access control constraint to tenant enabled collection
285289
*/
286290
addCollectionAccess({
291+
adminUsersSlug: adminUsersCollection.slug,
287292
collection,
288293
fieldName: tenantFieldName,
289294
tenantsArrayFieldName,

packages/plugin-multi-tenant/src/types.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ export type Tenant<IDType = number | string> = {
152152
}
153153

154154
export type UserWithTenantsField = {
155-
tenants: {
156-
tenant: number | string | Tenant
157-
}[]
155+
tenants?:
156+
| {
157+
tenant: number | string | Tenant
158+
}[]
159+
| null
158160
} & User

packages/plugin-multi-tenant/src/utilities/addCollectionAccess.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const collectionAccessKeys: AllAccessKeys<
1818
> = ['create', 'read', 'update', 'delete', 'readVersions', 'unlock'] as const
1919

2020
type Args<ConfigType> = {
21+
adminUsersSlug: string
2122
collection: CollectionConfig
2223
fieldName: string
2324
tenantsArrayFieldName?: string
@@ -32,6 +33,7 @@ type Args<ConfigType> = {
3233
* - constrains access a users assigned tenants
3334
*/
3435
export const addCollectionAccess = <ConfigType>({
36+
adminUsersSlug,
3537
collection,
3638
fieldName,
3739
tenantsArrayFieldName,
@@ -44,6 +46,7 @@ export const addCollectionAccess = <ConfigType>({
4446
}
4547
collection.access[key] = withTenantAccess<ConfigType>({
4648
accessFunction: collection.access?.[key],
49+
adminUsersSlug,
4750
collection,
4851
fieldName: key === 'readVersions' ? `version.${fieldName}` : fieldName,
4952
operation: key,

packages/plugin-multi-tenant/src/utilities/withTenantAccess.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { getTenantAccess } from './getTenantAccess.js'
1515

1616
type Args<ConfigType> = {
1717
accessFunction?: Access
18+
adminUsersSlug: string
1819
collection: CollectionConfig
1920
fieldName: string
2021
operation: AllOperations
@@ -27,6 +28,7 @@ type Args<ConfigType> = {
2728
export const withTenantAccess =
2829
<ConfigType>({
2930
accessFunction,
31+
adminUsersSlug,
3032
collection,
3133
fieldName,
3234
tenantsArrayFieldName,
@@ -49,6 +51,7 @@ export const withTenantAccess =
4951

5052
if (
5153
args.req.user &&
54+
args.req.user.collection === adminUsersSlug &&
5255
!userHasAccessToAllTenants(
5356
args.req.user as ConfigType extends { user: unknown } ? ConfigType['user'] : User,
5457
)

test/plugin-multi-tenant/int.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ describe('@payloadcms/plugin-multi-tenant', () => {
4545
data: {
4646
name: 'tenant1',
4747
domain: 'tenant1.com',
48-
slug: 'tenant1',
4948
},
5049
})
5150

0 commit comments

Comments
 (0)