mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-25 09:42:34 +00:00
Merge pull request #13583 from overleaf/bg-add-permissions-middleware
add permissions middleware for managed users GitOrigin-RevId: debd2398a3b75ce71023463ad3c0781750983b53
This commit is contained in:
parent
086e2a6794
commit
f0420000c5
3 changed files with 73 additions and 2 deletions
|
@ -0,0 +1,48 @@
|
|||
const { ForbiddenError } = require('../Errors/Errors')
|
||||
const { hasPermission } = require('./PermissionsManager')
|
||||
const ManagedUsersHandler = require('../Subscription/ManagedUsersHandler')
|
||||
|
||||
/**
|
||||
* Function that returns middleware to check if the user has permission to access a resource.
|
||||
* @param {[string]} requiredCapabilities - the capabilities required to access the resource.
|
||||
* @returns {Function} The middleware function that checks if the user has the required capabilities.
|
||||
*/
|
||||
function requirePermission(...requiredCapabilities) {
|
||||
if (
|
||||
requiredCapabilities.length === 0 ||
|
||||
requiredCapabilities.some(capability => typeof capability !== 'string')
|
||||
) {
|
||||
throw new Error('invalid required capabilities')
|
||||
}
|
||||
const doRequest = async function (req, res, next) {
|
||||
if (!req.user) {
|
||||
return next(new Error('no user'))
|
||||
}
|
||||
try {
|
||||
// get the group policy applying to the user
|
||||
const groupPolicy =
|
||||
await ManagedUsersHandler.promises.getGroupPolicyForUser(req.user)
|
||||
// if there is no group policy, the user is not managed
|
||||
if (!groupPolicy) {
|
||||
return next()
|
||||
}
|
||||
// check that the user has all the required capabilities
|
||||
for (const requiredCapability of requiredCapabilities) {
|
||||
// if the user has the permission, continue
|
||||
if (!hasPermission(groupPolicy, requiredCapability)) {
|
||||
throw new ForbiddenError(
|
||||
`user does not have permission for ${requiredCapability}`
|
||||
)
|
||||
}
|
||||
}
|
||||
next()
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
return doRequest
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
requirePermission,
|
||||
}
|
|
@ -148,6 +148,12 @@ class SubscriptionAdminDeletionError extends OErrorV2CompatibleError {
|
|||
}
|
||||
}
|
||||
|
||||
class SubscriptionNotFoundError extends OErrorV2CompatibleError {
|
||||
constructor(options) {
|
||||
super('subscription not found', options)
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectNotFoundError extends OErrorV2CompatibleError {
|
||||
constructor(options) {
|
||||
super('project not found', options)
|
||||
|
@ -213,6 +219,7 @@ module.exports = {
|
|||
ThirdPartyIdentityExistsError,
|
||||
ThirdPartyUserNotFoundError,
|
||||
SubscriptionAdminDeletionError,
|
||||
SubscriptionNotFoundError,
|
||||
ProjectNotFoundError,
|
||||
UserNotFoundError,
|
||||
UserNotCollaboratorError,
|
||||
|
|
|
@ -4,6 +4,10 @@ const { GroupPolicy } = require('../../models/GroupPolicy')
|
|||
const { User } = require('../../models/User')
|
||||
const ManagedUsersPolicy = require('./ManagedUsersPolicy')
|
||||
const OError = require('@overleaf/o-error')
|
||||
const {
|
||||
UserNotFoundError,
|
||||
SubscriptionNotFoundError,
|
||||
} = require('../Errors/Errors')
|
||||
|
||||
/**
|
||||
* This module contains functions for handling managed users in a
|
||||
|
@ -40,7 +44,14 @@ async function enableManagedUsers(subscriptionId) {
|
|||
* @returns {Promise<Object>} - A Promise that resolves with the group policy
|
||||
* object for the user's enrollment, or undefined if it does not exist.
|
||||
*/
|
||||
async function getGroupPolicyForUser(user) {
|
||||
async function getGroupPolicyForUser(requestedUser) {
|
||||
// Don't rely on the user being populated, it may be a session user without
|
||||
// the enrollment property. Force the user to be loaded from mongo.
|
||||
const user = await User.findById(requestedUser._id, 'enrollment')
|
||||
if (!user) {
|
||||
throw new UserNotFoundError({ info: { userId: requestedUser._id } })
|
||||
}
|
||||
// Now we are sure the user exists and we have the full contents
|
||||
if (user.enrollment?.managedBy == null) {
|
||||
return
|
||||
}
|
||||
|
@ -48,8 +59,13 @@ async function getGroupPolicyForUser(user) {
|
|||
const subscription = await Subscription.findById(user.enrollment.managedBy)
|
||||
.populate('groupPolicy', '-_id')
|
||||
.exec()
|
||||
if (!subscription) {
|
||||
throw new SubscriptionNotFoundError({
|
||||
info: { subscriptionId: user.enrollment.managedBy, userId: user._id },
|
||||
})
|
||||
}
|
||||
// return the group policy as a plain object (without the __v field)
|
||||
const groupPolicy = subscription?.groupPolicy.toObject({
|
||||
const groupPolicy = subscription.groupPolicy.toObject({
|
||||
versionKey: false,
|
||||
})
|
||||
return groupPolicy
|
||||
|
|
Loading…
Reference in a new issue