diff --git a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee index 72372345f8..f6b8ca7bbd 100644 --- a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee +++ b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee @@ -1,6 +1,5 @@ UserCreator = require('../User/UserCreator') Project = require("../../models/Project").Project -ProjectEntityHandler = require("../Project/ProjectEntityHandler") mimelib = require("mimelib") logger = require('logger-sharelatex') UserGetter = require "../User/UserGetter" @@ -108,6 +107,7 @@ module.exports = CollaboratorsHandler = Project.update { _id: project_id }, { $addToSet: level }, (error) -> return callback(error) if error? # Flush to TPDS in background to add files to collaborator's Dropbox + ProjectEntityHandler = require("../Project/ProjectEntityHandler") ProjectEntityHandler.flushProjectToThirdPartyDataStore project_id, (error) -> if error? logger.error {err: error, project_id, user_id}, "error flushing to TPDS after adding collaborator" diff --git a/services/web/test/acceptance/coffee/AuthorizationTests.coffee b/services/web/test/acceptance/coffee/AuthorizationTests.coffee index d5c1602ca6..478ef598a0 100644 --- a/services/web/test/acceptance/coffee/AuthorizationTests.coffee +++ b/services/web/test/acceptance/coffee/AuthorizationTests.coffee @@ -1,5 +1,6 @@ request = require("request") expect = require("chai").expect +async = require "async" count = 0 BASE_URL = "http://localhost:3000" @@ -40,6 +41,14 @@ class User return callback(error) if error? callback(null, body.project_id) + addUserToProject: (project_id, email, privileges, callback = (error, user) ->) -> + @request.post { + url: "/project/#{project_id}/users", + json: {email, privileges} + }, (error, response, body) -> + return callback(error) if error? + callback(null, body.user) + getCsrfToken: (callback = (error) ->) -> @request.get { url: "/register" @@ -54,33 +63,174 @@ class User }) callback() +try_read_access = (requester, project_id, test, callback) -> + async.parallel [ + (cb) -> + requester.get "/project/#{project_id}", (error, response, body) -> + return cb(error) if error? + test(response, body) + cb() + (cb) -> + requester.get "/project/#{project_id}/download/zip", (error, response, body) -> + return cb(error) if error? + test(response, body) + cb() + ], callback + +try_write_access = (requester, project_id, test, callback) -> + async.parallel [ + (cb) -> + requester.post { + uri: "/project/#{project_id}/settings" + json: + compiler: "latex" + }, (error, response, body) -> + return cb(error) if error? + test(response, body) + cb() + ], callback + +try_admin_access = (requester, project_id, test, callback) -> + async.parallel [ + (cb) -> + requester.post { + uri: "/project/#{project_id}/rename" + json: + newProjectName: "new-name" + }, (error, response, body) -> + return cb(error) if error? + test(response, body) + cb() + ], callback + +expect_read_access = (requester, project_id, callback) -> + try_read_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.be.oneOf [200, 204] + , callback) + +expect_write_access = (requester, project_id, callback) -> + try_write_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.be.oneOf [200, 204] + , callback) + +expect_admin_access = (requester, project_id, callback) -> + try_admin_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.be.oneOf [200, 204] + , callback) + +expect_no_read_access = (requester, project_id, callback) -> + try_read_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/restricted" + , callback) + +expect_no_write_access = (requester, project_id, callback) -> + try_write_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/restricted" + , callback) + +expect_no_admin_access = (requester, project_id, callback) -> + try_admin_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/restricted" + , callback) + +expect_no_anonymous_read_access = (requester, project_id, callback) -> + try_read_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/login" + , callback) + +expect_no_anonymous_write_access = (requester, project_id, callback) -> + try_write_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/login" + , callback) + +expect_no_anonymous_admin_access = (requester, project_id, callback) -> + try_admin_access(requester, project_id, (response, body) -> + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal "/login" + , callback) + describe "Authorization", -> + before (done) -> + @timeout(10000) + @owner = new User() + @other1 = new User() + @other2 = new User() + @anon = new User() + async.parallel [ + (cb) => @owner.login cb + (cb) => @other1.login cb + (cb) => @other2.login cb + (cb) => @anon.getCsrfToken cb + ], done + describe "private project", -> before (done) -> - @owner = new User() - @other = new User() - @owner.login (error) => + @owner.createProject "private-project", (error, project_id) => return done(error) if error? - @other.login (error) => - return done(error) if error? - @owner.createProject "private-project", (error, project_id) => - return done(error) if error? - @project_id = project_id - done() + @project_id = project_id + done() - it "should allow the owner to access it", (done) -> - @owner.request.get "/project/#{@project_id}", (error, response, body) -> - expect(response.statusCode).to.equal 200 - done() + it "should allow the owner read access to it", (done) -> + expect_read_access @owner.request, @project_id, done - it "should not allow another user to access it", (done) -> - @other.request.get "/project/#{@project_id}", (error, response, body) -> - expect(response.statusCode).to.equal 302 - expect(response.headers.location).to.equal "/restricted" - done() + it "should allow the owner write access to it", (done) -> + expect_write_access @owner.request, @project_id, done + + it "should allow the owner admin access to it", (done) -> + expect_admin_access @owner.request, @project_id, done - it "should not allow anonymous user to access it", (done) -> - request.get "/project/#{@project_id}", (error, response, body) -> - expect(response.statusCode).to.equal 302 - expect(response.headers.location).to.equal "/login" - done() \ No newline at end of file + it "should not allow another user read access to it", (done) -> + expect_no_read_access(@other1.request, @project_id, done) + + it "should not allow another user write access to it", (done) -> + expect_no_write_access(@other1.request, @project_id, done) + + it "should not allow another user admin access to it", (done) -> + expect_no_admin_access(@other1.request, @project_id, done) + + it "should not allow anonymous user read access to it", (done) -> + expect_no_anonymous_read_access(@anon.request, @project_id, done) + + it "should not allow anonymous user write access to it", (done) -> + expect_no_anonymous_write_access(@anon.request, @project_id, done) + + it "should not allow anonymous user write access to it", (done) -> + expect_no_anonymous_admin_access(@anon.request, @project_id, done) + + describe "shared project", -> + before (done) -> + @rw_user = @other1 + @ro_user = @other2 + @owner.createProject "private-project", (error, project_id) => + return done(error) if error? + @project_id = project_id + @owner.addUserToProject @project_id, @ro_user.email, "readOnly", (error) => + return done(error) if error? + @owner.addUserToProject @project_id, @rw_user.email, "readAndWrite", (error) => + return done(error) if error? + done() + + it "should allow the read-only user read access to it", (done) -> + expect_read_access @ro_user.request, @project_id, done + + it "should not allow the read-only user write access to it", (done) -> + expect_no_write_access @ro_user.request, @project_id, done + + it "should not allow the read-only user admin access to it", (done) -> + expect_no_admin_access @ro_user.request, @project_id, done + + it "should allow the read-write user read access to it", (done) -> + expect_read_access @rw_user.request, @project_id, done + + it "should allow the read-write user write access to it", (done) -> + expect_write_access @rw_user.request, @project_id, done + + it "should not allow the read-write user admin access to it", (done) -> + expect_no_admin_access @rw_user.request, @project_id, done + + \ No newline at end of file