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

Use Web MFA dialog for admin actions #50373

Open
wants to merge 16 commits into
base: joerger/fix-useMfa-error-state
Choose a base branch
from

Conversation

Joerger
Copy link
Contributor

@Joerger Joerger commented Dec 18, 2024

Changelog: Add MFA dialog in the WebUI for Admin actions instead of automatically opening up a webauthn/sso pop up.

Adds a global MFA context for prompting MFA from non-react contexts. Currently this is only used for admin actions, which prompts for MFA from basic API requests.

Depends on #49794

@Joerger Joerger changed the title Use Web MFA Dialog for Admin actui Use Web MFA dialog for admin actions Dec 18, 2024
@Joerger Joerger mentioned this pull request Dec 18, 2024
@Joerger Joerger force-pushed the joerger/web-admin-mfa-dialog branch from 18064df to aa5c0b7 Compare December 18, 2024 19:37
@Joerger Joerger marked this pull request as ready for review December 18, 2024 20:00
@github-actions github-actions bot requested review from avatus and gzdunek December 18, 2024 20:01
@Joerger Joerger requested review from ryanclark and bl-nero December 18, 2024 20:02
@Joerger Joerger force-pushed the joerger/sso-mfa-method branch from 235d2e1 to cfe07e1 Compare December 19, 2024 02:35
@Joerger Joerger force-pushed the joerger/web-admin-mfa-dialog branch 3 times, most recently from bf14661 to 4c3551c Compare December 19, 2024 03:08
@gzdunek
Copy link
Contributor

gzdunek commented Dec 19, 2024

Three levels of dialogs 💀
image

Maybe this one should be closed as soon as the user selects a method? I see an error in the background anyways and here I can't take any action.
image

@Joerger Joerger force-pushed the joerger/sso-mfa-method branch 2 times, most recently from 5ee3d03 to e103a1f Compare December 19, 2024 20:28
Base automatically changed from joerger/sso-mfa-method to master December 20, 2024 04:10
@Joerger Joerger force-pushed the joerger/web-admin-mfa-dialog branch from 4c3551c to e77d074 Compare January 2, 2025 21:32
@Joerger
Copy link
Contributor Author

Joerger commented Jan 3, 2025

@gzdunek

Three levels of dialogs 💀

Yeah, it might be nice to do some type of moving flow like we do for device management. e.g. edit user -> verify your identity in the same dialog, with option to continue (mfa challenge) or back (edit user page with error telling user mfa is required).

Maybe this one should be closed as soon as the user selects a method? I see an error in the background anyways and here I can't take any action.

Thanks for pointing this out, the cancellation logic turned out to be pretty fragile and only worked well for per-session MFA with SSH sessions. I've fixed it so you should now see just one error at a time - 0149c12

Screenshot 2025-01-02 at 7 57 22 PM
Screenshot 2025-01-02 at 7 57 32 PM

Also, you should be able to retry or cancel in the mfa dialog. Let me know if you still get locked with my changes. useMfa isn't safe to be called multiple times at the same time, so it's possible you're running into the consequences of that somehow?

web/packages/teleport/src/lib/useMfa.ts Outdated Show resolved Hide resolved
web/packages/teleport/src/MFAContext/MFAContext.tsx Outdated Show resolved Hide resolved
web/packages/teleport/src/services/auth/auth.ts Outdated Show resolved Hide resolved
web/packages/teleport/src/services/api/api.ts Outdated Show resolved Hide resolved
@avatus
Copy link
Contributor

avatus commented Jan 3, 2025

@bl-nero take a look at this one when you get some time please

@Joerger Joerger force-pushed the joerger/web-admin-mfa-dialog branch 2 times, most recently from cb74946 to 34fead1 Compare January 3, 2025 21:09
@Joerger Joerger requested review from ryanclark and gzdunek January 3, 2025 21:09
web/packages/teleport/src/lib/useMfa.ts Outdated Show resolved Hide resolved
web/packages/teleport/src/services/api/api.ts Outdated Show resolved Hide resolved
* This is intended as a workaround for such cases, and should not be used
* for methods with access to the React scope. Use useMfa directly instead.
*/
export const MfaContextProvider = ({ children }: PropsWithChildren) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this unset the mfaContext in auth/api on unmount? (I'm not sure if that matters)

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'm not sure how unmounting in React works, how would I go about this?

web/packages/teleport/src/lib/useMfa.ts Outdated Show resolved Hide resolved
setTimeout(() => {
if (!mfaContext)
throw new Error(
'Failed to set up MFA prompt for admin action. This is a bug.'
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this surface to the user? Should we be more helpful than "This is a bug"?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, looking at this again - this error doesn't go anywhere, as it's thrown within a setTimeout

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, for now I'll remove the timeout and just return a better error message:

Failed to set up MFA prompt for admin action. Please try refreshing the page to try again. If the issue persists, contact support as this is likely a bug.

web/packages/teleport/src/services/joinToken/joinToken.ts Outdated Show resolved Hide resolved
Comment on lines 41 to 48
const [mfaCtx, setMfaCtx] = useState<MfaContextValue>();

if (!mfaCtx) {
const mfaCtx = { getMfaChallengeResponse };
setMfaCtx(mfaCtx);
auth.setMfaContext(mfaCtx);
api.setMfaContext(mfaCtx);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using an initializer function. It will save you a re-render and make the state more consistent.

Suggested change
const [mfaCtx, setMfaCtx] = useState<MfaContextValue>();
if (!mfaCtx) {
const mfaCtx = { getMfaChallengeResponse };
setMfaCtx(mfaCtx);
auth.setMfaContext(mfaCtx);
api.setMfaContext(mfaCtx);
}
const [mfaCtx, setMfaCtx] = useState<MfaContextValue>(()=> {
const mfaCtx = { getMfaChallengeResponse };
auth.setMfaContext(mfaCtx);
api.setMfaContext(mfaCtx);
return mfaCtx;
});

// Since this is a global object outside of the react scope, there is a marginal
// chance for a race condition here (the react scope should generally be initialized
// before this has a chance of being called). This conditional is not expected to
// be hit, but will catch any major issues that could arise from this solution.
Copy link
Contributor

@bl-nero bl-nero Jan 7, 2025

Choose a reason for hiding this comment

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

Hmm. This is quite a hack. The fact that auth service started to depend on an MFA context that is injected on the top level by context provider makes me think that it should be turned into a class (just like the MFA service) that is instantiated by TeleportContext. This would allow establishing a link to the MFA service/context/whatever when constructing the auth service. Will it be a big refactoring?

Copy link
Contributor Author

@Joerger Joerger Jan 7, 2025

Choose a reason for hiding this comment

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

It does sound like a big refactor to me, but I'm not really in a position with my level of typescript/React experience to judge or carry out this type of refactor. I also have some other important work to move onto. Do you think it's something we can live with today and fix tomorrow, or do we need to scrap this approach for now?

Note that without this change, we still support SSO MFA for admin actions, we just don't provide the user with the choice between SSO MFA and Webauthn when applicable. Instead we automatically open the Webauthn or SSO MFA pop up without a dialog, which may be jarring, but not the end of the world. In the long term we should find a solution.

Copy link
Contributor

Choose a reason for hiding this comment

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

@Joerger I think that given above, it would be best to continue with the PR as is, and treat this part as a technical debt that we take to improve UX. Can you please create a tracking issue for this refactoring?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Joerger Joerger force-pushed the joerger/web-admin-mfa-dialog branch from 34fead1 to ebade41 Compare January 8, 2025 19:19
@Joerger Joerger requested review from ryanclark and bl-nero January 8, 2025 19:24
@Joerger Joerger changed the base branch from master to joerger/fix-useMfa-error-state January 8, 2025 20:27
@Joerger Joerger force-pushed the joerger/web-admin-mfa-dialog branch from ebade41 to b5581df Compare January 8, 2025 20:30
@Joerger Joerger force-pushed the joerger/web-admin-mfa-dialog branch from 7f9a2a2 to 9db6d2b Compare January 8, 2025 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants