mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #15726 from overleaf/ab-managed-users-module-cleanup
[web] Managed users / Group SSO module cleanup GitOrigin-RevId: a24d3278667059248d9563afe44cafca5f87a7c0
This commit is contained in:
parent
26fe632a22
commit
1ff830027f
16 changed files with 58 additions and 632 deletions
|
@ -4,7 +4,7 @@ const {
|
|||
getUserCapabilities,
|
||||
getUserRestrictions,
|
||||
} = require('./PermissionsManager')
|
||||
const ManagedUsersHandler = require('../Subscription/ManagedUsersHandler')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
|
||||
/**
|
||||
* Function that returns middleware to add an `assertPermission` function to the request object to check if the user has a specific capability.
|
||||
|
@ -26,19 +26,26 @@ function useCapabilities() {
|
|||
return next()
|
||||
}
|
||||
try {
|
||||
// get the group policy applying to the user
|
||||
const { groupPolicy, managedBy, isManagedGroupAdmin } =
|
||||
await ManagedUsersHandler.promises.getEnrollmentForUser(req.user)
|
||||
// attach the subscription ID to the request object
|
||||
req.managedBy = managedBy
|
||||
// attach the subscription admin status to the request object
|
||||
req.isManagedGroupAdmin = isManagedGroupAdmin
|
||||
// attach the new capabilities to the request object
|
||||
for (const cap of getUserCapabilities(groupPolicy)) {
|
||||
req.capabilitySet.add(cap)
|
||||
const result = (
|
||||
await Modules.promises.hooks.fire(
|
||||
'getManagedUsersEnrollmentForUser',
|
||||
req.user
|
||||
)
|
||||
)[0]
|
||||
if (result) {
|
||||
// get the group policy applying to the user
|
||||
const { groupPolicy, managedBy, isManagedGroupAdmin } = result
|
||||
// attach the subscription ID to the request object
|
||||
req.managedBy = managedBy
|
||||
// attach the subscription admin status to the request object
|
||||
req.isManagedGroupAdmin = isManagedGroupAdmin
|
||||
// attach the new capabilities to the request object
|
||||
for (const cap of getUserCapabilities(groupPolicy)) {
|
||||
req.capabilitySet.add(cap)
|
||||
}
|
||||
// also attach the user's restrictions (the capabilities they don't have)
|
||||
req.userRestrictions = getUserRestrictions(groupPolicy)
|
||||
}
|
||||
// also attach the user's restrictions (the capabilities they don't have)
|
||||
req.userRestrictions = getUserRestrictions(groupPolicy)
|
||||
next()
|
||||
} catch (error) {
|
||||
if (error instanceof UserNotFoundError) {
|
||||
|
@ -69,10 +76,14 @@ function requirePermission(...requiredCapabilities) {
|
|||
return next(new Error('no user'))
|
||||
}
|
||||
try {
|
||||
// get the group policy applying to the user
|
||||
const { groupPolicy, managedUsersEnabled } =
|
||||
await ManagedUsersHandler.promises.getEnrollmentForUser(req.user)
|
||||
|
||||
const result =
|
||||
(
|
||||
await Modules.promises.hooks.fire(
|
||||
'getManagedUsersEnrollmentForUser',
|
||||
req.user
|
||||
)
|
||||
)[0] || {}
|
||||
const { groupPolicy, managedUsersEnabled } = result
|
||||
if (!managedUsersEnabled) {
|
||||
return next()
|
||||
}
|
||||
|
|
|
@ -1,210 +0,0 @@
|
|||
const { callbackify } = require('util')
|
||||
const { Subscription } = require('../../models/Subscription')
|
||||
const { GroupPolicy } = require('../../models/GroupPolicy')
|
||||
const { User } = require('../../models/User')
|
||||
const ManagedUsersPolicy = require('./ManagedUsersPolicy')
|
||||
const OError = require('@overleaf/o-error')
|
||||
const settings = require('@overleaf/settings')
|
||||
const {
|
||||
UserNotFoundError,
|
||||
SubscriptionNotFoundError,
|
||||
} = require('../Errors/Errors')
|
||||
const UserGetter = require('../User/UserGetter')
|
||||
const UserUpdater = require('../User/UserUpdater')
|
||||
const EmailHandler = require('../Email/EmailHandler')
|
||||
const logger = require('@overleaf/logger')
|
||||
|
||||
/**
|
||||
* This module contains functions for handling managed users in a
|
||||
* group subscription.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enables managed users for a given subscription by creating a new
|
||||
* group policy with default settings for managed users and updating
|
||||
* the subscription to use the new policy.
|
||||
* @async
|
||||
* @function
|
||||
* @param {string} subscriptionId - The ID of the subscription to enable
|
||||
* managed users for.
|
||||
* @returns {Promise<void>} - A Promise that resolves when the subscription
|
||||
* has been updated with the new group policy.
|
||||
*/
|
||||
async function enableManagedUsers(subscriptionId) {
|
||||
const subscription = await Subscription.findById(subscriptionId).exec()
|
||||
|
||||
// create a new Group policy with the default settings for managed users
|
||||
const policy = ManagedUsersPolicy.getDefaultPolicy()
|
||||
const groupPolicy = new GroupPolicy(policy)
|
||||
await groupPolicy.save()
|
||||
// update the subscription to use the new policy
|
||||
subscription.groupPolicy = groupPolicy._id
|
||||
subscription.managedUsersEnabled = true
|
||||
await subscription.save()
|
||||
|
||||
await _sendEmailToGroupMembers(subscriptionId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables managed users for a given subscription by removing the
|
||||
* group policy and deleting enrolment information for all managed users.
|
||||
* @async
|
||||
* @function
|
||||
* @param {string} subscriptionId - The ID of the subscription to disable
|
||||
* managed users for.
|
||||
* @returns {Promise<void>} - A Promise that resolves when the subscription and
|
||||
* users have been updated.
|
||||
*/
|
||||
async function disableManagedUsers(subscriptionId) {
|
||||
const subscription = await Subscription.findById(subscriptionId).exec()
|
||||
for (const userId of subscription.member_ids || []) {
|
||||
const user = await UserGetter.promises.getUser(userId, { enrollment: 1 })
|
||||
if (
|
||||
user.enrollment?.managedBy?.toString() === subscription._id.toString()
|
||||
) {
|
||||
await UserUpdater.promises.updateUser(userId, {
|
||||
$unset: { enrollment: 1 },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
subscription.groupPolicy = undefined
|
||||
subscription.managedUsersEnabled = false
|
||||
await subscription.save()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the group policy for a user enrolled in a managed group.
|
||||
* @async
|
||||
* @function
|
||||
* @param {Object} requestedUser - The user object to retrieve the group policy for.
|
||||
* @returns {Promise<Object>} - A Promise that resolves with the group policy
|
||||
* and subscription objects for the user's enrollment, or null if it does not exist.
|
||||
*/
|
||||
async function getEnrollmentForUser(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 {}
|
||||
}
|
||||
// retrieve the subscription and the group policy (without the _id field)
|
||||
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 },
|
||||
})
|
||||
}
|
||||
|
||||
// check whether the user is an admin of the subscription
|
||||
const isManagedGroupAdmin = user._id.equals(subscription.admin_id)
|
||||
|
||||
// return the group policy as a plain object (without the __v field)
|
||||
const groupPolicy = subscription.groupPolicy.toObject({
|
||||
versionKey: false,
|
||||
})
|
||||
|
||||
return {
|
||||
groupPolicy,
|
||||
managedUsersEnabled: subscription.managedUsersEnabled,
|
||||
managedBy: user.enrollment.managedBy,
|
||||
isManagedGroupAdmin,
|
||||
}
|
||||
}
|
||||
|
||||
async function enrollInSubscription(userId, subscription) {
|
||||
// check whether the user is already enrolled in a subscription
|
||||
const user = await User.findOne(
|
||||
{
|
||||
_id: userId,
|
||||
'enrollment.managedBy': { $exists: true },
|
||||
},
|
||||
{ _id: 1 }
|
||||
).exec()
|
||||
if (user != null) {
|
||||
throw new OError('User is already enrolled in a subscription', {
|
||||
userId,
|
||||
subscriptionId: subscription._id,
|
||||
})
|
||||
}
|
||||
// update the user to be enrolled in the subscription
|
||||
const updatedUser = await User.findOneAndUpdate(
|
||||
{ _id: userId, 'enrollment.managedBy': { $exists: false } },
|
||||
{
|
||||
enrollment: {
|
||||
managedBy: subscription._id,
|
||||
enrolledAt: new Date(),
|
||||
},
|
||||
},
|
||||
{ new: true }
|
||||
).exec()
|
||||
// check whether the enrollment succeeded
|
||||
if (
|
||||
!updatedUser ||
|
||||
!subscription.equals(updatedUser?.enrollment?.managedBy)
|
||||
) {
|
||||
throw new OError('Failed to enroll user in subscription', {
|
||||
userId,
|
||||
subscriptionId: subscription._id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send email to all group members, irregardless of the member status.
|
||||
* @async
|
||||
* @function
|
||||
* @param {string} subscriptionId - The ID of the subscription to enable
|
||||
* managed users for.
|
||||
* @returns {Promise<void>} - A Promise that resolves when all the `sendEmail` function has been sent,
|
||||
* irregardless of whether they're successful or failed.
|
||||
*/
|
||||
async function _sendEmailToGroupMembers(subscriptionId) {
|
||||
const EMAIL_DELAY_IN_MS = 0
|
||||
|
||||
const subscription = await Subscription.findById(subscriptionId)
|
||||
.populate('member_ids', 'email')
|
||||
.populate('admin_id', ['first_name', 'last_name', 'email'])
|
||||
.exec()
|
||||
|
||||
// On failure, log the error and carry on so that one email failing does not prevent other emails sending
|
||||
for (const recipient of subscription.member_ids) {
|
||||
try {
|
||||
const opts = {
|
||||
to: recipient.email,
|
||||
admin: subscription.admin_id,
|
||||
groupName: subscription.teamName,
|
||||
acceptInviteUrl: `${settings.siteUrl}/subscription/${subscriptionId}/enrollment/`,
|
||||
}
|
||||
EmailHandler.sendDeferredEmail(
|
||||
'surrenderAccountForManagedUsers',
|
||||
opts,
|
||||
EMAIL_DELAY_IN_MS
|
||||
)
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
{ err, userId: recipient._id },
|
||||
'could not send notification email to surrender account'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
promises: {
|
||||
enableManagedUsers,
|
||||
disableManagedUsers,
|
||||
getEnrollmentForUser,
|
||||
enrollInSubscription,
|
||||
},
|
||||
enableManagedUsers: callbackify(enableManagedUsers),
|
||||
getEnrollmentForUser: callbackify(getEnrollmentForUser),
|
||||
enrollInSubscription: callbackify(enrollInSubscription),
|
||||
disableManagedUsers: callbackify(disableManagedUsers),
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
const {
|
||||
registerCapability,
|
||||
registerPolicy,
|
||||
} = require('../Authorization/PermissionsManager')
|
||||
const { getUsersSubscription, getGroupSubscriptionsMemberOf } =
|
||||
require('./SubscriptionLocator').promises
|
||||
const { subscriptionIsCanceledOrExpired } = require('./RecurlyClient')
|
||||
|
||||
// This file defines the capabilities and policies that are used to
|
||||
// determine what managed users can and cannot do.
|
||||
|
||||
// Register the capability for a user to delete their own account.
|
||||
registerCapability('delete-own-account', { default: true })
|
||||
|
||||
// Register the capability for a user to add a secondary email to their account.
|
||||
registerCapability('add-secondary-email', { default: true })
|
||||
|
||||
// Register the capability for a user to add an affiliation to their account.
|
||||
registerCapability('add-affiliation', { default: true })
|
||||
|
||||
// Register the capability for a user to endorse an email address.
|
||||
registerCapability('endorse-email', { default: true })
|
||||
|
||||
// Register the capability for a user to sign in with Google to their account
|
||||
registerCapability('link-google-sso', { default: true })
|
||||
|
||||
// Register the capability for a user to link other third party SSO to their account
|
||||
registerCapability('link-other-third-party-sso', { default: true })
|
||||
|
||||
// Register the capability for a user to leave a managed group subscription.
|
||||
registerCapability('leave-group-subscription', { default: true })
|
||||
|
||||
// Register the capability for a user to start a subscription.
|
||||
registerCapability('start-subscription', { default: true })
|
||||
|
||||
// Register the capability for a user to join a subscription.
|
||||
registerCapability('join-subscription', { default: true })
|
||||
|
||||
// Register the capability for a user to reactivate a subscription.
|
||||
registerCapability('reactivate-subscription', { default: true })
|
||||
|
||||
// Register a policy to prevent a user deleting their own account.
|
||||
registerPolicy('userCannotDeleteOwnAccount', {
|
||||
'delete-own-account': false,
|
||||
})
|
||||
|
||||
// Register a policy to prevent a user having secondary email addresses on their account.
|
||||
registerPolicy(
|
||||
'userCannotHaveSecondaryEmail',
|
||||
{
|
||||
'add-secondary-email': false,
|
||||
'add-affiliation': false,
|
||||
'endorse-email': false,
|
||||
},
|
||||
{
|
||||
validator: async ({ user }) => {
|
||||
// return true if the user does not have any secondary emails
|
||||
return user.emails.length === 1
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Register a policy to prevent a user leaving the group subscription they are managed by.
|
||||
registerPolicy('userCannotLeaveManagingGroupSubscription', {
|
||||
'leave-group-subscription': false,
|
||||
})
|
||||
|
||||
// Register a policy to prevent a user having third-party SSO linked to their account.
|
||||
registerPolicy(
|
||||
'userCannotHaveGoogleSSO',
|
||||
{ 'link-google-sso': false },
|
||||
{
|
||||
// return true if the user does not have Google SSO linked
|
||||
validator: async ({ user }) =>
|
||||
!user.thirdPartyIdentifiers?.some(
|
||||
identifier => identifier.providerId === 'google'
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
// Register a policy to prevent a user having third-party SSO linked to their account.
|
||||
registerPolicy(
|
||||
'userCannotHaveOtherThirdPartySSO',
|
||||
{ 'link-other-third-party-sso': false },
|
||||
{
|
||||
// return true if the user does not have any other third party SSO linked
|
||||
validator: async ({ user }) =>
|
||||
!user.thirdPartyIdentifiers?.some(
|
||||
identifier => identifier.providerId !== 'google'
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
// Register a policy to prevent a user having an active subscription or
|
||||
// being a member of another group subscription.
|
||||
registerPolicy(
|
||||
'userCannotHaveSubscription',
|
||||
{
|
||||
'start-subscription': false,
|
||||
'join-subscription': false,
|
||||
'reactivate-subscription': false,
|
||||
},
|
||||
{
|
||||
validator: async ({ user, subscription }) => {
|
||||
const usersSubscription = await getUsersSubscription(user)
|
||||
|
||||
// The user can be enrolled if:
|
||||
// 1. they do not have a subscription and are not a member of another subscription (apart from the managed group subscription)
|
||||
// 2. they have a subscription and it is canceled or expired
|
||||
// 3. they have a subscription and it is the subscription they are trying to join as a managed user
|
||||
// The last case is to allow the admin to join their own subscription as a managed user
|
||||
|
||||
const userHasSubscription =
|
||||
Boolean(usersSubscription) &&
|
||||
!subscriptionIsCanceledOrExpired(usersSubscription)
|
||||
|
||||
const userIsThisGroupAdmin =
|
||||
Boolean(usersSubscription) &&
|
||||
usersSubscription._id.toString() === subscription._id.toString()
|
||||
|
||||
const userMemberOfSubscriptions = await getGroupSubscriptionsMemberOf(
|
||||
user
|
||||
)
|
||||
|
||||
const isMemberOfOtherSubscriptions = userMemberOfSubscriptions.some(
|
||||
sub => {
|
||||
// ignore the subscription of the managed group itself
|
||||
if (sub._id.toString() === subscription._id.toString()) {
|
||||
return false
|
||||
}
|
||||
// ignore the user's own subscription
|
||||
if (
|
||||
usersSubscription &&
|
||||
sub._id.toString() === usersSubscription._id.toString()
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
(!userHasSubscription || userIsThisGroupAdmin) &&
|
||||
!isMemberOfOtherSubscriptions
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns the default group policy for managed users.
|
||||
* Managed users are users who are part of a group subscription, and are
|
||||
* managed by the group policy. Managed users have limited functionality.
|
||||
* This method returns an object with boolean values for each policy that
|
||||
* indicates whether the policy is enforced or not.
|
||||
*
|
||||
* @returns {Object} An object with boolean values for each policy that indicates whether it is enforced or not.
|
||||
* @function
|
||||
*/
|
||||
function getDefaultPolicy() {
|
||||
return {
|
||||
userCannotDeleteOwnAccount: true,
|
||||
userCannotHaveSecondaryEmail: true,
|
||||
userCannotHaveSubscription: true,
|
||||
userCannotLeaveManagingGroupSubscription: true,
|
||||
userCannotHaveGoogleSSO: false, // we want to allow google SSO by default
|
||||
userCannotHaveOtherThirdPartySSO: true,
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getDefaultPolicy,
|
||||
}
|
|
@ -2,7 +2,6 @@ const { promisify } = require('util')
|
|||
const { Subscription } = require('../../models/Subscription')
|
||||
const { DeletedSubscription } = require('../../models/DeletedSubscription')
|
||||
const logger = require('@overleaf/logger')
|
||||
const { SSOConfig } = require('../../models/SSOConfig')
|
||||
require('./GroupPlansData') // make sure dynamic group plans are loaded
|
||||
|
||||
const SubscriptionLocator = {
|
||||
|
@ -133,11 +132,6 @@ const SubscriptionLocator = {
|
|||
},
|
||||
}
|
||||
|
||||
async function hasSSOEnabled(subscription) {
|
||||
const ssoConfig = await SSOConfig.findById(subscription.ssoConfig).exec()
|
||||
return !!ssoConfig?.enabled
|
||||
}
|
||||
|
||||
SubscriptionLocator.promises = {
|
||||
getUsersSubscription: promisify(SubscriptionLocator.getUsersSubscription),
|
||||
getUserIndividualSubscription: promisify(
|
||||
|
@ -170,6 +164,5 @@ SubscriptionLocator.promises = {
|
|||
hasRecurlyGroupSubscription: promisify(
|
||||
SubscriptionLocator.hasRecurlyGroupSubscription
|
||||
),
|
||||
hasSSOEnabled,
|
||||
}
|
||||
module.exports = SubscriptionLocator
|
||||
|
|
|
@ -84,9 +84,9 @@ async function viewInvite(req, res, next) {
|
|||
personalSubscription.recurlySubscription_id &&
|
||||
personalSubscription.recurlySubscription_id !== ''
|
||||
|
||||
const groupSSOActive = await SubscriptionLocator.promises.hasSSOEnabled(
|
||||
subscription
|
||||
)
|
||||
const groupSSOActive = (
|
||||
await Modules.promises.hooks.fire('hasGroupSSOEnabled', subscription)
|
||||
)?.[0]
|
||||
|
||||
if (subscription?.groupPolicy) {
|
||||
if (!subscription.populated('groupPolicy')) {
|
||||
|
@ -194,9 +194,9 @@ async function acceptInvite(req, res, next) {
|
|||
token,
|
||||
userId
|
||||
)
|
||||
const groupSSOActive = await SubscriptionLocator.promises.hasSSOEnabled(
|
||||
subscription
|
||||
)
|
||||
const groupSSOActive = (
|
||||
await Modules.promises.hooks.fire('hasGroupSSOEnabled', subscription)
|
||||
)?.[0]
|
||||
|
||||
res.json({ groupSSOActive })
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ const logger = require('@overleaf/logger')
|
|||
const crypto = require('crypto')
|
||||
|
||||
const settings = require('@overleaf/settings')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
const { ObjectId } = require('mongodb')
|
||||
|
||||
const { Subscription } = require('../../models/Subscription')
|
||||
|
@ -11,7 +12,6 @@ const UserGetter = require('../User/UserGetter')
|
|||
const SubscriptionLocator = require('./SubscriptionLocator')
|
||||
const SubscriptionUpdater = require('./SubscriptionUpdater')
|
||||
const LimitationsManager = require('./LimitationsManager')
|
||||
const ManagedUsersHandler = require('./ManagedUsersHandler')
|
||||
|
||||
const EmailHandler = require('../Email/EmailHandler')
|
||||
const EmailHelper = require('../Helpers/EmailHelper')
|
||||
|
@ -22,7 +22,6 @@ const {
|
|||
callbackifyMultiResult,
|
||||
} = require('@overleaf/promise-utils')
|
||||
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
|
||||
async function getInvite(token) {
|
||||
const subscription = await Subscription.findOne({
|
||||
|
@ -74,7 +73,8 @@ async function acceptInvite(token, userId) {
|
|||
await SubscriptionUpdater.promises.addUserToGroup(subscription._id, userId)
|
||||
|
||||
if (subscription.managedUsersEnabled) {
|
||||
await ManagedUsersHandler.promises.enrollInSubscription(
|
||||
await Modules.promises.hooks.fire(
|
||||
'enrollInManagedSubscription',
|
||||
userId,
|
||||
subscription
|
||||
)
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
import GroupSettings from '../../../../modules/managed-users/frontend/js/components/group-settings'
|
||||
import { useMeta } from '../../hooks/use-meta'
|
||||
import useFetchMock from '../../hooks/use-fetch-mock'
|
||||
|
||||
export const GroupSettingsWithManagedUsersDisabledAndNoSSOFeature = () => {
|
||||
useMeta({
|
||||
'ol-managedUsersEnabled': false,
|
||||
'ol-hasGroupSSOFeature': false,
|
||||
})
|
||||
return <GroupSettings />
|
||||
}
|
||||
|
||||
export const GroupSettingsWithManagedUsersDisabledAndSSOFeature = () => {
|
||||
useFetchMock(fetchMock =>
|
||||
fetchMock.get('express:/manage/groups/:id/settings/sso', {})
|
||||
)
|
||||
useMeta({
|
||||
'ol-managedUsersEnabled': false,
|
||||
'ol-hasGroupSSOFeature': true,
|
||||
})
|
||||
return <GroupSettings />
|
||||
}
|
||||
|
||||
export const GroupSettingsWithManagedUsersEnabledAndNoSSOFeature = () => {
|
||||
useMeta({
|
||||
'ol-managedUsersEnabled': true,
|
||||
'ol-hasGroupSSOFeature': false,
|
||||
})
|
||||
return <GroupSettings />
|
||||
}
|
||||
|
||||
export const GroupSettingsWithManagedUsersEnabledAndSSOFeatureNotConfigured =
|
||||
() => {
|
||||
useMeta({
|
||||
'ol-managedUsersEnabled': true,
|
||||
'ol-hasGroupSSOFeature': true,
|
||||
})
|
||||
useFetchMock(fetchMock => {
|
||||
fetchMock.get(
|
||||
'express:/manage/groups/:id/settings/sso',
|
||||
{},
|
||||
{
|
||||
delay: 500,
|
||||
}
|
||||
)
|
||||
})
|
||||
return <GroupSettings />
|
||||
}
|
||||
|
||||
export const GroupSettingsWithManagedUsersEnabledAndSSOFeatureConfigured =
|
||||
() => {
|
||||
const config = {
|
||||
entryPoint: 'http://idp.example.com/entry_point',
|
||||
certificate:
|
||||
'X1JQa2tWQmYzYlN1aUZORVhzZGpURVp3c0U4T3J3bWtjYVZsQ2h4MkRyRUpOVGtxV2hXcG9KbG1WZ2hYclB1YUVNeFVjM0pFZW5Zd1dQRzB5bldxWm5xYm5IdEJ5d1VGQlQ2RWJ1bHdQeJ0VmpoMkFUeHlIaE5KUVBqYm1iUlB1ckZjQnZzRzlZWW5RZVpYU3pKd3V3Z1l3cE5ZeE9XZkx5ZlVJZGVKQk5JkFUeHlIaE5KUV',
|
||||
signatureAlgorithm: 'sha256',
|
||||
userIdAttribute: 'email',
|
||||
enabled: true,
|
||||
}
|
||||
useFetchMock(fetchMock => {
|
||||
fetchMock.get('express:/manage/groups/:id/settings/sso', config, {
|
||||
delay: 500,
|
||||
})
|
||||
})
|
||||
|
||||
useMeta({
|
||||
'ol-managedUsersEnabled': true,
|
||||
'ol-hasGroupSSOFeature': true,
|
||||
})
|
||||
return <GroupSettings />
|
||||
}
|
||||
|
||||
export const GroupSettingsWithManagedUsersDisabledAndSSOFeatureConfigured =
|
||||
() => {
|
||||
const config = {
|
||||
entryPoint: 'http://idp.example.com/entry_point',
|
||||
certificate:
|
||||
'X1JQa2tWQmYzYlN1aUZORVhzZGpURVp3c0U4T3J3bWtjYVZsQ2h4MkRyRUpOVGtxV2hXcG9KbG1WZ2hYclB1YUVNeFVjM0pFZW5Zd1dQRzB5bldxWm5xYm5IdEJ5d1VGQlQ2RWJ1bHdQeJ0VmpoMkFUeHlIaE5KUVBqYm1iUlB1ckZjQnZzRzlZWW5RZVpYU3pKd3V3Z1l3cE5ZeE9XZkx5ZlVJZGVKQk5JkFUeHlIaE5KUV',
|
||||
signatureAlgorithm: 'sha256',
|
||||
userIdAttribute: 'email',
|
||||
enabled: false,
|
||||
}
|
||||
useFetchMock(fetchMock => {
|
||||
fetchMock.get('express:/manage/groups/:id/settings/sso', config, {
|
||||
delay: 500,
|
||||
})
|
||||
})
|
||||
|
||||
useMeta({
|
||||
'ol-managedUsersEnabled': true,
|
||||
'ol-hasGroupSSOFeature': true,
|
||||
})
|
||||
return <GroupSettings />
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'Subscription / Managed Users',
|
||||
component: GroupSettings,
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
import SSODisableModal, {
|
||||
type SSODisableModalProps,
|
||||
} from '../../../../modules/managed-users/frontend/js/components/modals/sso-disable-modal'
|
||||
import useFetchMock from '../../hooks/use-fetch-mock'
|
||||
import { useMeta } from '../../hooks/use-meta'
|
||||
|
||||
export const DisableSSOModalDefault = (args: SSODisableModalProps) => {
|
||||
useMeta({ 'ol-groupId': '123' })
|
||||
useFetchMock(fetchMock => {
|
||||
fetchMock.post('express:/manage/groups/:id/settings/disableSSO', 200, {
|
||||
delay: 500,
|
||||
})
|
||||
})
|
||||
return <SSODisableModal {...args} />
|
||||
}
|
||||
|
||||
export const DisableSSOModalError = (args: SSODisableModalProps) => {
|
||||
useMeta({ 'ol-groupId': '123' })
|
||||
useFetchMock(fetchMock => {
|
||||
fetchMock.post('express:/manage/groups/:id/settings/enableSSO', 500, {
|
||||
delay: 500,
|
||||
})
|
||||
})
|
||||
return <SSODisableModal {...args} />
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'Subscription / SSO / Disable Modal',
|
||||
component: SSODisableModal,
|
||||
args: {
|
||||
show: true,
|
||||
},
|
||||
argTypes: {
|
||||
handleHide: { action: 'close modal' },
|
||||
onDisableSSO: { action: 'callback' },
|
||||
},
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
import SSOEnableModal, {
|
||||
type SSOEnableModalProps,
|
||||
} from '../../../../modules/managed-users/frontend/js/components/modals/sso-enable-modal'
|
||||
import useFetchMock from '../../hooks/use-fetch-mock'
|
||||
import { useMeta } from '../../hooks/use-meta'
|
||||
|
||||
export const EnableSSOModalDefault = (args: SSOEnableModalProps) => {
|
||||
useMeta({ 'ol-groupId': '123' })
|
||||
useFetchMock(fetchMock => {
|
||||
fetchMock.post('express:/manage/groups/:id/settings/enableSSO', 200, {
|
||||
delay: 500,
|
||||
})
|
||||
})
|
||||
return <SSOEnableModal {...args} />
|
||||
}
|
||||
|
||||
export const EnableSSOModalError = (args: SSOEnableModalProps) => {
|
||||
useMeta({ 'ol-groupId': '123' })
|
||||
useFetchMock(fetchMock => {
|
||||
fetchMock.post('express:/manage/groups/:id/settings/enableSSO', 500, {
|
||||
delay: 500,
|
||||
})
|
||||
})
|
||||
return <SSOEnableModal {...args} />
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'Subscription / SSO / Enable Modal',
|
||||
component: SSOEnableModal,
|
||||
args: {
|
||||
show: true,
|
||||
},
|
||||
argTypes: {
|
||||
handleHide: { action: 'close modal' },
|
||||
onEnableSSO: { action: 'callback' },
|
||||
},
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
import { useMeta } from '../../hooks/use-meta'
|
||||
import SSOLinkConfirm from '../../../../modules/managed-users/frontend/js/components/sso-link-confirm'
|
||||
|
||||
export const LinkConfirmInterstitial = () => {
|
||||
return <SSOLinkConfirm />
|
||||
}
|
||||
|
||||
export const LinkConfirmInterstitialWithError = () => {
|
||||
useMeta({ 'ol-error': 'SAMLInvalidSignatureError' })
|
||||
return <SSOLinkConfirm />
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'Subscription / SSO / Link',
|
||||
component: SSOLinkConfirm,
|
||||
decorators: [
|
||||
(Story: any) => {
|
||||
useMeta({ 'ol-groupId': '123' })
|
||||
useMeta({ 'ol-email': 'user@example.com' })
|
||||
return (
|
||||
<div className="container">
|
||||
<Story />
|
||||
</div>
|
||||
)
|
||||
},
|
||||
],
|
||||
}
|
|
@ -111,7 +111,7 @@
|
|||
// module styles
|
||||
// TODO: find a way for modules to add styles dynamically
|
||||
@import 'modules/symbol-palette.less';
|
||||
@import 'modules/managed-users.less';
|
||||
@import 'modules/group-settings.less';
|
||||
@import 'modules/git-bridge-modal.less';
|
||||
@import 'modules/admin-panel.less';
|
||||
@import 'modules/overleaf-integration.less';
|
||||
|
|
|
@ -144,5 +144,5 @@
|
|||
@import 'modules/symbol-palette.less';
|
||||
@import 'modules/admin-panel.less';
|
||||
@import 'modules/git-bridge-modal.less';
|
||||
@import 'modules/managed-users.less';
|
||||
@import 'modules/group-settings.less';
|
||||
@import 'modules/overleaf-integration.less';
|
||||
|
|
|
@ -2,13 +2,13 @@ const { db, ObjectId } = require('../../../../app/src/infrastructure/mongodb')
|
|||
const { expect } = require('chai')
|
||||
const { promisify } = require('util')
|
||||
const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater')
|
||||
const ManagedUsersHandler = require('../../../../app/src/Features/Subscription/ManagedUsersHandler')
|
||||
const PermissionsManager = require('../../../../app/src/Features/Authorization/PermissionsManager')
|
||||
const SSOConfigManager = require('../../../../modules/managed-users/app/src/SSOConfigManager')
|
||||
const SSOConfigManager = require('../../../../modules/group-settings/app/src/sso/SSOConfigManager')
|
||||
const SubscriptionModel =
|
||||
require('../../../../app/src/models/Subscription').Subscription
|
||||
const DeletedSubscriptionModel =
|
||||
require('../../../../app/src/models/DeletedSubscription').DeletedSubscription
|
||||
const Modules = require('../../../../app/src/infrastructure/Modules')
|
||||
|
||||
class Subscription {
|
||||
constructor(options = {}) {
|
||||
|
@ -78,11 +78,17 @@ class Subscription {
|
|||
}
|
||||
|
||||
enableManagedUsers(callback) {
|
||||
ManagedUsersHandler.enableManagedUsers(this._id, callback)
|
||||
Modules.hooks.fire('enableManagedUsers', this._id, callback)
|
||||
}
|
||||
|
||||
getEnrollmentForUser(user, callback) {
|
||||
ManagedUsersHandler.getEnrollmentForUser(user, callback)
|
||||
Modules.hooks.fire(
|
||||
'getManagedUsersEnrollmentForUser',
|
||||
user,
|
||||
(error, [enrollment]) => {
|
||||
callback(error, enrollment)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
getCapabilities(groupPolicy) {
|
||||
|
@ -98,7 +104,12 @@ class Subscription {
|
|||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
ManagedUsersHandler.enrollInSubscription(user._id, subscription, callback)
|
||||
Modules.hooks.fire(
|
||||
'enrollInManagedSubscription',
|
||||
user._id,
|
||||
subscription,
|
||||
callback
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import GroupSettingsSSORoot from '../../../../../../modules/managed-users/frontend/js/components/sso/group-settings-sso-root'
|
||||
import GroupSettingsSSORoot from '../../../../../../modules/group-settings/frontend/js/components/sso/group-settings-sso-root'
|
||||
|
||||
function GroupSettingsSSOComponent() {
|
||||
return (
|
||||
|
|
|
@ -76,12 +76,6 @@ describe('TeamInvitesHandler', function () {
|
|||
},
|
||||
}
|
||||
|
||||
this.ManagedUsersHandler = {
|
||||
promises: {
|
||||
enrollInSubscription: sinon.stub().resolves(),
|
||||
},
|
||||
}
|
||||
|
||||
this.newToken = 'bbbbbbbbb'
|
||||
|
||||
this.crypto = {
|
||||
|
@ -128,7 +122,6 @@ describe('TeamInvitesHandler', function () {
|
|||
'./SubscriptionUpdater': this.SubscriptionUpdater,
|
||||
'./LimitationsManager': this.LimitationsManager,
|
||||
'../Email/EmailHandler': this.EmailHandler,
|
||||
'./ManagedUsersHandler': this.ManagedUsersHandler,
|
||||
'../Notifications/NotificationsBuilder': this.NotificationsBuilder,
|
||||
'../../infrastructure/Modules': (this.Modules = {
|
||||
promises: { hooks: { fire: sinon.stub().resolves() } },
|
||||
|
@ -393,7 +386,8 @@ describe('TeamInvitesHandler', function () {
|
|||
|
||||
this.TeamInvitesHandler.acceptInvite('dddddddd', this.user.id, () => {
|
||||
sinon.assert.calledWith(
|
||||
this.ManagedUsersHandler.promises.enrollInSubscription,
|
||||
this.Modules.promises.hooks.fire,
|
||||
'enrollInManagedSubscription',
|
||||
this.user.id,
|
||||
this.subscription
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue