Implement authorization guards in Authorization{Manager,Controller}

This commit is contained in:
James Allen 2016-03-14 17:06:57 +00:00
parent 1bd8b8d1a3
commit 71ef045728
14 changed files with 753 additions and 28 deletions

View file

@ -99,6 +99,7 @@ module.exports = AuthenticationController =
_redirectToLoginPage: (req, res) ->
logger.log url: req.url, "user not logged in so redirecting to login page"
console.log req.session
req.query.redir = req.path
url = "/login?#{querystring.stringify(req.query)}"
res.redirect url
@ -141,4 +142,5 @@ module.exports = AuthenticationController =
req.session[key] = value
req.session.user = lightUser
console.log "LOGGED IN", req.session
callback()

View file

@ -1,12 +1,61 @@
module.exports =
getPrivilegeLevelForProject: (user_id, project_id, callback = (error, canAccess, privilegeLevel) ->) ->
return callback(null, true, "readAndWrite")
CollaboratorsHandler = require("../Collaborators/CollaboratorsHandler")
Project = require("../../models/Project").Project
User = require("../../models/User").User
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 = () ->
Project.findOne { _id: project_id }, { publicAccesLevel: 1 }, (error, project) ->
return callback(error) if error?
if project.publicAccesLevel in ["readOnly", "readAndWrite"]
return callback null, project.publicAccesLevel, true
else
return callback null, false, false
if !user_id?
getPublicAccessLevel()
else
CollaboratorsHandler.getMemberIdPrivilegeLevel user_id, project_id, (error, privilegeLevel) ->
return callback(error) if error?
if privilegeLevel? and privilegeLevel
# The user has direct access
callback null, privilegeLevel, false
else
getPublicAccessLevel()
canUserReadProject: (user_id, project_id, callback = (error, canRead) ->) ->
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) ->
return callback(error) if error?
return callback null, (privilegeLevel in ["owner", "readAndWrite", "readOnly"])
canUserWriteProjectContent: (user_id, project_id, callback = (error, canWriteContent) ->) ->
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) ->
return callback(error) if error?
return callback null, (privilegeLevel in ["owner", "readAndWrite"])
canUserWriteProjectSettings: (user_id, project_id, callback = (error, canWriteSettings) ->) ->
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel, becausePublic) ->
return callback(error) if error?
if privilegeLevel == "owner"
return callback null, true
else if privilegeLevel == "readAndWrite" and !becausePublic
return callback null, true
else
return callback null, false
canUserAdminProject: (user_id, project_id, callback = (error, canAdmin) ->) ->
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) ->
return callback(error) if error?
return callback null, (privilegeLevel == "owner")
isUserSiteAdmin: (user_id, callback = (error, isAdmin) ->) ->
if !user_id?
return callback null, false
User.findOne { _id: user_id }, { isAdmin: 1 }, (error, user) ->
return callback(error) if error?
return callback null, (user?.isAdmin == true)

View file

@ -1,21 +1,101 @@
module.exports =
AuthorizationManager = require("./AuthorizationManager")
async = require "async"
logger = require "logger-sharelatex"
module.exports = AuthorizationMiddlewear =
ensureUserCanReadMultipleProjects: (req, res, next) ->
next()
project_ids = (req.query.project_ids or "").split(",")
AuthorizationMiddlewear._getUserId req, (error, user_id) ->
return next(error) if error?
# 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) ->
return next(error) if error?
cb(canRead)
, (unauthorized_project_ids) ->
if unauthorized_project_ids.length > 0
AuthorizationMiddlewear.redirectToRestricted req, res, next
else
next()
ensureUserCanReadProject: (req, res, next) ->
next()
AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) ->
return next(error) if error?
AuthorizationManager.canUserReadProject 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"
next()
else
logger.log {user_id, project_id}, "denying user read access to project"
AuthorizationMiddlewear.redirectToRestricted req, res, next
ensureUserCanWriteProjectSettings: (req, res, next) ->
next()
AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) ->
return next(error) if error?
AuthorizationManager.canUserWriteProjectSettings 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"
next()
else
logger.log {user_id, project_id}, "denying user write access to project settings"
AuthorizationMiddlewear.redirectToRestricted req, res, next
ensureUserCanWriteProjectContent: (req, res, next) ->
next()
AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) ->
return next(error) if error?
AuthorizationManager.canUserWriteProjectContent 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"
next()
else
logger.log {user_id, project_id}, "denying user write access to project settings"
AuthorizationMiddlewear.redirectToRestricted req, res, next
ensureUserCanAdminProject: (req, res, next) ->
next()
AuthorizationMiddlewear._getUserAndProjectId req, (error, user_id, project_id) ->
return next(error) if error?
AuthorizationManager.canUserAdminProject 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"
next()
else
logger.log {user_id, project_id}, "denying user admin access to project"
AuthorizationMiddlewear.redirectToRestricted req, res, next
ensureUserIsSiteAdmin: (req, res, next) ->
next()
AuthorizationMiddlewear._getUserId req, (error, user_id) ->
return next(error) if error?
AuthorizationManager.isUserSiteAdmin user_id, (error, isAdmin) ->
return next(error) if error?
if isAdmin
logger.log {user_id}, "allowing user admin access to site"
next()
else
logger.log {user_id}, "denying user admin access to site"
AuthorizationMiddlewear.redirectToRestricted req, res, next
_getUserAndProjectId: (req, callback = (error, user_id, project_id) ->) ->
project_id = req.params?.project_id or req.params?.Project_id
if !project_id?
return callback(new Error("Expected project_id in request parameters"))
AuthorizationMiddlewear._getUserId req, (error, user_id) ->
return callback(error) if error?
callback(null, user_id, project_id)
_getUserId: (req, callback = (error, user_id) ->) ->
if req.session?.user?._id?
user_id = req.session.user._id
else
user_id = null
callback null, user_id
redirectToRestricted: (req, res, next) ->
res.redirect "/restricted"
restricted : (req, res, next)->
if req.session.user?

View file

@ -13,11 +13,11 @@ module.exports = CollaboratorsHandler =
return callback(error) if error?
return callback null, null if !project?
members = []
members.push { id: project.owner_ref.toString(), privilegeLevel: "admin" }
members.push { id: project.owner_ref.toString(), privilegeLevel: "owner" }
for member_id in project.readOnly_refs or []
members.push { id: member_id, privilegeLevel: "readOnly" }
members.push { id: member_id.toString(), privilegeLevel: "readOnly" }
for member_id in project.collaberator_refs or []
members.push { id: member_id, privilegeLevel: "readAndWrite" }
members.push { id: member_id.toString(), privilegeLevel: "readAndWrite" }
return callback null, members
getMemberIds: (project_id, callback = (error, member_ids) ->) ->
@ -33,7 +33,17 @@ module.exports = CollaboratorsHandler =
UserGetter.getUser member.id, (error, user) ->
return cb(error) if error?
return cb(null, { user: user, privilegeLevel: member.privilegeLevel })
callback
callback
getMemberIdPrivilegeLevel: (user_id, project_id, callback = (error, privilegeLevel) ->) ->
# In future if the schema changes and getting all member ids is more expensive (multiple documents)
# then optimise this.
CollaboratorsHandler.getMemberIdsWithPrivilegeLevels project_id, (error, members) ->
return callback(error) if error?
for member in members or []
if member.id == user_id?.toString()
return callback null, member.privilegeLevel
return callback null, false
getMemberCount: (project_id, callback = (error, count) ->) ->
CollaboratorsHandler.getMemberIdsWithPrivilegeLevels project_id, (error, members) ->

View file

@ -34,9 +34,9 @@ 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, canAccess, privilegeLevel) ->
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel) ->
return callback(error) if error?
if !canAccess
if !privilegeLevel
callback null, null, false
else
callback(null,

View file

@ -225,9 +225,9 @@ 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, canAccess, privilegeLevel)->
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, (error, privilegeLevel)->
return next(error) if error?
if !canAccess
if !privilegeLevel
return res.sendStatus 401
if subscription? and subscription.freeTrial? and subscription.freeTrial.expiresAt?

View file

@ -27,11 +27,12 @@ module.exports = ProjectEditorHandler =
owner = null
for member in members
if member.privilegeLevel == "admin"
if member.privilegeLevel == "owner"
owner = member.user
else
result.members.push @buildUserModelView member.user, member.privilegeLevel
result.owner = @buildUserModelView owner, "owner"
if owner?
result.owner = @buildUserModelView owner, "owner"
if owner?.features?
if owner.features.collaborators?

View file

@ -0,0 +1,340 @@
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../../app/js/Features/Authorization/AuthorizationManager.js"
SandboxedModule = require('sandboxed-module')
describe "AuthorizationManager", ->
beforeEach ->
@AuthorizationManager = SandboxedModule.require modulePath, requires:
"../Collaborators/CollaboratorsHandler": @CollaboratorsHandler = {}
"../../models/Project": Project: @Project = {}
"../../models/User": User: @User = {}
@user_id = "user-id-1"
@project_id = "project-id-1"
@callback = sinon.stub()
describe "getPrivilegeLevelForProject", ->
beforeEach ->
@Project.findOne = sinon.stub()
@CollaboratorsHandler.getMemberIdPrivilegeLevel = sinon.stub()
describe "with a private project", ->
beforeEach ->
@Project.findOne
.withArgs({ _id: @project_id }, { publicAccesLevel: 1 })
.yields(null, { publicAccesLevel: "private" })
describe "with a user_id with a privilege level", ->
beforeEach ->
@CollaboratorsHandler.getMemberIdPrivilegeLevel
.withArgs(@user_id, @project_id)
.yields(null, "readOnly")
@AuthorizationManager.getPrivilegeLevelForProject @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 ->
@CollaboratorsHandler.getMemberIdPrivilegeLevel
.withArgs(@user_id, @project_id)
.yields(null, false)
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback
it "should return false", ->
@callback.calledWith(null, false, false).should.equal true
describe "with no user (anonymous)", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject null, @project_id, @callback
it "should not call CollaboratorsHandler.getMemberIdPrivilegeLevel", ->
@CollaboratorsHandler.getMemberIdPrivilegeLevel.called.should.equal false
it "should return false", ->
@callback.calledWith(null, false, false).should.equal true
describe "with a public project", ->
beforeEach ->
@Project.findOne
.withArgs({ _id: @project_id }, { publicAccesLevel: 1 })
.yields(null, { publicAccesLevel: "readAndWrite" })
describe "with a user_id with a privilege level", ->
beforeEach ->
@CollaboratorsHandler.getMemberIdPrivilegeLevel
.withArgs(@user_id, @project_id)
.yields(null, "readOnly")
@AuthorizationManager.getPrivilegeLevelForProject @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 ->
@CollaboratorsHandler.getMemberIdPrivilegeLevel
.withArgs(@user_id, @project_id)
.yields(null, false)
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @callback
it "should return the public privilege level", ->
@callback.calledWith(null, "readAndWrite", true).should.equal true
describe "with no user (anonymous)", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject null, @project_id, @callback
it "should not call CollaboratorsHandler.getMemberIdPrivilegeLevel", ->
@CollaboratorsHandler.getMemberIdPrivilegeLevel.called.should.equal false
it "should return the public privilege level", ->
@callback.calledWith(null, "readAndWrite", true).should.equal true
describe "canUserReadProject", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()
describe "when user is owner", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject
.withArgs(@user_id, @project_id)
.yields(null, "owner", false)
it "should return true", (done) ->
@AuthorizationManager.canUserReadProject @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)
.yields(null, "readAndWrite", false)
it "should return true", (done) ->
@AuthorizationManager.canUserReadProject @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)
.yields(null, "readOnly", false)
it "should return true", (done) ->
@AuthorizationManager.canUserReadProject @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)
.yields(null, false, false)
it "should return false", (done) ->
@AuthorizationManager.canUserReadProject @user_id, @project_id, (error, canRead) ->
expect(canRead).to.equal false
done()
describe "canUserWriteProjectContent", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()
describe "when user is owner", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject
.withArgs(@user_id, @project_id)
.yields(null, "owner", false)
it "should return true", (done) ->
@AuthorizationManager.canUserWriteProjectContent @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)
.yields(null, "readAndWrite", false)
it "should return true", (done) ->
@AuthorizationManager.canUserWriteProjectContent @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)
.yields(null, "readOnly", false)
it "should return false", (done) ->
@AuthorizationManager.canUserWriteProjectContent @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)
.yields(null, false, false)
it "should return false", (done) ->
@AuthorizationManager.canUserWriteProjectContent @user_id, @project_id, (error, canWrite) ->
expect(canWrite).to.equal false
done()
describe "canUserWriteProjectSettings", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()
describe "when user is owner", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject
.withArgs(@user_id, @project_id)
.yields(null, "owner", false)
it "should return true", (done) ->
@AuthorizationManager.canUserWriteProjectSettings @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)
.yields(null, "readAndWrite", false)
it "should return true", (done) ->
@AuthorizationManager.canUserWriteProjectSettings @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)
.yields(null, "readAndWrite", true)
it "should return false", (done) ->
@AuthorizationManager.canUserWriteProjectSettings @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)
.yields(null, "readOnly", false)
it "should return false", (done) ->
@AuthorizationManager.canUserWriteProjectSettings @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)
.yields(null, false, false)
it "should return false", (done) ->
@AuthorizationManager.canUserWriteProjectSettings @user_id, @project_id, (error, canWrite) ->
expect(canWrite).to.equal false
done()
describe "canUserAdminProject", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()
describe "when user is owner", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject
.withArgs(@user_id, @project_id)
.yields(null, "owner", false)
it "should return true", (done) ->
@AuthorizationManager.canUserAdminProject @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)
.yields(null, "readAndWrite", false)
it "should return false", (done) ->
@AuthorizationManager.canUserAdminProject @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)
.yields(null, "readOnly", false)
it "should return false", (done) ->
@AuthorizationManager.canUserAdminProject @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)
.yields(null, false, false)
it "should return false", (done) ->
@AuthorizationManager.canUserAdminProject @user_id, @project_id, (error, canAdmin) ->
expect(canAdmin).to.equal false
done()
describe "isUserSiteAdmin", ->
beforeEach ->
@User.findOne = sinon.stub()
describe "when user is admin", ->
beforeEach ->
@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) =>
@User.findOne.called.should.equal false
expect(isAdmin).to.equal false
done()

View file

@ -0,0 +1,221 @@
sinon = require('sinon')
chai = require('chai')
should = chai.should()
expect = chai.expect
modulePath = "../../../../app/js/Features/Authorization/AuthorizationMiddlewear.js"
SandboxedModule = require('sandboxed-module')
describe "AuthorizationMiddlewear", ->
beforeEach ->
@AuthorizationMiddlewear = SandboxedModule.require modulePath, requires:
"./AuthorizationManager": @AuthorizationManager = {}
"logger-sharelatex": {log: () ->}
@user_id = "user-id-123"
@project_id = "project-id-123"
@req = {}
@res = {}
@next = sinon.stub()
METHODS_TO_TEST = {
"ensureUserCanReadProject": "canUserReadProject"
"ensureUserCanWriteProjectSettings": "canUserWriteProjectSettings"
"ensureUserCanWriteProjectContent": "canUserWriteProjectContent"
"ensureUserCanAdminProject": "canUserAdminProject"
}
for middlewearMethod, managerMethod of METHODS_TO_TEST
do (middlewearMethod, managerMethod) ->
describe middlewearMethod, ->
beforeEach ->
@req.params =
project_id: @project_id
@AuthorizationManager[managerMethod] = sinon.stub()
@AuthorizationMiddlewear.redirectToRestricted = sinon.stub()
describe "with missing project_id", ->
beforeEach ->
@req.params = {}
it "should return an error to next", ->
@AuthorizationMiddlewear[middlewearMethod] @req, @res, @next
@next.calledWith(new Error()).should.equal true
describe "with logged in user", ->
beforeEach ->
@req.session =
user: _id: @user_id
describe "when user has permission", ->
beforeEach ->
@AuthorizationManager[managerMethod]
.withArgs(@user_id, @project_id)
.yields(null, true)
it "should return next", ->
@AuthorizationMiddlewear[middlewearMethod] @req, @res, @next
@next.called.should.equal true
describe "when user doesn't have permission", ->
beforeEach ->
@AuthorizationManager[managerMethod]
.withArgs(@user_id, @project_id)
.yields(null, false)
it "should redirect to redirectToRestricted", ->
@AuthorizationMiddlewear[middlewearMethod] @req, @res, @next
@next.called.should.equal false
@AuthorizationMiddlewear.redirectToRestricted
.calledWith(@req, @res, @next)
.should.equal true
describe "with anonymous user", ->
describe "when user has permission", ->
beforeEach ->
@AuthorizationManager[managerMethod]
.withArgs(null, @project_id)
.yields(null, true)
it "should return next", ->
@AuthorizationMiddlewear[middlewearMethod] @req, @res, @next
@next.called.should.equal true
describe "when user doesn't have permission", ->
beforeEach ->
@AuthorizationManager[managerMethod]
.withArgs(null, @project_id)
.yields(null, false)
it "should redirect to redirectToRestricted", ->
@AuthorizationMiddlewear[middlewearMethod] @req, @res, @next
@next.called.should.equal false
@AuthorizationMiddlewear.redirectToRestricted
.calledWith(@req, @res, @next)
.should.equal true
describe "ensureUserIsSiteAdmin", ->
beforeEach ->
@AuthorizationManager.isUserSiteAdmin = sinon.stub()
@AuthorizationMiddlewear.redirectToRestricted = sinon.stub()
describe "with logged in user", ->
beforeEach ->
@req.session =
user: _id: @user_id
describe "when user has permission", ->
beforeEach ->
@AuthorizationManager.isUserSiteAdmin
.withArgs(@user_id)
.yields(null, true)
it "should return next", ->
@AuthorizationMiddlewear.ensureUserIsSiteAdmin @req, @res, @next
@next.called.should.equal true
describe "when user doesn't have permission", ->
beforeEach ->
@AuthorizationManager.isUserSiteAdmin
.withArgs(@user_id)
.yields(null, false)
it "should redirect to redirectToRestricted", ->
@AuthorizationMiddlewear.ensureUserIsSiteAdmin @req, @res, @next
@next.called.should.equal false
@AuthorizationMiddlewear.redirectToRestricted
.calledWith(@req, @res, @next)
.should.equal true
describe "with anonymous user", ->
describe "when user has permission", ->
beforeEach ->
@AuthorizationManager.isUserSiteAdmin
.withArgs(null)
.yields(null, true)
it "should return next", ->
@AuthorizationMiddlewear.ensureUserIsSiteAdmin @req, @res, @next
@next.called.should.equal true
describe "when user doesn't have permission", ->
beforeEach ->
@AuthorizationManager.isUserSiteAdmin
.withArgs(null)
.yields(null, false)
it "should redirect to redirectToRestricted", ->
@AuthorizationMiddlewear.ensureUserIsSiteAdmin @req, @res, @next
@next.called.should.equal false
@AuthorizationMiddlewear.redirectToRestricted
.calledWith(@req, @res, @next)
.should.equal true
describe "ensureUserCanReadMultipleProjects", ->
beforeEach ->
@AuthorizationManager.canUserReadProject = sinon.stub()
@AuthorizationMiddlewear.redirectToRestricted = sinon.stub()
@req.query =
project_ids: "project1,project2"
describe "with logged in user", ->
beforeEach ->
@req.session =
user: _id: @user_id
describe "when user has permission to access all projects", ->
beforeEach ->
@AuthorizationManager.canUserReadProject
.withArgs(@user_id, "project1")
.yields(null, true)
@AuthorizationManager.canUserReadProject
.withArgs(@user_id, "project2")
.yields(null, true)
it "should return next", ->
@AuthorizationMiddlewear.ensureUserCanReadMultipleProjects @req, @res, @next
@next.called.should.equal true
describe "when user doesn't have permission to access one of the projects", ->
beforeEach ->
@AuthorizationManager.canUserReadProject
.withArgs(@user_id, "project1")
.yields(null, true)
@AuthorizationManager.canUserReadProject
.withArgs(@user_id, "project2")
.yields(null, false)
it "should redirect to redirectToRestricted", ->
@AuthorizationMiddlewear.ensureUserCanReadMultipleProjects @req, @res, @next
@next.called.should.equal false
@AuthorizationMiddlewear.redirectToRestricted
.calledWith(@req, @res, @next)
.should.equal true
describe "with anonymous user", ->
describe "when user has permission", ->
describe "when user has permission to access all projects", ->
beforeEach ->
@AuthorizationManager.canUserReadProject
.withArgs(null, "project1")
.yields(null, true)
@AuthorizationManager.canUserReadProject
.withArgs(null, "project2")
.yields(null, true)
it "should return next", ->
@AuthorizationMiddlewear.ensureUserCanReadMultipleProjects @req, @res, @next
@next.called.should.equal true
describe "when user doesn't have permission to access one of the projects", ->
beforeEach ->
@AuthorizationManager.canUserReadProject
.withArgs(null, "project1")
.yields(null, true)
@AuthorizationManager.canUserReadProject
.withArgs(null, "project2")
.yields(null, false)
it "should redirect to redirectToRestricted", ->
@AuthorizationMiddlewear.ensureUserCanReadMultipleProjects @req, @res, @next
@next.called.should.equal false
@AuthorizationMiddlewear.redirectToRestricted
.calledWith(@req, @res, @next)
.should.equal true

View file

@ -36,7 +36,7 @@ describe "CollaboratorsHandler", ->
it "should return an array of member ids with their privilege levels", ->
@callback
.calledWith(null, [
{ id: "owner-ref", privilegeLevel: "admin" }
{ id: "owner-ref", privilegeLevel: "owner" }
{ id: "read-only-ref-1", privilegeLevel: "readOnly" }
{ id: "read-only-ref-2", privilegeLevel: "readOnly" }
{ id: "read-write-ref-1", privilegeLevel: "readAndWrite" }
@ -83,6 +83,26 @@ describe "CollaboratorsHandler", ->
])
.should.equal true
describe "getMemberIdPrivilegeLevel", ->
beforeEach ->
@CollaboratorHandler.getMemberIdsWithPrivilegeLevels = sinon.stub()
@CollaboratorHandler.getMemberIdsWithPrivilegeLevels
.withArgs(@project_id)
.yields(null, [
{id: "member-id-1", privilegeLevel: "readAndWrite"}
{id: "member-id-2", privilegeLevel: "readOnly"}
])
it "should return the privilege level if it exists", (done) ->
@CollaboratorHandler.getMemberIdPrivilegeLevel "member-id-2", @project_id, (error, level) ->
expect(level).to.equal "readOnly"
done()
it "should return false if the member has no privilege level", (done) ->
@CollaboratorHandler.getMemberIdPrivilegeLevel "member-id-3", @project_id, (error, level) ->
expect(level).to.equal false
done()
describe "isUserMemberOfProject", ->
beforeEach ->
@CollaboratorHandler.getMemberIdsWithPrivilegeLevels = sinon.stub()

View file

@ -99,7 +99,7 @@ describe "EditorHttpController", ->
describe "when authorized", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject =
sinon.stub().callsArgWith(2, null, true, "owner")
sinon.stub().callsArgWith(2, null, "owner")
@EditorHttpController._buildJoinProjectView(@project_id, @user_id, @callback)
it "should find the project without doc lines", ->
@ -128,7 +128,7 @@ describe "EditorHttpController", ->
describe "when not authorized", ->
beforeEach ->
@AuthorizationManager.getPrivilegeLevelForProject =
sinon.stub().callsArgWith(2, null, false, null)
sinon.stub().callsArgWith(2, null, null)
@EditorHttpController._buildJoinProjectView(@project_id, @user_id, @callback)
it "should return false in the callback", ->

View file

@ -299,7 +299,7 @@ describe "ProjectController", ->
@ProjectModel.findOne.callsArgWith 1, null, @project
@UserModel.findById.callsArgWith(1, null, @user)
@SubscriptionLocator.getUsersSubscription.callsArgWith(1, null, {})
@AuthorizationManager.getPrivilegeLevelForProject.callsArgWith 2, null, true, "owner"
@AuthorizationManager.getPrivilegeLevelForProject.callsArgWith 2, null, "owner"
@ProjectDeleter.unmarkAsDeletedByExternalSource = sinon.stub()
@InactiveProjectManager.reactivateProjectIfRequired.callsArgWith(1)
@ProjectUpdateHandler.markAsOpened.callsArgWith(1)
@ -332,7 +332,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, false
@AuthorizationManager.getPrivilegeLevelForProject = sinon.stub().callsArgWith 2, null, null
@res.sendStatus = (resCode, opts)=>
resCode.should.equal 401
done()

View file

@ -49,7 +49,7 @@ describe "ProjectEditorHandler", ->
last_name : "ShareLaTeX"
email : "owner@sharelatex.com"
},
privilegeLevel: "admin"
privilegeLevel: "owner"
},{
user: {
_id: "read-only-id"

View file

@ -44,6 +44,8 @@ class User
projectName: name
}, (error, response, body) ->
return callback(error) if error?
if !body?.project_id?
console.error "SOMETHING WENT WRONG CREATING PROJECT", response.statusCode, response.headers["location"], body
callback(null, body.project_id)
addUserToProject: (project_id, email, privileges, callback = (error, user) ->) ->
@ -240,7 +242,7 @@ describe "Authorization", ->
expect_no_admin_access @other1, @project_id, redirect_to: "/restricted", done
it "should not allow anonymous user read access to it", (done) ->
expect_no_read_access @anon, @project_id, redirect_to: "/login", done
expect_no_read_access @anon, @project_id, redirect_to: "/restricted", done
it "should not allow anonymous user write access to its settings", (done) ->
expect_no_settings_write_access @anon, @project_id, redirect_to: "/restricted", done