deb.open-vault/ui/tests/acceptance/mfa-login-test.js

191 lines
7.1 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { click, currentRouteName, fillIn, visit, waitUntil, find } from '@ember/test-helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import ENV from 'vault/config/environment';
import { validationHandler } from '../../mirage/handlers/mfa-login';
module('Acceptance | mfa-login', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.before(function () {
ENV['ember-cli-mirage'].handler = 'mfaLogin';
});
hooks.beforeEach(function () {
this.select = async (select = 0, option = 1) => {
const selector = `[data-test-mfa-select="${select}"]`;
const value = this.element.querySelector(`${selector} option:nth-child(${option + 1})`).value;
await fillIn(`${selector} select`, value);
};
});
hooks.after(function () {
ENV['ember-cli-mirage'].handler = null;
});
const login = async (user) => {
await visit('/vault/auth');
await fillIn('[data-test-select="auth-method"]', 'userpass');
await fillIn('[data-test-username]', user);
await fillIn('[data-test-password]', 'test');
await click('[data-test-auth-submit]');
};
const didLogin = (assert) => {
assert.strictEqual(currentRouteName(), 'vault.cluster.secrets.backends', 'Route transitions after login');
};
const validate = async (multi) => {
await fillIn('[data-test-mfa-passcode="0"]', 'test');
if (multi) {
await fillIn('[data-test-mfa-passcode="1"]', 'test');
}
await click('[data-test-mfa-validate]');
};
test('it should handle single mfa constraint with passcode method', async function (assert) {
assert.expect(4);
await login('mfa-a');
assert
.dom('[data-test-mfa-description]')
.includesText(
'Enter your authentication code to log in.',
'Mfa form displays with correct description'
);
assert.dom('[data-test-mfa-select]').doesNotExist('Select is hidden for single method');
assert.dom('[data-test-mfa-passcode]').exists({ count: 1 }, 'Single passcode input renders');
await validate();
didLogin(assert);
});
test('it should handle single mfa constraint with push method', async function (assert) {
assert.expect(6);
server.post('/sys/mfa/validate', async (schema, req) => {
await waitUntil(() => find('[data-test-mfa-description]'));
assert
.dom('[data-test-mfa-description]')
.hasText(
'Multi-factor authentication is enabled for your account.',
'Mfa form displays with correct description'
);
assert.dom('[data-test-mfa-label]').hasText('Okta push notification', 'Correct method renders');
assert
.dom('[data-test-mfa-push-instruction]')
.hasText('Check device for push notification', 'Push notification instruction renders');
assert.dom('[data-test-mfa-validate]').isDisabled('Button is disabled while validating');
assert
.dom('[data-test-mfa-validate]')
.hasClass('is-loading', 'Loading class applied to button while validating');
return validationHandler(schema, req);
});
await login('mfa-b');
didLogin(assert);
});
test('it should handle single mfa constraint with 2 passcode methods', async function (assert) {
assert.expect(4);
await login('mfa-c');
assert
.dom('[data-test-mfa-description]')
.includesText('Select the MFA method you wish to use.', 'Mfa form displays with correct description');
assert
.dom('[data-test-mfa-select]')
.exists({ count: 1 }, 'Select renders for single constraint with multiple methods');
assert.dom('[data-test-mfa-passcode]').doesNotExist('Passcode input hidden until selection is made');
await this.select();
await validate();
didLogin(assert);
});
test('it should handle single mfa constraint with 2 push methods', async function (assert) {
assert.expect(1);
await login('mfa-d');
await this.select();
await click('[data-test-mfa-validate]');
didLogin(assert);
});
test('it should handle single mfa constraint with 1 passcode and 1 push method', async function (assert) {
assert.expect(3);
await login('mfa-e');
await this.select(0, 2);
assert.dom('[data-test-mfa-passcode]').exists('Passcode input renders');
await this.select();
assert.dom('[data-test-mfa-passcode]').doesNotExist('Passcode input is hidden for push method');
await click('[data-test-mfa-validate]');
didLogin(assert);
});
test('it should handle multiple mfa constraints with 1 passcode method each', async function (assert) {
assert.expect(3);
await login('mfa-f');
assert
.dom('[data-test-mfa-description]')
.includesText(
'Two methods are required for successful authentication.',
'Mfa form displays with correct description'
);
assert.dom('[data-test-mfa-select]').doesNotExist('Selects do not render for single methods');
await validate(true);
didLogin(assert);
});
test('it should handle multi mfa constraint with 1 push method each', async function (assert) {
assert.expect(1);
await login('mfa-g');
didLogin(assert);
});
test('it should handle multiple mfa constraints with 1 passcode and 1 push method', async function (assert) {
assert.expect(4);
await login('mfa-h');
assert
.dom('[data-test-mfa-description]')
.includesText(
'Two methods are required for successful authentication.',
'Mfa form displays with correct description'
);
assert.dom('[data-test-mfa-select]').doesNotExist('Select is hidden for single method');
assert.dom('[data-test-mfa-passcode]').exists({ count: 1 }, 'Passcode input renders');
await validate();
didLogin(assert);
});
test('it should handle multiple mfa constraints with multiple mixed methods', async function (assert) {
assert.expect(2);
await login('mfa-i');
assert
.dom('[data-test-mfa-description]')
.includesText(
'Two methods are required for successful authentication.',
'Mfa form displays with correct description'
);
await this.select();
await fillIn('[data-test-mfa-passcode="1"]', 'test');
await click('[data-test-mfa-validate]');
didLogin(assert);
});
test('it should render unauthorized message for push failure', async function (assert) {
await login('mfa-j');
assert.dom('[data-test-auth-form]').doesNotExist('Auth form hidden when mfa fails');
assert.dom('[data-test-empty-state-title]').hasText('Unauthorized', 'Error title renders');
assert
.dom('[data-test-empty-state-subText]')
.hasText('PingId MFA validation failed', 'Error message from server renders');
assert
.dom('[data-test-empty-state-message]')
.hasText(
'Multi-factor authentication is required, but failed. Go back and try again, or contact your administrator.',
'Error description renders'
);
await click('[data-test-mfa-error] button');
assert.dom('[data-test-auth-form]').exists('Auth form renders after mfa error dismissal');
});
});