UserMembershipAuthorizationTests.mjs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import { expect } from 'chai'
  2. import async from 'async'
  3. import User from './helpers/User.mjs'
  4. import Institution from './helpers/Institution.mjs'
  5. import Subscription from './helpers/Subscription.mjs'
  6. import Publisher from './helpers/Publisher.mjs'
  7. import sinon from 'sinon'
  8. import RecurlyClient from '../../../app/src/Features/Subscription/RecurlyClient.mjs'
  9. import Settings from '@overleaf/settings'
  10. import Features from '../../../app/src/infrastructure/Features.mjs'
  11. describe('UserMembershipAuthorization', function () {
  12. beforeEach(function (done) {
  13. if (!Features.hasFeature('saas')) {
  14. this.skip()
  15. }
  16. this.user = new User()
  17. sinon.stub(RecurlyClient.promises, 'getSubscription').resolves({})
  18. this.adminRolesEnabledStub = sinon.stub(Settings, 'adminRolesEnabled')
  19. this.adminRolesEnabledStub.value(true)
  20. this.adminPrivilegeAvailableStub = sinon.stub(
  21. Settings,
  22. 'adminPrivilegeAvailable'
  23. )
  24. this.adminPrivilegeAvailableStub.value(true)
  25. async.series([this.user.ensureUserExists.bind(this.user)], done)
  26. })
  27. afterEach(function () {
  28. if (!Features.hasFeature('saas')) {
  29. return
  30. }
  31. RecurlyClient.promises.getSubscription.restore()
  32. this.adminRolesEnabledStub.restore()
  33. this.adminPrivilegeAvailableStub.restore()
  34. })
  35. describe('group', function () {
  36. beforeEach(function (done) {
  37. this.subscription = new Subscription({
  38. groupPlan: true,
  39. })
  40. async.series(
  41. [
  42. this.subscription.ensureExists.bind(this.subscription),
  43. cb => this.user.login(cb),
  44. ],
  45. done
  46. )
  47. })
  48. describe('users management', function () {
  49. it('should allow managers only', function (done) {
  50. const url = `/manage/groups/${this.subscription._id}/members`
  51. async.series(
  52. [
  53. expectAccess(this.user, url, 403),
  54. cb => this.subscription.setManagerIds([this.user._id], cb),
  55. expectAccess(this.user, url, 200),
  56. ],
  57. done
  58. )
  59. })
  60. })
  61. describe('managers management', function () {
  62. it('should allow managers only', function (done) {
  63. const url = `/manage/groups/${this.subscription._id}/managers`
  64. async.series(
  65. [
  66. expectAccess(this.user, url, 403),
  67. cb => this.subscription.setManagerIds([this.user._id], cb),
  68. expectAccess(this.user, url, 200),
  69. ],
  70. done
  71. )
  72. })
  73. })
  74. })
  75. describe('institution', function () {
  76. beforeEach(async function () {
  77. this.institution = new Institution()
  78. await this.institution.ensureExists(this.institution)
  79. })
  80. describe('users management', function () {
  81. it('should allow managers', function (done) {
  82. const url = `/manage/institutions/${this.institution.v1Id}/managers`
  83. async.series(
  84. [
  85. this.user.login.bind(this.user),
  86. expectAccess(this.user, url, 403),
  87. cb => this.institution.setManagerIds([this.user._id], cb),
  88. expectAccess(this.user, url, 200),
  89. ],
  90. done
  91. )
  92. })
  93. it('should allow admin users', function (done) {
  94. const url = `/manage/institutions/${this.institution.v1Id}/managers`
  95. async.series(
  96. [
  97. this.user.login.bind(this.user),
  98. expectAccess(this.user, url, 403),
  99. cb => this.user.ensureAdmin(cb),
  100. cb => this.user.ensureAdminRole('sales', cb),
  101. this.user.login.bind(this.user),
  102. expectAccess(this.user, url, 200),
  103. ],
  104. done
  105. )
  106. })
  107. it('should not allow "sales" admin to add managers', function (done) {
  108. const url = `/manage/institutions/${this.institution.v1Id}/managers`
  109. async.series(
  110. [
  111. this.user.login.bind(this.user),
  112. expectPost(this.user, url, { email: this.user.email }, 403),
  113. cb => this.user.ensureAdmin(cb),
  114. cb => this.user.ensureAdminRole('sales', cb),
  115. this.user.login.bind(this.user),
  116. expectPost(this.user, url, { email: this.user.email }, 403),
  117. ],
  118. done
  119. )
  120. })
  121. it('should allow "engineering" admin to add managers', function (done) {
  122. const user = new User()
  123. const url = `/manage/institutions/${this.institution.v1Id}/managers`
  124. async.series(
  125. [
  126. user.ensureUserExists.bind(user),
  127. this.user.login.bind(this.user),
  128. expectPost(this.user, url, { email: user.email }, 403),
  129. cb => this.user.ensureAdmin(cb),
  130. cb => this.user.ensureAdminRole('engineering', cb),
  131. this.user.login.bind(this.user),
  132. expectPost(this.user, url, { email: user.email }, 200),
  133. cb => this.institution.setManagerIds([], cb),
  134. ],
  135. done
  136. )
  137. })
  138. })
  139. describe('creation', function () {
  140. it('should allow admin only', function (done) {
  141. const url = `/entities/institution/create/foo`
  142. async.series(
  143. [
  144. this.user.login.bind(this.user),
  145. expectAccess(this.user, url, 403),
  146. cb => this.user.ensureAdmin(cb),
  147. cb => this.user.ensureAdminRole('engineering', cb),
  148. this.user.login.bind(this.user),
  149. expectAccess(this.user, url, 200),
  150. ],
  151. done
  152. )
  153. })
  154. })
  155. })
  156. describe('publisher', function () {
  157. beforeEach(function (done) {
  158. this.publisher = new Publisher({})
  159. async.series(
  160. [
  161. this.publisher.ensureExists.bind(this.publisher),
  162. cb => this.user.login(cb),
  163. ],
  164. done
  165. )
  166. })
  167. describe('managers management', function () {
  168. it('should allow managers only', function (done) {
  169. const url = `/manage/publishers/${this.publisher.slug}/managers`
  170. async.series(
  171. [
  172. expectAccess(this.user, url, 403),
  173. cb => this.publisher.setManagerIds([this.user._id], cb),
  174. expectAccess(this.user, url, 200),
  175. ],
  176. done
  177. )
  178. })
  179. })
  180. describe('creation', function () {
  181. it('should redirect admin only', function (done) {
  182. const url = `/manage/publishers/foo/managers`
  183. async.series(
  184. [
  185. this.user.login.bind(this.user),
  186. expectAccess(this.user, url, 404),
  187. cb => this.user.ensureAdmin(cb),
  188. cb => this.user.ensureAdminRole('engineering', cb),
  189. this.user.login.bind(this.user),
  190. expectAccess(this.user, url, 302, /\/create/),
  191. ],
  192. done
  193. )
  194. })
  195. it('should allow admin only', function (done) {
  196. const url = `/entities/publisher/create/foo`
  197. async.series(
  198. [
  199. expectAccess(this.user, url, 403),
  200. cb => this.user.ensureAdmin(cb),
  201. cb => this.user.ensureAdminRole('engineering', cb),
  202. this.user.login.bind(this.user),
  203. expectAccess(this.user, url, 200),
  204. ],
  205. done
  206. )
  207. })
  208. })
  209. })
  210. })
  211. function expectAccess(user, url, status, pattern) {
  212. return callback => {
  213. user.request.get({ url }, (error, response, body) => {
  214. if (error) {
  215. return callback(error)
  216. }
  217. expect(response.statusCode).to.equal(status)
  218. if (pattern) {
  219. expect(body).to.match(pattern)
  220. }
  221. callback()
  222. })
  223. }
  224. }
  225. function expectPost(user, url, body, status, pattern) {
  226. return callback => {
  227. user.request.post({ url, json: body }, (error, response, body) => {
  228. if (error) {
  229. return callback(error)
  230. }
  231. expect(response.statusCode).to.equal(status)
  232. if (pattern) {
  233. expect(body).to.match(pattern)
  234. }
  235. callback()
  236. })
  237. }
  238. }