Explorar el Código

[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
Antoine Clausse hace 11 meses
padre
commit
ed4a863cd3

+ 13 - 1
services/web/app/src/Features/UserMembership/UserMembershipAuthorization.js

@@ -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

+ 16 - 87
services/web/app/src/Features/UserMembership/UserMembershipMiddleware.js

@@ -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'),

+ 21 - 9
services/web/app/src/Features/UserMembership/UserMembershipRouter.mjs

@@ -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
     )