2020-03-30 08:55:47 -04:00
|
|
|
'use strict'
|
|
|
|
|
|
|
|
const fs = require('fs')
|
|
|
|
const minimist = require('minimist')
|
|
|
|
|
|
|
|
const InstitutionsAPI = require('../../app/src/Features/Institutions/InstitutionsAPI')
|
|
|
|
.promises
|
|
|
|
|
|
|
|
const argv = minimist(process.argv.slice(2))
|
|
|
|
const commit = argv.commit !== undefined
|
|
|
|
const ignoreNulls = !!argv['ignore-nulls']
|
|
|
|
|
|
|
|
if (!commit) {
|
|
|
|
console.log('DOING DRY RUN. TO SAVE CHANGES PASS --commit')
|
|
|
|
}
|
|
|
|
|
|
|
|
const userEntitlements = loadUserEntitlements(argv['user-entitlements'])
|
|
|
|
const cachedEntitlements = loadCachedEntitlements(argv['cached-entitlements'])
|
|
|
|
|
|
|
|
syncUserEntitlements(userEntitlements, cachedEntitlements)
|
|
|
|
.catch(err => console.error(err.stack))
|
|
|
|
.then(() => process.exit())
|
|
|
|
|
|
|
|
async function syncUserEntitlements(userEntitlements, cachedEntitlements) {
|
|
|
|
// check for user entitlements in mongo but not in postgres
|
|
|
|
for (const userEntitlement of Object.values(userEntitlements)) {
|
|
|
|
// find any email(s) that are linked through sso
|
|
|
|
for (const email of userEntitlement.emails) {
|
|
|
|
if (!email.samlProviderId) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// get samlIdentifiers entry for email
|
|
|
|
const samlIdentifier = userEntitlement.samlIdentifiers.find(
|
|
|
|
samlIdentifier => samlIdentifier.providerId === email.samlProviderId
|
|
|
|
)
|
|
|
|
// validate that entitlement is cached
|
|
|
|
if (samlIdentifier) {
|
|
|
|
const cachedEntitlment = cachedEntitlements[email.email]
|
|
|
|
// validate that record is correct
|
|
|
|
if (cachedEntitlment) {
|
|
|
|
if (
|
|
|
|
cachedEntitlment.hasEntitlement !== samlIdentifier.hasEntitlement
|
|
|
|
) {
|
|
|
|
console.log(
|
2020-12-15 05:23:54 -05:00
|
|
|
`cached entitlement mismatch for user ${userEntitlement.userId} mongo(${samlIdentifier.hasEntitlement}) postgres(${cachedEntitlment.hasEntitlement})`
|
2020-03-30 08:55:47 -04:00
|
|
|
)
|
|
|
|
await syncUserEntitlement(
|
|
|
|
userEntitlement.userId,
|
|
|
|
email.email,
|
|
|
|
samlIdentifier.hasEntitlement
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// there is not record in postgres at all
|
|
|
|
else {
|
|
|
|
console.log(
|
|
|
|
`missing cached entitlement for user ${userEntitlement.userId}`
|
|
|
|
)
|
|
|
|
await syncUserEntitlement(
|
|
|
|
userEntitlement.userId,
|
|
|
|
email.email,
|
|
|
|
samlIdentifier.hasEntitlement
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if identifier is missing for email this is internal inconsistency in mongo
|
|
|
|
else {
|
|
|
|
console.log(`missing samlIdentifier for user ${userEntitlement.userId}`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find any samlIdentifier records missing email entry
|
|
|
|
for (const samlIdentifier of userEntitlement.samlIdentifiers) {
|
|
|
|
const email = userEntitlement.emails.find(
|
|
|
|
email => email.samlProviderId === samlIdentifier.providerId
|
|
|
|
)
|
|
|
|
if (!email) {
|
|
|
|
console.log(
|
2020-12-15 05:23:54 -05:00
|
|
|
`missing email entry for samlIdentifier for user ${userEntitlement.userId}`
|
2020-03-30 08:55:47 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for user entitlements in postgres but not in mongo
|
|
|
|
for (const cachedEntitlment of Object.values(cachedEntitlements)) {
|
|
|
|
if (!cachedEntitlment.hasEntitlement) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
const userEntitlement = userEntitlements[cachedEntitlment.userId]
|
|
|
|
// validate that mongo has correct entitlement
|
|
|
|
if (userEntitlement) {
|
|
|
|
// find samlIdentifier for provider
|
|
|
|
const samlIdentifier = userEntitlement.samlIdentifiers.find(
|
|
|
|
samlIdentifier =>
|
|
|
|
samlIdentifier.providerId === cachedEntitlment.providerId
|
|
|
|
)
|
|
|
|
if (!samlIdentifier || !samlIdentifier.hasEntitlement) {
|
|
|
|
console.log(
|
2020-12-15 05:23:54 -05:00
|
|
|
`cached entitlement mismatch for user ${userEntitlement.userId} mongo(false) postgres(true)`
|
2020-03-30 08:55:47 -04:00
|
|
|
)
|
|
|
|
await syncUserEntitlement(
|
|
|
|
userEntitlement.userId,
|
|
|
|
cachedEntitlment.email,
|
|
|
|
false
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if the record does not exist it is probably because users without
|
|
|
|
// entitlements were not exported
|
|
|
|
else {
|
|
|
|
console.log(
|
2020-12-15 05:23:54 -05:00
|
|
|
`missing cached entitlement in mongo for user ${cachedEntitlment.userId}`
|
2020-03-30 08:55:47 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function syncUserEntitlement(userId, email, hasEntitlement) {
|
|
|
|
if (!commit) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (hasEntitlement) {
|
|
|
|
await InstitutionsAPI.addEntitlement(userId, email)
|
|
|
|
} else {
|
|
|
|
await InstitutionsAPI.removeEntitlement(userId, email)
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.error(
|
2020-12-15 05:23:54 -05:00
|
|
|
`error setting entitlement: ${userId}, ${email}, ${hasEntitlement} - ${err.message}`
|
2020-03-30 08:55:47 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadUserEntitlements(userEntitlementsFilename) {
|
|
|
|
const userEntitlementsFile = fs.readFileSync(userEntitlementsFilename, {
|
|
|
|
encoding: 'utf8'
|
|
|
|
})
|
|
|
|
|
|
|
|
const userEntitlements = {}
|
|
|
|
|
|
|
|
for (const userEntitlementLine of userEntitlementsFile.split('\n')) {
|
|
|
|
if (!userEntitlementLine) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
const userEntitlementExport = JSON.parse(userEntitlementLine)
|
|
|
|
const userId = userEntitlementExport._id.$oid
|
|
|
|
delete userEntitlementExport._id
|
|
|
|
userEntitlementExport.userId = userId
|
|
|
|
userEntitlements[userId] = userEntitlementExport
|
|
|
|
}
|
|
|
|
|
|
|
|
return userEntitlements
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadCachedEntitlements(cachedEntitlementsFilename) {
|
|
|
|
const cachedEntitlementsFile = fs.readFileSync(cachedEntitlementsFilename, {
|
|
|
|
encoding: 'utf8'
|
|
|
|
})
|
|
|
|
|
|
|
|
const cachedEntitlements = {}
|
|
|
|
|
|
|
|
for (const cachedEntitlementLine of cachedEntitlementsFile.split('\n')) {
|
|
|
|
// this is safe because comma is not an allowed value for any column
|
|
|
|
const [
|
|
|
|
userId,
|
|
|
|
email,
|
|
|
|
hasEntitlement,
|
|
|
|
providerId
|
|
|
|
] = cachedEntitlementLine.split(',')
|
|
|
|
let hasEntitlementBoolean
|
|
|
|
if (ignoreNulls) {
|
|
|
|
hasEntitlementBoolean = hasEntitlement === 't'
|
|
|
|
} else {
|
|
|
|
hasEntitlementBoolean =
|
|
|
|
hasEntitlement === 't' ? true : hasEntitlement === 'f' ? false : null
|
|
|
|
}
|
|
|
|
cachedEntitlements[email] = {
|
|
|
|
email,
|
|
|
|
hasEntitlement: hasEntitlementBoolean,
|
|
|
|
providerId,
|
|
|
|
userId
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cachedEntitlements
|
|
|
|
}
|