Selaa lähdekoodia

[web] Map admin capabilities to project PrivilegeLevels (#27488)

* Add capability `copy-project`

* Check `copy-project` (frontend)

* Update tests

* Suggestion: map `modify-project`-`PrivilegeLevels.OWNER` and `view-project`-`PrivilegeLevels.READ_ONLY`

* Suggestion: remove capability `copy-project`. Use `view-project` instead

* Revert unrelated changes

* Add tests on AuthorizationManager when `adminRolesEnabled`

* Update `Modules.promises.hooks.fire` stubs with `.withArgs('getAdminCapabilities')`

Co-authored-by: Andrew Rumble <andrew.rumble@overleaf.com>

* Use `getAdminCapabilities` from AdminAuthorizationHelper.js

---------

Co-authored-by: Andrew Rumble <andrew.rumble@overleaf.com>
GitOrigin-RevId: 61167509c4a035c99831a5b0346347c2e6b5fae0
Antoine Clausse 1 vuosi sitten
vanhempi
sitoutus
422e892231

+ 18 - 3
services/web/app/src/Features/Authorization/AuthorizationManager.js

@@ -8,7 +8,10 @@ const PrivilegeLevels = require('./PrivilegeLevels')
 const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
 const PublicAccessLevels = require('./PublicAccessLevels')
 const Errors = require('../Errors/Errors')
-const { hasAdminAccess } = require('../Helpers/AdminAuthorizationHelper')
+const {
+  hasAdminAccess,
+  getAdminCapabilities,
+} = require('../Helpers/AdminAuthorizationHelper')
 const Settings = require('@overleaf/settings')
 const DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
 
@@ -146,10 +149,18 @@ async function getPrivilegeLevelForProjectWithUser(
   projectAccess,
   opts = {}
 ) {
-  if (!opts.ignoreSiteAdmin) {
-    if (await isUserSiteAdmin(userId)) {
+  let adminReadOnly = false
+  if (!opts.ignoreSiteAdmin && (await isUserSiteAdmin(userId))) {
+    if (!Settings.adminRolesEnabled) {
       return PrivilegeLevels.OWNER
     }
+    const { adminCapabilities } = await getAdminCapabilities({ _id: userId })
+    if (adminCapabilities.includes('modify-project')) {
+      return PrivilegeLevels.OWNER
+    }
+    if (adminCapabilities.includes('view-project')) {
+      adminReadOnly = true
+    }
   }
 
   projectAccess =
@@ -174,6 +185,10 @@ async function getPrivilegeLevelForProjectWithUser(
     }
   }
 
+  if (adminReadOnly) {
+    return PrivilegeLevels.READ_ONLY
+  }
+
   return PrivilegeLevels.NONE
 }
 

+ 38 - 5
services/web/test/unit/src/Authorization/AuthorizationManagerTests.js

@@ -58,7 +58,12 @@ describe('AuthorizationManager', function () {
           .resolves({ metadata: { user_id: new ObjectId() } }),
       },
     }
-
+    this.Modules = { promises: { hooks: { fire: sinon.stub() } } }
+    this.settings = {
+      passwordStrengthOptions: {},
+      adminPrivilegeAvailable: true,
+      adminRolesEnabled: false,
+    }
     this.AuthorizationManager = SandboxedModule.require(modulePath, {
       requires: {
         'mongodb-legacy': { ObjectId },
@@ -69,10 +74,8 @@ describe('AuthorizationManager', function () {
         '../TokenAccess/TokenAccessHandler': this.TokenAccessHandler,
         '../DocumentUpdater/DocumentUpdaterHandler':
           this.DocumentUpdaterHandler,
-        '@overleaf/settings': {
-          passwordStrengthOptions: {},
-          adminPrivilegeAvailable: true,
-        },
+        '../../infrastructure/Modules': this.Modules,
+        '@overleaf/settings': this.settings,
       },
     })
   })
@@ -678,6 +681,36 @@ function testPermission(permission, privilegeLevels) {
         })
         expectPermission(permission, privilegeLevels.siteAdmin || false)
       })
+      describe('admin without permissions', function () {
+        beforeEach(function () {
+          this.user.isAdmin = true
+          this.settings.adminRolesEnabled = true
+          this.Modules.promises.hooks.fire
+            .withArgs('getAdminCapabilities')
+            .resolves([])
+        })
+        expectPermission(permission, false)
+      })
+      describe('admin with `view-project`', function () {
+        beforeEach(function () {
+          this.user.isAdmin = true
+          this.settings.adminRolesEnabled = true
+          this.Modules.promises.hooks.fire
+            .withArgs('getAdminCapabilities')
+            .resolves([['view-project']])
+        })
+        expectPermission(permission, privilegeLevels.readOnly || false)
+      })
+      describe('admin with `modify-project`', function () {
+        beforeEach(function () {
+          this.user.isAdmin = true
+          this.settings.adminRolesEnabled = true
+          this.Modules.promises.hooks.fire
+            .withArgs('getAdminCapabilities')
+            .resolves([['view-project', 'modify-project']])
+        })
+        expectPermission(permission, privilegeLevels.siteAdmin || false)
+      })
 
       describe('when user is owner', function () {
         setupUserPrivilegeLevel(PrivilegeLevels.OWNER)