AuthorizationMiddleware.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. let AuthorizationMiddleware
  2. const AuthorizationManager = require('./AuthorizationManager')
  3. const async = require('async')
  4. const logger = require('logger-sharelatex')
  5. const { ObjectId } = require('mongodb')
  6. const Errors = require('../Errors/Errors')
  7. const HttpErrorHandler = require('../Errors/HttpErrorHandler')
  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. blockRestrictedUserFromProject(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.isRestrictedUserForProject(
  55. userId,
  56. projectId,
  57. token,
  58. (err, isRestrictedUser) => {
  59. if (err) {
  60. return next(err)
  61. }
  62. if (isRestrictedUser) {
  63. return res.sendStatus(403)
  64. }
  65. next()
  66. }
  67. )
  68. })
  69. },
  70. ensureUserCanReadProject(req, res, next) {
  71. AuthorizationMiddleware._getUserAndProjectId(req, function(
  72. error,
  73. userId,
  74. projectId
  75. ) {
  76. if (error) {
  77. return next(error)
  78. }
  79. const token = TokenAccessHandler.getRequestToken(req, projectId)
  80. AuthorizationManager.canUserReadProject(
  81. userId,
  82. projectId,
  83. token,
  84. function(error, canRead) {
  85. if (error) {
  86. return next(error)
  87. }
  88. if (canRead) {
  89. logger.log(
  90. { userId, projectId },
  91. 'allowing user read access to project'
  92. )
  93. return next()
  94. }
  95. logger.log(
  96. { userId, projectId },
  97. 'denying user read access to project'
  98. )
  99. HttpErrorHandler.forbidden(req, res)
  100. }
  101. )
  102. })
  103. },
  104. ensureUserCanWriteProjectSettings(req, res, next) {
  105. AuthorizationMiddleware._getUserAndProjectId(req, function(
  106. error,
  107. userId,
  108. projectId
  109. ) {
  110. if (error) {
  111. return next(error)
  112. }
  113. const token = TokenAccessHandler.getRequestToken(req, projectId)
  114. AuthorizationManager.canUserWriteProjectSettings(
  115. userId,
  116. projectId,
  117. token,
  118. function(error, canWrite) {
  119. if (error) {
  120. return next(error)
  121. }
  122. if (canWrite) {
  123. logger.log(
  124. { userId, projectId },
  125. 'allowing user write access to project settings'
  126. )
  127. return next()
  128. }
  129. logger.log(
  130. { userId, projectId },
  131. 'denying user write access to project settings'
  132. )
  133. HttpErrorHandler.forbidden(req, res)
  134. }
  135. )
  136. })
  137. },
  138. ensureUserCanWriteProjectContent(req, res, next) {
  139. AuthorizationMiddleware._getUserAndProjectId(req, function(
  140. error,
  141. userId,
  142. projectId
  143. ) {
  144. if (error) {
  145. return next(error)
  146. }
  147. const token = TokenAccessHandler.getRequestToken(req, projectId)
  148. AuthorizationManager.canUserWriteProjectContent(
  149. userId,
  150. projectId,
  151. token,
  152. function(error, canWrite) {
  153. if (error) {
  154. return next(error)
  155. }
  156. if (canWrite) {
  157. logger.log(
  158. { userId, projectId },
  159. 'allowing user write access to project content'
  160. )
  161. return next()
  162. }
  163. logger.log(
  164. { userId, projectId },
  165. 'denying user write access to project settings'
  166. )
  167. HttpErrorHandler.forbidden(req, res)
  168. }
  169. )
  170. })
  171. },
  172. ensureUserCanAdminProject(req, res, next) {
  173. AuthorizationMiddleware._getUserAndProjectId(req, function(
  174. error,
  175. userId,
  176. projectId
  177. ) {
  178. if (error) {
  179. return next(error)
  180. }
  181. const token = TokenAccessHandler.getRequestToken(req, projectId)
  182. AuthorizationManager.canUserAdminProject(
  183. userId,
  184. projectId,
  185. token,
  186. function(error, canAdmin) {
  187. if (error) {
  188. return next(error)
  189. }
  190. if (canAdmin) {
  191. logger.log(
  192. { userId, projectId },
  193. 'allowing user admin access to project'
  194. )
  195. return next()
  196. }
  197. logger.log(
  198. { userId, projectId },
  199. 'denying user admin access to project'
  200. )
  201. HttpErrorHandler.forbidden(req, res)
  202. }
  203. )
  204. })
  205. },
  206. ensureUserIsSiteAdmin(req, res, next) {
  207. AuthorizationMiddleware._getUserId(req, function(error, userId) {
  208. if (error) {
  209. return next(error)
  210. }
  211. AuthorizationManager.isUserSiteAdmin(userId, function(error, isAdmin) {
  212. if (error) {
  213. return next(error)
  214. }
  215. if (isAdmin) {
  216. logger.log({ userId }, 'allowing user admin access to site')
  217. return next()
  218. }
  219. logger.log({ userId }, 'denying user admin access to site')
  220. AuthorizationMiddleware.redirectToRestricted(req, res, next)
  221. })
  222. })
  223. },
  224. _getUserAndProjectId(req, callback) {
  225. const projectId = req.params.project_id || req.params.Project_id
  226. if (!projectId) {
  227. return callback(new Error('Expected project_id in request parameters'))
  228. }
  229. if (!ObjectId.isValid(projectId)) {
  230. return callback(
  231. new Errors.NotFoundError(`invalid projectId: ${projectId}`)
  232. )
  233. }
  234. AuthorizationMiddleware._getUserId(req, function(error, userId) {
  235. if (error) {
  236. return callback(error)
  237. }
  238. callback(null, userId, projectId)
  239. })
  240. },
  241. _getUserId(req, callback) {
  242. const userId =
  243. AuthenticationController.getLoggedInUserId(req) ||
  244. (req.oauth_user && req.oauth_user._id) ||
  245. null
  246. callback(null, userId)
  247. },
  248. redirectToRestricted(req, res, next) {
  249. // TODO: move this to throwing ForbiddenError
  250. res.redirect(
  251. `/restricted?from=${encodeURIComponent(res.locals.currentUrl)}`
  252. )
  253. },
  254. restricted(req, res, next) {
  255. if (AuthenticationController.isUserLoggedIn(req)) {
  256. return res.render('user/restricted', { title: 'restricted' })
  257. }
  258. const { from } = req.query
  259. logger.log({ from }, 'redirecting to login')
  260. if (from) {
  261. AuthenticationController.setRedirectInSession(req, from)
  262. }
  263. res.redirect('/login')
  264. }
  265. }