AuthorizationMiddlewareTests.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /* eslint-disable
  2. camelcase,
  3. max-len,
  4. no-return-assign,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const sinon = require('sinon')
  15. const chai = require('chai')
  16. const should = chai.should()
  17. const { expect } = chai
  18. const modulePath =
  19. '../../../../app/src/Features/Authorization/AuthorizationMiddleware.js'
  20. const SandboxedModule = require('sandboxed-module')
  21. const Errors = require('../../../../app/src/Features/Errors/Errors.js')
  22. describe('AuthorizationMiddleware', function() {
  23. beforeEach(function() {
  24. this.user_id = 'user-id-123'
  25. this.project_id = 'project-id-123'
  26. this.token = 'some-token'
  27. this.AuthenticationController = {
  28. getLoggedInUserId: sinon.stub().returns(this.user_id),
  29. isUserLoggedIn: sinon.stub().returns(true)
  30. }
  31. this.AuthorizationMiddleware = SandboxedModule.require(modulePath, {
  32. requires: {
  33. './AuthorizationManager': (this.AuthorizationManager = {}),
  34. 'logger-sharelatex': { log() {} },
  35. mongojs: {
  36. ObjectId: (this.ObjectId = {})
  37. },
  38. '../Errors/Errors': Errors,
  39. '../Authentication/AuthenticationController': this
  40. .AuthenticationController,
  41. '../TokenAccess/TokenAccessHandler': (this.TokenAccessHandler = {
  42. getRequestToken: sinon.stub().returns(this.token)
  43. })
  44. }
  45. })
  46. this.req = {}
  47. this.res = {}
  48. this.ObjectId.isValid = sinon.stub()
  49. this.ObjectId.isValid.withArgs(this.project_id).returns(true)
  50. return (this.next = sinon.stub())
  51. })
  52. describe('_getUserId', function() {
  53. beforeEach(function() {
  54. return (this.req = {})
  55. })
  56. it('should get the user from session', function(done) {
  57. this.AuthenticationController.getLoggedInUserId = sinon
  58. .stub()
  59. .returns('1234')
  60. return this.AuthorizationMiddleware._getUserId(
  61. this.req,
  62. (err, user_id) => {
  63. expect(err).to.not.exist
  64. expect(user_id).to.equal('1234')
  65. return done()
  66. }
  67. )
  68. })
  69. it('should get oauth_user from request', function(done) {
  70. this.AuthenticationController.getLoggedInUserId = sinon
  71. .stub()
  72. .returns(null)
  73. this.req.oauth_user = { _id: '5678' }
  74. return this.AuthorizationMiddleware._getUserId(
  75. this.req,
  76. (err, user_id) => {
  77. expect(err).to.not.exist
  78. expect(user_id).to.equal('5678')
  79. return done()
  80. }
  81. )
  82. })
  83. it('should fall back to null', function(done) {
  84. this.AuthenticationController.getLoggedInUserId = sinon
  85. .stub()
  86. .returns(null)
  87. this.req.oauth_user = undefined
  88. return this.AuthorizationMiddleware._getUserId(
  89. this.req,
  90. (err, user_id) => {
  91. expect(err).to.not.exist
  92. expect(user_id).to.equal(null)
  93. return done()
  94. }
  95. )
  96. })
  97. })
  98. const METHODS_TO_TEST = {
  99. ensureUserCanReadProject: 'canUserReadProject',
  100. ensureUserCanWriteProjectSettings: 'canUserWriteProjectSettings',
  101. ensureUserCanWriteProjectContent: 'canUserWriteProjectContent',
  102. ensureUserCanAdminProject: 'canUserAdminProject'
  103. }
  104. for (let middlewareMethod in METHODS_TO_TEST) {
  105. const managerMethod = METHODS_TO_TEST[middlewareMethod]
  106. ;((middlewareMethod, managerMethod) =>
  107. describe(middlewareMethod, function() {
  108. beforeEach(function() {
  109. this.req.params = { project_id: this.project_id }
  110. this.AuthorizationManager[managerMethod] = sinon.stub()
  111. return (this.AuthorizationMiddleware.redirectToRestricted = sinon.stub())
  112. })
  113. describe('with missing project_id', function() {
  114. beforeEach(function() {
  115. return (this.req.params = {})
  116. })
  117. it('should return an error to next', function() {
  118. this.AuthorizationMiddleware[middlewareMethod](
  119. this.req,
  120. this.res,
  121. this.next
  122. )
  123. return this.next.calledWith(new Error()).should.equal(true)
  124. })
  125. })
  126. describe('with logged in user', function() {
  127. beforeEach(function() {
  128. return this.AuthenticationController.getLoggedInUserId.returns(
  129. this.user_id
  130. )
  131. })
  132. describe('when user has permission', function() {
  133. beforeEach(function() {
  134. return this.AuthorizationManager[managerMethod]
  135. .withArgs(this.user_id, this.project_id, this.token)
  136. .yields(null, true)
  137. })
  138. it('should return next', function() {
  139. this.AuthorizationMiddleware[middlewareMethod](
  140. this.req,
  141. this.res,
  142. this.next
  143. )
  144. return this.next.called.should.equal(true)
  145. })
  146. })
  147. describe("when user doesn't have permission", function() {
  148. beforeEach(function() {
  149. return this.AuthorizationManager[managerMethod]
  150. .withArgs(this.user_id, this.project_id, this.token)
  151. .yields(null, false)
  152. })
  153. it('should redirect to redirectToRestricted', function() {
  154. this.AuthorizationMiddleware[middlewareMethod](
  155. this.req,
  156. this.res,
  157. this.next
  158. )
  159. this.next.called.should.equal(false)
  160. return this.AuthorizationMiddleware.redirectToRestricted
  161. .calledWith(this.req, this.res, this.next)
  162. .should.equal(true)
  163. })
  164. })
  165. })
  166. describe('with anonymous user', function() {
  167. describe('when user has permission', function() {
  168. beforeEach(function() {
  169. this.AuthenticationController.getLoggedInUserId.returns(null)
  170. return this.AuthorizationManager[managerMethod]
  171. .withArgs(null, this.project_id, this.token)
  172. .yields(null, true)
  173. })
  174. it('should return next', function() {
  175. this.AuthorizationMiddleware[middlewareMethod](
  176. this.req,
  177. this.res,
  178. this.next
  179. )
  180. return this.next.called.should.equal(true)
  181. })
  182. })
  183. describe("when user doesn't have permission", function() {
  184. beforeEach(function() {
  185. this.AuthenticationController.getLoggedInUserId.returns(null)
  186. return this.AuthorizationManager[managerMethod]
  187. .withArgs(null, this.project_id, this.token)
  188. .yields(null, false)
  189. })
  190. it('should redirect to redirectToRestricted', function() {
  191. this.AuthorizationMiddleware[middlewareMethod](
  192. this.req,
  193. this.res,
  194. this.next
  195. )
  196. this.next.called.should.equal(false)
  197. return this.AuthorizationMiddleware.redirectToRestricted
  198. .calledWith(this.req, this.res, this.next)
  199. .should.equal(true)
  200. })
  201. })
  202. })
  203. describe('with malformed project id', function() {
  204. beforeEach(function() {
  205. this.req.params = { project_id: 'blah' }
  206. return (this.ObjectId.isValid = sinon.stub().returns(false))
  207. })
  208. it('should return a not found error', function(done) {
  209. return this.AuthorizationMiddleware[middlewareMethod](
  210. this.req,
  211. this.res,
  212. function(error) {
  213. error.should.be.instanceof(Errors.NotFoundError)
  214. return done()
  215. }
  216. )
  217. })
  218. })
  219. }))(middlewareMethod, managerMethod)
  220. }
  221. describe('ensureUserIsSiteAdmin', function() {
  222. beforeEach(function() {
  223. this.AuthorizationManager.isUserSiteAdmin = sinon.stub()
  224. return (this.AuthorizationMiddleware.redirectToRestricted = sinon.stub())
  225. })
  226. describe('with logged in user', function() {
  227. beforeEach(function() {
  228. return this.AuthenticationController.getLoggedInUserId.returns(
  229. this.user_id
  230. )
  231. })
  232. describe('when user has permission', function() {
  233. beforeEach(function() {
  234. return this.AuthorizationManager.isUserSiteAdmin
  235. .withArgs(this.user_id)
  236. .yields(null, true)
  237. })
  238. it('should return next', function() {
  239. this.AuthorizationMiddleware.ensureUserIsSiteAdmin(
  240. this.req,
  241. this.res,
  242. this.next
  243. )
  244. return this.next.called.should.equal(true)
  245. })
  246. })
  247. describe("when user doesn't have permission", function() {
  248. beforeEach(function() {
  249. return this.AuthorizationManager.isUserSiteAdmin
  250. .withArgs(this.user_id)
  251. .yields(null, false)
  252. })
  253. it('should redirect to redirectToRestricted', function() {
  254. this.AuthorizationMiddleware.ensureUserIsSiteAdmin(
  255. this.req,
  256. this.res,
  257. this.next
  258. )
  259. this.next.called.should.equal(false)
  260. return this.AuthorizationMiddleware.redirectToRestricted
  261. .calledWith(this.req, this.res, this.next)
  262. .should.equal(true)
  263. })
  264. })
  265. })
  266. describe('with anonymous user', function() {
  267. describe('when user has permission', function() {
  268. beforeEach(function() {
  269. this.AuthenticationController.getLoggedInUserId.returns(null)
  270. return this.AuthorizationManager.isUserSiteAdmin
  271. .withArgs(null)
  272. .yields(null, true)
  273. })
  274. it('should return next', function() {
  275. this.AuthorizationMiddleware.ensureUserIsSiteAdmin(
  276. this.req,
  277. this.res,
  278. this.next
  279. )
  280. return this.next.called.should.equal(true)
  281. })
  282. })
  283. describe("when user doesn't have permission", function() {
  284. beforeEach(function() {
  285. this.AuthenticationController.getLoggedInUserId.returns(null)
  286. return this.AuthorizationManager.isUserSiteAdmin
  287. .withArgs(null)
  288. .yields(null, false)
  289. })
  290. it('should redirect to redirectToRestricted', function() {
  291. this.AuthorizationMiddleware.ensureUserIsSiteAdmin(
  292. this.req,
  293. this.res,
  294. this.next
  295. )
  296. this.next.called.should.equal(false)
  297. return this.AuthorizationMiddleware.redirectToRestricted
  298. .calledWith(this.req, this.res, this.next)
  299. .should.equal(true)
  300. })
  301. })
  302. })
  303. })
  304. describe('ensureUserCanReadMultipleProjects', function() {
  305. beforeEach(function() {
  306. this.AuthorizationManager.canUserReadProject = sinon.stub()
  307. this.AuthorizationMiddleware.redirectToRestricted = sinon.stub()
  308. return (this.req.query = { project_ids: 'project1,project2' })
  309. })
  310. describe('with logged in user', function() {
  311. beforeEach(function() {
  312. return this.AuthenticationController.getLoggedInUserId.returns(
  313. this.user_id
  314. )
  315. })
  316. describe('when user has permission to access all projects', function() {
  317. beforeEach(function() {
  318. this.AuthorizationManager.canUserReadProject
  319. .withArgs(this.user_id, 'project1', this.token)
  320. .yields(null, true)
  321. return this.AuthorizationManager.canUserReadProject
  322. .withArgs(this.user_id, 'project2', this.token)
  323. .yields(null, true)
  324. })
  325. it('should return next', function() {
  326. this.AuthorizationMiddleware.ensureUserCanReadMultipleProjects(
  327. this.req,
  328. this.res,
  329. this.next
  330. )
  331. return this.next.called.should.equal(true)
  332. })
  333. })
  334. describe("when user doesn't have permission to access one of the projects", function() {
  335. beforeEach(function() {
  336. this.AuthorizationManager.canUserReadProject
  337. .withArgs(this.user_id, 'project1', this.token)
  338. .yields(null, true)
  339. return this.AuthorizationManager.canUserReadProject
  340. .withArgs(this.user_id, 'project2', this.token)
  341. .yields(null, false)
  342. })
  343. it('should redirect to redirectToRestricted', function() {
  344. this.AuthorizationMiddleware.ensureUserCanReadMultipleProjects(
  345. this.req,
  346. this.res,
  347. this.next
  348. )
  349. this.next.called.should.equal(false)
  350. return this.AuthorizationMiddleware.redirectToRestricted
  351. .calledWith(this.req, this.res, this.next)
  352. .should.equal(true)
  353. })
  354. })
  355. })
  356. describe('with anonymous user', () =>
  357. describe('when user has permission', function() {
  358. describe('when user has permission to access all projects', function() {
  359. beforeEach(function() {
  360. this.AuthenticationController.getLoggedInUserId.returns(null)
  361. this.AuthorizationManager.canUserReadProject
  362. .withArgs(null, 'project1', this.token)
  363. .yields(null, true)
  364. return this.AuthorizationManager.canUserReadProject
  365. .withArgs(null, 'project2', this.token)
  366. .yields(null, true)
  367. })
  368. it('should return next', function() {
  369. this.AuthorizationMiddleware.ensureUserCanReadMultipleProjects(
  370. this.req,
  371. this.res,
  372. this.next
  373. )
  374. return this.next.called.should.equal(true)
  375. })
  376. })
  377. describe("when user doesn't have permission to access one of the projects", function() {
  378. beforeEach(function() {
  379. this.AuthenticationController.getLoggedInUserId.returns(null)
  380. this.AuthorizationManager.canUserReadProject
  381. .withArgs(null, 'project1', this.token)
  382. .yields(null, true)
  383. return this.AuthorizationManager.canUserReadProject
  384. .withArgs(null, 'project2', this.token)
  385. .yields(null, false)
  386. })
  387. it('should redirect to redirectToRestricted', function() {
  388. this.AuthorizationMiddleware.ensureUserCanReadMultipleProjects(
  389. this.req,
  390. this.res,
  391. this.next
  392. )
  393. this.next.called.should.equal(false)
  394. return this.AuthorizationMiddleware.redirectToRestricted
  395. .calledWith(this.req, this.res, this.next)
  396. .should.equal(true)
  397. })
  398. })
  399. }))
  400. })
  401. })