Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Feature/OIDC e2e tests #595

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions .github/workflows/oidc-e2e-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Snapshot based E2E OIDC tests workflow
on:
pull_request:
branches: [ '**' ]
env:
VERSION: '2.6.0'
KEYCLOAK_VERSION: '21.0.1'
jobs:
tests:
name: Run Cypress E2E tests
runs-on: ubuntu-latest
env:
# prevents extra Cypress installation progress messages
CI: 1
# avoid warnings like "tput: No value for $TERM and no -T specified"
TERM: xterm
steps:
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 17
- name: Get and run Keycloak
run: |
echo "Downloading Keycloak ${{ env.KEYCLOAK_VERSION }}"
wget https://github.com/keycloak/keycloak/releases/download/${{ env.KEYCLOAK_VERSION }}/keycloak-${{ env.KEYCLOAK_VERSION }}.tar.gz
echo "Unpacking Keycloak"
tar -xzf keycloak-${{ env.KEYCLOAK_VERSION }}.tar.gz
export KEYCLOAK_ADMIN=admin
export KEYCLOAK_ADMIN_PASSWORD=admin
cd keycloak-${{ env.KEYCLOAK_VERSION }}/bin
chmod +x kc.sh
echo "Starting keycloak"
./kc.sh start-dev --http-enabled=true --hostname-strict-https=false --http-host=localhost --http-relative-path /auth --health-enabled=true &
timeout 300 bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8080/auth/health)" != "200" ]]; do sleep 5; done'
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 'redirectUris=["http://localhost:5603/auth/openid/#", "http://localhost:5601", "http://localhost:5601/auth/openid/#"]' -i)
./kcadm.sh get clients/$CID/installation/providers/keycloak-oidc-keycloak-json > tmp
echo "Getting client secret for dashboards configuration purpose"
echo "KEYCLOAK_CLIENT_SECRET=$(grep -o '"secret" : "[^"]*' tmp | grep -o '[^"]*$')" >> $GITHUB_ENV
echo "Creating client mapper"
./kcadm.sh create clients/$CID/protocol-mappers/models -r master -s 'config."id.token.claim"=true' -s 'config."multivalued"=true' -s 'config."claim.name"="roles"' -s 'config."userinfo.token.claim"=true' -s 'config."access.token.claim"=true' -s 'name=rolemapper' -s 'protocolMapper=oidc-usermodel-realm-role-mapper' -s "protocol=openid-connect"
- name: Get and run OpenSearch
run: |
echo "Downloading OpenSearch ${{ env.VERSION }}"
wget https://artifacts.opensearch.org/releases/bundle/opensearch/${{ env.VERSION }}/opensearch-${{ env.VERSION }}-linux-x64.tar.gz
echo "Unpacking OpenSearch"
tar -xzf opensearch-${{ env.VERSION }}-linux-x64.tar.gz
cd opensearch-${{ env.VERSION }}
echo "Injecting OIDC configuration"
cd config/opensearch-security/
wget -O yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
chmod +x yq
yq -i ".config.dynamic.authc.openid_auth_domain.http_enabled = true" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.transport_enabled = true" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.order = 1" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.http_authenticator.type = \"openid\"" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.http_authenticator.challenge = false" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.http_authenticator.config.subject_key = \"preferred_username\"" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.http_authenticator.config.roles_key = \"roles\"" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.http_authenticator.config.openid_connect_url = \"http://localhost:8080/auth/realms/master/.well-known/openid-configuration\"" config.yml
yq -i ".config.dynamic.authc.openid_auth_domain.authentication_backend.type = \"noop\"" config.yml
echo "Installing demo configuration"
cd ../../plugins/opensearch-security/tools
chmod +x install_demo_configuration.sh
./install_demo_configuration.sh -y
echo "Starting OpenSearch"
../../../bin/opensearch &
timeout 300 bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' https://localhost:9200 -ku admin:admin)" != "503" ]]; do sleep 5; done'
echo "Setting up certificates"
chmod +x securityadmin.sh
./securityadmin.sh -cd ../../../config/opensearch-security/ -icl -nhnv \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is running securityadmin necessary here? The certificates should already be installed from the output of ./install_demo_configuration.sh.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command is needed mostly for reloading previously changed confg.yml, without it opensearch won't have notion about OIDC provider.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's the first time that the opensearch node starts up it should already be taking care of initializing the security index anew and including the OIDC backend in the authc list. Securityadmin is needed if the security index had been previously initialized and changes are being applied.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've checked without this command opensearch responds with following line:

OpenSearch Security not initialized.%

-cacert ../../../config/root-ca.pem \
-cert ../../../config/kirk.pem \
-key ../../../config/kirk-key.pem
timeout 300 bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' https://localhost:9200 -ku admin:admin)" != "200" ]]; do sleep 5; done'
- name: Get and run OpenSearch-Dashboards
run: |
echo "Downloading OpenSearch-Dashboards ${{ env.VERSION }}"
wget https://artifacts.opensearch.org/releases/bundle/opensearch-dashboards/${{ env.VERSION }}/opensearch-dashboards-${{ env.VERSION }}-linux-x64.tar.gz
echo "Unpacking OpenSearch-Dashboards"
tar -xzf opensearch-dashboards-${{ env.VERSION }}-linux-x64.tar.gz
echo "Injecting OIDC configuration"
cd opensearch-dashboards-${{ env.VERSION }}/config
echo "opensearch_security.openid.connect_url: \"http://localhost:8080/auth/realms/master/.well-known/openid-configuration\"" >> opensearch_dashboards.yml
echo "opensearch_security.openid.client_id: \"opensearch\"" >> opensearch_dashboards.yml
echo "opensearch_security.openid.client_secret: \"${{ env.KEYCLOAK_CLIENT_SECRET }}\"">> opensearch_dashboards.yml
echo "opensearch_security.auth.type: [\"openid\"]" >> opensearch_dashboards.yml
echo "opensearch_security.auth.multiple_auth_enabled: true" >> opensearch_dashboards.yml
echo "opensearch_security.ui.openid.login.buttonname: \"OIDC\"" >> opensearch_dashboards.yml
echo "home.disableWelcomeScreen: true" >> opensearch_dashboards.yml
echo "Starting OpenSearch-Dashboards"
cd ../bin
chmod +x opensearch-dashboards
./opensearch-dashboards serve &
- name: Checkout functional-test
uses: actions/checkout@v2
with:
repository: ${{github.repository}}
path: functional-test
- name: Get Cypress version
id: cypress_version
run: |
echo "::set-output name=cypress_version::$(cat ./functional-test/package.json | jq '.devDependencies.cypress' | tr -d '"')"
- run: npx cypress cache list
- run: npx cypress cache path
- name: Yarn install
uses: cypress-io/github-action@v2
with:
working-directory: functional-test
command: yarn install
- name: Cypress tests
uses: cypress-io/github-action@v2
with:
working-directory: functional-test
command: yarn cypress:run-without-security --browser chromium --spec 'cypress/integration/plugins/security-dashboards-plugin/*.js'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this run-without-security here since this workflow explicitly installs the security plugin? IMO this is confusing since these tests are being run with the security plugin installed, but a different configuration.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, we can change it.

wait-on: 'http://localhost:5601'
- name: Upload E2E test reports
if: always()
uses: actions/upload-artifact@v3
with:
name: test-report
path: /home/runner/work/opensearch-dashboards-functional-test/opensearch-dashboards-functional-test/functional-test/cypress/reports/index.html
sebastianmichalski marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 9 additions & 3 deletions cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
"requestTimeout": 60000,
"responseTimeout": 60000,
"baseUrl": "http://localhost:5601",
"reporter": "cypress-multi-reporters",
"reporter": "cypress-mochawesome-reporter",
"reporterOptions": {
"configFile": "reporter-config.json"
"reportDir": "cypress/reports",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"charts": true,
"reportPageTitle": "My Test Suite",
"embeddedScreenshots": true,
"inlineAssets": true
},
"video": false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Videos are huge help when debugging failures.

"viewportWidth": 2000,
"viewportHeight": 1320,
"env": {
Expand All @@ -20,5 +25,6 @@
"VISBUILDER_ENABLED": true,
"DATASOURCE_MANAGEMENT_ENABLED": false,
"ML_COMMONS_DASHBOARDS_ENABLED": false
}
},
"experimentalSessionAndOrigin": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

describe('Log in via OIDC', () => {
const login = 'admin';
const password = 'admin';

const kcLogin = () => {
cy.get('#kc-page-title').should('be.visible');
cy.get('#username').type(login);
cy.get('#password').type(password);
cy.get('#kc-login').click();
};

const logout = () => {
cy.get('#user-icon-btn').should('be.visible', { timeout: 15000 });
cy.get('#user-icon-btn').click();
cy.get('button[data-test-subj^="log-out-"]').click();
cy.get('#kc-page-title').should('be.visible');
};

afterEach(async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also include cy.clearCookies() here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RyanL1997 @sebastianmichalski sure, good idea, will fix that :)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sebastianmichalski Took a first pass and overall this looks very good. Thank you for the contribution!

I see this PR adds a yarn.lock file when there is already a package-lock.json. Should there only be a single lockfile?

Correct, will fix that as well. :)

logout();
});

it('Login to app/opensearch_dashboards_overview#/ when OIDC is enabled', () => {
cy.visit('http://localhost:5601/app/opensearch_dashboards_overview#/');

kcLogin();

cy.get('#osdOverviewPageHeader__title').should('be.visible');

cy.getCookie('security_authentication').should('exist');
cy.clearCookies();
});

it('Login to app/dev_tools#/console when OIDC is enabled', () => {
cy.visit('http://localhost:5601/app/dev_tools#/console');

kcLogin();

cy.get('button[data-test-subj="sendRequestButton"]').should('be.visible');

cy.getCookie('security_authentication').should('exist');
cy.clearCookies();
});

it('Login to Dashboard with Hash', () => {
cy.visit(
`http://localhost:5601/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?_g=(filters:!(),refreshInterval:(pause:!f,value:900000),time:(from:now-24h,to:now))&_a=(description:'Analyze%20mock%20flight%20data%20for%20OpenSearch-Air,%20Logstash%20Airways,%20OpenSearch%20Dashboards%20Airlines%20and%20BeatsWest',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),query:(language:kuery,query:''),timeRestore:!t,title:'%5BFlights%5D%20Global%20Flight%20Dashboard',viewMode:view)`
);

kcLogin();

cy.get(
'.euiHeader.euiHeader--default.euiHeader--fixed.primaryHeader'
).should('be.visible');

cy.getCookie('security_authentication').should('exist');
cy.clearCookies();
});

it('Tenancy persisted after logout in OIDC', () => {
cy.visit('http://localhost:5601/app/opensearch_dashboards_overview#/');

kcLogin();

cy.get('#global').should('be.enabled');
cy.get('#global').click({ force: true });

cy.get('button[data-test-subj="confirm"]').click();

cy.get('#osdOverviewPageHeader__title').should('be.visible');

logout();

kcLogin();

cy.get('#user-icon-btn').should('be.visible');
cy.get('#user-icon-btn').click();

cy.get('#tenantName').should('have.text', 'Global');
});
});
1 change: 1 addition & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
require('cypress-mochawesome-reporter/plugin')(on);
};
3 changes: 3 additions & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ import '../utils/plugins/security/commands';
import '../utils/plugins/security-dashboards-plugin/commands';
import '../utils/plugins/alerting-dashboards-plugin/commands';
import '../utils/plugins/ml-commons-dashboards/commands';
import 'cypress-mochawesome-reporter/register';

// Alternatively you can use CommonJS syntax:
// require('./commands')

require('@cypress/xpath');

const resizeObserverLoopErrRe = /^[^(ResizeObserver loop limit exceeded)]/;
Cypress.on('uncaught:exception', (err) => {
/* returning false here prevents Cypress from failing the test */
Expand Down
Loading