Merge pull request #19946 from overleaf/ac-remove-ol-int-imports-from-tests

[web] Remove overleaf-integration imports from tests

GitOrigin-RevId: 96a3afaab386c486c948d35999f2acf4cedc77cf
This commit is contained in:
Alexandre Bourdin 2024-08-19 14:34:50 +02:00 committed by Copybot
parent 0e43a18bc6
commit a6c97cd506
2 changed files with 265 additions and 0 deletions

View file

@ -0,0 +1,219 @@
const fs = require('fs')
const Path = require('path')
const User = require('./User').promises
const Subscription = require('./Subscription').promises
const { SSOConfig } = require('../../../../app/src/models/SSOConfig')
const UserHelper = require('./UserHelper')
const SAMLHelper = require('./SAMLHelper')
const Settings = require('@overleaf/settings')
const {
getProviderId,
} = require('../../../../app/src/Features/Subscription/GroupUtils')
const UserGetter = require('../../../../app/src/Features/User/UserGetter')
const {
Subscription: SubscriptionModel,
} = require('../../../../app/src/models/Subscription')
const SAML_TEST_CERT = fs
.readFileSync(Path.resolve(__dirname, '../../files/saml-cert.crt'), 'utf8')
.replace(/-----BEGIN CERTIFICATE-----/, '')
.replace(/-----END CERTIFICATE-----/, '')
.replace(/\n/g, '')
function getEnrollmentUrl(groupId) {
return `/subscription/${groupId}/sso_enrollment`
}
const userIdAttribute = 'nameID'
const baseSsoConfig = {
entryPoint: 'http://example-sso.com/saml',
certificates: [SAML_TEST_CERT],
signatureAlgorithm: 'sha256',
userIdAttribute,
} // the database also sets enabled and validated, but we cannot set that in the POST request for /manage/groups/:ID/settings/sso
async function createGroupSSO() {
const nonSSOMemberHelper = await UserHelper.createUser()
const nonSSOMember = nonSSOMemberHelper.user
const groupAdminUser = new User()
const memberUser = new User()
await groupAdminUser.ensureUserExists()
await memberUser.ensureUserExists()
const ssoConfig = new SSOConfig({
...baseSsoConfig,
enabled: true,
validated: true,
})
await ssoConfig.save()
const subscription = new Subscription({
adminId: groupAdminUser._id,
memberIds: [memberUser._id, nonSSOMember._id, groupAdminUser._id],
groupPlan: true,
planCode: 'group_professional_10_enterprise',
features: {
groupSSO: true,
},
ssoConfig: ssoConfig._id,
membersLimit: 10,
})
await subscription.ensureExists()
const subscriptionId = subscription._id.toString()
const enrollmentUrl = getEnrollmentUrl(subscriptionId)
const internalProviderId = getProviderId(subscriptionId)
await linkGroupMember(
memberUser.email,
memberUser.password,
subscriptionId,
'mock@email.com'
)
const userHelper = new UserHelper()
return {
ssoConfig,
internalProviderId,
userIdAttribute,
subscription,
subscriptionId,
groupAdminUser,
memberUser,
nonSSOMemberHelper,
nonSSOMember,
userHelper,
enrollmentUrl,
}
}
async function linkGroupMember(
userEmail,
userPassword,
groupId,
externalUserId
) {
// eslint-disable-next-line no-restricted-syntax
const subscription = await SubscriptionModel.findById(groupId)
.populate('ssoConfig')
.exec()
const userIdAttribute = subscription?.ssoConfig?.userIdAttribute
const internalProviderId = getProviderId(groupId)
const enrollmentUrl = getEnrollmentUrl(groupId)
const userHelper = await UserHelper.loginUser(
{
email: userEmail,
password: userPassword,
},
`/subscription/${groupId}/sso_enrollment`
)
const { headers } = await userHelper.fetch(enrollmentUrl, {
method: 'POST',
})
if (
!headers.get('location') ||
!headers.get('location').includes(Settings.saml.groupSSO.initPath)
) {
throw new Error('invalid redirect when linking to group SSO')
}
const redirectTo = new URL(headers.get('location'))
const initSSOResponse = await userHelper.fetch(redirectTo)
// redirect to IdP
const idpEntryPointUrl = new URL(initSSOResponse.headers.get('location'))
const requestId = await SAMLHelper.getRequestId(idpEntryPointUrl)
const response = await userHelper.fetch(Settings.saml.groupSSO.path, {
method: 'POST',
body: new URLSearchParams({
SAMLResponse: SAMLHelper.createMockSamlResponse({
requestId,
userIdAttribute,
uniqueId: externalUserId,
issuer: 'https://www.overleaf.test/saml/group-sso/meta',
}),
}),
})
if (response.status !== 302) {
throw new Error('failed to link group SSO')
}
// ensure user linked
const user = await UserGetter.promises.getUser(
{ email: userEmail },
{ samlIdentifiers: 1, enrollment: 1 }
)
const { enrollment, samlIdentifiers } = user
const linkedToGroupSSO = samlIdentifiers.some(
identifier => identifier.providerId === internalProviderId
)
const userIsEnrolledInSSO = enrollment.sso.some(
sso => sso.groupId.toString() === groupId.toString()
)
if (!linkedToGroupSSO || !userIsEnrolledInSSO) {
throw new Error('error setting up test user with group SSO linked')
}
return userHelper
}
async function setConfigAndEnableSSO(
subscriptionHelper,
adminEmailPassword,
config
) {
config = config || {
entryPoint: 'http://idp.example.com/entry_point',
certificates: [SAML_TEST_CERT],
userIdAttribute: 'email',
userLastNameAttribute: 'lastName',
}
const { email, password } = adminEmailPassword
const userHelper = await UserHelper.loginUser({
email,
password,
})
const createResponse = await userHelper.fetch(
`/manage/groups/${subscriptionHelper._id}/settings/sso`,
{
method: 'POST',
body: JSON.stringify(config),
headers: {
'Content-Type': 'application/json',
},
}
)
if (createResponse.status !== 201) {
throw new Error(
`failed to set SSO config. Status = ${createResponse.status}`
)
}
await subscriptionHelper.setValidatedSSO()
const enableResponse = await userHelper.fetch(
`/manage/groups/${subscriptionHelper._id}/settings/enableSSO`,
{ method: 'POST' }
)
if (enableResponse.status !== 200) {
throw new Error(`failed to enable SSO. Status = ${enableResponse.status}`)
}
}
module.exports = {
createGroupSSO,
linkGroupMember,
baseSsoConfig,
setConfigAndEnableSSO,
}

View file

@ -0,0 +1,46 @@
const AbstractMockApi = require('./AbstractMockApi')
class MockGoogleOauthApi extends AbstractMockApi {
reset() {
this.profiles = {}
this.tokens = {}
}
addProfile(profile, token, authorizationCode) {
this.profiles[token] = {
picture: 'https://example.com/picture.jpg',
email_verified: true,
locale: 'en-GB',
...profile,
}
this.tokens[authorizationCode] = token
}
applyRoutes() {
this.app.post('/oauth/token', (req, res, next) => {
if (!this.tokens[req.body.code]) {
return res.sendStatus(400)
}
res.json({
access_token: this.tokens[req.body.code],
})
})
this.app.get('/oauth2/v3/userinfo', (req, res, next) => {
if (!this.profiles[req.query.access_token]) {
return res.sendStatus(400)
}
res.json(this.profiles[req.query.access_token])
})
}
}
module.exports = MockGoogleOauthApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockGoogleOauthApi
* @static
* @returns {MockGoogleOauthApi}
*/