Skip to content

Conversation

hellobontempo
Copy link
Contributor

Description

Fetching mounts in the component started to feel really awkward and resulted in a lot of manual state management. The sys/internal/ui/mounts request has to be re-fetched anytime the namespace query param changes anyway (which can happen when the namespace input is updated).

While I don't entirely agree with the namespace being a query param in the URL (see note below) it's out of scope to change it for this auth form refactor work. In short, fetching this data in the route model hook seems to most sensible and as you can see drastically cleaned up the component logic 🎉

Why the namespace param in the url is confusing
The namespace architecture of the web ui (and vault) is confusing because there is a narrow distinction between authenticating vs navigating to a namespace.

  • authenticating: Users can only log in to namespace where their auth method is mounted**. For example, if the ldap method is mounted in the admin/ namespace, users can only log in to the admin namespace.
  • navigating: Once authenticated, users can navigate to whatever namespace their policy grants access to. So if a user logs in the admin/ but has access to admin/west they can navigate to that namespace. But they cannot authenticate to admin/west

**Tokens generated in a namespace can log in without specifying the namespace and will be navigated accordingly because their root namespace is returned as part of the token data.

TODO only if you're a HashiCorp employee

  • Backport Labels: If this fix needs to be backported, use the appropriate backport/ label that matches the desired release branch. Note that in the CE repo, the latest release branch will look like backport/x.x.x, but older release branches will be backport/ent/x.x.x+ent.
    • LTS: If this fixes a critical security vulnerability or severity 1 bug, it will also need to be backported to the current LTS versions of Vault. To ensure this, use all available enterprise labels.
  • ENT Breakage: If this PR either 1) removes a public function OR 2) changes the signature
    of a public function, even if that change is in a CE file, double check that
    applying the patch for this PR to the ENT repo and running tests doesn't
    break any tests. Sometimes ENT only tests rely on public functions in CE
    files.
  • Jira: If this change has an associated Jira, it's referenced either
    in the PR description, commit message, or branch name.
  • RFC: If this change has an associated RFC, please link it in the description.
  • ENT PR: If this change has an associated ENT PR, please link it in the
    description. Also, make sure the changelog is in this PR, not in your ENT PR.

@hellobontempo hellobontempo requested a review from a team as a code owner May 3, 2025 00:16
@hellobontempo hellobontempo added this to the 1.20.0-rc milestone May 3, 2025
@github-actions github-actions bot added the hashicorp-contributed-pr If the PR is HashiCorp (i.e. not-community) contributed label May 3, 2025
Copy link

github-actions bot commented May 3, 2025

Build Results:
All builds succeeded! ✅

Copy link

github-actions bot commented May 3, 2025

CI Results:
All Go tests succeeded! ✅

Comment on lines -164 to -166
this.authTabs = null;
// fetch mounts for that namespace
this.fetchMounts.perform(500);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no longer necessary since the namespace update re-fires the model hook which re-requests mounts 🎉

@@ -22,7 +22,7 @@
@text="Sign in"
@isFullWidth={{true}}
type="submit"
class="has-top-margin-m has-bottom-margin-m"
class="has-top-margin-xl has-bottom-margin-xl"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept accidentally clicking "Sign in with other methods" 🙃 so added some spacing


initializeState() {
// FORMAT MOUNT DATA
this.authTabData = this._formatTabs();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting happens here instead of in the route because there will be some additional logic if the cluster has login customizations (like a default method set)

Comment on lines -204 to -211
// SET FORM STATE
if (!this.args.preselectedAuthType) {
// set selectedAuthMethod auth type to first tab if nothing has been preselected
this.setAuthTypeFromTab(0);
}
// selectedTabIndex returns -1 if selectedAuthMethod is not a tab (i.e. preselected method exists)
// so display the dropdown of other methods (and not tabs)
this.showOtherMethods = this.selectedTabIndex < 0 ? true : false;
Copy link
Contributor Author

@hellobontempo hellobontempo May 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setting up the form state moved to initializeFormState

onSuccess: CallableFunction;
}

interface AuthTabs {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to a d.ts file

@value={{@namespace}}
autocomplete="namespace"
@value={{@namespaceValue}}
autocomplete="off"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow-on from #30444


get cspError() {
const isStandby = this.args.cluster.standby;
const hasConnectionViolations = this.csp.connectionViolations.length;
return isStandby && hasConnectionViolations ? CSP_ERROR : '';
}

get authTabData() {
Copy link
Contributor Author

@hellobontempo hellobontempo May 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This getter will eventually also include logic for managing tabs depending on the login customization settings. I decided it should live here because it only needs to be computed once (based on the fetch mounts request in the route) and does not change with user interactions (which everything in Auth::FormTemplate does).

It could also technically live in the route, but having it in the component makes it easier to test

}

resetController(controller) {
controller.set('authMethod', 'token');
}

afterModel() {
afterModel(model) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the transition to the afterModel hook because Error: TransitionAborted was occasionally failing the wrapped_token tests. This way the model gets to cleanly finish its transition and then we redirect the user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double 🎉

}
return super.model(...arguments);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super.model() returned the cluster model previously

model() {
return this.modelFor('vault.cluster');
},

clusterId,
backend: 'token',
data: { token: auth.clientToken },
selectedAuth: 'token',
});
// handles transition
return authController.send('authSuccess', authResponse);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to afterModel hook

@@ -17,7 +17,7 @@ export const BASE_LOGIN_METHODS = [
},
{
type: 'userpass',
displayName: 'Username',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lots of methods use username and password to login, changed this to match vault documentation so it's clear this is referencing the userpass auth type

@@ -7,15 +7,14 @@ import Component from '@glimmer/component';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love to see these no longer needed

import { ALL_LOGIN_METHODS, supportedTypes } from 'vault/utils/supported-login-methods';
import { getRelativePath } from 'core/utils/sanitize-path';

import type FlagsService from 'vault/services/flags';
import type Store from '@ember-data/store';
import type VersionService from 'vault/services/version';
import type ClusterModel from 'vault/models/cluster';
import type { AuthTabData } from 'vault/vault/auth/form';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the double 'vault/vault' intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -29,32 +28,24 @@ import type { HTMLElementEvent } from 'vault/forms';
* dynamically renders the corresponding form.
*
*
* @param {object} authTabData - auth methods to render as tabs, contains mount data for any mounts with listing_visibility="unauth"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great description!

@@ -155,9 +155,12 @@ module('Acceptance | oidc provider', function (hooks) {
'Once you log in, you will be redirected back to your application. If you require login credentials, contact your administrator.',
'Has updated text for client authorization flow'
);
await fillIn(AUTH_FORM.method, authMethodPath);

await fillIn(GENERAL.selectByAttr('auth-method'), 'userpass');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the cleanup!

Copy link
Contributor

@Monkeychip Monkeychip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Biggest comment is on the use of setTimeout. However, this is side-branch and I don't consider it blocking but more of a recommendation. Really great description on the PR—that makes any future questions/debugging so much easier. Thank you for taking the time to be detailed there.

@hellobontempo hellobontempo merged commit e77f206 into VAULT-35470/wire-up-accessible-auth-components May 5, 2025
25 checks passed
@hellobontempo hellobontempo deleted the fetch-mounts-in-route branch May 5, 2025 17:05
hellobontempo added a commit that referenced this pull request May 8, 2025
* 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>
Erfankam pushed a commit to Erfankam/vault that referenced this pull request Sep 1, 2025
* UI: Move `wrapped_token` login functionality to route (hashicorp#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 (hashicorp#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 (hashicorp#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 (hashicorp#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` (hashicorp#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 (hashicorp#30527)

* delete old components

* update codeowners

* Update `with` query param functionality (hashicorp#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hashicorp-contributed-pr If the PR is HashiCorp (i.e. not-community) contributed pr/no-changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants