AuthorizationMiddleware.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. let AuthorizationMiddleware
  2. const AuthorizationManager = require('./AuthorizationManager')
  3. const async = require('async')
  4. const logger = require('logger-sharelatex')
  5. const { ObjectId } = require('mongojs')
  6. const Errors = require('../Errors/Errors')
  7. const HttpErrors = require('@overleaf/o-error/http')
  8. const AuthenticationController = require('../Authentication/AuthenticationController')
  9. const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
  10. module.exports = AuthorizationMiddleware = {
  11. ensureUserCanReadMultipleProjects(req, res, next) {
  12. const projectIds = (req.query.project_ids || '').split(',')
  13. AuthorizationMiddleware._getUserId(req, function(error, userId) {
  14. if (error) {
  15. return next(error)
  16. }
  17. // Remove the projects we have access to. Note rejectSeries doesn't use
  18. // errors in callbacks
  19. async.rejectSeries(
  20. projectIds,
  21. function(projectId, cb) {
  22. const token = TokenAccessHandler.getRequestToken(req, projectId)
  23. AuthorizationManager.canUserReadProject(
  24. userId,
  25. projectId,
  26. token,
  27. function(error, canRead) {
  28. if (error) {
  29. return next(error)
  30. }
  31. cb(canRead)
  32. }
  33. )
  34. },
  35. function(unauthorizedProjectIds) {
  36. if (unauthorizedProjectIds.length > 0) {
  37. return AuthorizationMiddleware.redirectToRestricted(req, res, next)
  38. }
  39. next()
  40. }
  41. )
  42. })
  43. },
  44. ensureUserCanReadProject(req, res, next) {
  45. AuthorizationMiddleware._getUserAndProjectId(req, function(
  46. error,
  47. userId,
  48. projectId
  49. ) {
  50. if (error) {
  51. return next(error)
  52. }
  53. const token = TokenAccessHandler.getRequestToken(req, projectId)
  54. AuthorizationManager.canUserReadProject(
  55. userId,
  56. projectId,
  57. token,
  58. function(error, canRead) {
  59. if (error) {
  60. return next(error)
  61. }
  62. if (canRead) {
  63. logger.log(
  64. { userId, projectId },
  65. 'allowing user read access to project'
  66. )
  67. return next()
  68. }
  69. logger.log(
  70. { userId, projectId },
  71. 'denying user read access to project'
  72. )
  73. const acceptHeader = req.headers && req.headers['accept']
  74. if (acceptHeader && acceptHeader.match(/^application\/json.*$/)) {
  75. return res.sendStatus(403)
  76. }
  77. AuthorizationMiddleware.redirectToRestricted(req, res, next)
  78. }
  79. )
  80. })
  81. },
  82. ensureUserCanWriteProjectSettings(req, res, next) {
  83. AuthorizationMiddleware._getUserAndProjectId(req, function(
  84. error,
  85. userId,
  86. projectId
  87. ) {
  88. if (error) {
  89. return next(error)
  90. }
  91. const token = TokenAccessHandler.getRequestToken(req, projectId)
  92. AuthorizationManager.canUserWriteProjectSettings(
  93. userId,
  94. projectId,
  95. token,
  96. function(error, canWrite) {
  97. if (error) {
  98. return next(error)
  99. }
  100. if (canWrite) {
  101. logger.log(
  102. { userId, projectId },
  103. 'allowing user write access to project settings'
  104. )
  105. return next()
  106. }
  107. logger.log(
  108. { userId, projectId },
  109. 'denying user write access to project settings'
  110. )
  111. AuthorizationMiddleware.redirectToRestricted(req, res, next)
  112. }
  113. )
  114. })
  115. },
  116. ensureUserCanWriteProjectContent(req, res, next) {
  117. AuthorizationMiddleware._getUserAndProjectId(req, function(
  118. error,
  119. userId,
  120. projectId
  121. ) {
  122. if (error) {
  123. return next(error)
  124. }
  125. const token = TokenAccessHandler.getRequestToken(req, projectId)
  126. AuthorizationManager.canUserWriteProjectContent(
  127. userId,
  128. projectId,
  129. token,
  130. function(error, canWrite) {
  131. if (error) {
  132. return next(error)
  133. }
  134. if (canWrite) {
  135. logger.log(
  136. { userId, projectId },
  137. 'allowing user write access to project content'
  138. )
  139. return next()
  140. }
  141. logger.log(
  142. { userId, projectId },
  143. 'denying user write access to project settings'
  144. )
  145. AuthorizationMiddleware.redirectToRestricted(req, res, next)
  146. }
  147. )
  148. })
  149. },
  150. ensureUserCanAdminProject(req, res, next) {
  151. AuthorizationMiddleware._getUserAndProjectId(req, function(
  152. error,
  153. userId,
  154. projectId
  155. ) {
  156. if (error) {
  157. return next(error)
  158. }
  159. const token = TokenAccessHandler.getRequestToken(req, projectId)
  160. AuthorizationManager.canUserAdminProject(
  161. userId,
  162. projectId,
  163. token,
  164. function(error, canAdmin) {
  165. if (error) {
  166. return next(error)
  167. }
  168. if (canAdmin) {
  169. logger.log(
  170. { userId, projectId },
  171. 'allowing user admin access to project'
  172. )
  173. return next()
  174. }
  175. logger.log(
  176. { userId, projectId },
  177. 'denying user admin access to project'
  178. )
  179. next(new HttpErrors.ForbiddenError({}))
  180. }
  181. )
  182. })
  183. },
  184. ensureUserIsSiteAdmin(req, res, next) {
  185. AuthorizationMiddleware._getUserId(req, function(error, userId) {
  186. if (error) {
  187. return next(error)
  188. }
  189. AuthorizationManager.isUserSiteAdmin(userId, function(error, isAdmin) {
  190. if (error) {
  191. return next(error)
  192. }
  193. if (isAdmin) {
  194. logger.log({ userId }, 'allowing user admin access to site')
  195. return next()
  196. }
  197. logger.log({ userId }, 'denying user admin access to site')
  198. AuthorizationMiddleware.redirectToRestricted(req, res, next)
  199. })
  200. })
  201. },
  202. _getUserAndProjectId(req, callback) {
  203. const projectId = req.params.project_id || req.params.Project_id
  204. if (!projectId) {
  205. return callback(new Error('Expected project_id in request parameters'))
  206. }
  207. if (!ObjectId.isValid(projectId)) {
  208. return callback(
  209. new Errors.NotFoundError(`invalid projectId: ${projectId}`)
  210. )
  211. }
  212. AuthorizationMiddleware._getUserId(req, function(error, userId) {
  213. if (error) {
  214. return callback(error)
  215. }
  216. callback(null, userId, projectId)
  217. })
  218. },
  219. _getUserId(req, callback) {
  220. const userId =
  221. AuthenticationController.getLoggedInUserId(req) ||
  222. (req.oauth_user && req.oauth_user._id) ||
  223. null
  224. callback(null, userId)
  225. },
  226. redirectToRestricted(req, res, next) {
  227. // TODO: move this to throwing ForbiddenError
  228. res.redirect(`/restricted?from=${encodeURIComponent(req.url)}`)
  229. },
  230. restricted(req, res, next) {
  231. if (AuthenticationController.isUserLoggedIn(req)) {
  232. return res.render('user/restricted', { title: 'restricted' })
  233. }
  234. const { from } = req.query
  235. logger.log({ from }, 'redirecting to login')
  236. if (from) {
  237. AuthenticationController.setRedirectInSession(req, from)
  238. }
  239. res.redirect('/login')
  240. }
  241. }