[web] SSO linking for existing group members (#15471)

* [web] SSO linking for existing group users

GitOrigin-RevId: 22a5a5a28a213860f88ae0284c1ef51a31bb268f
This commit is contained in:
Miguel Serrano 2023-10-31 13:16:49 +01:00 committed by Copybot
parent 1f56441184
commit e22e8ff7a8
2 changed files with 110 additions and 1 deletions

View file

@ -0,0 +1,100 @@
const { SSOConfig } = require('../../models/SSOConfig')
const UserAuditLogHandler = require('../User/UserAuditLogHandler')
const UserUpdater = require('../User/UserUpdater')
const SAMLIdentityManager = require('../User/SAMLIdentityManager')
const { User } = require('../../models/User')
const Errors = require('../Errors/Errors')
async function canEnrollInSubscription(userId, subscription) {
const ssoEnabled = await isSSOEnabled(subscription)
if (!ssoEnabled) {
return false
}
const userIsMember = subscription.member_ids.some(
memberId => memberId.toString() === userId.toString()
)
if (!userIsMember) {
return false
}
const user = await User.findOne(
{ _id: userId },
{ projection: { enrollment: 1 } }
).exec()
const userIsEnrolled = user.enrollment?.sso?.some(
enrollment => enrollment.groupId.toString() === subscription._id.toString()
)
if (userIsEnrolled) {
return false
}
return true
}
async function enrollInSubscription(
userId,
subscription,
externalUserId,
userIdAttribute,
auditLog
) {
const canEnroll = await canEnrollInSubscription(userId, subscription)
if (!canEnroll) {
throw new Errors.SubscriptionNotFoundError(
'cannot enroll user in SSO subscription',
{
info: { userId, subscription },
}
)
}
const providerId = `ol-group-subscription-id:${subscription._id.toString()}`
const userBySamlIdentifier = await SAMLIdentityManager.getUser(
providerId,
externalUserId,
userIdAttribute
)
if (userBySamlIdentifier) {
throw new Errors.SAMLIdentityExistsError()
}
const samlIdentifiers = {
externalUserId,
userIdAttribute,
providerId,
}
await UserUpdater.promises.updateUser(userId, {
$push: {
samlIdentifiers,
'enrollment.sso': {
groupId: subscription._id,
linkedAt: new Date(),
primary: true,
},
},
})
await UserAuditLogHandler.promises.addEntry(
userId,
'group-sso-link',
auditLog.initiatorId,
auditLog.ipAddress,
samlIdentifiers
)
}
async function isSSOEnabled(subscription) {
const ssoConfig = await SSOConfig.findById(subscription.ssoConfig).exec()
return ssoConfig?.enabled
}
module.exports = {
promises: {
canEnrollInSubscription,
enrollInSubscription,
isSSOEnabled,
},
}

View file

@ -32,7 +32,16 @@ const UserSchema = new Schema(
institution: { type: String, default: '' },
hashedPassword: String,
enrollment: {
// sso: { type: Boolean, default: false },
sso: [
{
groupId: {
type: ObjectId,
ref: 'Subscription',
},
linkedAt: Date,
primary: { type: Boolean, default: false },
},
],
managedBy: {
type: ObjectId,
ref: 'Subscription',