claire bontempo 9832c90037
UI: Implement accessible auth form components (#30500)
* UI: Move `wrapped_token` login functionality to route (#30465)

* move token unwrap functionality to page component

* update mfa test

* remove wrapped_token logic from page component

* more cleanup to relocate unwrap logic

* move wrapped_token to route

* move unwrap tests to acceptance

* move mfa form back

* add some padding

* update mfa-form tests

* get param from params

* wait for auth form on back

* run rests

* UI: Add MFA support for SSO methods (#30489)

* initial implementation of mfa validation for sso methods

* update typescript interfaces

* add stopgap changes to auth service

* switch order backend is defined

* update login form for tests even though it will be deleted

* attempt to stabilize wrapped_query test

* =update login form test why not

* Update ui/app/components/auth/form/saml.ts

Co-authored-by: lane-wetmore <lane.wetmore@hashicorp.com>

---------

Co-authored-by: lane-wetmore <lane.wetmore@hashicorp.com>

* Move CSP error to page component (#30492)

* initial implementation of mfa validation for sso methods

* update typescript interfaces

* add stopgap changes to auth service

* switch order backend is defined

* update login form for tests even though it will be deleted

* attempt to stabilize wrapped_query test

* =update login form test why not

* move csp error to page component

* move csp error to page component

* Move fetching unauthenticated mounts to the route (#30509)

* rename namespace arg to namespaceQueryParam

* move fetch mounts to route

* add margin to sign in button spacing

* update selectors for oidc provider test

* add todo delete comments

* fix arg typo in test

* change method name

* fix args handling tab click

* remove tests that no longer relate to components functionality

* add tests for preselectedAuthType functionality

* move typescript interfaces, fix selector

* add await

* oops

* move format method down, make private

* move tab formatting to the route

* move to page object

* fix token unwrap aborting transition

* not sure what that is doing there..

* add comments

* rename to presetAuthType

* use did-insert instead

* UI: Implement `Auth::FormTemplate` (#30521)

* replace Auth::LoginForm with Auth::FormTemplate

* first round of test updates

* return null if mounts object is empty

* add comment and test for empty sys/internal/mounts data

* more test updates

* delete listing_visibility test, delete login-form component test

* update divs to Hds::Card::Container

* add overflow class

* remove unused getters

* move requesting stored auth type to page component

* fix typo

* Update ui/app/components/auth/form/oidc-jwt.ts

make comment make more sense

* small cleanup items, update imports

* Delete old auth components (#30527)

* delete old components

* update codeowners

* Update `with` query param functionality (#30537)

* update path input to type=hidden

* add test coverage

* update page test

* update auth route

* delete login form

* update ent test

* consolidate logic in getter

* add more comments

* more comments..

* rename selector

* refresh model as well

* redirect for invalid query params

* move unwrap to redirect

* only redirect on invalid query params

* add tests for query param

* test selector updates

* remove todos, update relevant ones with initials

* add changelog

---------

Co-authored-by: lane-wetmore <lane.wetmore@hashicorp.com>
2025-05-08 09:58:20 -07:00

104 lines
3.1 KiB
TypeScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import AuthBase from './base';
import { action } from '@ember/object';
import { service } from '@ember/service';
import { task, timeout } from 'ember-concurrency';
import { tracked } from '@glimmer/tracking';
import { waitFor } from '@ember/test-waiters';
import errorMessage from 'vault/utils/error-message';
import uuid from 'core/utils/uuid';
import type AuthService from 'vault/vault/services/auth';
/**
* @module Auth::Form::Okta
* see Auth::Base
* */
export default class AuthFormOkta extends AuthBase {
@service declare readonly auth: AuthService;
@tracked challengeAnswer = '';
@tracked oktaVerifyError = '';
@tracked showNumberChallenge = false;
loginFields = [{ name: 'username' }, { name: 'password' }];
login = task(
waitFor(async (data) => {
// wait for 1s to wait to see if there is a login error before polling
await timeout(1000);
data.nonce = uuid();
this.pollForOktaNumberChallenge.perform(data.nonce, data.path);
try {
// selecting the correct okta verify answer on the personal device resolves this request
const authResponse = await this.auth.authenticate({
clusterId: this.args.cluster.id,
backend: this.args.authType,
data,
selectedAuth: this.args.authType,
});
this.handleAuthResponse(authResponse);
} catch (error) {
// if a user fails the okta verify challenge, the POST login request fails (made by this.auth.authenticate above)
// bubble those up for consistency instead of managing error state in this component
this.onError(error as Error);
// cancel polling tasks and reset state
this.reset();
}
})
);
pollForOktaNumberChallenge = task(
waitFor(async (nonce, mountPath) => {
this.showNumberChallenge = true;
// keep polling /auth/okta/verify/:nonce API every 1s until response returns with correct_number
let verifyNumber = null;
while (verifyNumber === null) {
await timeout(1000);
verifyNumber = await this.requestOktaVerify(nonce, mountPath);
}
// display correct number so user can select on personal MFA device
this.challengeAnswer = verifyNumber ?? '';
})
);
@action
async requestOktaVerify(nonce: string, mountPath: string) {
const url = `/v1/auth/${mountPath}/verify/${nonce}`;
try {
const response = await this.auth.ajax(url, 'GET', {});
return response.data.correct_answer;
} catch (e) {
const error = e as Response;
if (error?.status === 404) {
// if error status is 404 return null to keep polling for a response
return null;
} else {
// this would be unusual, but handling just in case
this.oktaVerifyError = errorMessage(e);
return;
}
}
}
@action
reset() {
// reset tracked variables and stop polling tasks
this.challengeAnswer = '';
this.oktaVerifyError = '';
this.showNumberChallenge = false;
this.login.cancelAll();
this.pollForOktaNumberChallenge.cancelAll();
}
}