diff --git a/services/web/app/src/Features/Authorization/AuthorizationManager.js b/services/web/app/src/Features/Authorization/AuthorizationManager.js index 22d92ea9d9..87c957574b 100644 --- a/services/web/app/src/Features/Authorization/AuthorizationManager.js +++ b/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 } diff --git a/services/web/test/unit/src/Authorization/AuthorizationManagerTests.js b/services/web/test/unit/src/Authorization/AuthorizationManagerTests.js index e4c67d2f77..8370ba9bdc 100644 --- a/services/web/test/unit/src/Authorization/AuthorizationManagerTests.js +++ b/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)