mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-25 09:31:35 +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 {
|
class ProjectNotFoundError extends OErrorV2CompatibleError {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
super('project not found', options)
|
super('project not found', options)
|
||||||
|
@ -213,6 +219,7 @@ module.exports = {
|
||||||
ThirdPartyIdentityExistsError,
|
ThirdPartyIdentityExistsError,
|
||||||
ThirdPartyUserNotFoundError,
|
ThirdPartyUserNotFoundError,
|
||||||
SubscriptionAdminDeletionError,
|
SubscriptionAdminDeletionError,
|
||||||
|
SubscriptionNotFoundError,
|
||||||
ProjectNotFoundError,
|
ProjectNotFoundError,
|
||||||
UserNotFoundError,
|
UserNotFoundError,
|
||||||
UserNotCollaboratorError,
|
UserNotCollaboratorError,
|
||||||
|
|
|
@ -4,6 +4,10 @@ const { GroupPolicy } = require('../../models/GroupPolicy')
|
||||||
const { User } = require('../../models/User')
|
const { User } = require('../../models/User')
|
||||||
const ManagedUsersPolicy = require('./ManagedUsersPolicy')
|
const ManagedUsersPolicy = require('./ManagedUsersPolicy')
|
||||||
const OError = require('@overleaf/o-error')
|
const OError = require('@overleaf/o-error')
|
||||||
|
const {
|
||||||
|
UserNotFoundError,
|
||||||
|
SubscriptionNotFoundError,
|
||||||
|
} = require('../Errors/Errors')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This module contains functions for handling managed users in a
|
* 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
|
* @returns {Promise<Object>} - A Promise that resolves with the group policy
|
||||||
* object for the user's enrollment, or undefined if it does not exist.
|
* 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) {
|
if (user.enrollment?.managedBy == null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -48,8 +59,13 @@ async function getGroupPolicyForUser(user) {
|
||||||
const subscription = await Subscription.findById(user.enrollment.managedBy)
|
const subscription = await Subscription.findById(user.enrollment.managedBy)
|
||||||
.populate('groupPolicy', '-_id')
|
.populate('groupPolicy', '-_id')
|
||||||
.exec()
|
.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)
|
// return the group policy as a plain object (without the __v field)
|
||||||
const groupPolicy = subscription?.groupPolicy.toObject({
|
const groupPolicy = subscription.groupPolicy.toObject({
|
||||||
versionKey: false,
|
versionKey: false,
|
||||||
})
|
})
|
||||||
return groupPolicy
|
return groupPolicy
|
||||||
|
|
Loading…
Reference in a new issue