Files
vault/ui/tests/acceptance/auth-test.js
Chelsea Shaw 872f31fa1d UI: remove renew self call after login (#28204)
* check for renewAfterEpoch before comparing it

* add test coverage for regression

* add comment. Fixes VAULT-4630

* throw error

* add changelog
2024-08-28 10:05:29 -05:00

212 lines
6.9 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { click, currentURL, visit, waitUntil, find, fillIn } from '@ember/test-helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { allSupportedAuthBackends, supportedAuthBackends } from 'vault/helpers/supported-auth-backends';
import VAULT_KEYS from 'vault/tests/helpers/vault-keys';
const AUTH_FORM = {
method: '[data-test-select=auth-method]',
token: '[data-test-token]',
login: '[data-test-auth-submit]',
};
const ENT_AUTH_METHODS = ['saml'];
const { rootToken } = VAULT_KEYS;
module('Acceptance | auth', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
test('auth query params', async function (assert) {
const backends = supportedAuthBackends();
assert.expect(backends.length + 1);
await visit('/vault/auth');
assert.strictEqual(currentURL(), '/vault/auth?with=token');
for (const backend of backends.reverse()) {
await fillIn(AUTH_FORM.method, backend.type);
assert.strictEqual(
currentURL(),
`/vault/auth?with=${backend.type}`,
`has the correct URL for ${backend.type}`
);
}
});
test('it clears token when changing selected auth method', async function (assert) {
await visit('/vault/auth');
await fillIn(AUTH_FORM.token, 'token');
await fillIn(AUTH_FORM.method, 'github');
await fillIn(AUTH_FORM.method, 'token');
assert.dom(AUTH_FORM.token).hasNoValue('it clears the token value when toggling methods');
});
module('it sends the right payload when authenticating', function (hooks) {
hooks.beforeEach(function () {
this.assertReq = () => {};
this.server.get('/auth/token/lookup-self', (schema, req) => {
this.assertReq(req);
req.passthrough();
});
this.server.post('/auth/:mount/login', (schema, req) => {
// github only
this.assertReq(req);
req.passthrough();
});
this.server.post('/auth/:mount/oidc/auth_url', (schema, req) => {
// For JWT and OIDC
this.assertReq(req);
req.passthrough();
});
this.server.post('/auth/:mount/login/:username', (schema, req) => {
this.assertReq(req);
req.passthrough();
});
this.server.put('/auth/:mount/sso_service_url', (schema, req) => {
// SAML only (enterprise)
this.assertReq(req);
req.passthrough();
});
this.expected = {
token: {
url: '/v1/auth/token/lookup-self',
payload: {
'X-Vault-Token': 'some-token',
},
},
userpass: {
url: '/v1/auth/custom-userpass/login/some-username',
payload: {
password: 'some-password',
},
},
ldap: {
url: '/v1/auth/custom-ldap/login/some-username',
payload: {
password: 'some-password',
},
},
okta: {
url: '/v1/auth/custom-okta/login/some-username',
payload: {
password: 'some-password',
},
},
jwt: {
url: '/v1/auth/custom-jwt/oidc/auth_url',
payload: {
redirect_uri: 'http://localhost:7357/ui/vault/auth/custom-jwt/oidc/callback',
role: 'some-role',
},
},
oidc: {
url: '/v1/auth/custom-oidc/oidc/auth_url',
payload: {
redirect_uri: 'http://localhost:7357/ui/vault/auth/custom-oidc/oidc/callback',
role: 'some-role',
},
},
radius: {
url: '/v1/auth/custom-radius/login/some-username',
payload: {
password: 'some-password',
},
},
github: {
url: '/v1/auth/custom-github/login',
payload: {
token: 'some-token',
},
},
saml: {
url: '/v1/auth/custom-saml/sso_service_url',
payload: {
role: 'some-role',
},
},
};
});
for (const backend of allSupportedAuthBackends().reverse()) {
test(`for ${backend.type} ${
ENT_AUTH_METHODS.includes(backend.type) ? '(enterprise)' : ''
}`, async function (assert) {
const { type } = backend;
const expected = this.expected[type];
const isOidc = ['oidc', 'jwt'].includes(type);
assert.expect(isOidc ? 6 : 2);
this.assertReq = (req) => {
const body = type === 'token' ? req.requestHeaders : JSON.parse(req.requestBody);
if (isOidc && !body.role) {
// OIDC and JWT auth form calls the endpoint every time the role or mount is updated.
// if role is not provided, it means we haven't filled out the full info yet so don't
// validate the payload until all data is provided
// eslint-disable-next-line qunit/no-early-return
return {};
}
assert.strictEqual(req.url, expected.url, `${type} calls the correct URL`);
Object.keys(expected.payload).forEach((expKey) => {
assert.strictEqual(
body[expKey],
expected.payload[expKey],
`${type} payload includes ${expKey} with expected value`
);
});
};
await visit('/vault/auth');
await fillIn(AUTH_FORM.method, type);
if (type !== 'token') {
// set custom mount
await click('[data-test-auth-form-options-toggle]');
await fillIn('[data-test-auth-form-mount-path]', `custom-${type}`);
}
backend.formAttributes.forEach(async (key) => {
// fill in all form items, except JWT which is not rendered
if (key === 'jwt') return;
await fillIn(`[data-test-${key}]`, `some-${key}`);
});
await click(AUTH_FORM.login);
});
}
});
test('it shows the push notification warning after submit', async function (assert) {
assert.expect(1);
this.server.get(
'/auth/token/lookup-self',
async () => {
assert.ok(
await waitUntil(() => find('[data-test-auth-message="push"]')),
'shows push notification message'
);
return {};
},
{ timing: 1000 }
);
await visit('/vault/auth');
await fillIn(AUTH_FORM.method, 'token');
await click('[data-test-auth-submit]');
});
test('it does not call renew-self after successful login with non-renewable token', async function (assert) {
this.server.post(
'/auth/token/renew-self',
() => new Error('should not call renew-self directly after logging in')
);
await visit('/vault/auth');
await fillIn(AUTH_FORM.method, 'token');
await fillIn(AUTH_FORM.token, rootToken);
await click('[data-test-auth-submit]');
assert.strictEqual(currentURL(), '/vault/dashboard');
});
});