mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Merge pull request #13366 from overleaf/bg-group-policy
Add permission system for managed users GitOrigin-RevId: 9d7b38c594cc77204dbee22c92263d002fc8778f
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* This module exports functions for managing permissions and policies.
|
||||
*
|
||||
* It provides a way to:
|
||||
*
|
||||
* - Register capabilities and policies
|
||||
* - Associate policies with custom validators
|
||||
* - Apply collections of policies to a user
|
||||
* - Check whether a user has a given capability
|
||||
* - Check whether a user complies with a given policy
|
||||
*
|
||||
* Capabilities: boolean values that represent whether a user is allowed to
|
||||
* perform a certain action or not. The capabilities are represented as a Set.
|
||||
* For example, to delete their account a user would need the
|
||||
* `delete-own-account` capability. A user starts with a set of default
|
||||
* capabilities that let them do all the things they can currently do in
|
||||
* Overleaf.
|
||||
*
|
||||
* Policy: a rule which specifies which capabilities will be removed from a user
|
||||
* when the policy is applied.
|
||||
*
|
||||
* For example, a policy `userCannotDeleteOwnAccount` is represented as
|
||||
* `{'delete-own-account' : false}` meaning that the `delete-own-account`
|
||||
* capability will be removed. A policy can remove more than one capability, and
|
||||
* more than one policy could apply to a user.
|
||||
*
|
||||
* Validator: a function that takes a user and returns a boolean indicating
|
||||
* whether the user satisfies the policy or not. For example, a validator for
|
||||
* the `userCannotAddSecondaryEmail` policy would check whether the user has
|
||||
* more than one email address.
|
||||
*
|
||||
* Group Policies: a collection of policies with a setting indicating whether
|
||||
* they are enforced or not. Used to place restrictions on managed users in a
|
||||
* group.
|
||||
*
|
||||
* For example, a group policy could be
|
||||
*
|
||||
* {
|
||||
* "userCannotDeleteOwnAccount": true, // enforced
|
||||
* "userCannotAddSecondaryEmail": false // not enforced
|
||||
* }
|
||||
*/
|
||||
|
||||
const { callbackify } = require('util')
|
||||
|
||||
const POLICY_TO_CAPABILITY_MAP = new Map()
|
||||
const POLICY_TO_VALIDATOR_MAP = new Map()
|
||||
const DEFAULT_PERMISSIONS = new Map()
|
||||
|
||||
/**
|
||||
* Throws an error if the given capability is not registered.
|
||||
*
|
||||
* @private
|
||||
* @param {string} capability - The name of the capability to check.
|
||||
* @throws {Error} If the capability is not registered.
|
||||
*/
|
||||
function ensureCapabilityExists(capability) {
|
||||
if (!DEFAULT_PERMISSIONS.has(capability)) {
|
||||
throw new Error(`unknown capability: ${capability}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new capability with the given name and options.
|
||||
*
|
||||
* @param {string} name - The name of the capability to register.
|
||||
* @param {Object} options - The options for the capability.
|
||||
* @param {boolean} options.default - The default value for the capability
|
||||
* (required).
|
||||
* @throws {Error} If the default value is not a boolean or if the capability is
|
||||
* already registered.
|
||||
*/
|
||||
function registerCapability(name, options) {
|
||||
// check that the default value is a boolean
|
||||
const defaultValue = options?.default
|
||||
if (typeof defaultValue !== 'boolean') {
|
||||
throw new Error('default value must be a boolean')
|
||||
}
|
||||
if (DEFAULT_PERMISSIONS.has(name)) {
|
||||
throw new Error(`capability already registered: ${name}`)
|
||||
}
|
||||
DEFAULT_PERMISSIONS.set(name, defaultValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new policy with the given name, capabilities, and options.
|
||||
*
|
||||
* @param {string} name - The name of the policy to register.
|
||||
* @param {Object} capabilities - The capabilities for the policy.
|
||||
* @param {Object} [options] - The options for the policy.
|
||||
* @param {Function?} [options.validator] - The optional validator function for the
|
||||
* policy.
|
||||
* @throws {Error} If the policy is already registered or if a capability is not
|
||||
* a boolean or is unknown.
|
||||
*/
|
||||
function registerPolicy(name, capabilities, options = {}) {
|
||||
const { validator } = options
|
||||
// check that the only options provided are capabilities and validators
|
||||
// FIXME: maybe use a schema validator here?
|
||||
if (POLICY_TO_CAPABILITY_MAP.has(name)) {
|
||||
throw new Error(`policy already registered: ${name}`)
|
||||
}
|
||||
// check that all the entries in the capability set exist and are booleans
|
||||
for (const [capabilityName, capabilityValue] of Object.entries(
|
||||
capabilities
|
||||
)) {
|
||||
// check that the capability exists (look in the default permissions)
|
||||
if (!DEFAULT_PERMISSIONS.has(capabilityName)) {
|
||||
throw new Error(`unknown capability: ${capabilityName}`)
|
||||
}
|
||||
// check that the value is a boolean
|
||||
if (typeof capabilityValue !== 'boolean') {
|
||||
throw new Error(
|
||||
`capability value must be a boolean: ${capabilityName} = ${capabilityValue}`
|
||||
)
|
||||
}
|
||||
}
|
||||
// set the policy capabilities
|
||||
POLICY_TO_CAPABILITY_MAP.set(name, new Map(Object.entries(capabilities)))
|
||||
|
||||
// set the policy validator (if present)
|
||||
if (validator) {
|
||||
POLICY_TO_VALIDATOR_MAP.set(name, validator)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of policy names that are enforced based on the provided
|
||||
* group policy object.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} groupPolicy - The group policy object to check.
|
||||
* @returns {Array} An array of policy names that are enforced.
|
||||
*/
|
||||
function getEnforcedPolicyNames(groupPolicy = {}) {
|
||||
return Object.keys(groupPolicy).filter(
|
||||
policyName => groupPolicy[policyName] !== false
|
||||
) // filter out the policies that are not enforced
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the specified capability for the given policy.
|
||||
*
|
||||
* @private
|
||||
* @param {string} policyName - The name of the policy to retrieve the
|
||||
* capability value from.
|
||||
* @param {string} capability - The name of the capability to retrieve the value
|
||||
* for.
|
||||
* @returns {boolean | undefined} The value of the capability for the policy, or
|
||||
* undefined if the policy or capability is not found.
|
||||
*/
|
||||
function getCapabilityValueFromPolicy(policyName, capability) {
|
||||
return POLICY_TO_CAPABILITY_MAP.get(policyName)?.get(capability)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value for the specified capability.
|
||||
*
|
||||
* @private
|
||||
* @param {string} capability - The name of the capability to retrieve the
|
||||
* default value for.
|
||||
* @returns {boolean | undefined} The default value for the capability, or
|
||||
* undefined if the capability is not found.
|
||||
*/
|
||||
function getDefaultPermission(capability) {
|
||||
return DEFAULT_PERMISSIONS.get(capability)
|
||||
}
|
||||
|
||||
function getValidatorFromPolicy(policyName) {
|
||||
return POLICY_TO_VALIDATOR_MAP.get(policyName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of default capabilities based on the DEFAULT_PERMISSIONS map.
|
||||
*
|
||||
* @private
|
||||
* @returns {Set} A set of default capabilities.
|
||||
*/
|
||||
function getDefaultCapabilities() {
|
||||
const defaultCapabilities = new Set()
|
||||
for (const [
|
||||
capabilityName,
|
||||
capabilityValue,
|
||||
] of DEFAULT_PERMISSIONS.entries()) {
|
||||
if (capabilityValue === true) {
|
||||
defaultCapabilities.add(capabilityName)
|
||||
}
|
||||
}
|
||||
return defaultCapabilities
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a given policy to a set of capabilities, to remove those capabilities
|
||||
* which are not allowed by the policy.
|
||||
*
|
||||
* @private
|
||||
* @param {Set} capabilitySet - The set of capabilities to apply the policy to.
|
||||
* @param {string} policyName - The name of the policy to apply.
|
||||
* @throws {Error} If the policy is unknown.
|
||||
*/
|
||||
function applyPolicy(capabilitySet, policyName) {
|
||||
const policyCapabilities = POLICY_TO_CAPABILITY_MAP.get(policyName)
|
||||
if (!policyCapabilities) {
|
||||
throw new Error(`unknown policy: ${policyName}`)
|
||||
}
|
||||
for (const [
|
||||
capabilityName,
|
||||
capabilityValue,
|
||||
] of policyCapabilities.entries()) {
|
||||
if (capabilityValue !== true) {
|
||||
capabilitySet.delete(capabilityName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of capabilities that a user has based on their group policy.
|
||||
*
|
||||
* @param {Object} groupPolicy - The group policy object to check.
|
||||
* @returns {Set} A set of capabilities that the user has, based on their group
|
||||
* policy.
|
||||
* @throws {Error} If the policy is unknown.
|
||||
*/
|
||||
function getUserCapabilities(groupPolicy) {
|
||||
const userCapabilities = getDefaultCapabilities()
|
||||
const enforcedPolicyNames = getEnforcedPolicyNames(groupPolicy)
|
||||
for (const enforcedPolicyName of enforcedPolicyNames) {
|
||||
applyPolicy(userCapabilities, enforcedPolicyName)
|
||||
}
|
||||
return userCapabilities
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has permission for a given capability based on their group
|
||||
* policy.
|
||||
*
|
||||
* @param {Object} groupPolicy - The group policy object for the user.
|
||||
* @param {string} capability - The name of the capability to check permission
|
||||
* for.
|
||||
* @returns {boolean} True if the user has permission for the capability, false
|
||||
* otherwise.
|
||||
* @throws {Error} If the capability does not exist.
|
||||
*/
|
||||
function hasPermission(groupPolicy, capability) {
|
||||
ensureCapabilityExists(capability)
|
||||
// look through all the entries in the group policy and see if any of them apply to the capability
|
||||
const results = getEnforcedPolicyNames(groupPolicy).map(userPolicyName =>
|
||||
getCapabilityValueFromPolicy(userPolicyName, capability)
|
||||
)
|
||||
// if there are no results, return the default permission
|
||||
if (results.length === 0) {
|
||||
return getDefaultPermission(capability)
|
||||
}
|
||||
// only allow the permission if all the results are true, otherwise deny it
|
||||
return results.every(result => result === true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously checks which policies a user complies with using the
|
||||
* applicable validators. Each validator is an async function that takes a user
|
||||
* and returns a boolean.
|
||||
*
|
||||
* @param {Object} user - The user object to check.
|
||||
* @param {Object} groupPolicy - The group policy object to check.
|
||||
* @returns {Promise<Map>} A promise that resolves with a Map object containing
|
||||
* the validation status for each enforced policy. The keys of the Map are the
|
||||
* enforced policy names, and the values are booleans indicating whether the
|
||||
* user complies with the policy.
|
||||
*/
|
||||
async function getUserValidationStatus(user, groupPolicy) {
|
||||
// find all the enforced policies for the user
|
||||
const enforcedPolicyNames = getEnforcedPolicyNames(groupPolicy)
|
||||
// for each enforced policy, we have a list of capabilities with expected values
|
||||
// some of those capabilities have validators
|
||||
// we need to run the validators and the result to see if if the user is complies with the policy
|
||||
const userValidationStatus = new Map()
|
||||
for (const enforcedPolicyName of enforcedPolicyNames) {
|
||||
const validator = getValidatorFromPolicy(enforcedPolicyName)
|
||||
if (validator) {
|
||||
userValidationStatus.set(enforcedPolicyName, await validator(user))
|
||||
}
|
||||
}
|
||||
return userValidationStatus
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
registerCapability,
|
||||
registerPolicy,
|
||||
hasPermission,
|
||||
getUserCapabilities,
|
||||
getUserValidationStatus: callbackify(getUserValidationStatus),
|
||||
promises: { getUserValidationStatus },
|
||||
}
|
||||
26
services/web/app/src/models/GroupPolicy.js
Normal file
26
services/web/app/src/models/GroupPolicy.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const mongoose = require('../infrastructure/Mongoose')
|
||||
|
||||
const { Schema } = mongoose
|
||||
|
||||
const GroupPolicySchema = new Schema(
|
||||
{
|
||||
// User can't delete their own account
|
||||
userCannotDeleteOwnAccount: Boolean,
|
||||
|
||||
// User can't add a secondary email address, or affiliation
|
||||
userCannotAddSecondaryEmail: Boolean,
|
||||
|
||||
// User can't have an active (currently auto-renewing) personal subscription, nor can they start one
|
||||
userCannotHaveSubscription: Boolean,
|
||||
|
||||
// User can't choose to leave the group subscription they are managed by
|
||||
userCannotLeaveManagingGroupSubscription: Boolean,
|
||||
|
||||
// User can't have Google/Twitter/ORCID SSO active on their account, nor can they link it to their account
|
||||
userCannotHaveThirdPartySSO: Boolean,
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
exports.GroupPolicy = mongoose.model('GroupPolicy', GroupPolicySchema)
|
||||
exports.GroupPolicySchema = GroupPolicySchema
|
||||
@@ -21,6 +21,7 @@ const SubscriptionSchema = new Schema(
|
||||
},
|
||||
},
|
||||
member_ids: [{ type: ObjectId, ref: 'User' }],
|
||||
groupPolicy: { type: ObjectId, ref: 'GroupPolicy' },
|
||||
invited_emails: [String],
|
||||
teamInvites: [TeamInviteSchema],
|
||||
recurlySubscription_id: String,
|
||||
|
||||
@@ -31,6 +31,14 @@ const UserSchema = new Schema(
|
||||
role: { type: String, default: '' },
|
||||
institution: { type: String, default: '' },
|
||||
hashedPassword: String,
|
||||
enrollment: {
|
||||
// sso: { type: Boolean, default: false },
|
||||
managedBy: {
|
||||
type: ObjectId,
|
||||
ref: 'Subscription',
|
||||
},
|
||||
enrolledAt: { type: Date },
|
||||
},
|
||||
isAdmin: { type: Boolean, default: false },
|
||||
staffAccess: {
|
||||
publisherMetrics: { type: Boolean, default: false },
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
const { expect } = require('chai')
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Authorization/PermissionsManager.js'
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
|
||||
describe('PermissionsManager', function () {
|
||||
beforeEach(function () {
|
||||
this.PermissionsManager = SandboxedModule.require(modulePath, {
|
||||
requires: {},
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability1', {
|
||||
default: true,
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability2', {
|
||||
default: true,
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability3', {
|
||||
default: true,
|
||||
})
|
||||
this.PermissionsManager.registerCapability('capability4', {
|
||||
default: false,
|
||||
})
|
||||
})
|
||||
|
||||
describe('hasPermission', function () {
|
||||
describe('when no policies apply to the user', function () {
|
||||
it('should return true if default permission is true', function () {
|
||||
const groupPolicy = {}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return false if the default permission is false', function () {
|
||||
const groupPolicy = {}
|
||||
const capability = 'capability4'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a policy applies to the user', function () {
|
||||
it('should return true if the user has the capability after the policy is applied', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy: true,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return false if the user does not have the capability after the policy is applied', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy: true,
|
||||
}
|
||||
const capability = 'capability2'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.false
|
||||
})
|
||||
|
||||
it('should return the default permission if the policy does not apply to the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy: true,
|
||||
}
|
||||
const capability = 'capability3'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.false
|
||||
})
|
||||
|
||||
it('should return the default permission if the policy is not enforced', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy: false,
|
||||
}
|
||||
const capability1 = 'capability1'
|
||||
const result1 = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability1
|
||||
)
|
||||
const capability2 = 'capability2'
|
||||
const result2 = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability2
|
||||
)
|
||||
expect(result1).to.be.true
|
||||
expect(result2).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('when multiple policies apply to the user', function () {
|
||||
it('should return true if all policies allow the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy1: true,
|
||||
policy2: true,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return false if any policy denies the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy1: true,
|
||||
policy2: true,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.false
|
||||
})
|
||||
|
||||
it('should return the default permssion when the applicable policy is not enforced', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
})
|
||||
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy1: true,
|
||||
policy2: false,
|
||||
}
|
||||
const capability = 'capability1'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.true
|
||||
})
|
||||
|
||||
it('should return the default permission if the policies do not restrict to the capability', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy: true,
|
||||
}
|
||||
const capability = 'capability3'
|
||||
const result = this.PermissionsManager.hasPermission(
|
||||
groupPolicy,
|
||||
capability
|
||||
)
|
||||
expect(result).to.be.false
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getUserCapabilities', function () {
|
||||
it('should return the default capabilities when no group policy is provided', function () {
|
||||
const groupPolicy = {}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(
|
||||
new Set(['capability1', 'capability2', 'capability3'])
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a reduced capability set when a group policy is provided', function () {
|
||||
this.PermissionsManager.registerPolicy('policy', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy: true,
|
||||
}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(
|
||||
new Set(['capability1', 'capability3'])
|
||||
)
|
||||
})
|
||||
|
||||
it('should return a reduced capability set when multiple group policies are provided', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
|
||||
const groupPolicy = {
|
||||
policy1: true,
|
||||
policy2: true,
|
||||
}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(new Set(['capability3']))
|
||||
})
|
||||
|
||||
it('should return an empty capability set when group policies remove all permissions', function () {
|
||||
this.PermissionsManager.registerPolicy('policy1', {
|
||||
capability1: true,
|
||||
capability2: false,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('policy2', {
|
||||
capability1: false,
|
||||
capability2: true,
|
||||
})
|
||||
this.PermissionsManager.registerPolicy('policy3', {
|
||||
capability1: true,
|
||||
capability2: true,
|
||||
capability3: false,
|
||||
})
|
||||
const groupPolicy = {
|
||||
policy1: true,
|
||||
policy2: true,
|
||||
policy3: true,
|
||||
}
|
||||
const capabilities =
|
||||
this.PermissionsManager.getUserCapabilities(groupPolicy)
|
||||
expect(capabilities).to.deep.equal(new Set())
|
||||
})
|
||||
})
|
||||
|
||||
describe('getUserValidationStatus', function () {
|
||||
it('should return the status for the policy when the user conforms', async function () {
|
||||
this.PermissionsManager.registerPolicy(
|
||||
'policy',
|
||||
{},
|
||||
{
|
||||
validator: async user => {
|
||||
return user.prop === 'allowed'
|
||||
},
|
||||
}
|
||||
)
|
||||
const groupPolicy = {
|
||||
policy: true,
|
||||
}
|
||||
const user = { prop: 'allowed' }
|
||||
const result =
|
||||
await this.PermissionsManager.promises.getUserValidationStatus(
|
||||
user,
|
||||
groupPolicy
|
||||
)
|
||||
expect(result).to.deep.equal(new Map([['policy', true]]))
|
||||
})
|
||||
|
||||
it('should return the status for the policy when the user does not conform', async function () {
|
||||
this.PermissionsManager.registerPolicy(
|
||||
'policy',
|
||||
{},
|
||||
{
|
||||
validator: async user => {
|
||||
return user.prop === 'allowed'
|
||||
},
|
||||
}
|
||||
)
|
||||
const groupPolicy = {
|
||||
policy: true,
|
||||
}
|
||||
const user = { prop: 'not allowed' }
|
||||
const result =
|
||||
await this.PermissionsManager.promises.getUserValidationStatus(
|
||||
user,
|
||||
groupPolicy
|
||||
)
|
||||
expect(result).to.deep.equal(new Map([['policy', false]]))
|
||||
})
|
||||
it('should return the status for multiple policies according to whether the user conforms', async function () {
|
||||
this.PermissionsManager.registerPolicy(
|
||||
'policy1',
|
||||
{},
|
||||
{
|
||||
validator: async user => {
|
||||
return user.prop === 'allowed'
|
||||
},
|
||||
}
|
||||
)
|
||||
this.PermissionsManager.registerPolicy(
|
||||
'policy2',
|
||||
{},
|
||||
{
|
||||
validator: async user => {
|
||||
return user.prop === 'other'
|
||||
},
|
||||
}
|
||||
)
|
||||
this.PermissionsManager.registerPolicy(
|
||||
'policy3',
|
||||
{},
|
||||
{
|
||||
validator: async user => {
|
||||
return user.prop === 'allowed'
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const groupPolicy = {
|
||||
policy1: true,
|
||||
policy2: true,
|
||||
policy3: false, // this policy is not enforced
|
||||
}
|
||||
const user = { prop: 'allowed' }
|
||||
const result =
|
||||
await this.PermissionsManager.promises.getUserValidationStatus(
|
||||
user,
|
||||
groupPolicy
|
||||
)
|
||||
expect(result).to.deep.equal(
|
||||
new Map([
|
||||
['policy1', true],
|
||||
['policy2', false],
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user