Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI/update auth form to fetchRoles after a namespace is inputted, prior to OIDC auth #19541

Merged
merged 6 commits into from
Mar 21, 2023

Conversation

hellobontempo
Copy link
Contributor

@hellobontempo hellobontempo commented Mar 14, 2023

So this was tricky to reproduce and due to the whack-a-mole nature of these bugs, here is a very thorough breakdown:

The auth form component updates as the namespace changes to show the correct associated login methods (and corresponding button styles, if applicable). This means the form often reverts to the dropdown menu because by default auth methods are not listed as tabs when unauthenticated (this is a separate config option)

Notice in the gif below, there is an oidc tab because in /Root oidc has been configured so listing_visibility='unauth' (docs). However, as another namespace is typed, the default form changes because testns has no unuath'd methods.


the bug 🐛

For both OIDC and JWT, the role is updated when the method is selected and the AuthJwt component fires off its didReceiveAttrs lifecycle hook which runs the task fetchRole with whatever namespace has been set by the url params.

If a user very quickly types in a namespace (admin) that has the same method (oidc), mounted at the same path (also oidc) but only one of them have a default role configured (stick with me!) then the UI remains on the oidc tab, but the task to fetch for a role is not re-fired with the new namespace value. This is because the fetchRole only fires if the auth path has changed. You can see in the gif when we go from root to the admin namespace, we get the Invalid role error because root does not have a default role. However, after refreshing, the namespace stays in the url params and thus the role is set properly.

oidc-bug

fix 🔧

Because the component is often torn down when the namespace changes it doesn't make sense to check if the namespace has changed (like we do for the auth path by this.oldSelectedAuthPath !== this.selectedAuthPath).

Instead, opted to reorder the methods in startOIDCAuth and tested with the following situations to insure the bug fixes introduced by #17661 were preserved.

  1. oidc method mounted at incorrect-uris-oidc/ with missing URI data
  2. mounted at missing-role-oidc with no role configured
  3. mounted at proper-config-oidc with a default role setup, properly
    fix-oidc

@hellobontempo hellobontempo added ui bug Used to indicate a potential bug labels Mar 15, 2023
@hellobontempo hellobontempo marked this pull request as ready for review March 15, 2023 01:33
@Monkeychip
Copy link
Contributor

Thanks for going after this. I know we're waiting for an AD FS environment, but a reminder to add the backport labels.

@hellobontempo
Copy link
Contributor Author

Thanks for going after this. I know we're waiting for an AD FS environment, but a reminder to add the backport labels.

This is a different bug actually, so no need to wait for AD FS to reproduce. There aren't release milestone tags made for the next patch version yet - so holding off on adding PR tags until they've been created. Should have mentioned this!

@hellobontempo hellobontempo changed the title UI/re-fetch roles if there is a namespace UI/fix auth form updating with namespace and fetchRoles before performing OIDC authentication Mar 16, 2023
@hellobontempo hellobontempo changed the title UI/fix auth form updating with namespace and fetchRoles before performing OIDC authentication UI/update auth form so fetchRoles happens after a namespace is inputted, prior to OIDC auth Mar 16, 2023
@hellobontempo hellobontempo changed the title UI/update auth form so fetchRoles happens after a namespace is inputted, prior to OIDC auth UI/update auth form to fetchRoles after a namespace is inputted, prior to OIDC auth Mar 16, 2023
Copy link
Contributor

@zofskeez zofskeez left a comment

Choose a reason for hiding this comment

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

🚀

Comment on lines +174 to +181
try {
await this.fetchRole.perform(this.roleName, { debounce: false });
} catch (error) {
// this task could be cancelled if the instances in didReceiveAttrs resolve after this was started
if (error?.name !== 'TaskCancelation') {
throw error;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I can't see an issue with moving this above the conditional. If anything, since a role is required it should have come before in the first place to ensure we have the necessary data.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's my understanding? I'm guessing it wasn't above before because firing it off in didReceiveAttrs seems like it'd be sufficient. Unfortunately the conditionals that wrap fetchRole in that function don't account for the namespace updating

@@ -32,18 +32,16 @@
</li>
{{/let}}
{{/each}}
{{#if this.hasMethodsWithPath}}
Copy link
Contributor

Choose a reason for hiding this comment

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

This condition is already wrapped higher up correct? It looks like removing it is the only change here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah - meant to comment. It looked like this was redundant? So removed to clean it up - but want to make sure I'm not misreading...

@@ -88,4 +89,90 @@ module('Acceptance | Enterprise | namespaces', function (hooks) {
'Does not prepend root to namespace'
);
});

module('auth form', function (hooks) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think I've seen modules nested in other modules before. Neat idea!

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 copied @hashishaw 's idea from the pki tests, thought it was a neat way to organize. (And make the setup reusable if/when we add more namespace tests?) : https://github.com/hashicorp/vault/blob/main/ui/tests/acceptance/pki/pki-engine-workflow-test.js#L154

Copy link
Contributor

Choose a reason for hiding this comment

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

🎉

Copy link
Contributor

@hashishaw hashishaw left a comment

Choose a reason for hiding this comment

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

A couple smol comments. Great test coverage and comments!


module('auth form', function (hooks) {
setupMirage(hooks);
const SELECTORS = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Usually these live outside of the module, not sure if it's necessary but this here caught me off guard

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I didn't know what to do with the module in a module situation? Should I move them just outside this module? or outside the "parent" module?

});
await visit('/vault/auth?with=oidc%2F');
assert.dom(SELECTORS.authTab(this.rootOidc)).exists('renders oidc method tab for root');
await authPage.namespaceInput(this.namespace);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it worth using the typeIn method here rather than the page object's fillable (which I think uses fillin under the hood)?

Copy link
Contributor Author

@hellobontempo hellobontempo Mar 20, 2023

Choose a reason for hiding this comment

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

I actually used fillIn on purpose because that's what caused the bug in the first place

Copy link
Contributor

@hashishaw hashishaw left a comment

Choose a reason for hiding this comment

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

Played around with this locally too, I think this is a reasonable approach for the fix! But I hope the next time we touch this file it's to rewrite it 🙃 Thank you for the very thorough bug description/breakdown!

@hellobontempo hellobontempo added this to the 1.13.1 milestone Mar 21, 2023
hellobontempo added a commit that referenced this pull request Mar 23, 2023
…is inputted, prior to OIDC auth #19541 (#19661)

* UI/update auth form to fetchRoles after a namespace is inputted, prior to OIDC auth (#19541)

* re-fetch roles if there is a namespace

* remove redundant conditional

* reorder oidc auth operations

* add test

* test cleanup

* add changelog

* UI: fix enterprise test failures (#19671)

* move oidc tests into new file

* remove module from namespace test

* remove entered line

* add logout to afterEach hook

* remove ns test

* move test setup to within test

* use logout.visit() instead

* updates oidc auth namespaces test

* reverts to authPage logout

---------

Co-authored-by: Jordan Reimer <zofskeez@gmail.com>

---------

Co-authored-by: Jordan Reimer <zofskeez@gmail.com>
@hellobontempo hellobontempo deleted the ui/VAULT-12868/update-auth-method-with-direct-nav branch March 23, 2023 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Used to indicate a potential bug ui
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants