[web] Update UserMembershipMiddleware with flexible requireEntityAccess (#28018)

* Update `requireGroupSettingsReadAccess` to be available to all admins when adminRolesEnabled is true

* Update `UserMembershipMiddleware` with a flexible `requireEntityAccess` method

* Update `UserMembershipMiddleware` further

Update endpoints permissions when admin roles are enabled:

`GET /manage/groups/:id/audit-logs` -> view-audit-log
`GET /manage/groups/:id/audit-logs/zip` -> view-audit-log
`GET /manage/groups/:id/settings` -> all admins
`GET /subscription/:id/sso_configuration_test` -> all admins
`GET /manage/groups/:id/members` -> all admins
`DELETE /manage/groups/:id/user/:user_id` -> `modify-group-member`/`modify-managed-group-member`
`GET /manage/groups/:id/members/export` -> all admins

* Update `requireEntityAccess` to parameters to an object

* Rename `hasAdminAccess` to `hasAnyAdminRole`

GitOrigin-RevId: 740ea5148edc50987fbc86607b1aaa7b7523ffcb
This commit is contained in:
Antoine Clausse
2025-08-27 11:13:54 +02:00
committed by Copybot
parent 72c53bcd8c
commit 0dae38bb55
3 changed files with 50 additions and 97 deletions

View File

@@ -1,4 +1,9 @@
const { hasAdminCapability } = require('../Helpers/AdminAuthorizationHelper')
const {
hasAdminCapability,
hasAdminAccess,
} = require('../Helpers/AdminAuthorizationHelper')
const SessionManager = require('../Authentication/SessionManager')
const Settings = require('@overleaf/settings')
const UserMembershipAuthorization = {
hasStaffAccess(requiredStaffAccess) {
@@ -16,6 +21,13 @@ const UserMembershipAuthorization = {
hasAdminCapability,
hasAnyAdminRole(req) {
return (
Settings.adminRolesEnabled &&
hasAdminAccess(SessionManager.getSessionUser(req.session))
)
},
hasModifyGroupMemberCapability(req, res) {
return hasAdminCapability(
req.entity.managedUsersEnabled

View File

@@ -12,17 +12,6 @@ const { useAdminCapabilities } = require('../Helpers/AdminAuthorizationHelper')
// set of middleware arrays or functions that checks user access to an entity
// (publisher, institution, group, template, etc.)
const UserMembershipMiddleware = {
requireTeamMetricsAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('team'),
fetchEntity(),
requireEntity(),
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupMetrics'),
]),
],
requireGroup: [fetchEntityConfig('group'), fetchEntity(), requireEntity()],
requireGroupAccess: [
@@ -32,28 +21,37 @@ const UserMembershipMiddleware = {
requireEntity(),
],
requireGroupMemberAccess: [
requireEntityAccess: ({ entityName, staffAccess, adminCapability }) => [
AuthenticationController.requireLogin(),
fetchEntityConfig('groupMember'),
fetchEntityConfig(entityName),
fetchEntity(),
requireEntity(),
allowAccessIfAny([UserMembershipAuthorization.hasEntityAccess()]),
allowAccessIfAny(
[
UserMembershipAuthorization.hasEntityAccess(),
staffAccess && UserMembershipAuthorization.hasStaffAccess(staffAccess),
adminCapability &&
UserMembershipAuthorization.hasAdminCapability(adminCapability),
].filter(Boolean)
),
],
requireGroupManagementAccess: [
requireEntityAccessOrAdminAccess: entityName => [
AuthenticationController.requireLogin(),
fetchEntityConfig('group'),
fetchEntityConfig(entityName),
fetchEntity(),
requireEntity(),
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupManagement'),
// allow to all admins when `adminRolesEnabled` is true
UserMembershipAuthorization.hasAnyAdminRole,
]),
],
requireGroupMemberManagementAccess: [
requireGroupMemberManagement: entityName => [
AuthenticationController.requireLogin(),
fetchEntityConfig('group'),
fetchEntityConfig(entityName),
fetchEntity(),
requireEntity(),
useAdminCapabilities,
@@ -64,75 +62,6 @@ const UserMembershipMiddleware = {
]),
],
requireGroupMetricsAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('group'),
fetchEntity(),
requireEntity(),
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupMetrics'),
]),
],
requireGroupManagersManagementAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('groupManagers'),
fetchEntity(),
requireEntity(),
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupManagement'),
]),
],
requireGroupManagersWriteAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('groupManagers'),
fetchEntity(),
requireEntity(),
useAdminCapabilities,
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupManagement'),
UserMembershipAuthorization.hasAdminCapability('modify-group-manager'),
]),
],
requireGroupAdminAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('groupAdmin'),
fetchEntity(),
requireEntity(),
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupManagement'),
]),
],
requireGroupSettingsReadAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('groupAdmin'),
fetchEntity(),
requireEntity(),
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupManagement'),
]),
],
requireGroupSettingsWriteAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('groupAdmin'),
fetchEntity(),
requireEntity(),
allowAccessIfAny([
UserMembershipAuthorization.hasEntityAccess(),
UserMembershipAuthorization.hasStaffAccess('groupManagement'),
UserMembershipAuthorization.hasAdminCapability('modify-group-setting'),
]),
],
requireInstitutionMetricsAccess: [
AuthenticationController.requireLogin(),
fetchEntityConfig('institution'),

View File

@@ -21,34 +21,34 @@ export default {
// group members routes
webRouter.get(
'/manage/groups/:id/members',
UserMembershipMiddleware.requireGroupManagementAccess,
UserMembershipMiddleware.requireEntityAccessOrAdminAccess('group'),
UserMembershipController.manageGroupMembers
)
webRouter.post(
'/manage/groups/:id/invites',
UserMembershipMiddleware.requireGroupMemberManagementAccess,
UserMembershipMiddleware.requireGroupMemberManagement('group'),
RateLimiterMiddleware.rateLimit(rateLimiters.createTeamInvite),
TeamInvitesController.createInvite
)
webRouter.post(
'/manage/groups/:id/resendInvite',
UserMembershipMiddleware.requireGroupMemberManagementAccess,
UserMembershipMiddleware.requireGroupMemberManagement('group'),
RateLimiterMiddleware.rateLimit(rateLimiters.createTeamInvite),
TeamInvitesController.resendInvite
)
webRouter.delete(
'/manage/groups/:id/user/:user_id',
UserMembershipMiddleware.requireGroupManagementAccess,
UserMembershipMiddleware.requireGroupMemberManagement('group'),
SubscriptionGroupController.removeUserFromGroup
)
webRouter.delete(
'/manage/groups/:id/invites/:email',
UserMembershipMiddleware.requireGroupMemberManagementAccess,
UserMembershipMiddleware.requireGroupMemberManagement('group'),
TeamInvitesController.revokeInvite
)
webRouter.get(
'/manage/groups/:id/members/export',
UserMembershipMiddleware.requireGroupManagementAccess,
UserMembershipMiddleware.requireEntityAccessOrAdminAccess('group'),
RateLimiterMiddleware.rateLimit(rateLimiters.exportTeamCsv),
UserMembershipController.exportCsv
)
@@ -56,17 +56,29 @@ export default {
// group managers routes
webRouter.get(
'/manage/groups/:id/managers',
UserMembershipMiddleware.requireGroupManagersManagementAccess,
UserMembershipMiddleware.requireEntityAccess({
entityName: 'groupManagers',
staffAccess: 'groupManagement',
adminCapability: 'view-group-manager',
}),
UserMembershipController.manageGroupManagers
)
webRouter.post(
'/manage/groups/:id/managers',
UserMembershipMiddleware.requireGroupManagersWriteAccess,
UserMembershipMiddleware.requireEntityAccess({
entityName: 'groupManagers',
staffAccess: 'groupManagement',
adminCapability: 'modify-group-manager',
}),
UserMembershipController.add
)
webRouter.delete(
'/manage/groups/:id/managers/:userId',
UserMembershipMiddleware.requireGroupManagersWriteAccess,
UserMembershipMiddleware.requireEntityAccess({
entityName: 'groupManagers',
staffAccess: 'groupManagement',
adminCapability: 'modify-group-manager',
}),
UserMembershipController.remove
)