diff --git a/services/web/app/coffee/Features/Authorization/AuthorizationManager.coffee b/services/web/app/coffee/Features/Authorization/AuthorizationManager.coffee index c38ffa3f41..76c8260092 100644 --- a/services/web/app/coffee/Features/Authorization/AuthorizationManager.coffee +++ b/services/web/app/coffee/Features/Authorization/AuthorizationManager.coffee @@ -5,34 +5,48 @@ PrivilegeLevels = require("./PrivilegeLevels") PublicAccessLevels = require("./PublicAccessLevels") Errors = require("../Errors/Errors") ObjectId = require("mongojs").ObjectId +TokenAccessHandler = require('../TokenAccess/TokenAccessHandler') module.exports = AuthorizationManager = + + # Get the privilege level that the user has for the project # Returns: # * privilegeLevel: "owner", "readAndWrite", of "readOnly" if the user has # access. false if the user does not have access # * becausePublic: true if the access level is only because the project is public. - getPrivilegeLevelForProject: (user_id, project_id, callback = (error, privilegeLevel, becausePublic) ->) -> - getPublicAccessLevel = () -> + getPrivilegeLevelForProject: (req, user_id, project_id, + callback = (error, privilegeLevel, becausePublic) ->) -> + + getPublicAccessLevel = (project_id, cb=(err, level)->) -> if !ObjectId.isValid(project_id) - return callback(new Error("invalid project id")) + return cb(new Error("invalid project id")) Project.findOne { _id: project_id }, { publicAccesLevel: 1 }, (error, project) -> - return callback(error) if error? + return cb(error) if error? if !project? - return callback new Errors.NotFoundError("no project found with id #{project_id}") - if project.publicAccesLevel == PublicAccessLevels.READ_ONLY - return callback null, PrivilegeLevels.READ_ONLY, true - else if project.publicAccesLevel == PublicAccessLevels.READ_AND_WRITE - return callback null, PrivilegeLevels.READ_AND_WRITE, true - else if project.publicAccesLevel == PublicAccessLevels.TOKEN_BASED - return callback null, PrivilegeLevels.READ_ONLY, false - else - return callback null, PrivilegeLevels.NONE, false + return cb new Errors.NotFoundError("no project found with id #{project_id}") + cb null, project.publicAccesLevel if !user_id? - getPublicAccessLevel() + # User is Anonymous, Try Token-based access + getPublicAccessLevel project_id, (err, publicAccessLevel) -> + return callback(err) if err? + if publicAccessLevel == PublicAccessLevels.TOKEN_BASED + TokenAccessHandler.requestHasReadOnlyTokenAccess req, project_id, (err, allowed) -> + return callback(err) if err? + if allowed + callback null, PrivilegeLevels.READ_ONLY, false + else + callback null, PrivilegeLevels.NONE, false + else if publicAccessLevel == PublicAccessLevels.READ_ONLY + callback null, PrivilegeLevels.READ_ONLY, true + else if publicAccessLevel == PublicAccessLevels.READ_AND_WRITE + callback null, PrivilegeLevels.READ_AND_WRITE, true + else + callback null, PrivilegeLevels.NONE, false else + # User is present, get their privilege level from database CollaboratorsHandler.getMemberIdPrivilegeLevel user_id, project_id, (error, privilegeLevel) -> return callback(error) if error? if privilegeLevel? and privilegeLevel != PrivilegeLevels.NONE @@ -44,20 +58,29 @@ module.exports = AuthorizationManager = if isAdmin callback null, PrivilegeLevels.OWNER, false else - getPublicAccessLevel() + # Legacy public-access system + # User is present (not anonymous), but does not have direct access + getPublicAccessLevel project_id, (err, publicAccessLevel) -> + return callback(err) if err? + if publicAccessLevel == PublicAccessLevels.READ_ONLY + callback null, PrivilegeLevels.READ_ONLY, true + if publicAccessLevel == PublicAccessLevels.READ_AND_WRITE + callback null, PrivilegeLevels.READ_AND_WRITE, true + else + callback null, PrivilegeLevels.NONE, false - canUserReadProject: (user_id, project_id, callback = (error, canRead) ->) -> - AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) -> + canUserReadProject: (req, user_id, project_id, callback = (error, canRead) ->) -> + AuthorizationManager.getPrivilegeLevelForProject req, user_id, project_id, (error, privilegeLevel) -> return callback(error) if error? return callback null, (privilegeLevel in [PrivilegeLevels.OWNER, PrivilegeLevels.READ_AND_WRITE, PrivilegeLevels.READ_ONLY]) - canUserWriteProjectContent: (user_id, project_id, callback = (error, canWriteContent) ->) -> - AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) -> + canUserWriteProjectContent: (req, user_id, project_id, callback = (error, canWriteContent) ->) -> + AuthorizationManager.getPrivilegeLevelForProject req, user_id, project_id, (error, privilegeLevel) -> return callback(error) if error? return callback null, (privilegeLevel in [PrivilegeLevels.OWNER, PrivilegeLevels.READ_AND_WRITE]) - canUserWriteProjectSettings: (user_id, project_id, callback = (error, canWriteSettings) ->) -> - AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel, becausePublic) -> + canUserWriteProjectSettings: (req, user_id, project_id, callback = (error, canWriteSettings) ->) -> + AuthorizationManager.getPrivilegeLevelForProject req, user_id, project_id, (error, privilegeLevel, becausePublic) -> return callback(error) if error? if privilegeLevel == PrivilegeLevels.OWNER return callback null, true @@ -66,8 +89,8 @@ module.exports = AuthorizationManager = else return callback null, false - canUserAdminProject: (user_id, project_id, callback = (error, canAdmin) ->) -> - AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) -> + canUserAdminProject: (req, user_id, project_id, callback = (error, canAdmin) ->) -> + AuthorizationManager.getPrivilegeLevelForProject req, user_id, project_id, (error, privilegeLevel) -> return callback(error) if error? return callback null, (privilegeLevel == PrivilegeLevels.OWNER) @@ -76,4 +99,4 @@ module.exports = AuthorizationManager = return callback null, false User.findOne { _id: user_id }, { isAdmin: 1 }, (error, user) -> return callback(error) if error? - return callback null, (user?.isAdmin == true) \ No newline at end of file + return callback null, (user?.isAdmin == true) diff --git a/services/web/app/coffee/Features/Authorization/AuthorizationMiddlewear.coffee b/services/web/app/coffee/Features/Authorization/AuthorizationMiddlewear.coffee index be0a85107c..dfbc773cf8 100644 --- a/services/web/app/coffee/Features/Authorization/AuthorizationMiddlewear.coffee +++ b/services/web/app/coffee/Features/Authorization/AuthorizationMiddlewear.coffee @@ -13,7 +13,7 @@ module.exports = AuthorizationMiddlewear = # Remove the projects we have access to. Note rejectSeries doesn't use # errors in callbacks async.rejectSeries project_ids, (project_id, cb) -> - AuthorizationManager.canUserReadProject user_id, project_id, (error, canRead) -> + AuthorizationManager.canUserReadProject req, user_id, project_id, (error, canRead) -> return next(error) if error? cb(canRead) , (unauthorized_project_ids) -> @@ -25,7 +25,7 @@ module.exports = AuthorizationMiddlewear = ensureUserCanReadProject: (req, res, next) -> AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) -> return next(error) if error? - AuthorizationManager.canUserReadProject user_id, project_id, (error, canRead) -> + AuthorizationManager.canUserReadProject req, user_id, project_id, (error, canRead) -> return next(error) if error? if canRead logger.log {user_id, project_id}, "allowing user read access to project" @@ -37,7 +37,7 @@ module.exports = AuthorizationMiddlewear = ensureUserCanWriteProjectSettings: (req, res, next) -> AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) -> return next(error) if error? - AuthorizationManager.canUserWriteProjectSettings user_id, project_id, (error, canWrite) -> + AuthorizationManager.canUserWriteProjectSettings req, user_id, project_id, (error, canWrite) -> return next(error) if error? if canWrite logger.log {user_id, project_id}, "allowing user write access to project settings" @@ -49,7 +49,7 @@ module.exports = AuthorizationMiddlewear = ensureUserCanWriteProjectContent: (req, res, next) -> AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) -> return next(error) if error? - AuthorizationManager.canUserWriteProjectContent user_id, project_id, (error, canWrite) -> + AuthorizationManager.canUserWriteProjectContent req, user_id, project_id, (error, canWrite) -> return next(error) if error? if canWrite logger.log {user_id, project_id}, "allowing user write access to project content" @@ -61,7 +61,7 @@ module.exports = AuthorizationMiddlewear = ensureUserCanAdminProject: (req, res, next) -> AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) -> return next(error) if error? - AuthorizationManager.canUserAdminProject user_id, project_id, (error, canAdmin) -> + AuthorizationManager.canUserAdminProject req, user_id, project_id, (error, canAdmin) -> return next(error) if error? if canAdmin logger.log {user_id, project_id}, "allowing user admin access to project" diff --git a/services/web/app/coffee/Features/Editor/EditorHttpController.coffee b/services/web/app/coffee/Features/Editor/EditorHttpController.coffee index 4288ad4cfb..d74c9dd4d9 100644 --- a/services/web/app/coffee/Features/Editor/EditorHttpController.coffee +++ b/services/web/app/coffee/Features/Editor/EditorHttpController.coffee @@ -20,7 +20,7 @@ module.exports = EditorHttpController = user_id = null logger.log {user_id, project_id}, "join project request" Metrics.inc "editor.join-project" - EditorHttpController._buildJoinProjectView project_id, user_id, (error, project, privilegeLevel) -> + EditorHttpController._buildJoinProjectView req, project_id, user_id, (error, project, privilegeLevel) -> return next(error) if error? res.json { project: project @@ -30,7 +30,7 @@ module.exports = EditorHttpController = if project?.deletedByExternalDataSource ProjectDeleter.unmarkAsDeletedByExternalSource project_id - _buildJoinProjectView: (project_id, user_id, callback = (error, project, privilegeLevel) ->) -> + _buildJoinProjectView: (req, project_id, user_id, callback = (error, project, privilegeLevel) ->) -> logger.log {project_id, user_id}, "building the joinProject view" ProjectGetter.getProjectWithoutDocLines project_id, (error, project) -> return callback(error) if error? @@ -39,7 +39,7 @@ module.exports = EditorHttpController = return callback(error) if error? UserGetter.getUser user_id, { isAdmin: true }, (error, user) -> return callback(error) if error? - AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) -> + AuthorizationManager.getPrivilegeLevelForProject req, user_id, project_id, (error, privilegeLevel) -> return callback(error) if error? if !privilegeLevel? or privilegeLevel == PrivilegeLevels.NONE logger.log {project_id, user_id, privilegeLevel}, "not an acceptable privilege level, returning null" diff --git a/services/web/app/coffee/Features/Project/ProjectController.coffee b/services/web/app/coffee/Features/Project/ProjectController.coffee index 84fa89ea37..1150ccaccd 100644 --- a/services/web/app/coffee/Features/Project/ProjectController.coffee +++ b/services/web/app/coffee/Features/Project/ProjectController.coffee @@ -260,7 +260,7 @@ module.exports = ProjectController = daysSinceLastUpdated = (new Date() - project.lastUpdated) /86400000 logger.log project_id:project_id, daysSinceLastUpdated:daysSinceLastUpdated, "got db results for loading editor" - AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel)-> + AuthorizationManager.getPrivilegeLevelForProject req, user_id, project_id, (error, privilegeLevel)-> return next(error) if error? if !privilegeLevel? or privilegeLevel == PrivilegeLevels.NONE return res.sendStatus 401 diff --git a/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee b/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee index 6520d15cbd..350d55de66 100644 --- a/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee +++ b/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee @@ -28,7 +28,7 @@ module.exports = TokenAccessController = logger.err {err, token, userId, projectId: project._id}, "error adding user to project with readAndWrite token" return next(err) - return res.redirect("/project/#{project._id}") + return res.redirect(307, "/project/#{project._id}") readOnlyToken: (req, res, next) -> userId = AuthenticationController.getLoggedInUserId(req) @@ -46,8 +46,8 @@ module.exports = TokenAccessController = if !userId? logger.log {userId, projectId: project._id}, "adding anonymous user to project with readOnly token" - TokenAccessHandler.grantAnonymousUserTokenAccessViaSession(req, project._id) - return res.redirect("/project/#{project._id}") + TokenAccessHandler.grantSessionReadOnlyTokenAccess(req, project._id, token) + return res.redirect(307, "/project/#{project._id}") else logger.log {userId, projectId: project._id}, "adding user to project with readOnly token" @@ -56,6 +56,6 @@ module.exports = TokenAccessController = logger.err {err, token, userId, projectId: project._id}, "error adding user to project with readAndWrite token" return next(err) - res.redirect("/project/#{project._id}") + res.redirect(307, "/project/#{project._id}") diff --git a/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee b/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee index 7b29bbe9bc..e7e4938f79 100644 --- a/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee +++ b/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee @@ -10,7 +10,7 @@ module.exports = TokenAccessHandler = Project.findOne { 'tokens.readOnly': token, 'publicAccesLevel': PublicAccessLevels.TOKEN_BASED - }, {_id: 1}, (err, project) -> + }, {_id: 1, publicAccesLevel: 1}, (err, project) -> return callback(err) if err? callback(null, project) @@ -18,7 +18,7 @@ module.exports = TokenAccessHandler = Project.findOne { 'tokens.readAndWrite': token, 'publicAccesLevel': PublicAccessLevels.TOKEN_BASED - }, {_id: 1}, (err, project) -> + }, {_id: 1, publicAccesLevel: 1}, (err, project) -> return callback(err) if err? callback(null, project) @@ -42,13 +42,25 @@ module.exports = TokenAccessHandler = }, (err) -> callback(err) - grantAnonymousUserTokenAccessViaSession: (req, projectId) -> + grantSessionReadOnlyTokenAccess: (req, projectId, token) -> if req.session? if !req.session.anonReadOnlyTokenAccess? req.session.anonReadOnlyTokenAccess = {} - req.session.anonReadOnlyTokenAccess[projectId.toString()] = true - - anonymousUserHasTokenAccessViaSession: (req, projectId) -> - req?.session?.anonReadOnlyTokenAccess?[projectId.toString()] == true + req.session.anonReadOnlyTokenAccess[projectId.toString()] = token.toString() + requestHasReadOnlyTokenAccess: (req, projectId, callback=(err, allowed)->) -> + token = ( + req?.session?.anonReadOnlyTokenAccess?[projectId.toString()] or + req.headers['x-sl-anon-token'] + ) + if !token + return callback null, false + TokenAccessHandler.findProjectWithReadOnlyToken token, (err, project) -> + return callback(err) if err? + isAllowed = ( + project? and + project.publicAccesLevel == PublicAccessLevels.TOKEN_BASED and + project._id.toString() == projectId.toString() + ) + callback null, isAllowed diff --git a/services/web/test/UnitTests/coffee/Authorization/AuthorizationManagerTests.coffee b/services/web/test/UnitTests/coffee/Authorization/AuthorizationManagerTests.coffee index d779934055..6882c71b52 100644 --- a/services/web/test/UnitTests/coffee/Authorization/AuthorizationManagerTests.coffee +++ b/services/web/test/UnitTests/coffee/Authorization/AuthorizationManagerTests.coffee @@ -5,6 +5,7 @@ expect = chai.expect modulePath = "../../../../app/js/Features/Authorization/AuthorizationManager.js" SandboxedModule = require('sandboxed-module') Errors = require "../../../../app/js/Features/Errors/Errors.js" +MockRequest = require '../helpers/MockRequest' describe "AuthorizationManager", -> beforeEach -> @@ -13,6 +14,9 @@ describe "AuthorizationManager", -> "../../models/Project": Project: @Project = {} "../../models/User": User: @User = {} "../Errors/Errors": Errors + "../TokenAccess/TokenAccessHandler": @TokenAccessHandler = { + requestHasReadOnlyTokenAccess: sinon.stub().callsArgWith(2, null, false) + } @user_id = "user-id-1" @project_id = "project-id-1" @callback = sinon.stub() @@ -25,53 +29,54 @@ describe "AuthorizationManager", -> describe "with a private project", -> beforeEach -> + @req = new MockRequest() @Project.findOne .withArgs({ _id: @project_id }, { publicAccesLevel: 1 }) .yields(null, { publicAccesLevel: "private" }) - + describe "with a user_id with a privilege level", -> beforeEach -> @AuthorizationManager.isUserSiteAdmin.withArgs(@user_id).yields(null, false) @CollaboratorsHandler.getMemberIdPrivilegeLevel .withArgs(@user_id, @project_id) .yields(null, "readOnly") - @AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, @user_id, @project_id, @callback + it "should return the user's privilege level", -> @callback.calledWith(null, "readOnly", false).should.equal true - + describe "with a user_id with no privilege level", -> beforeEach -> @AuthorizationManager.isUserSiteAdmin.withArgs(@user_id).yields(null, false) @CollaboratorsHandler.getMemberIdPrivilegeLevel .withArgs(@user_id, @project_id) .yields(null, false) - @AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, @user_id, @project_id, @callback + it "should return false", -> @callback.calledWith(null, false, false).should.equal true - + describe "with a user_id who is an admin", -> beforeEach -> @AuthorizationManager.isUserSiteAdmin.withArgs(@user_id).yields(null, true) @CollaboratorsHandler.getMemberIdPrivilegeLevel .withArgs(@user_id, @project_id) .yields(null, false) - @AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, @user_id, @project_id, @callback + it "should return the user as an owner", -> @callback.calledWith(null, "owner", false).should.equal true - + describe "with no user (anonymous)", -> beforeEach -> - @AuthorizationManager.getPrivilegeLevelForProject null, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, null, @project_id, @callback + it "should not call CollaboratorsHandler.getMemberIdPrivilegeLevel", -> @CollaboratorsHandler.getMemberIdPrivilegeLevel.called.should.equal false - + it "should not call AuthorizationManager.isUserSiteAdmin", -> @AuthorizationManager.isUserSiteAdmin.called.should.equal false - + it "should return false", -> @callback.calledWith(null, false, false).should.equal true @@ -80,61 +85,61 @@ describe "AuthorizationManager", -> @Project.findOne .withArgs({ _id: @project_id }, { publicAccesLevel: 1 }) .yields(null, { publicAccesLevel: "readAndWrite" }) - + describe "with a user_id with a privilege level", -> beforeEach -> @AuthorizationManager.isUserSiteAdmin.withArgs(@user_id).yields(null, false) @CollaboratorsHandler.getMemberIdPrivilegeLevel .withArgs(@user_id, @project_id) .yields(null, "readOnly") - @AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, @user_id, @project_id, @callback + it "should return the user's privilege level", -> @callback.calledWith(null, "readOnly", false).should.equal true - + describe "with a user_id with no privilege level", -> beforeEach -> @AuthorizationManager.isUserSiteAdmin.withArgs(@user_id).yields(null, false) @CollaboratorsHandler.getMemberIdPrivilegeLevel .withArgs(@user_id, @project_id) .yields(null, false) - @AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, @user_id, @project_id, @callback + it "should return the public privilege level", -> @callback.calledWith(null, "readAndWrite", true).should.equal true - + describe "with a user_id who is an admin", -> beforeEach -> @AuthorizationManager.isUserSiteAdmin.withArgs(@user_id).yields(null, true) @CollaboratorsHandler.getMemberIdPrivilegeLevel .withArgs(@user_id, @project_id) .yields(null, false) - @AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, @user_id, @project_id, @callback + it "should return the user as an owner", -> @callback.calledWith(null, "owner", false).should.equal true - + describe "with no user (anonymous)", -> beforeEach -> - @AuthorizationManager.getPrivilegeLevelForProject null, @project_id, @callback - + @AuthorizationManager.getPrivilegeLevelForProject @req, null, @project_id, @callback + it "should not call CollaboratorsHandler.getMemberIdPrivilegeLevel", -> @CollaboratorsHandler.getMemberIdPrivilegeLevel.called.should.equal false - + it "should not call AuthorizationManager.isUserSiteAdmin", -> @AuthorizationManager.isUserSiteAdmin.called.should.equal false - + it "should return the public privilege level", -> @callback.calledWith(null, "readAndWrite", true).should.equal true - + describe "when the project doesn't exist", -> beforeEach -> @Project.findOne .withArgs({ _id: @project_id }, { publicAccesLevel: 1 }) .yields(null, null) - + it "should return a NotFoundError", -> - @AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, (error) -> + @AuthorizationManager.getPrivilegeLevelForProject @req, @user_id, @project_id, (error) -> error.should.be.instanceof Errors.NotFoundError describe "when the project id is not valid", -> @@ -145,214 +150,218 @@ describe "AuthorizationManager", -> .yields(null, "readOnly") it "should return a error", (done)-> - @AuthorizationManager.getPrivilegeLevelForProject undefined, "not project id", (err) => + @AuthorizationManager.getPrivilegeLevelForProject @req, undefined, "not project id", (err) => @Project.findOne.called.should.equal false expect(err).to.exist done() describe "canUserReadProject", -> beforeEach -> + @req = new MockRequest() @AuthorizationManager.getPrivilegeLevelForProject = sinon.stub() - + describe "when user is owner", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "owner", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserReadProject @user_id, @project_id, (error, canRead) -> + @AuthorizationManager.canUserReadProject @req, @user_id, @project_id, (error, canRead) -> expect(canRead).to.equal true done() - + describe "when user has read-write access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readAndWrite", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserReadProject @user_id, @project_id, (error, canRead) -> + @AuthorizationManager.canUserReadProject @req, @user_id, @project_id, (error, canRead) -> expect(canRead).to.equal true done() - + describe "when user has read-only access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readOnly", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserReadProject @user_id, @project_id, (error, canRead) -> + @AuthorizationManager.canUserReadProject @req, @user_id, @project_id, (error, canRead) -> expect(canRead).to.equal true done() - + describe "when user has no access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, false, false) - + it "should return false", (done) -> - @AuthorizationManager.canUserReadProject @user_id, @project_id, (error, canRead) -> + @AuthorizationManager.canUserReadProject @req, @user_id, @project_id, (error, canRead) -> expect(canRead).to.equal false done() describe "canUserWriteProjectContent", -> beforeEach -> + @req = new MockRequest() @AuthorizationManager.getPrivilegeLevelForProject = sinon.stub() - + describe "when user is owner", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "owner", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserWriteProjectContent @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectContent @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal true done() - + describe "when user has read-write access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readAndWrite", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserWriteProjectContent @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectContent @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal true done() - + describe "when user has read-only access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readOnly", false) - + it "should return false", (done) -> - @AuthorizationManager.canUserWriteProjectContent @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectContent @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal false done() - + describe "when user has no access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, false, false) - + it "should return false", (done) -> - @AuthorizationManager.canUserWriteProjectContent @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectContent @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal false done() describe "canUserWriteProjectSettings", -> beforeEach -> + @req = new MockRequest() @AuthorizationManager.getPrivilegeLevelForProject = sinon.stub() - + describe "when user is owner", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "owner", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserWriteProjectSettings @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectSettings @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal true done() - + describe "when user has read-write access as a collaborator", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readAndWrite", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserWriteProjectSettings @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectSettings @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal true done() - + describe "when user has read-write access as the public", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readAndWrite", true) - + it "should return false", (done) -> - @AuthorizationManager.canUserWriteProjectSettings @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectSettings @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal false done() - + describe "when user has read-only access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readOnly", false) - + it "should return false", (done) -> - @AuthorizationManager.canUserWriteProjectSettings @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectSettings @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal false done() - + describe "when user has no access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, false, false) - + it "should return false", (done) -> - @AuthorizationManager.canUserWriteProjectSettings @user_id, @project_id, (error, canWrite) -> + @AuthorizationManager.canUserWriteProjectSettings @req, @user_id, @project_id, (error, canWrite) -> expect(canWrite).to.equal false done() describe "canUserAdminProject", -> beforeEach -> + @req = new MockRequest() @AuthorizationManager.getPrivilegeLevelForProject = sinon.stub() - + describe "when user is owner", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "owner", false) - + it "should return true", (done) -> - @AuthorizationManager.canUserAdminProject @user_id, @project_id, (error, canAdmin) -> + @AuthorizationManager.canUserAdminProject @req, @user_id, @project_id, (error, canAdmin) -> expect(canAdmin).to.equal true done() - + describe "when user has read-write access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readAndWrite", false) - + it "should return false", (done) -> - @AuthorizationManager.canUserAdminProject @user_id, @project_id, (error, canAdmin) -> + @AuthorizationManager.canUserAdminProject @req, @user_id, @project_id, (error, canAdmin) -> expect(canAdmin).to.equal false done() - + describe "when user has read-only access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, "readOnly", false) - + it "should return false", (done) -> - @AuthorizationManager.canUserAdminProject @user_id, @project_id, (error, canAdmin) -> + @AuthorizationManager.canUserAdminProject @req, @user_id, @project_id, (error, canAdmin) -> expect(canAdmin).to.equal false done() - + describe "when user has no access", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject - .withArgs(@user_id, @project_id) + .withArgs(@req, @user_id, @project_id) .yields(null, false, false) - + it "should return false", (done) -> - @AuthorizationManager.canUserAdminProject @user_id, @project_id, (error, canAdmin) -> + @AuthorizationManager.canUserAdminProject @req, @user_id, @project_id, (error, canAdmin) -> expect(canAdmin).to.equal false done() - + describe "isUserSiteAdmin", -> beforeEach -> @User.findOne = sinon.stub() @@ -362,34 +371,34 @@ describe "AuthorizationManager", -> @User.findOne .withArgs({ _id: @user_id }, { isAdmin: 1 }) .yields(null, { isAdmin: true }) - + it "should return true", (done) -> @AuthorizationManager.isUserSiteAdmin @user_id, (error, isAdmin) -> expect(isAdmin).to.equal true done() - + describe "when user is not admin", -> beforeEach -> @User.findOne .withArgs({ _id: @user_id }, { isAdmin: 1 }) .yields(null, { isAdmin: false }) - + it "should return false", (done) -> @AuthorizationManager.isUserSiteAdmin @user_id, (error, isAdmin) -> expect(isAdmin).to.equal false done() - + describe "when user is not found", -> beforeEach -> @User.findOne .withArgs({ _id: @user_id }, { isAdmin: 1 }) .yields(null, null) - + it "should return false", (done) -> @AuthorizationManager.isUserSiteAdmin @user_id, (error, isAdmin) -> expect(isAdmin).to.equal false done() - + describe "when no user is passed", -> it "should return false", (done) -> @AuthorizationManager.isUserSiteAdmin null, (error, isAdmin) => diff --git a/services/web/test/UnitTests/coffee/Authorization/AuthorizationMiddlewearTests.coffee b/services/web/test/UnitTests/coffee/Authorization/AuthorizationMiddlewearTests.coffee index 8631938807..f269782ba3 100644 --- a/services/web/test/UnitTests/coffee/Authorization/AuthorizationMiddlewearTests.coffee +++ b/services/web/test/UnitTests/coffee/Authorization/AuthorizationMiddlewearTests.coffee @@ -55,7 +55,7 @@ describe "AuthorizationMiddlewear", -> describe "when user has permission", -> beforeEach -> @AuthorizationManager[managerMethod] - .withArgs(@user_id, @project_id) + .withArgs(sinon.match.any, @user_id, @project_id) .yields(null, true) it "should return next", -> @@ -65,7 +65,7 @@ describe "AuthorizationMiddlewear", -> describe "when user doesn't have permission", -> beforeEach -> @AuthorizationManager[managerMethod] - .withArgs(@user_id, @project_id) + .withArgs(sinon.match.any, @user_id, @project_id) .yields(null, false) it "should redirect to redirectToRestricted", -> @@ -80,7 +80,7 @@ describe "AuthorizationMiddlewear", -> beforeEach -> @AuthenticationController.getLoggedInUserId.returns(null) @AuthorizationManager[managerMethod] - .withArgs(null, @project_id) + .withArgs(@req, null, @project_id) .yields(null, true) it "should return next", -> @@ -91,7 +91,7 @@ describe "AuthorizationMiddlewear", -> beforeEach -> @AuthenticationController.getLoggedInUserId.returns(null) @AuthorizationManager[managerMethod] - .withArgs(null, @project_id) + .withArgs(@req, null, @project_id) .yields(null, false) it "should redirect to redirectToRestricted", -> @@ -184,10 +184,10 @@ describe "AuthorizationMiddlewear", -> describe "when user has permission to access all projects", -> beforeEach -> @AuthorizationManager.canUserReadProject - .withArgs(@user_id, "project1") + .withArgs(sinon.match.any, @user_id, "project1") .yields(null, true) @AuthorizationManager.canUserReadProject - .withArgs(@user_id, "project2") + .withArgs(sinon.match.any, @user_id, "project2") .yields(null, true) it "should return next", -> @@ -197,10 +197,10 @@ describe "AuthorizationMiddlewear", -> describe "when user doesn't have permission to access one of the projects", -> beforeEach -> @AuthorizationManager.canUserReadProject - .withArgs(@user_id, "project1") + .withArgs(sinon.match.any, @user_id, "project1") .yields(null, true) @AuthorizationManager.canUserReadProject - .withArgs(@user_id, "project2") + .withArgs(sinon.match.any, @user_id, "project2") .yields(null, false) it "should redirect to redirectToRestricted", -> @@ -216,10 +216,10 @@ describe "AuthorizationMiddlewear", -> beforeEach -> @AuthenticationController.getLoggedInUserId.returns(null) @AuthorizationManager.canUserReadProject - .withArgs(null, "project1") + .withArgs(sinon.match.any, null, "project1") .yields(null, true) @AuthorizationManager.canUserReadProject - .withArgs(null, "project2") + .withArgs(sinon.match.any, null, "project2") .yields(null, true) it "should return next", -> @@ -230,10 +230,10 @@ describe "AuthorizationMiddlewear", -> beforeEach -> @AuthenticationController.getLoggedInUserId.returns(null) @AuthorizationManager.canUserReadProject - .withArgs(null, "project1") + .withArgs(sinon.match.any, null, "project1") .yields(null, true) @AuthorizationManager.canUserReadProject - .withArgs(null, "project2") + .withArgs(sinon.match.any, null, "project2") .yields(null, false) it "should redirect to redirectToRestricted", -> diff --git a/services/web/test/UnitTests/coffee/Editor/EditorHttpControllerTests.coffee b/services/web/test/UnitTests/coffee/Editor/EditorHttpControllerTests.coffee index 73e0b80d18..8bdb1e33b4 100644 --- a/services/web/test/UnitTests/coffee/Editor/EditorHttpControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Editor/EditorHttpControllerTests.coffee @@ -39,7 +39,7 @@ describe "EditorHttpController", -> @projectView = { _id: @project_id } - @EditorHttpController._buildJoinProjectView = sinon.stub().callsArgWith(2, null, @projectView, "owner") + @EditorHttpController._buildJoinProjectView = sinon.stub().callsArgWith(3, null, @projectView, "owner") @ProjectDeleter.unmarkAsDeletedByExternalSource = sinon.stub() describe "successfully", -> @@ -48,7 +48,7 @@ describe "EditorHttpController", -> it "should get the project view", -> @EditorHttpController._buildJoinProjectView - .calledWith(@project_id, @user_id) + .calledWith(@req, @project_id, @user_id) .should.equal true it "should return the project and privilege level", -> @@ -87,7 +87,7 @@ describe "EditorHttpController", -> it "should pass the user id as null", -> @EditorHttpController._buildJoinProjectView - .calledWith(@project_id, null) + .calledWith(@req, @project_id, null) .should.equal true describe "_buildJoinProjectView", -> @@ -116,8 +116,8 @@ describe "EditorHttpController", -> describe "when authorized", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject = - sinon.stub().callsArgWith(2, null, "owner") - @EditorHttpController._buildJoinProjectView(@project_id, @user_id, @callback) + sinon.stub().callsArgWith(3, null, "owner") + @EditorHttpController._buildJoinProjectView(@req, @project_id, @user_id, @callback) it "should find the project without doc lines", -> @ProjectGetter.getProjectWithoutDocLines @@ -136,7 +136,7 @@ describe "EditorHttpController", -> it "should check the privilege level", -> @AuthorizationManager.getPrivilegeLevelForProject - .calledWith(@user_id, @project_id) + .calledWith(@req, @user_id, @project_id) .should.equal true it 'should include the invites', -> @@ -150,8 +150,8 @@ describe "EditorHttpController", -> describe "when not authorized", -> beforeEach -> @AuthorizationManager.getPrivilegeLevelForProject = - sinon.stub().callsArgWith(2, null, null) - @EditorHttpController._buildJoinProjectView(@project_id, @user_id, @callback) + sinon.stub().callsArgWith(3, null, null) + @EditorHttpController._buildJoinProjectView(@req, @project_id, @user_id, @callback) it "should return false in the callback", -> @callback.calledWith(null, null, false).should.equal true diff --git a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee index 626ff71442..cb0d16ed99 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectControllerTests.coffee @@ -302,7 +302,7 @@ describe "ProjectController", -> @ProjectGetter.getProject.callsArgWith 2, null, @project @UserModel.findById.callsArgWith(1, null, @user) @SubscriptionLocator.getUsersSubscription.callsArgWith(1, null, {}) - @AuthorizationManager.getPrivilegeLevelForProject.callsArgWith 2, null, "owner" + @AuthorizationManager.getPrivilegeLevelForProject.callsArgWith 3, null, "owner" @ProjectDeleter.unmarkAsDeletedByExternalSource = sinon.stub() @InactiveProjectManager.reactivateProjectIfRequired.callsArgWith(1) @AnalyticsManager.getLastOccurance.yields(null, {"mock": "event"}) @@ -335,7 +335,7 @@ describe "ProjectController", -> @ProjectController.loadEditor @req, @res it "should not render the page if the project can not be accessed", (done)-> - @AuthorizationManager.getPrivilegeLevelForProject = sinon.stub().callsArgWith 2, null, null + @AuthorizationManager.getPrivilegeLevelForProject = sinon.stub().callsArgWith 3, null, null @res.sendStatus = (resCode, opts)=> resCode.should.equal 401 done()