vault/ui/tests/integration/components/auth-jwt-test.js
Jordan Reimer d4766766f2
Ember Upgrade to 4.4 (#17086)
* runs ember-cli-update to 4.4.0

* updates yarn.lock

* updates dependencies causing runtime errors (#17135)

* Inject Store Service When Accessed Implicitly (#17345)

* adds codemod for injecting store service

* adds custom babylon parser with decorators-legacy plugin for jscodeshift transforms

* updates inject-store-service codemod to only look for .extend object expressions and adds recast options

* runs inject-store-service codemod on js files

* replace query-params helper with hash (#17404)

* Updates/removes dependencies throwing errors in Ember 4.4 (#17396)

* updates ember-responsive to latest

* updates ember-composable-helpers to latest and uses includes helper since contains was removed

* updates ember-concurrency to latest

* updates ember-cli-clipboard to latest

* temporary workaround for toolbar-link component throwing errors for using params arg with LinkTo

* adds missing store injection to auth configure route

* fixes issue with string-list component throwing error for accessing prop in same computation

* fixes non-iterable query params issue in mfa methods controller

* refactors field-to-attrs to handle belongsTo rather than fragments

* converts mount-config fragment to belongsTo on auth-method model

* removes ember-api-actions and adds tune method to auth-method adapter

* converts cluster replication attributes from fragment to relationship

* updates ember-data, removes ember-data-fragments and updates yarn to latest

* removes fragments from secret-engine model

* removes fragment from test-form-model

* removes commented out code

* minor change to inject-store-service codemod and runs again on js files

* Remove LinkTo positional params (#17421)

* updates ember-cli-page-object to latest version

* update toolbar-link to support link-to args and not positional params

* adds replace arg to toolbar-link component

* Clean up js lint errors (#17426)

* replaces assert.equal to assert.strictEqual

* update eslint no-console to error and disables invididual intended uses of console

* cleans up hbs lint warnings (#17432)

* Upgrade bug and test fixes (#17500)

* updates inject-service codemod to take arg for service name and runs for flashMessages service

* fixes hbs lint error after merging main

* fixes flash messages

* updates more deps

* bug fixes

* test fixes

* updates ember-cli-content-security-policy and prevents default form submission throwing errors

* more bug and test fixes

* removes commented out code

* fixes issue with code-mirror modifier sending change event on setup causing same computation error

* Upgrade Clean Up (#17543)

* updates deprecation workflow and filter

* cleans up build errors, removes unused ivy-codemirror and sass and updates ember-cli-sass and node-sass to latest

* fixes control groups test that was skipped after upgrade

* updates control group service tests

* addresses review feedback

* updates control group service handleError method to use router.currentURL rather that transition.intent.url

* adds changelog entry
2022-10-18 09:46:02 -06:00

244 lines
8.0 KiB
JavaScript

import { _cancelTimers as cancelTimers } from '@ember/runloop';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, settled, waitUntil } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import sinon from 'sinon';
import Pretender from 'pretender';
import { resolve } from 'rsvp';
import { create } from 'ember-cli-page-object';
import form from '../../pages/components/auth-jwt';
import { ERROR_WINDOW_CLOSED, ERROR_MISSING_PARAMS, ERROR_JWT_LOGIN } from 'vault/components/auth-jwt';
import { fakeWindow, buildMessage } from '../../helpers/oidc-window-stub';
const component = create(form);
const windows = [];
fakeWindow.reopen({
init() {
this._super(...arguments);
windows.push(this);
},
open() {
return fakeWindow.create();
},
close() {
windows.forEach((w) => w.trigger('close'));
},
});
const OIDC_AUTH_RESPONSE = {
auth: {
client_token: 'token',
},
};
const renderIt = async (context, path = 'jwt') => {
let handler = (data, e) => {
if (e && e.preventDefault) e.preventDefault();
return resolve();
};
let fake = fakeWindow.create();
context.set('window', fake);
context.set('handler', sinon.spy(handler));
context.set('roleName', '');
context.set('selectedAuthPath', path);
await render(hbs`
<AuthJwt
@window={{this.window}}
@roleName={{this.roleName}}
@selectedAuthPath={{this.selectedAuthPath}}
@onError={{action (mut this.error)}}
@onLoading={{action (mut this.isLoading)}}
@onToken={{action (mut this.token)}}
@onNamespace={{action (mut this.namespace)}}
@onSelectedAuth={{action (mut this.selectedAuth)}}
@onSubmit={{action this.handler}}
@onRoleName={{action (mut this.roleName)}}
/>
`);
};
module('Integration | Component | auth jwt', function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
this.openSpy = sinon.spy(fakeWindow.proto(), 'open');
this.owner.lookup('service:router').reopen({
urlFor() {
return 'http://example.com';
},
});
this.server = new Pretender(function () {
this.get('/v1/auth/:path/oidc/callback', function () {
return [200, { 'Content-Type': 'application/json' }, JSON.stringify(OIDC_AUTH_RESPONSE)];
});
this.post('/v1/auth/:path/oidc/auth_url', (request) => {
let body = JSON.parse(request.requestBody);
if (body.role === 'test') {
return [
200,
{ 'Content-Type': 'application/json' },
JSON.stringify({
data: {
auth_url: 'http://example.com',
},
}),
];
}
if (body.role === 'okta') {
return [
200,
{ 'Content-Type': 'application/json' },
JSON.stringify({
data: {
auth_url: 'http://okta.com',
},
}),
];
}
return [400, { 'Content-Type': 'application/json' }, JSON.stringify({ errors: [ERROR_JWT_LOGIN] })];
});
});
});
hooks.afterEach(function () {
this.openSpy.restore();
this.server.shutdown();
});
test('it renders the yield', async function (assert) {
await render(hbs`<AuthJwt @onSubmit={{action (mut this.submit)}}>Hello!</AuthJwt>`);
assert.strictEqual(component.yieldContent, 'Hello!', 'yields properly');
});
test('jwt: it renders and makes auth_url requests', async function (assert) {
await renderIt(this);
await settled();
assert.ok(component.jwtPresent, 'renders jwt field');
assert.ok(component.rolePresent, 'renders jwt field');
assert.strictEqual(this.server.handledRequests.length, 1, 'request to the default path is made');
assert.strictEqual(this.server.handledRequests[0].url, '/v1/auth/jwt/oidc/auth_url');
this.set('selectedAuthPath', 'foo');
await settled();
assert.strictEqual(this.server.handledRequests.length, 2, 'a second request was made');
assert.strictEqual(
this.server.handledRequests[1].url,
'/v1/auth/foo/oidc/auth_url',
'requests when path is set'
);
});
test('jwt: it calls passed action on login', async function (assert) {
await renderIt(this);
await component.login();
assert.ok(this.handler.calledOnce);
});
test('oidc: test role: it renders', async function (assert) {
await renderIt(this);
await settled();
this.set('selectedAuthPath', 'foo');
await component.role('test');
await settled();
assert.notOk(component.jwtPresent, 'does not show jwt input for OIDC type login');
assert.strictEqual(component.loginButtonText, 'Sign in with OIDC Provider');
await component.role('okta');
// 1 for initial render, 1 for each time role changed = 3
assert.strictEqual(this.server.handledRequests.length, 4, 'fetches the auth_url when the path changes');
assert.strictEqual(
component.loginButtonText,
'Sign in with Okta',
'recognizes auth methods with certain urls'
);
});
test('oidc: it calls window.open popup window on login', async function (assert) {
await renderIt(this);
this.set('selectedAuthPath', 'foo');
await component.role('test');
component.login();
await waitUntil(() => {
return this.openSpy.calledOnce;
});
cancelTimers();
let call = this.openSpy.getCall(0);
assert.deepEqual(
call.args,
['http://example.com', 'vaultOIDCWindow', 'width=500,height=600,resizable,scrollbars=yes,top=0,left=0'],
'called with expected args'
);
});
test('oidc: it calls error handler when popup is closed', async function (assert) {
await renderIt(this);
this.set('selectedAuthPath', 'foo');
await component.role('test');
component.login();
await waitUntil(() => {
return this.openSpy.calledOnce;
});
this.window.close();
await settled();
assert.strictEqual(this.error, ERROR_WINDOW_CLOSED, 'calls onError with error string');
});
test('oidc: shows error when message posted with state key, wrong params', async function (assert) {
await renderIt(this);
this.set('selectedAuthPath', 'foo');
await component.role('test');
component.login();
await waitUntil(() => {
return this.openSpy.calledOnce;
});
this.window.trigger(
'message',
buildMessage({ data: { source: 'oidc-callback', state: 'state', foo: 'bar' } })
);
cancelTimers();
assert.strictEqual(this.error, ERROR_MISSING_PARAMS, 'calls onError with params missing error');
});
test('oidc: storage event fires with state key, correct params', async function (assert) {
await renderIt(this);
this.set('selectedAuthPath', 'foo');
await component.role('test');
component.login();
await waitUntil(() => {
return this.openSpy.calledOnce;
});
this.window.trigger('message', buildMessage());
await settled();
assert.strictEqual(this.token, 'token', 'calls onToken with token');
assert.ok(this.handler.calledOnce, 'calls the onSubmit handler');
});
test('oidc: fails silently when event origin does not match window origin', async function (assert) {
await renderIt(this);
this.set('selectedAuthPath', 'foo');
await component.role('test');
component.login();
await waitUntil(() => {
return this.openSpy.calledOnce;
});
this.window.trigger('message', buildMessage({ origin: 'http://hackerz.com' }));
cancelTimers();
await settled();
assert.notOk(this.handler.called, 'should not call the submit handler');
});
test('oidc: fails silently when event is not trusted', async function (assert) {
await renderIt(this);
this.set('selectedAuthPath', 'foo');
await component.role('test');
component.login();
await waitUntil(() => {
return this.openSpy.calledOnce;
});
this.window.trigger('message', buildMessage({ isTrusted: false }));
cancelTimers();
await settled();
assert.notOk(this.handler.called, 'should not call the submit handler');
});
});