2019-05-29 05:21:06 -04:00
|
|
|
let AuthorizationMiddleware
|
|
|
|
const AuthorizationManager = require('./AuthorizationManager')
|
|
|
|
const async = require('async')
|
|
|
|
const logger = require('logger-sharelatex')
|
2020-09-23 04:49:26 -04:00
|
|
|
const { ObjectId } = require('mongodb')
|
2019-05-29 05:21:06 -04:00
|
|
|
const Errors = require('../Errors/Errors')
|
2020-07-09 09:47:43 -04:00
|
|
|
const HttpErrorHandler = require('../Errors/HttpErrorHandler')
|
2019-05-29 05:21:06 -04:00
|
|
|
const AuthenticationController = require('../Authentication/AuthenticationController')
|
|
|
|
const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
|
|
|
|
|
|
|
|
module.exports = AuthorizationMiddleware = {
|
|
|
|
ensureUserCanReadMultipleProjects(req, res, next) {
|
2019-09-24 04:43:56 -04:00
|
|
|
const projectIds = (req.query.project_ids || '').split(',')
|
|
|
|
AuthorizationMiddleware._getUserId(req, function(error, userId) {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
|
|
|
// Remove the projects we have access to. Note rejectSeries doesn't use
|
|
|
|
// errors in callbacks
|
2019-09-24 04:43:56 -04:00
|
|
|
async.rejectSeries(
|
|
|
|
projectIds,
|
|
|
|
function(projectId, cb) {
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
AuthorizationManager.canUserReadProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
token,
|
|
|
|
function(error, canRead) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
cb(canRead)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
2019-09-24 04:43:56 -04:00
|
|
|
function(unauthorizedProjectIds) {
|
|
|
|
if (unauthorizedProjectIds.length > 0) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return AuthorizationMiddleware.redirectToRestricted(req, res, next)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
next()
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2020-06-04 04:47:12 -04:00
|
|
|
blockRestrictedUserFromProject(req, res, next) {
|
|
|
|
AuthorizationMiddleware._getUserAndProjectId(req, function(
|
|
|
|
error,
|
|
|
|
userId,
|
|
|
|
projectId
|
|
|
|
) {
|
|
|
|
if (error) {
|
|
|
|
return next(error)
|
|
|
|
}
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
AuthorizationManager.isRestrictedUserForProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token,
|
|
|
|
(err, isRestrictedUser) => {
|
|
|
|
if (err) {
|
|
|
|
return next(err)
|
|
|
|
}
|
|
|
|
if (isRestrictedUser) {
|
|
|
|
return res.sendStatus(403)
|
|
|
|
}
|
|
|
|
next()
|
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2019-05-29 05:21:06 -04:00
|
|
|
ensureUserCanReadProject(req, res, next) {
|
2019-09-24 04:43:56 -04:00
|
|
|
AuthorizationMiddleware._getUserAndProjectId(req, function(
|
2019-05-29 05:21:06 -04:00
|
|
|
error,
|
2019-09-24 04:43:56 -04:00
|
|
|
userId,
|
|
|
|
projectId
|
2019-05-29 05:21:06 -04:00
|
|
|
) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
AuthorizationManager.canUserReadProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
token,
|
|
|
|
function(error, canRead) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
|
|
|
if (canRead) {
|
|
|
|
logger.log(
|
2019-09-24 04:43:56 -04:00
|
|
|
{ userId, projectId },
|
2019-05-29 05:21:06 -04:00
|
|
|
'allowing user read access to project'
|
|
|
|
)
|
|
|
|
return next()
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
logger.log(
|
|
|
|
{ userId, projectId },
|
|
|
|
'denying user read access to project'
|
|
|
|
)
|
2020-07-27 06:46:27 -04:00
|
|
|
HttpErrorHandler.forbidden(req, res)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
ensureUserCanWriteProjectSettings(req, res, next) {
|
2019-09-24 04:43:56 -04:00
|
|
|
AuthorizationMiddleware._getUserAndProjectId(req, function(
|
2019-05-29 05:21:06 -04:00
|
|
|
error,
|
2019-09-24 04:43:56 -04:00
|
|
|
userId,
|
|
|
|
projectId
|
2019-05-29 05:21:06 -04:00
|
|
|
) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
AuthorizationManager.canUserWriteProjectSettings(
|
|
|
|
userId,
|
|
|
|
projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
token,
|
|
|
|
function(error, canWrite) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
|
|
|
if (canWrite) {
|
|
|
|
logger.log(
|
2019-09-24 04:43:56 -04:00
|
|
|
{ userId, projectId },
|
2019-05-29 05:21:06 -04:00
|
|
|
'allowing user write access to project settings'
|
|
|
|
)
|
|
|
|
return next()
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
logger.log(
|
|
|
|
{ userId, projectId },
|
|
|
|
'denying user write access to project settings'
|
|
|
|
)
|
2020-07-27 06:46:27 -04:00
|
|
|
HttpErrorHandler.forbidden(req, res)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
ensureUserCanWriteProjectContent(req, res, next) {
|
2019-09-24 04:43:56 -04:00
|
|
|
AuthorizationMiddleware._getUserAndProjectId(req, function(
|
2019-05-29 05:21:06 -04:00
|
|
|
error,
|
2019-09-24 04:43:56 -04:00
|
|
|
userId,
|
|
|
|
projectId
|
2019-05-29 05:21:06 -04:00
|
|
|
) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
AuthorizationManager.canUserWriteProjectContent(
|
|
|
|
userId,
|
|
|
|
projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
token,
|
|
|
|
function(error, canWrite) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
|
|
|
if (canWrite) {
|
|
|
|
logger.log(
|
2019-09-24 04:43:56 -04:00
|
|
|
{ userId, projectId },
|
2019-05-29 05:21:06 -04:00
|
|
|
'allowing user write access to project content'
|
|
|
|
)
|
|
|
|
return next()
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
logger.log(
|
|
|
|
{ userId, projectId },
|
|
|
|
'denying user write access to project settings'
|
|
|
|
)
|
2020-07-27 06:46:27 -04:00
|
|
|
HttpErrorHandler.forbidden(req, res)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
ensureUserCanAdminProject(req, res, next) {
|
2019-09-24 04:43:56 -04:00
|
|
|
AuthorizationMiddleware._getUserAndProjectId(req, function(
|
2019-05-29 05:21:06 -04:00
|
|
|
error,
|
2019-09-24 04:43:56 -04:00
|
|
|
userId,
|
|
|
|
projectId
|
2019-05-29 05:21:06 -04:00
|
|
|
) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
AuthorizationManager.canUserAdminProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
token,
|
|
|
|
function(error, canAdmin) {
|
2019-09-24 04:43:56 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
|
|
|
if (canAdmin) {
|
|
|
|
logger.log(
|
2019-09-24 04:43:56 -04:00
|
|
|
{ userId, projectId },
|
2019-05-29 05:21:06 -04:00
|
|
|
'allowing user admin access to project'
|
|
|
|
)
|
|
|
|
return next()
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
logger.log(
|
|
|
|
{ userId, projectId },
|
|
|
|
'denying user admin access to project'
|
|
|
|
)
|
2020-07-09 09:47:43 -04:00
|
|
|
HttpErrorHandler.forbidden(req, res)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
ensureUserIsSiteAdmin(req, res, next) {
|
2019-09-24 04:43:56 -04:00
|
|
|
AuthorizationMiddleware._getUserId(req, function(error, userId) {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
AuthorizationManager.isUserSiteAdmin(userId, function(error, isAdmin) {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return next(error)
|
|
|
|
}
|
|
|
|
if (isAdmin) {
|
2019-09-24 04:43:56 -04:00
|
|
|
logger.log({ userId }, 'allowing user admin access to site')
|
2019-05-29 05:21:06 -04:00
|
|
|
return next()
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
logger.log({ userId }, 'denying user admin access to site')
|
|
|
|
AuthorizationMiddleware.redirectToRestricted(req, res, next)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
_getUserAndProjectId(req, callback) {
|
2019-09-24 04:43:56 -04:00
|
|
|
const projectId = req.params.project_id || req.params.Project_id
|
|
|
|
if (!projectId) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(new Error('Expected project_id in request parameters'))
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
if (!ObjectId.isValid(projectId)) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(
|
2019-09-24 04:43:56 -04:00
|
|
|
new Errors.NotFoundError(`invalid projectId: ${projectId}`)
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
AuthorizationMiddleware._getUserId(req, function(error, userId) {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(error)
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
callback(null, userId, projectId)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
_getUserId(req, callback) {
|
2019-09-24 04:43:56 -04:00
|
|
|
const userId =
|
2019-05-29 05:21:06 -04:00
|
|
|
AuthenticationController.getLoggedInUserId(req) ||
|
2019-09-24 04:43:56 -04:00
|
|
|
(req.oauth_user && req.oauth_user._id) ||
|
2019-05-29 05:21:06 -04:00
|
|
|
null
|
2019-09-24 04:43:56 -04:00
|
|
|
callback(null, userId)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
redirectToRestricted(req, res, next) {
|
|
|
|
// TODO: move this to throwing ForbiddenError
|
2020-06-18 10:05:22 -04:00
|
|
|
res.redirect(
|
|
|
|
`/restricted?from=${encodeURIComponent(res.locals.currentUrl)}`
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
restricted(req, res, next) {
|
|
|
|
if (AuthenticationController.isUserLoggedIn(req)) {
|
|
|
|
return res.render('user/restricted', { title: 'restricted' })
|
|
|
|
}
|
2019-09-24 04:43:56 -04:00
|
|
|
const { from } = req.query
|
|
|
|
logger.log({ from }, 'redirecting to login')
|
|
|
|
if (from) {
|
|
|
|
AuthenticationController.setRedirectInSession(req, from)
|
|
|
|
}
|
|
|
|
res.redirect('/login')
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
}
|