2019-08-27 16:48:00 -04:00
|
|
|
const Errors = require('../Errors/Errors')
|
2019-09-12 10:01:12 -04:00
|
|
|
const logger = require('logger-sharelatex')
|
|
|
|
const OError = require('@overleaf/o-error')
|
2019-08-27 16:48:00 -04:00
|
|
|
const { User } = require('../../models/User')
|
2019-09-12 10:01:12 -04:00
|
|
|
const UserGetter = require('../User/UserGetter')
|
|
|
|
const UserUpdater = require('../User/UserUpdater')
|
|
|
|
|
|
|
|
function _addIdentifier(userId, externalUserId, providerId) {
|
2019-09-30 09:21:31 -04:00
|
|
|
providerId = providerId.toString()
|
2019-09-12 10:01:12 -04:00
|
|
|
const query = {
|
|
|
|
_id: userId,
|
|
|
|
'samlIdentifiers.providerId': {
|
|
|
|
$ne: providerId
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const update = {
|
|
|
|
$push: {
|
|
|
|
samlIdentifiers: {
|
|
|
|
externalUserId,
|
|
|
|
providerId
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// First update user.samlIdentifiers
|
|
|
|
let updatedUser = User.findOneAndUpdate(query, update, { new: true }).exec()
|
|
|
|
try {
|
|
|
|
updatedUser = User.findOneAndUpdate(query, update, { new: true }).exec()
|
|
|
|
} catch (err) {
|
|
|
|
if (err && err.code === 11000) {
|
|
|
|
throw new Errors.SAMLIdentityExistsError()
|
|
|
|
} else if (err != null) {
|
|
|
|
logger.log(err, userId, 'failed to add institution SAML identifier')
|
|
|
|
throw new OError(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return updatedUser
|
|
|
|
}
|
|
|
|
|
2019-09-30 09:21:31 -04:00
|
|
|
function _getUserQuery(providerId, externalUserId) {
|
|
|
|
externalUserId = externalUserId.toString()
|
|
|
|
providerId = providerId.toString()
|
|
|
|
const query = {
|
|
|
|
'samlIdentifiers.externalUserId': externalUserId,
|
|
|
|
'samlIdentifiers.providerId': providerId
|
|
|
|
}
|
|
|
|
return query
|
|
|
|
}
|
|
|
|
|
|
|
|
async function _addInstitutionEmail(userId, email, providerId) {
|
2019-09-12 10:01:12 -04:00
|
|
|
const user = await UserGetter.promises.getUser(userId)
|
2019-09-30 09:21:31 -04:00
|
|
|
const query = {
|
|
|
|
_id: userId,
|
|
|
|
'emails.email': email
|
|
|
|
}
|
|
|
|
const update = {
|
|
|
|
$set: {
|
|
|
|
'emails.$.samlProviderId': providerId.toString()
|
|
|
|
}
|
|
|
|
}
|
2019-09-12 10:01:12 -04:00
|
|
|
if (user == null) {
|
|
|
|
logger.log(userId, 'could not find user for institution SAML linking')
|
|
|
|
throw new Errors.NotFoundError('user not found')
|
|
|
|
}
|
|
|
|
const emailAlreadyAssociated = user.emails.find(e => e.email === email)
|
|
|
|
if (emailAlreadyAssociated && emailAlreadyAssociated.confirmedAt) {
|
2019-09-30 09:21:31 -04:00
|
|
|
await UserUpdater.promises.updateUser(query, update)
|
2019-09-12 10:01:12 -04:00
|
|
|
} else if (emailAlreadyAssociated) {
|
|
|
|
// add and confirm email
|
2019-09-30 09:21:31 -04:00
|
|
|
await UserUpdater.promises.confirmEmail(user._id, email)
|
|
|
|
await UserUpdater.promises.updateUser(query, update)
|
2019-09-12 10:01:12 -04:00
|
|
|
} else {
|
|
|
|
// add and confirm email
|
2019-09-30 09:21:31 -04:00
|
|
|
await UserUpdater.promises.addEmailAddress(user._id, email)
|
|
|
|
await UserUpdater.promises.confirmEmail(user._id, email)
|
|
|
|
await UserUpdater.promises.updateUser(query, update)
|
2019-09-12 10:01:12 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-27 16:48:00 -04:00
|
|
|
async function getUser(providerId, externalUserId) {
|
|
|
|
if (providerId == null || externalUserId == null) {
|
|
|
|
throw new Error('invalid arguments')
|
|
|
|
}
|
|
|
|
try {
|
2019-09-30 09:21:31 -04:00
|
|
|
const query = _getUserQuery(providerId, externalUserId)
|
2019-08-27 16:48:00 -04:00
|
|
|
let user = await User.findOne(query).exec()
|
|
|
|
if (!user) {
|
|
|
|
throw new Errors.SAMLUserNotFoundError()
|
|
|
|
}
|
|
|
|
return user
|
|
|
|
} catch (error) {
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-12 10:01:12 -04:00
|
|
|
async function linkAccounts(
|
|
|
|
userId,
|
|
|
|
externalUserId,
|
|
|
|
institutionEmail,
|
|
|
|
providerId
|
|
|
|
) {
|
2019-09-30 09:21:31 -04:00
|
|
|
try {
|
|
|
|
await _addIdentifier(userId, externalUserId, providerId)
|
|
|
|
await _addInstitutionEmail(userId, institutionEmail, providerId)
|
|
|
|
} catch (error) {
|
|
|
|
throw error
|
|
|
|
}
|
2019-09-12 10:01:12 -04:00
|
|
|
}
|
|
|
|
|
2019-08-27 16:48:00 -04:00
|
|
|
const SAMLIdentityManager = {
|
2019-09-12 10:01:12 -04:00
|
|
|
getUser,
|
|
|
|
linkAccounts
|
2019-08-27 16:48:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = SAMLIdentityManager
|