Просмотр исходного кода

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

[web] Remove overleaf-integration imports from tests

GitOrigin-RevId: 96a3afaab386c486c948d35999f2acf4cedc77cf
Alexandre Bourdin 2 лет назад
Родитель
Сommit
a6c97cd506

+ 219 - 0
services/web/test/acceptance/src/helpers/groupSSO.js

@@ -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,
+}

+ 46 - 0
services/web/test/acceptance/src/mocks/MockGoogleOauthApi.js

@@ -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}
+ */