2022-05-05 20:05:13 +00:00
|
|
|
|
/* eslint-disable qunit/require-expect */
|
2021-04-13 16:56:59 +00:00
|
|
|
|
import { currentURL, find, visit } from '@ember/test-helpers';
|
2019-03-13 00:04:16 +00:00
|
|
|
|
import { module, skip, test } from 'qunit';
|
|
|
|
|
import { setupApplicationTest } from 'ember-qunit';
|
2019-09-26 18:47:07 +00:00
|
|
|
|
import { setupMirage } from 'ember-cli-mirage/test-support';
|
2020-07-28 17:59:14 +00:00
|
|
|
|
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
|
2018-07-10 07:39:02 +00:00
|
|
|
|
import Tokens from 'nomad-ui/tests/pages/settings/tokens';
|
2018-07-11 19:42:43 +00:00
|
|
|
|
import Jobs from 'nomad-ui/tests/pages/jobs/list';
|
|
|
|
|
import JobDetail from 'nomad-ui/tests/pages/jobs/detail';
|
|
|
|
|
import ClientDetail from 'nomad-ui/tests/pages/clients/detail';
|
2021-04-01 18:21:30 +00:00
|
|
|
|
import Layout from 'nomad-ui/tests/pages/layout';
|
2022-05-05 20:05:13 +00:00
|
|
|
|
import percySnapshot from '@percy/ember';
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
|
|
|
|
let job;
|
|
|
|
|
let node;
|
2017-10-14 18:53:48 +00:00
|
|
|
|
let managementToken;
|
|
|
|
|
let clientToken;
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
module('Acceptance | tokens', function (hooks) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
setupApplicationTest(hooks);
|
2019-03-13 01:09:19 +00:00
|
|
|
|
setupMirage(hooks);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
hooks.beforeEach(function () {
|
2020-04-03 18:31:19 +00:00
|
|
|
|
window.localStorage.clear();
|
|
|
|
|
window.sessionStorage.clear();
|
2019-03-14 06:44:53 +00:00
|
|
|
|
|
2017-09-19 14:47:10 +00:00
|
|
|
|
server.create('agent');
|
|
|
|
|
node = server.create('node');
|
|
|
|
|
job = server.create('job');
|
2017-10-14 18:53:48 +00:00
|
|
|
|
managementToken = server.create('token');
|
|
|
|
|
clientToken = server.create('token');
|
2019-03-13 00:04:16 +00:00
|
|
|
|
});
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('it passes an accessibility audit', async function (assert) {
|
2021-12-28 19:30:38 +00:00
|
|
|
|
assert.expect(1);
|
|
|
|
|
|
2020-07-28 17:59:14 +00:00
|
|
|
|
await Tokens.visit();
|
2020-08-25 15:56:02 +00:00
|
|
|
|
await a11yAudit(assert);
|
2020-07-28 17:59:14 +00:00
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('the token form sets the token in local storage', async function (assert) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
const { secretId } = managementToken;
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Tokens.visit();
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
window.localStorage.nomadTokenSecret,
|
|
|
|
|
null,
|
|
|
|
|
'No token secret set'
|
|
|
|
|
);
|
2019-07-17 20:02:58 +00:00
|
|
|
|
assert.equal(document.title, 'Tokens - Nomad');
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Tokens.secret(secretId).submit();
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
window.localStorage.nomadTokenSecret,
|
|
|
|
|
secretId,
|
|
|
|
|
'Token secret was set'
|
|
|
|
|
);
|
2017-09-19 14:47:10 +00:00
|
|
|
|
});
|
|
|
|
|
|
2019-03-13 00:04:16 +00:00
|
|
|
|
// TODO: unskip once store.unloadAll reliably waits for in-flight requests to settle
|
2021-12-28 14:45:20 +00:00
|
|
|
|
skip('the x-nomad-token header gets sent with requests once it is set', async function (assert) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
const { secretId } = managementToken;
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await JobDetail.visit({ id: job.id });
|
|
|
|
|
await ClientDetail.visit({ id: node.id });
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.ok(
|
|
|
|
|
server.pretender.handledRequests.length > 1,
|
|
|
|
|
'Requests have been made'
|
|
|
|
|
);
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
server.pretender.handledRequests.forEach((req) => {
|
2020-05-21 00:46:29 +00:00
|
|
|
|
assert.notOk(getHeader(req, 'x-nomad-token'), `No token for ${req.url}`);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
});
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2019-03-14 18:35:46 +00:00
|
|
|
|
const requestPosition = server.pretender.handledRequests.length;
|
2018-07-10 07:39:02 +00:00
|
|
|
|
|
2019-03-14 18:35:46 +00:00
|
|
|
|
await Tokens.visit();
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Tokens.secret(secretId).submit();
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await JobDetail.visit({ id: job.id });
|
|
|
|
|
await ClientDetail.visit({ id: node.id });
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
const newRequests = server.pretender.handledRequests.slice(requestPosition);
|
|
|
|
|
assert.ok(newRequests.length > 1, 'New requests have been made');
|
2017-09-19 14:47:10 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
// Cross-origin requests can't have a token
|
2021-12-28 14:45:20 +00:00
|
|
|
|
newRequests.forEach((req) => {
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
getHeader(req, 'x-nomad-token'),
|
|
|
|
|
secretId,
|
|
|
|
|
`Token set for ${req.url}`
|
|
|
|
|
);
|
2017-10-14 18:53:48 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('an error message is shown when authenticating a token fails', async function (assert) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
const { secretId } = managementToken;
|
|
|
|
|
const bogusSecret = 'this-is-not-the-secret';
|
|
|
|
|
assert.notEqual(
|
|
|
|
|
secretId,
|
|
|
|
|
bogusSecret,
|
|
|
|
|
'bogus secret is not somehow coincidentally equal to the real secret'
|
|
|
|
|
);
|
2017-10-14 18:53:48 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Tokens.visit();
|
|
|
|
|
await Tokens.secret(bogusSecret).submit();
|
2017-10-14 18:53:48 +00:00
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
window.localStorage.nomadTokenSecret,
|
|
|
|
|
null,
|
|
|
|
|
'Token secret is discarded on failure'
|
|
|
|
|
);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
assert.ok(Tokens.errorMessage, 'Token error message is shown');
|
|
|
|
|
assert.notOk(Tokens.successMessage, 'Token success message is not shown');
|
|
|
|
|
assert.equal(Tokens.policies.length, 0, 'No token policies are shown');
|
2017-10-14 18:53:48 +00:00
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('a success message and a special management token message are shown when authenticating succeeds', async function (assert) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
const { secretId } = managementToken;
|
2017-10-14 18:53:48 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Tokens.visit();
|
|
|
|
|
await Tokens.secret(secretId).submit();
|
2017-10-14 18:53:48 +00:00
|
|
|
|
|
2022-05-05 20:05:13 +00:00
|
|
|
|
await percySnapshot(assert);
|
|
|
|
|
|
2019-03-13 00:04:16 +00:00
|
|
|
|
assert.ok(Tokens.successMessage, 'Token success message is shown');
|
|
|
|
|
assert.notOk(Tokens.errorMessage, 'Token error message is not shown');
|
|
|
|
|
assert.ok(Tokens.managementMessage, 'Token management message is shown');
|
|
|
|
|
assert.equal(Tokens.policies.length, 0, 'No token policies are shown');
|
2017-10-14 18:53:48 +00:00
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('a success message and associated policies are shown when authenticating succeeds', async function (assert) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
const { secretId } = clientToken;
|
|
|
|
|
const policy = clientToken.policies.models[0];
|
|
|
|
|
policy.update('description', 'Make sure there is a description');
|
2017-10-14 18:53:48 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Tokens.visit();
|
|
|
|
|
await Tokens.secret(secretId).submit();
|
2017-10-14 18:53:48 +00:00
|
|
|
|
|
2019-03-13 00:04:16 +00:00
|
|
|
|
assert.ok(Tokens.successMessage, 'Token success message is shown');
|
|
|
|
|
assert.notOk(Tokens.errorMessage, 'Token error message is not shown');
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.notOk(
|
|
|
|
|
Tokens.managementMessage,
|
|
|
|
|
'Token management message is not shown'
|
|
|
|
|
);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
Tokens.policies.length,
|
|
|
|
|
clientToken.policies.length,
|
|
|
|
|
'Each policy associated with the token is listed'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const policyElement = Tokens.policies.objectAt(0);
|
|
|
|
|
|
|
|
|
|
assert.equal(policyElement.name, policy.name, 'Policy Name');
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
policyElement.description,
|
|
|
|
|
policy.description,
|
|
|
|
|
'Policy Description'
|
|
|
|
|
);
|
2019-03-13 00:04:16 +00:00
|
|
|
|
assert.equal(policyElement.rules, policy.rules, 'Policy Rules');
|
2017-09-19 14:47:10 +00:00
|
|
|
|
});
|
2017-10-18 23:42:08 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('setting a token clears the store', async function (assert) {
|
2019-03-13 00:04:16 +00:00
|
|
|
|
const { secretId } = clientToken;
|
2017-10-18 23:42:08 +00:00
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Jobs.visit();
|
2017-10-18 23:42:08 +00:00
|
|
|
|
assert.ok(find('.job-row'), 'Jobs found');
|
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Tokens.visit();
|
|
|
|
|
await Tokens.secret(secretId).submit();
|
2017-10-18 23:42:08 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
server.pretender.get('/v1/jobs', function () {
|
2017-10-18 23:42:08 +00:00
|
|
|
|
return [200, {}, '[]'];
|
|
|
|
|
});
|
|
|
|
|
|
2019-03-14 06:44:53 +00:00
|
|
|
|
await Jobs.visit();
|
2017-10-18 23:42:08 +00:00
|
|
|
|
|
2019-03-13 00:04:16 +00:00
|
|
|
|
// If jobs are lingering in the store, they would show up
|
|
|
|
|
assert.notOk(find('[data-test-job-row]'), 'No jobs found');
|
|
|
|
|
});
|
2017-10-19 02:04:19 +00:00
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('when the ott query parameter is present upon application load it’s exchanged for a token', async function (assert) {
|
2021-04-01 18:21:30 +00:00
|
|
|
|
const { oneTimeSecret, secretId } = managementToken;
|
|
|
|
|
|
|
|
|
|
await JobDetail.visit({ id: job.id, ott: oneTimeSecret });
|
2021-04-13 16:56:59 +00:00
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.notOk(
|
|
|
|
|
currentURL().includes(oneTimeSecret),
|
|
|
|
|
'OTT is cleared from the URL after loading'
|
|
|
|
|
);
|
2021-04-13 16:56:59 +00:00
|
|
|
|
|
2021-04-01 18:21:30 +00:00
|
|
|
|
await Tokens.visit();
|
|
|
|
|
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
window.localStorage.nomadTokenSecret,
|
|
|
|
|
secretId,
|
|
|
|
|
'Token secret was set'
|
|
|
|
|
);
|
2021-04-01 18:21:30 +00:00
|
|
|
|
});
|
|
|
|
|
|
2021-12-28 14:45:20 +00:00
|
|
|
|
test('when the ott exchange fails an error is shown', async function (assert) {
|
2021-04-01 18:21:30 +00:00
|
|
|
|
await visit('/?ott=fake');
|
|
|
|
|
|
|
|
|
|
assert.ok(Layout.error.isPresent);
|
|
|
|
|
assert.equal(Layout.error.title, 'Token Exchange Error');
|
2021-12-28 16:08:12 +00:00
|
|
|
|
assert.equal(
|
|
|
|
|
Layout.error.message,
|
|
|
|
|
'Failed to exchange the one-time token.'
|
|
|
|
|
);
|
2021-04-01 18:21:30 +00:00
|
|
|
|
});
|
|
|
|
|
|
2019-03-13 00:04:16 +00:00
|
|
|
|
function getHeader({ requestHeaders }, name) {
|
|
|
|
|
// Headers are case-insensitive, but object property look up is not
|
|
|
|
|
return (
|
2019-03-13 01:09:19 +00:00
|
|
|
|
requestHeaders[name] ||
|
|
|
|
|
requestHeaders[name.toLowerCase()] ||
|
|
|
|
|
requestHeaders[name.toUpperCase()]
|
2019-03-13 00:04:16 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|