From 30a64401b2659aedcc320bcd08f8b24caef94125 Mon Sep 17 00:00:00 2001 From: Miguel Serrano Date: Mon, 1 Jul 2024 17:02:37 +0200 Subject: [PATCH] [SP] e2e tests for SAML/LDAP (#19182) * [SP] e2e tests for SAML/LDAP * [server-pro] tests: prefetch ldap and saml docker images --------- Co-authored-by: Jakob Ackermann GitOrigin-RevId: 64298df3f3941a8267a8aacd431757d21b43c75b --- server-ce/test/Makefile | 4 +- server-ce/test/docker-compose.native.yml | 7 +++ server-ce/test/docker-compose.yml | 12 +++++ server-ce/test/external-auth.spec.ts | 65 ++++++++++++++++++++++++ server-ce/test/helpers/config.ts | 7 ++- server-ce/test/history.spec.ts | 2 + server-ce/test/host-admin.js | 23 +++++++++ 7 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 server-ce/test/external-auth.spec.ts diff --git a/server-ce/test/Makefile b/server-ce/test/Makefile index 949640dfff..4f4bf838db 100644 --- a/server-ce/test/Makefile +++ b/server-ce/test/Makefile @@ -12,7 +12,7 @@ export IMAGE_TAG_PRO ?= quay.io/sharelatex/sharelatex-pro:latest test-e2e-native: docker compose -f docker-compose.yml -f docker-compose.native.yml up --build --no-log-prefix sharelatex host-admin -d - CYPRESS_ADMIN_CLIENT_URL='http://localhost:8081' CYPRESS_GIT_BRIDGE_PUBLIC_HOST='localhost' npm run cypress:open + CYPRESS_ADMIN_CLIENT_URL='http://localhost:8081' CYPRESS_GIT_BRIDGE_PUBLIC_HOST='localhost' CYPRESS_SAML_PUBLIC_HOST='localhost:8082' CYPRESS_OVERLEAF_PUBLIC_HOST='localhost:8082' npm run cypress:open test-e2e: docker compose up --build --no-log-prefix --exit-code-from=e2e e2e @@ -24,7 +24,7 @@ clean: docker compose down --volumes --timeout 0 prefetch: - docker compose pull e2e mongo redis + docker compose pull e2e mongo redis saml ldap docker compose build echo -n "$$ALL_TEX_LIVE_DOCKER_IMAGES" | xargs -d, -I% \ sh -exc 'tag=%; re_tag=quay.io/sharelatex/$${tag#*/}; docker pull $$tag; docker tag $$tag $$re_tag' diff --git a/server-ce/test/docker-compose.native.yml b/server-ce/test/docker-compose.native.yml index d8e92f309d..1830ff7e87 100644 --- a/server-ce/test/docker-compose.native.yml +++ b/server-ce/test/docker-compose.native.yml @@ -12,3 +12,10 @@ services: environment: NATIVE_CYPRESS: 'true' ACCESS_CONTROL_ALLOW_ORIGIN: 'http://localhost' + + saml: + ports: + - 127.0.0.1:8082:80 + environment: + SAML_BASE_URL_PATH: 'http://localhost:8082/simplesaml/' + SAML_TEST_SP_LOCATION: 'http://localhost/saml/callback' diff --git a/server-ce/test/docker-compose.yml b/server-ce/test/docker-compose.yml index 60a8afbce3..bd6b255710 100644 --- a/server-ce/test/docker-compose.yml +++ b/server-ce/test/docker-compose.yml @@ -108,3 +108,15 @@ services: interval: 3s timeout: 3s retries: 30 + + saml: + restart: always + image: gcr.io/overleaf-ops/saml-test + environment: + SAML_TEST_SP_ENTITY_ID: 'sharelatex-test-saml' + SAML_BASE_URL_PATH: 'http://saml/simplesaml/' + SAML_TEST_SP_LOCATION: 'http://sharelatex/saml/callback' + + ldap: + restart: always + image: rroemhild/test-openldap:1.1 diff --git a/server-ce/test/external-auth.spec.ts b/server-ce/test/external-auth.spec.ts new file mode 100644 index 0000000000..fae6945ccd --- /dev/null +++ b/server-ce/test/external-auth.spec.ts @@ -0,0 +1,65 @@ +import { startWith } from './helpers/config' + +describe('SAML', () => { + const overleafPublicHost = Cypress.env('OVERLEAF_PUBLIC_HOST') || 'sharelatex' + const samlPublicHost = Cypress.env('SAML_PUBLIC_HOST') || 'saml' + + startWith({ + pro: true, + vars: { + EXTERNAL_AUTH: 'saml', + OVERLEAF_SAML_ENTRYPOINT: `http://${samlPublicHost}/simplesaml/saml2/idp/SSOService.php`, + OVERLEAF_SAML_CALLBACK_URL: `http://${overleafPublicHost}/saml/callback`, + OVERLEAF_SAML_ISSUER: 'sharelatex-test-saml', + OVERLEAF_SAML_IDENTITY_SERVICE_NAME: 'SAML Test Server', + OVERLEAF_SAML_EMAIL_FIELD: 'email', + OVERLEAF_SAML_FIRST_NAME_FIELD: 'givenName', + OVERLEAF_SAML_LAST_NAME_FIELD: 'sn', + OVERLEAF_SAML_UPDATE_USER_DETAILS_ON_LOGIN: 'true', + OVERLEAF_SAML_CERT: + 'MIIDXTCCAkWgAwIBAgIJAOvOeQ4xFTzsMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkdCMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTYxMTE1MTQxMjU5WhcNMjYxMTE1MTQxMjU5WjBFMQswCQYDVQQGEwJHQjETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCT6MBe5G9VoLU8MfztOEbUhnwLp17ak8eFUqxqeXkkqtWB0b/cmIBU3xoQoO3dIF8PBzfqehqfYVhrNt/TFgcmDfmJnPJRL1RJWMW3VmiP5odJ3LwlkKbZpkeT3wZ8HEJIR1+zbpxiBNkbd2GbdR1iumcsHzMYX1A2CBj+ZMV5VijC+K4P0e9c05VsDEUtLmfeAasJAiumQoVVgAe/BpiXjICGGewa6EPFI7mKkifIRKOGxdRESwZZjxP30bI31oDN0cgKqIgSJtJ9nfCn9jgBMBkQHu42WMuaWD4jrGd7+vYdX+oIfArs9aKgAH5kUGhGdew2R9SpBefrhbNxG8QIDAQABo1AwTjAdBgNVHQ4EFgQU+aSojSyyLChP/IpZcafvSdhj7KkwHwYDVR0jBBgwFoAU+aSojSyyLChP/IpZcafvSdhj7KkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABl3+OOVLBWMKs6PjA8lPuloWDNzSr3v76oUcHqAb+cfbucjXrOVsS9RJ0X9yxvCQyfM9FfY43DbspnN3izYhdvbJD8kKLNf0LA5st+ZxLfy0ACyL2iyAwICaqndqxAjQYplFAHmpUiu1DiHckyBPekokDJd+ze95urHMOsaGS5RWPoKJVE0bkaAeZCmEu0NNpXRSBiuxXSTeSAJfv6kyE/rkdhzUKyUl/cGQFrsVYfAFQVA+W6CKOh74ErSEzSHQQYndl7nD33snD/YqdU1ROxV6aJzLKCg+sdj+wRXSP2u/UHnM4jW9TGJfhO42jzL6WVuEvr9q4l7zWzUQKKKhtQ==', + }, + }) + + it('login', () => { + cy.visit('/') + cy.findByText('Log in with SAML Test Server').click() + + cy.origin(`http://${samlPublicHost}`, () => { + cy.get('input[name="username"]').type('sally') + cy.get('input[name="password"]').type('sally123') + cy.get('button[type="submit"]').click() + }) + + cy.findByText('Create a new project') + }) +}) + +describe('LDAP', () => { + startWith({ + pro: true, + vars: { + EXTERNAL_AUTH: 'ldap', + OVERLEAF_LDAP_URL: 'ldap://ldap:389', + OVERLEAF_LDAP_SEARCH_BASE: 'ou=people,dc=planetexpress,dc=com', + OVERLEAF_LDAP_SEARCH_FILTER: '(uid={{username}})', + OVERLEAF_LDAP_BIND_DN: 'cn=admin,dc=planetexpress,dc=com', + OVERLEAF_LDAP_BIND_CREDENTIALS: 'GoodNewsEveryone', + OVERLEAF_LDAP_EMAIL_ATT: 'mail', + OVERLEAF_LDAP_NAME_ATT: 'cn', + OVERLEAF_LDAP_LAST_NAME_ATT: 'sn', + OVERLEAF_LDAP_UPDATE_USER_DETAILS_ON_LOGIN: 'true', + }, + }) + + it('login', () => { + cy.visit('/') + cy.findByText('Log in LDAP') + + cy.get('input[name="login"]').type('fry') + cy.get('input[name="password"]').type('fry') + cy.get('button[type="submit"]').click() + + cy.findByText('Create a new project') + }) +}) diff --git a/server-ce/test/helpers/config.ts b/server-ce/test/helpers/config.ts index 23d20bb82e..e7a59378f4 100644 --- a/server-ce/test/helpers/config.ts +++ b/server-ce/test/helpers/config.ts @@ -14,7 +14,12 @@ export function startWith({ }) { before(async function () { Object.assign(vars, varsFn()) - const cfg = JSON.stringify({ pro, version, vars, withDataDir }) + const cfg = JSON.stringify({ + pro, + version, + vars, + withDataDir, + }) if (lastConfig === cfg) return this.timeout(STARTUP_TIMEOUT) diff --git a/server-ce/test/history.spec.ts b/server-ce/test/history.spec.ts index 6b851a8cd3..9f7e6c2bc2 100644 --- a/server-ce/test/history.spec.ts +++ b/server-ce/test/history.spec.ts @@ -1,8 +1,10 @@ import { createProject } from './helpers/project' import { throttledRecompile } from './helpers/compile' import { ensureUserExists, login } from './helpers/login' +import { startWith } from './helpers/config' describe('History', function () { + startWith({}) ensureUserExists({ email: 'user@example.com' }) beforeEach(function () { login('user@example.com') diff --git a/server-ce/test/host-admin.js b/server-ce/test/host-admin.js index 41365af551..96201bf2e7 100644 --- a/server-ce/test/host-admin.js +++ b/server-ce/test/host-admin.js @@ -132,6 +132,25 @@ const allowedVars = Joi.object( 'OVERLEAF_NEW_PROJECT_TEMPLATE_LINKS', 'OVERLEAF_ALLOW_PUBLIC_ACCESS', 'OVERLEAF_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING', + 'EXTERNAL_AUTH', + 'OVERLEAF_SAML_ENTRYPOINT', + 'OVERLEAF_SAML_CALLBACK_URL', + 'OVERLEAF_SAML_ISSUER', + 'OVERLEAF_SAML_IDENTITY_SERVICE_NAME', + 'OVERLEAF_SAML_EMAIL_FIELD', + 'OVERLEAF_SAML_FIRST_NAME_FIELD', + 'OVERLEAF_SAML_LAST_NAME_FIELD', + 'OVERLEAF_SAML_UPDATE_USER_DETAILS_ON_LOGIN', + 'OVERLEAF_SAML_CERT', + 'OVERLEAF_LDAP_URL', + 'OVERLEAF_LDAP_SEARCH_BASE', + 'OVERLEAF_LDAP_SEARCH_FILTER', + 'OVERLEAF_LDAP_BIND_DN', + 'OVERLEAF_LDAP_BIND_CREDENTIALS', + 'OVERLEAF_LDAP_EMAIL_ATT', + 'OVERLEAF_LDAP_NAME_ATT', + 'OVERLEAF_LDAP_LAST_NAME_ATT', + 'OVERLEAF_LDAP_UPDATE_USER_DETAILS_ON_LOGIN', // Old branding, used for upgrade tests 'SHARELATEX_MONGO_URL', 'SHARELATEX_REDIS_HOST', @@ -153,6 +172,10 @@ function setVarsDockerCompose({ pro, vars, version, withDataDir }) { cfg.services.sharelatex.depends_on = [] } + if (['ldap', 'saml'].includes(vars.EXTERNAL_AUTH)) { + cfg.services.sharelatex.depends_on.push(vars.EXTERNAL_AUTH) + } + const dataDirInContainer = version === 'latest' || version >= '5.0' ? '/var/lib/overleaf/data'