From 347f57966851fea9e96bad35d2b094f8b16f2478 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 9 May 2024 16:38:12 -0400 Subject: [PATCH 1/2] Fix bugs where pages were stuck in error state (#1944) Signed-off-by: Derek Ho --- .../configuration/panels/auth-view/auth-view.tsx | 12 +++++++++++- .../panels/permission-list/permission-list.tsx | 1 + public/apps/configuration/panels/role-list.tsx | 1 + public/apps/configuration/panels/user-list.tsx | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/public/apps/configuration/panels/auth-view/auth-view.tsx b/public/apps/configuration/panels/auth-view/auth-view.tsx index 7a5eb4b9d..f425a357c 100644 --- a/public/apps/configuration/panels/auth-view/auth-view.tsx +++ b/public/apps/configuration/panels/auth-view/auth-view.tsx @@ -51,7 +51,17 @@ export function AuthView(props: AppDependencies) { }, [props.coreStart.http, dataSource.id]); if (isEmpty(authentication)) { - return ; + return ( + <> + + + + ); } return ( diff --git a/public/apps/configuration/panels/permission-list/permission-list.tsx b/public/apps/configuration/panels/permission-list/permission-list.tsx index e89bb2d03..d7237c7b5 100644 --- a/public/apps/configuration/panels/permission-list/permission-list.tsx +++ b/public/apps/configuration/panels/permission-list/permission-list.tsx @@ -209,6 +209,7 @@ export function PermissionList(props: AppDependencies) { const actionGroups = await fetchActionGroups(props.coreStart.http, dataSource.id); setActionGroupDict(actionGroups); setPermissionList(await mergeAllPermissions(actionGroups)); + setErrorFlag(false); } catch (e) { console.log(e); setErrorFlag(true); diff --git a/public/apps/configuration/panels/role-list.tsx b/public/apps/configuration/panels/role-list.tsx index 7bdf66593..72b8a5837 100644 --- a/public/apps/configuration/panels/role-list.tsx +++ b/public/apps/configuration/panels/role-list.tsx @@ -117,6 +117,7 @@ export function RoleList(props: AppDependencies) { const rawRoleMappingData = await fetchRoleMapping(props.coreStart.http, dataSource.id); const processedData = transformRoleData(rawRoleData, rawRoleMappingData); setRoleData(processedData); + setErrorFlag(false); } catch (e) { console.log(e); setErrorFlag(true); diff --git a/public/apps/configuration/panels/user-list.tsx b/public/apps/configuration/panels/user-list.tsx index 0d8c20015..100cef0e0 100644 --- a/public/apps/configuration/panels/user-list.tsx +++ b/public/apps/configuration/panels/user-list.tsx @@ -118,6 +118,7 @@ export function UserList(props: AppDependencies) { ); setCurrentUsername((await getAuthInfo(props.coreStart.http)).user_name); setUserData(await userDataPromise); + setErrorFlag(false); } catch (e) { console.log(e); setErrorFlag(true); From 96620250612943896978f30bc08a537fb6bc5290 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 9 May 2024 22:27:52 -0400 Subject: [PATCH 2/2] Fix issue when using OpenID Authentication with serverBasePath (#1899) * Test OIDC with basePath Signed-off-by: Craig Perkins * Run OIDC tests with basePath Signed-off-by: Craig Perkins * Run all tests with basePath Signed-off-by: Craig Perkins * Fix kibana url Signed-off-by: Craig Perkins * Remove requirement on nextUrl Signed-off-by: Craig Perkins * Remove duplicate Signed-off-by: Craig Perkins * Add basePath to acs endpoint Signed-off-by: Craig Perkins * Update snapshot Signed-off-by: Craig Perkins * Start IdP where acs contains the basePath Signed-off-by: Craig Perkins * es:lint --fix Signed-off-by: Craig Perkins * Generalize SAML tests to include basePath Signed-off-by: Craig Perkins * Add default Signed-off-by: Craig Perkins * Use -z Signed-off-by: Craig Perkins * Cypress env Signed-off-by: Craig Perkins * Cypress env Signed-off-by: Craig Perkins * Handle undefined Signed-off-by: Craig Perkins * Always pass basePath Signed-off-by: Craig Perkins * Remove ampersand Signed-off-by: Craig Perkins * Pass basePath in yarn_command Signed-off-by: Craig Perkins * re-add osd_base_path Signed-off-by: Craig Perkins * Try ternary Signed-off-by: Craig Perkins * Start with basePath Signed-off-by: Craig Perkins * Use separate steps Signed-off-by: Craig Perkins * Update shortenUrl Signed-off-by: Craig Perkins * Remove basePath in acs endpoint and fix shorten URL Signed-off-by: Craig Perkins * Comma-separated env Signed-off-by: Craig Perkins * update oidc_auth_test.spec.js Signed-off-by: Craig Perkins * Check cookie after login Signed-off-by: Craig Perkins * failOnStatusCode false Signed-off-by: Craig Perkins * mimic SAML Signed-off-by: Craig Perkins * mimic SAML Signed-off-by: Craig Perkins * Remove cy.origin Signed-off-by: Craig Perkins * Add cy.origin back Signed-off-by: Craig Perkins * Try wrapping in cy.url Signed-off-by: Craig Perkins * Visit directly Signed-off-by: Craig Perkins * Try localhost Signed-off-by: Craig Perkins * Comment out test for now Signed-off-by: Craig Perkins * Add another request after logout Signed-off-by: Craig Perkins * Wait for logout Signed-off-by: Craig Perkins * Small update Signed-off-by: Craig Perkins * Add base_redirect_url Signed-off-by: Craig Perkins * Explicitly add minimist as dev dependency Signed-off-by: Craig Perkins --------- Signed-off-by: Craig Perkins Co-authored-by: Darshit Chanpura Co-authored-by: Jialiang Liang --- .github/actions/run-cypress-tests/action.yml | 16 +++++++++++-- .../workflows/cypress-test-multiauth-e2e.yml | 21 ++++++++++++++-- .github/workflows/cypress-test-oidc-e2e.yml | 24 +++++++++++++++---- .github/workflows/cypress-test-saml-e2e.yml | 21 ++++++++++++++-- package.json | 11 +++++---- public/apps/login/login-page.tsx | 2 +- .../__snapshots__/login-page.test.tsx.snap | 8 +++---- public/apps/login/test/login-page.test.tsx | 2 +- server/auth/types/openid/routes.ts | 6 +++-- server/auth/types/saml/routes.ts | 6 +++-- server/session/security_cookie.ts | 2 +- test/cypress/e2e/oidc/oidc_auth_test.spec.js | 20 +++++++++------- test/cypress/e2e/saml/saml_auth_test.spec.js | 14 ++++++----- test/cypress/support/constants.js | 6 +++-- test/jest_integration/runIdpServer.js | 8 ++++++- 15 files changed, 124 insertions(+), 43 deletions(-) diff --git a/.github/actions/run-cypress-tests/action.yml b/.github/actions/run-cypress-tests/action.yml index eae07eac8..d77adf5a2 100644 --- a/.github/actions/run-cypress-tests/action.yml +++ b/.github/actions/run-cypress-tests/action.yml @@ -11,6 +11,10 @@ inputs: yarn_command: description: 'The yarn command to start running cypress tests' required: true + osd_base_path: + description: 'The base path for OpenSearch Dashboards' + required: false + default: '' runs: using: "composite" @@ -56,14 +60,22 @@ runs: if: ${{ runner.os == 'Linux' }} run: | cd ./OpenSearch-Dashboards/plugins/security-dashboards-plugin - yarn runIdp + if [ -z "${{ inputs.osd_base_path }}" ]; then + yarn runIdp & + else + yarn runIdp --basePath ${{ inputs.osd_base_path }} & + fi shell: bash - name: Run OpenSearch Dashboards with provided configuration if: ${{ runner.os == 'Linux' }} run: | cd ./OpenSearch-Dashboards - nohup yarn start --no-base-path --no-watch --csp.warnLegacyBrowsers=false | tee dashboard.log & + if [ -z "${{ inputs.osd_base_path }}" ]; then + nohup yarn start --no-base-path --no-watch --csp.warnLegacyBrowsers=false | tee dashboard.log & + else + nohup yarn start --no-watch --csp.warnLegacyBrowsers=false | tee dashboard.log & + fi shell: bash # Check if OSD is ready with a max timeout of 600 seconds diff --git a/.github/workflows/cypress-test-multiauth-e2e.yml b/.github/workflows/cypress-test-multiauth-e2e.yml index 3b9827b0f..bb7985f9b 100644 --- a/.github/workflows/cypress-test-multiauth-e2e.yml +++ b/.github/workflows/cypress-test-multiauth-e2e.yml @@ -17,6 +17,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest ] + basePath: [ "", "/osd" ] runs-on: ${{ matrix.os }} steps: @@ -61,7 +62,7 @@ jobs: metadata_url: http://localhost:7000/metadata sp: entity_id: https://localhost:9200 - kibana_url: http://localhost:5601 + kibana_url: http://localhost:5601${{ matrix.basePath }} exchange_key: 6aff3042-1327-4f3d-82f0-40a157ac4464 authentication_backend: type: noop @@ -82,14 +83,30 @@ jobs: opensearch_security.multitenancy.tenants.preferred: ["Private", "Global"] opensearch_security.readonly_mode.roles: ["kibana_read_only"] opensearch_security.cookie.secure: false - server.xsrf.allowlist: ["/_plugins/_security/api/authtoken", "/_opendistro/_security/api/authtoken", "/_opendistro/_security/saml/acs", "/_opendistro/_security/saml/acs/idpinitiated", "/_opendistro/_security/saml/logout"] + server.xsrf.allowlist: ["/_opendistro/_security/saml/acs", "/_opendistro/_security/saml/acs/idpinitiated", "/_opendistro/_security/saml/logout"] opensearch_security.auth.type: ["basicauth","saml"] opensearch_security.auth.multiple_auth_enabled: true opensearch_security.auth.anonymous_auth_enabled: false home.disableWelcomeScreen: true EOT + - name: Run OSD with basePath + if: ${{ matrix.basePath != '' }} + run: | + echo "server.basePath: \"${{ matrix.basePath }}\"" >> opensearch_dashboards_multiauth.yml + echo "server.rewriteBasePath: true" >> opensearch_dashboards_multiauth.yml + + - name: Run Cypress Tests with basePath + if: ${{ matrix.basePath != '' }} + uses: ./.github/actions/run-cypress-tests + with: + security_config_file: config_multiauth.yml + dashboards_config_file: opensearch_dashboards_multiauth.yml + yarn_command: 'yarn cypress:run --browser chrome --headless --env loginMethod=saml_multiauth,basePath=${{ matrix.basePath }} --spec "test/cypress/e2e/saml/*.js"' + osd_base_path: ${{ matrix.basePath }} + - name: Run Cypress Tests + if: ${{ matrix.basePath == '' }} uses: ./.github/actions/run-cypress-tests with: security_config_file: config_multiauth.yml diff --git a/.github/workflows/cypress-test-oidc-e2e.yml b/.github/workflows/cypress-test-oidc-e2e.yml index 59bfe08e4..11e51d390 100644 --- a/.github/workflows/cypress-test-oidc-e2e.yml +++ b/.github/workflows/cypress-test-oidc-e2e.yml @@ -21,6 +21,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest ] + basePath: [ "", "/osd" ] runs-on: ${{ matrix.os }} steps: @@ -62,7 +63,7 @@ jobs: chmod +x kcadm.sh echo "Creating client" ./kcadm.sh config credentials --server http://localhost:8080/auth --realm master --user admin --password admin - CID=$(./kcadm.sh create clients -r master -s clientId=opensearch -s secret="${{ env.TEST_KEYCLOAK_CLIENT_SECRET }}" -s 'attributes."access.token.lifespan"=60' -s 'redirectUris=["http://localhost:5603/auth/openid/login", "http://localhost:5601", "http://localhost:5601/auth/openid/login"]' -i) + CID=$(./kcadm.sh create clients -r master -s clientId=opensearch -s secret="${{ env.TEST_KEYCLOAK_CLIENT_SECRET }}" -s 'attributes."access.token.lifespan"=60' -s 'redirectUris=["http://localhost:5603${{ matrix.basePath }}/auth/openid/login", "http://localhost:5601${{ matrix.basePath }}", "http://localhost:5601${{ matrix.basePath }}/auth/openid/login"]' -i) ./kcadm.sh get clients/$CID/installation/providers/keycloak-oidc-keycloak-json > tmp echo "Getting client secret for dashboards configuration purpose" CLIENT_SECRET=$(grep -o '"secret" : "[^"]*' tmp | grep -o '[^"]*$') @@ -129,13 +130,28 @@ jobs: opensearch_security.openid.connect_url: "http://127.0.0.1:8080/auth/realms/master/.well-known/openid-configuration" opensearch_security.openid.client_id: "opensearch" opensearch_security.openid.client_secret: "${{ env.TEST_KEYCLOAK_CLIENT_SECRET }}" - opensearch_security.auth.type: ["openid"] - opensearch_security.auth.multiple_auth_enabled: true - opensearch_security.ui.openid.login.buttonname: "OIDC" + opensearch_security.openid.base_redirect_url: http://localhost:5601${{ matrix.basePath }} + opensearch_security.auth.type: "openid" home.disableWelcomeScreen: true EOT + - name: Run OSD with basePath + if: ${{ matrix.basePath != '' }} + run: | + echo "server.basePath: \"${{ matrix.basePath }}\"" >> opensearch_dashboards_openid.yml + echo "server.rewriteBasePath: true" >> opensearch_dashboards_openid.yml + + - name: Run Cypress Tests with basePath + if: ${{ matrix.basePath != '' }} + uses: ./.github/actions/run-cypress-tests + with: + security_config_file: config_openid.yml + dashboards_config_file: opensearch_dashboards_openid.yml + yarn_command: 'yarn cypress:run --browser chrome --headless --spec "test/cypress/e2e/oidc/*.js" --env basePath=${{ matrix.basePath }}' + osd_base_path: ${{ matrix.basePath }} + - name: Run Cypress Tests + if: ${{ matrix.basePath == '' }} uses: ./.github/actions/run-cypress-tests with: security_config_file: config_openid.yml diff --git a/.github/workflows/cypress-test-saml-e2e.yml b/.github/workflows/cypress-test-saml-e2e.yml index b5b697ba4..3025c2cde 100644 --- a/.github/workflows/cypress-test-saml-e2e.yml +++ b/.github/workflows/cypress-test-saml-e2e.yml @@ -17,6 +17,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest ] + basePath: [ "", "/osd" ] runs-on: ${{ matrix.os }} steps: @@ -61,7 +62,7 @@ jobs: metadata_url: http://localhost:7000/metadata sp: entity_id: https://localhost:9200 - kibana_url: http://localhost:5601 + kibana_url: http://localhost:5601${{ matrix.basePath }} exchange_key: 6aff3042-1327-4f3d-82f0-40a157ac4464 authentication_backend: type: noop @@ -82,14 +83,30 @@ jobs: opensearch_security.multitenancy.tenants.preferred: ["Private", "Global"] opensearch_security.readonly_mode.roles: ["kibana_read_only"] opensearch_security.cookie.secure: false - server.xsrf.allowlist: ["/_plugins/_security/api/authtoken", "/_opendistro/_security/api/authtoken", "/_opendistro/_security/saml/acs", "/_opendistro/_security/saml/acs/idpinitiated", "/_opendistro/_security/saml/logout"] + server.xsrf.allowlist: ["/_opendistro/_security/saml/acs", "/_opendistro/_security/saml/acs/idpinitiated", "/_opendistro/_security/saml/logout"] opensearch_security.auth.type: ["saml"] opensearch_security.auth.multiple_auth_enabled: true opensearch_security.auth.anonymous_auth_enabled: false home.disableWelcomeScreen: true EOT + - name: Run OSD with basePath + if: ${{ matrix.basePath != '' }} + run: | + echo "server.basePath: \"${{ matrix.basePath }}\"" >> opensearch_dashboards_saml.yml + echo "server.rewriteBasePath: true" >> opensearch_dashboards_saml.yml + + - name: Run Cypress Tests with basePath + if: ${{ matrix.basePath != '' }} + uses: ./.github/actions/run-cypress-tests + with: + security_config_file: config_saml.yml + dashboards_config_file: opensearch_dashboards_saml.yml + yarn_command: 'yarn cypress:run --browser chrome --headless --spec "test/cypress/e2e/saml/*.js" --env basePath=${{ matrix.basePath }}' + osd_base_path: ${{ matrix.basePath }} + - name: Run Cypress Tests + if: ${{ matrix.basePath == '' }} uses: ./.github/actions/run-cypress-tests with: security_config_file: config_saml.yml diff --git a/package.json b/package.json index 944c3f426..c8b786ad8 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "lint:es": "node ../../scripts/eslint", "lint:style": "node ../../scripts/stylelint", "lint": "yarn run lint:es && yarn run lint:style", - "runIdp": "node ./test/jest_integration/runIdpServer.js &", + "runIdp": "node ./test/jest_integration/runIdpServer.js", "test:jest_server": "ADMIN_PASSWORD=$ADMIN_PASSWORD node ./test/run_jest_tests.js --config ./test/jest.config.server.js", "test:jest_ui": "node ./test/run_jest_tests.js --config ./test/jest.config.ui.js", "prepare": "husky install" @@ -30,14 +30,15 @@ "@types/hapi__wreck": "^15.0.1", "cypress": "^13.6.0", "cypress-mochawesome-reporter": "^3.3.0", + "eslint-plugin-cypress": "^2.8.1", + "eslint-plugin-unused-imports": "3.1.0", "gulp-rename": "2.0.0", + "husky": "^8.0.0", "jose": "^5.2.4", + "minimist": "^1.2.8", "saml-idp": "^1.2.1", "selfsigned": "^2.0.1", - "typescript": "4.0.2", - "eslint-plugin-cypress": "^2.8.1", - "eslint-plugin-unused-imports": "3.1.0", - "husky": "^8.0.0" + "typescript": "4.0.2" }, "dependencies": { "@hapi/cryptiles": "5.0.0", diff --git a/public/apps/login/login-page.tsx b/public/apps/login/login-page.tsx index 1e5f43dd8..abebf304b 100644 --- a/public/apps/login/login-page.tsx +++ b/public/apps/login/login-page.tsx @@ -84,7 +84,7 @@ export function extractNextUrlFromWindowLocation(): string { const urlParams = new URLSearchParams(window.location.search); let nextUrl = urlParams.get('nextUrl'); if (!nextUrl || nextUrl.toLowerCase().includes('//')) { - nextUrl = encodeURIComponent('/'); + return ''; } else { nextUrl = encodeURIComponent(nextUrl); const hash = window.location.hash || ''; diff --git a/public/apps/login/test/__snapshots__/login-page.test.tsx.snap b/public/apps/login/test/__snapshots__/login-page.test.tsx.snap index de432dcca..f04a02a1d 100644 --- a/public/apps/login/test/__snapshots__/login-page.test.tsx.snap +++ b/public/apps/login/test/__snapshots__/login-page.test.tsx.snap @@ -121,7 +121,7 @@ exports[`Login page renders renders with config value for multiauth 1`] = ` aria-label="openid_login_button" className="test-btn-style" data-test-subj="submit" - href="/app/opensearch-dashboards/auth/openid/captureUrlFragment?nextUrl=%2F" + href="/app/opensearch-dashboards/auth/openid/captureUrlFragment" iconType="http://localhost:5601/images/test.png" size="s" type="prime" @@ -141,7 +141,7 @@ exports[`Login page renders renders with config value for multiauth 1`] = ` aria-label="saml_login_button" className="test-btn-style" data-test-subj="submit" - href="/app/opensearch-dashboards/auth/saml/captureUrlFragment?nextUrl=%2F" + href="/app/opensearch-dashboards/auth/saml/captureUrlFragment" iconType="http://localhost:5601/images/test.png" size="s" type="prime" @@ -292,7 +292,7 @@ exports[`Login page renders renders with config value for multiauth with anonymo aria-label="openid_login_button" className="test-btn-style" data-test-subj="submit" - href="/app/opensearch-dashboards/auth/openid/captureUrlFragment?nextUrl=%2F" + href="/app/opensearch-dashboards/auth/openid/captureUrlFragment" iconType="http://localhost:5601/images/test.png" size="s" type="prime" @@ -312,7 +312,7 @@ exports[`Login page renders renders with config value for multiauth with anonymo aria-label="saml_login_button" className="test-btn-style" data-test-subj="submit" - href="/app/opensearch-dashboards/auth/saml/captureUrlFragment?nextUrl=%2F" + href="/app/opensearch-dashboards/auth/saml/captureUrlFragment" iconType="http://localhost:5601/images/test.png" size="s" type="prime" diff --git a/public/apps/login/test/login-page.test.tsx b/public/apps/login/test/login-page.test.tsx index d764d56fa..167c9f148 100644 --- a/public/apps/login/test/login-page.test.tsx +++ b/public/apps/login/test/login-page.test.tsx @@ -91,7 +91,7 @@ describe('test extractNextUrlFromWindowLocation', () => { const originalLocation = window.location; delete window.location; window.location = new URL('http://localhost:5601/app/home'); - expect(extractNextUrlFromWindowLocation()).toEqual('?nextUrl=%2F'); + expect(extractNextUrlFromWindowLocation()).toEqual(''); }); }); diff --git a/server/auth/types/openid/routes.ts b/server/auth/types/openid/routes.ts index c23e26b1f..51ac1a85d 100644 --- a/server/auth/types/openid/routes.ts +++ b/server/auth/types/openid/routes.ts @@ -336,8 +336,10 @@ export class OpenIdAuthRoutes { } let params = new URLSearchParams(window.location.search); let nextUrl = params.get("nextUrl"); - finalUrl = "login?nextUrl=" + encodeURIComponent(nextUrl); - finalUrl += "&redirectHash=" + encodeURIComponent(redirectHash); + finalUrl = "login?redirectHash=" + encodeURIComponent(redirectHash); + if (!!nextUrl) { + finalUrl += "&nextUrl=" + encodeURIComponent(nextUrl); + } window.location.replace(finalUrl); `, }); diff --git a/server/auth/types/saml/routes.ts b/server/auth/types/saml/routes.ts index d14d0711b..52af443af 100644 --- a/server/auth/types/saml/routes.ts +++ b/server/auth/types/saml/routes.ts @@ -314,8 +314,10 @@ export class SamlAuthRoutes { } let params = new URLSearchParams(window.location.search); let nextUrl = params.get("nextUrl"); - finalUrl = "login?nextUrl=" + encodeURIComponent(nextUrl); - finalUrl += "&redirectHash=" + encodeURIComponent(redirectHash); + finalUrl = "login?redirectHash=" + encodeURIComponent(redirectHash); + if (!!nextUrl) { + finalUrl += "&nextUrl=" + encodeURIComponent(nextUrl); + } window.location.replace(finalUrl); `, }); diff --git a/server/session/security_cookie.ts b/server/session/security_cookie.ts index 4b0c52b89..d2a02ff98 100644 --- a/server/session/security_cookie.ts +++ b/server/session/security_cookie.ts @@ -59,7 +59,7 @@ export function getSecurityCookieOptions( // TODO: with setting redirect attributes to support OIDC and SAML, // we need to do additional cookie validation in AuthenticationHandlers. // if SAML fields present - if (sessionStorage.saml && sessionStorage.saml.requestId && sessionStorage.saml.nextUrl) { + if (sessionStorage.saml && sessionStorage.saml.requestId) { return { isValid: true, path: '/' }; } diff --git a/test/cypress/e2e/oidc/oidc_auth_test.spec.js b/test/cypress/e2e/oidc/oidc_auth_test.spec.js index 978cd0ec3..2228d2fbf 100644 --- a/test/cypress/e2e/oidc/oidc_auth_test.spec.js +++ b/test/cypress/e2e/oidc/oidc_auth_test.spec.js @@ -18,6 +18,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +const basePath = Cypress.env('basePath') || ''; + describe('Log in via OIDC', () => { afterEach(() => { cy.clearCookies(); @@ -37,7 +39,7 @@ describe('Log in via OIDC', () => { }; it('Login to app/opensearch_dashboards_overview#/ when OIDC is enabled', () => { - cy.visit('http://localhost:5601/app/opensearch_dashboards_overview', { + cy.visit(`http://localhost:5601${basePath}/app/opensearch_dashboards_overview`, { failOnStatusCode: false, }); @@ -52,24 +54,22 @@ describe('Log in via OIDC', () => { }); it('Login to app/dev_tools#/console when OIDC is enabled', () => { - cy.visit('http://localhost:5601/app/opensearch_dashboards_overview', { + cy.visit(`http://localhost:5601${basePath}/app/dev_tools#/console`, { failOnStatusCode: false, }); kcLogin(); + cy.getCookie('security_authentication').should('exist'); + localStorage.setItem('opendistro::security::tenant::saved', '""'); localStorage.setItem('home:newThemeModal:show', 'false'); - cy.visit('http://localhost:5601/app/dev_tools#/console'); - cy.get('a[data-test-subj="breadcrumb first last"]').contains('Dev Tools').should('be.visible'); - - cy.getCookie('security_authentication').should('exist'); }); it('Login to Dashboard with Hash', () => { - const urlWithHash = `http://localhost:5601/app/security-dashboards-plugin#/getstarted`; + const urlWithHash = `http://localhost:5601${basePath}/app/security-dashboards-plugin#/getstarted`; cy.visit(urlWithHash, { failOnStatusCode: false, @@ -92,7 +92,7 @@ describe('Log in via OIDC', () => { }); it('Tenancy persisted after logout in OIDC', () => { - cy.visit('http://localhost:5601/app/opensearch_dashboards_overview#/', { + cy.visit(`http://localhost:5601${basePath}/app/opensearch_dashboards_overview#/`, { failOnStatusCode: false, }); @@ -115,8 +115,12 @@ describe('Log in via OIDC', () => { cy.get('button[id="user-icon-btn"]').click(); + cy.intercept('GET', `${basePath}/auth/openid/logout`).as('openidLogout'); + cy.get('button[data-test-subj^="log-out-"]').click(); + cy.wait('@openidLogout').then(() => {}); + kcLogin(); cy.get('#user-icon-btn').should('be.visible'); diff --git a/test/cypress/e2e/saml/saml_auth_test.spec.js b/test/cypress/e2e/saml/saml_auth_test.spec.js index b8f6a134f..34f58da2b 100644 --- a/test/cypress/e2e/saml/saml_auth_test.spec.js +++ b/test/cypress/e2e/saml/saml_auth_test.spec.js @@ -22,12 +22,14 @@ import { ALL_ACCESS_ROLE, SHORTEN_URL_DATA } from '../../support/constants'; import samlUserRoleMapping from '../../fixtures/saml/samlUserRoleMappiing.json'; +const basePath = Cypress.env('basePath') || ''; + before(() => { cy.intercept('https://localhost:9200'); // Avoid Cypress lock onto the ipv4 range, so fake `visit()` before `request()`. // See: https://github.com/cypress-io/cypress/issues/25397#issuecomment-1402556488 - cy.visit('http://localhost:5601'); + cy.visit(`http://localhost:5601${basePath}`); cy.createRoleMapping(ALL_ACCESS_ROLE, samlUserRoleMapping); cy.clearCookies(); @@ -52,7 +54,7 @@ describe('Log in via SAML', () => { localStorage.setItem('opendistro::security::tenant::saved', '"__user__"'); localStorage.setItem('home:newThemeModal:show', 'false'); - cy.visit('http://localhost:5601/app/opensearch_dashboards_overview', { + cy.visit(`http://localhost:5601${basePath}/app/opensearch_dashboards_overview`, { failOnStatusCode: false, }); @@ -66,7 +68,7 @@ describe('Log in via SAML', () => { localStorage.setItem('opendistro::security::tenant::saved', '"__user__"'); localStorage.setItem('home:newThemeModal:show', 'false'); - cy.visit('http://localhost:5601/app/dev_tools#/console', { + cy.visit(`http://localhost:5601${basePath}/app/dev_tools#/console`, { failOnStatusCode: false, }); @@ -80,7 +82,7 @@ describe('Log in via SAML', () => { localStorage.setItem('opendistro::security::tenant::saved', '"__user__"'); localStorage.setItem('home:newThemeModal:show', 'false'); - const urlWithHash = `http://localhost:5601/app/security-dashboards-plugin#/getstarted`; + const urlWithHash = `http://localhost:5601${basePath}/app/security-dashboards-plugin#/getstarted`; cy.visit(urlWithHash, { failOnStatusCode: false, @@ -95,7 +97,7 @@ describe('Log in via SAML', () => { it('Tenancy persisted after logout in SAML', () => { localStorage.setItem('home:newThemeModal:show', 'false'); - cy.visit('http://localhost:5601/app/opensearch_dashboards_overview', { + cy.visit(`http://localhost:5601${basePath}/app/opensearch_dashboards_overview`, { failOnStatusCode: false, }); @@ -128,7 +130,7 @@ describe('Log in via SAML', () => { // We need to explicitly clear cookies, // since the Shorten URL api is return's set-cookie header for admin user. cy.clearCookies().then(() => { - const gotoUrl = `http://localhost:5601/goto/${response.urlId}?security_tenant=global`; + const gotoUrl = `http://localhost:5601${basePath}/goto/${response.urlId}?security_tenant=global`; cy.visit(gotoUrl); samlLogin(); cy.getCookie('security_authentication').should('exist'); diff --git a/test/cypress/support/constants.js b/test/cypress/support/constants.js index b357659c6..a9ce18f3f 100644 --- a/test/cypress/support/constants.js +++ b/test/cypress/support/constants.js @@ -32,6 +32,8 @@ export const ADMIN_AUTH = { password: Cypress.env('adminPassword'), }; +const basePath = Cypress.env('basePath') || ''; + //Security API Constants export const SEC_API_PREFIX = '/_plugins/_security/api'; export const SEC_API = { @@ -41,6 +43,6 @@ export const SEC_API = { ROLE_MAPPING_BASE: `${SEC_API_PREFIX}/rolesmapping`, }; export const DASHBOARDS_API = { - SHORTEN_URL: '/api/shorten_url', + SHORTEN_URL: `${basePath}/api/shorten_url`, }; -export const SHORTEN_URL_DATA = { url: '/app/home#/tutorial_directory' }; +export const SHORTEN_URL_DATA = { url: `/app/home#/tutorial_directory` }; diff --git a/test/jest_integration/runIdpServer.js b/test/jest_integration/runIdpServer.js index 35533ae6c..13149dbd5 100644 --- a/test/jest_integration/runIdpServer.js +++ b/test/jest_integration/runIdpServer.js @@ -17,15 +17,21 @@ const { runServer } = require('saml-idp'); const { generate } = require('selfsigned'); +const minimist = require('minimist'); + const pems = generate(null, { keySize: 2048, clientCertificateCN: '/C=US/ST=California/L=San Francisco/O=JankyCo/CN=Test Identity Provider', days: 7300, }); +const argv = minimist(process.argv.slice(2), { + default: { basePath: '' }, +}); + // Create certificate pair on the fly and pass it to runServer runServer({ - acsUrl: 'http://localhost:5601/_opendistro/_security/saml/acs', + acsUrl: `http://localhost:5601${argv.basePath}/_opendistro/_security/saml/acs`, audience: 'https://localhost:9200', cert: pems.cert, key: pems.private.toString().replace(/\r\n/, '\n'),